Majumapan is a web-based Point of Sale (POS) system designed with offline-first architecture, featuring automatic synchronization when internet connectivity is restored. The system includes a dedicated Admin Panel for system administrators.
+-------------------+
| nginx |
| (reverse proxy) |
+---------+---------+
|
+---------------------+---------------------+
| | |
v v v
+---------------+ +---------------+ +---------------+
| POS Web | | Admin Panel | | API |
| (port 5173) | | (port 5174) | | (port 3000) |
| | | | | |
| pos.example | | admin.example | | api.example |
+---------------+ +---------------+ +---------------+
- Offline-First: Full functionality without internet using IndexedDB
- Auto-Sync: Background sync when connection restored
- Multi-Store: Support for multiple stores with isolated data
- Role-Based Access: Manager/Cashier with granular permissions
- Product Management: Categories, SKU, barcode scanning, images
- Stock Management: Real-time tracking, low-stock alerts
- Discounts: Product-level and cart-level coupons
- Transactions: Full POS checkout flow with cash/card
- Receipt Printing: Browser print dialog, 80mm thermal format
- Hold Orders: Temporarily save and resume in-progress orders
- Customer Display: Secondary window showing cart contents to customers in real-time
- Split Payments: Pay with multiple payment methods (documentation only, pending implementation)
- Dashboard: Daily sales summary, transaction history
- PWA: Installable app with offline support
- Dashboard: System-wide KPIs, store comparison, audit activity
- Store Management: CRUD operations for all stores
- User Management: Cross-store user administration
- Reports: Cross-store analytics, sales trends, top performers
- Audit Logs: Track all system activities with filters
- Data Management: CSV import/export for products, categories, users
- Settings: App-wide configuration (tax rate, currency, etc.)
| Layer | Technology |
|---|---|
| Monorepo | Turborepo |
| Runtime | Bun |
| Backend | Hono |
| Database | PostgreSQL + Drizzle ORM |
| Frontend | React + Vite |
| Styling | TailwindCSS |
| Local DB | Dexie.js (IndexedDB) |
| State | Zustand |
| Validation | Zod |
| PWA | vite-plugin-pwa |
| Container | Docker |
| Package | Purpose |
|---|---|
@pos/shared |
Shared types, Zod schemas, constants |
@pos/ui |
Reusable UI components (Button, Input, Modal, Card, etc.) |
@pos/api-client |
HTTP client with auth integration |
majumapan/
├── apps/
│ ├── api/ # Hono API server
│ │ └── src/
│ │ ├── db/ # Database schema, migrations, seed
│ │ ├── routes/ # API endpoints
│ │ ├── middleware/ # Auth, RBAC, error handling
│ │ └── utils/ # JWT, password, audit utilities
│ ├── web/ # POS web app (offline-first PWA)
│ │ └── src/
│ │ ├── components/ # React components
│ │ ├── pages/ # Page components
│ │ ├── hooks/ # Custom React hooks
│ │ ├── stores/ # Zustand stores
│ │ ├── services/ # API and sync services
│ │ ├── db/ # IndexedDB schema (Dexie.js)
│ │ └── lib/ # Utilities
│ └── admin/ # Admin panel (online-only)
│ └── src/
│ ├── components/ # React components
│ ├── pages/ # Page components
│ ├── stores/ # Zustand stores
│ ├── services/ # API services
│ └── lib/ # Utilities
├── packages/
│ ├── shared/ # Shared types, schemas, constants
│ ├── ui/ # Reusable UI components
│ └── api-client/ # HTTP client library
├── docker-compose.yml # Development Docker setup
├── docker-compose.prod.yml # Production Docker setup
└── PLAN.md # Detailed implementation plan
-
Clone the repository
git clone <repository-url> cd majumapan
-
Install dependencies
bun install
-
Set up environment variables
cp .env.example .env # Edit .env with your settings -
Start PostgreSQL
docker-compose up postgres -d
-
Run database migrations
cd apps/api bun run db:migrate -
Seed the database
bun run db:seed
-
Start development servers
# From root directory bun run devThis starts:
- API: http://localhost:3000
- POS Web: http://localhost:5173
- Admin Panel: http://localhost:5174
| Role | Password | PIN | Access | |
|---|---|---|---|---|
| Admin | admin@pos.local | admin123 | 000000 | Admin Panel only |
| Manager | manager@downtown.pos.local | manager123 | 111111 | POS Web |
| Cashier | cashier1@downtown.pos.local | cashier123 | 123456 | POS Web |
| Code | Description |
|---|---|
| WELCOME10 | $10 off (min $50 purchase) |
| SAVE20 | 20% off (min $100, max $50 discount) |
| SUMMER15 | 15% off (limited to 100 uses) |
-
Create production environment file
cp .env.example .env.production
-
Update production settings
POSTGRES_PASSWORD=secure_password_here JWT_SECRET=generate_secure_random_string
-
Build and start services
docker-compose -f docker-compose.prod.yml up -d --build
-
Run migrations and seed
docker-compose -f docker-compose.prod.yml exec api bun run db:migrate docker-compose -f docker-compose.prod.yml exec api bun run db:seed
The apps will be available at:
- POS Web: http://localhost (port 80)
- Admin Panel: http://localhost/admin (via nginx)
- API: proxied through nginx at /api
| Variable | Description | Default |
|---|---|---|
DATABASE_URL |
PostgreSQL connection string | - |
POSTGRES_USER |
Database user | pos_user |
POSTGRES_PASSWORD |
Database password | Required |
POSTGRES_DB |
Database name | pos |
JWT_SECRET |
JWT signing key | Required |
JWT_EXPIRES_IN |
Access token expiry | 15m |
REFRESH_TOKEN_EXPIRES_IN |
Refresh token expiry | 7d |
VITE_API_URL |
API URL for POS web | /api/v1 |
VITE_ADMIN_API_URL |
API URL for admin panel | /api/v1 |
POST /api/v1/auth/login- Login with email/passwordPOST /api/v1/auth/pin-login- Quick login with PINPOST /api/v1/auth/refresh- Refresh access tokenPOST /api/v1/auth/logout- Logout
GET /api/v1/stores- List storesPOST /api/v1/stores- Create storeGET /api/v1/stores/:id- Get storePUT /api/v1/stores/:id- Update storeDELETE /api/v1/stores/:id- Soft delete store
GET /api/v1/users- List usersPOST /api/v1/users- Create userGET /api/v1/users/:id- Get userPUT /api/v1/users/:id- Update userDELETE /api/v1/users/:id- Soft delete userPUT /api/v1/users/:id/password- Change passwordPUT /api/v1/users/:id/pin- Set PIN
GET /api/v1/categories- List categoriesPOST /api/v1/categories- Create categoryGET /api/v1/categories/:id- Get categoryPUT /api/v1/categories/:id- Update categoryDELETE /api/v1/categories/:id- Soft delete category
GET /api/v1/products- List products (paginated)POST /api/v1/products- Create productGET /api/v1/products/:id- Get productGET /api/v1/products/barcode/:code- Get by barcodePUT /api/v1/products/:id- Update productDELETE /api/v1/products/:id- Soft delete productPOST /api/v1/products/:id/image- Upload image
GET /api/v1/stock- List stock levelsPUT /api/v1/stock/:productId- Update stockPOST /api/v1/stock/adjust- Bulk adjustment
GET /api/v1/discounts- List discountsPOST /api/v1/discounts- Create discountGET /api/v1/discounts/:id- Get discountPUT /api/v1/discounts/:id- Update discountDELETE /api/v1/discounts/:id- Deactivate discountPOST /api/v1/discounts/validate- Validate coupon
GET /api/v1/transactions- List transactionsPOST /api/v1/transactions- Create transactionGET /api/v1/transactions/:id- Get transactionPOST /api/v1/transactions/:id/void- Void transactionGET /api/v1/transactions/:id/receipt- Get receipt
GET /api/v1/sync/full- Full data syncGET /api/v1/sync/pull?since=<timestamp>- Incremental pullPOST /api/v1/sync/push- Push offline transactionsGET /api/v1/sync/status- Sync status
GET /api/v1/audit-logs- List audit logs with filtersGET /api/v1/reports/system-overview- System-wide metricsGET /api/v1/reports/stores-comparison- Store comparisonGET /api/v1/reports/sales-by-store- Sales trendGET /api/v1/reports/top-stores- Top performing storesGET /api/v1/data/export/:type- Export data to CSVPOST /api/v1/data/import/:type- Import data from CSVGET /api/v1/settings- Get settingsPUT /api/v1/settings- Update settings
GET /api/v1/reports/daily- Daily sales summaryGET /api/v1/reports/products- Product sales reportGET /api/v1/reports/cashiers- Cashier performanceGET /api/v1/reports/export- Export report (CSV)
- Initial Login: Full sync downloads all store data to IndexedDB
- While Online: Auto-sync every 5 minutes
- While Offline: Transactions saved locally in queue
- Coming Online: Pending transactions pushed, changes pulled
- Rejected Transactions: UI to view, retry, or delete
Default: 10% (configurable in admin panel or app_settings table)
TXN-{YYYYMMDD}-{sequence}
30 days for synced transactions
# Install dependencies
bun install
# Start all development servers
bun run dev
# Start individual apps
bun run dev:api # API only
bun run dev:web # POS web only
bun run dev:admin # Admin panel only
# Build all apps
bun run build
# Build individual apps
bun run build:api
bun run build:web
bun run build:admin
# Database commands
bun run db:generate # Generate migrations
bun run db:migrate # Run migrations
bun run db:seed # Seed database
bun run db:reset # Reset and reseed
bun run db:studio # Open Drizzle Studio
# Type checking
bun run typecheck
# Linting
bun run lint
# Testing
bun run test
bun run test:run # Run tests once- PLAN.md - Detailed implementation plan
- docs/adr/ - Architecture Decision Records
- docs/features/ - Feature specifications
MIT