- TypeScript 92.9%
- Python 6%
- CSS 0.6%
- Dockerfile 0.3%
- HTML 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| apps | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| bun.lock | ||
| docker-compose.dev.yml | ||
| docker-compose.prod.yml | ||
| docker-compose.synology.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| generate_pdf_report.py | ||
| generate_pos_data.py | ||
| generate_restaurant_data.py | ||
| nginx.conf | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| restaurant_performance_report.pdf | ||
| restaurant_pos_data.csv | ||
Phê La POS System
🎯 Overview
A modern Point of Sale (POS) System built for the Phê La Vietnamese coffee & tea chain. Designed for multi-store operations with real-time inventory, sales analytics, and role-based access control.
🏗️ Architecture
graph TB
A[🌐 React 19 + Vite 6] -->|REST API| B[🔧 NestJS 11 + Prisma]
B --> C[(PostgreSQL 17)]
B --> D[🔴 Redis 7]
A -->|Static Assets| E[🌐 Nginx]
style A fill:#61DAFB,color:#000
style B fill:#E0234E,color:#fff
style C fill:#4169E1,color:#fff
style D fill:#DC382D,color:#fff
style E fill:#009639,color:#fff
🛠️ Tech Stack
| Layer | Technology | Version |
|---|---|---|
| Frontend | React, Vite, TanStack Router/Query, Tailwind CSS v4, i18next | 19 / 6 |
| Backend | NestJS, Prisma ORM, JWT, PDFKit, ExcelJS | 11 |
| Database | PostgreSQL, Redis | 17 / 7 |
| Container | Docker (multi-stage), Nginx | Latest |
🚀 Quick Start
Prerequisites
- Docker & Docker Compose
- Bun (optional, for local development)
🐳 Quick Start with Docker Compose
# Clone and start
git clone https://git.khoavo.myds.me/vndangkhoa/POSv.git
cd POSv
docker compose up --build -d
# Check status
docker compose ps
# View logs
docker compose logs -f api
# Stop services
docker compose down
# Full reset (removes data volumes)
docker compose down -v
🔧 Local Development
# Install dependencies
bun install
# Start development servers
bun run dev # API at http://localhost:3000
cd apps/web && bun run dev # Web at http://localhost:5173
# Database
bun run db:push # Push schema changes
bun run db:studio # Prisma Studio
bun run seed # Seed demo data
# Testing
bun run test # Unit tests
bun run test:e2e # E2E tests
Synology NAS Deployment
Deploy the full stack on a Synology NAS using Container Manager (GUI).
Prerequisites
- Synology NAS with Container Manager installed (Package Center)
- SSH access (optional, for manual migration/seed)
- Registry login: In Container Manager → Registry → Settings → add
https://git.khoavo.myds.mewith your Forgejo username & token
Setup Steps
1. Prepare the project folder
On your Synology, create a shared folder (e.g., posv) via File Station. Upload the entire project directory into it (or clone via Git if SSH is available).
2. Create .env file
In the project folder, create a .env file with your production settings:
DB_USER=pos
DB_PASSWORD=pos_secret
DB_NAME=pos_management
JWT_SECRET=your-strong-random-secret-here
JWT_EXPIRATION=7d
JWT_REFRESH_EXPIRATION=30d
CORS_ORIGIN=http://localhost:8080,http://192.168.1.100:8080
Replace 192.168.1.100 with your Synology NAS IP address.
3. Import the stack into Container Manager
- Open Container Manager on your Synology DSM
- Go to Project → Add
- Select the project folder (e.g.,
/volume1/posv) - Set the file to
docker-compose.synology.yml - Click Next → Apply
Container Manager will pull the pre-built images from the registry and start all services.
4. Run database migration
After the stack is running, run the migration service:
# Via SSH into the Synology:
cd /volume1/posv
docker compose -f docker-compose.synology.yml --profile migrate run --rm migrate
Or from Container Manager: go to Project → select your project → YAML Settings → add --profile migrate to the run command, then start the migrate service manually.
5. (Optional) Seed demo data
# SSH into the Synology:
docker compose -f docker-compose.synology.yml exec api bun add prisma
docker compose -f docker-compose.synology.yml exec api bun prisma/seed-phela.ts
Access the System
| Service | URL |
|---|---|
| Web App | http://<synology-ip>:8080 |
| API | http://<synology-ip>:3000/api |
| API Docs (Swagger) | http://<synology-ip>:3000/api/docs |
Login Credentials
| Role | Email / Code | Password |
|---|---|---|
| Super Admin | admin@phela.vn |
admin@123 |
| Store Manager | manager.hanoi@phela.vn |
manager@123 |
| Staff (Kiosk) | NV001 – NV016 |
1234 |
Update & Restart
git pull
docker compose -f docker-compose.synology.yml pull
docker compose -f docker-compose.synology.yml up -d
# Re-run migration if schema changed
docker compose -f docker-compose.synology.yml --profile migrate run --rm migrate
🔐 Demo Accounts
Primary Seed (bun run seed:phela)
| Role | Email / Code | Password | Access |
|---|---|---|---|
| Super Admin | admin@phela.vn |
admin@123 |
Full system access, all stores |
| Store Manager | manager.hanoi@phela.vn |
manager@123 |
Phê La Phạm Ngọc Thạch (HN) |
| Store Manager | manager.dalat@phela.vn |
manager@123 |
Phê La Nguyễn Chí Thanh (ĐL) |
| Store Manager | manager.danang@phela.vn |
manager@123 |
Phê La Bạch Đằng (ĐN) |
| Store Manager | manager.hcm@phela.vn |
manager@123 |
Phê La Hai Bà Trưng (HCM) |
| Store Manager | manager.nhatrang@phela.vn |
manager@123 |
Phê La Trần Phú (NT) |
| Store Manager | manager.haiphong@phela.vn |
manager@123 |
Phê La Bùi Thị Xuân (HP) |
Mock Seed (bun run seed:mock — adds staff + 30-day orders)
| Role | Code | PIN | Access |
|---|---|---|---|
| Staff | NV001 – NV016 |
1234 |
POS/Kiosk mode only |
Staff Login: Uses
code+PINat/kioskroute
🐳 Docker Compose Files
| File | Purpose |
|---|---|
docker-compose.yml |
Default stack (postgres, redis, api, web on port 80) |
docker-compose.dev.yml |
Dev services (postgres, redis only — run API/web locally) |
docker-compose.prod.yml |
Production variant (web on port 8080) |
docker-compose.synology.yml |
Synology NAS optimized (pre-built images, web on 8080, healthchecks, migrate profile) |
Quick Reference (docker-compose.synology.yml)
services:
postgres:
image: postgres:17-alpine
environment:
POSTGRES_USER: pos
POSTGRES_PASSWORD: pos_secret
POSTGRES_DB: pos_management
volumes: [postgres_data:/var/lib/postgresql/data]
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U pos -d pos_management"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
volumes: [redis_data:/data]
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
api:
image: git.khoavo.myds.me/vndangkhoa/posv-api:latest
environment:
NODE_ENV: production
PORT: 3000
DATABASE_URL: postgresql://pos:pos_secret@postgres:5432/pos_management
REDIS_URL: redis://redis:6379
JWT_SECRET: ${JWT_SECRET}
CORS_ORIGIN: http://localhost:8080,http://${HOST_IP:-localhost}:8080
ports: ["3000:3000"]
depends_on:
postgres: { condition: service_healthy }
redis: { condition: service_healthy }
volumes: [uploads:/app/uploads]
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
web:
image: git.khoavo.myds.me/vndangkhoa/posv-web:latest
ports: ["8080:80"]
depends_on:
api: { condition: service_healthy }
restart: unless-stopped
volumes:
postgres_data:
redis_data:
uploads:
🔌 API Endpoints
| Module | Endpoints |
|---|---|
| Auth | POST /api/auth/login, POST /api/auth/staff-login, GET /api/auth/me |
| Products | GET /api/products, POST /api/products, POST /api/products/import |
| Sales | GET /api/sales/orders, GET /api/sales/revenue |
| Inventory | GET /api/inventory/stock, POST /api/inventory/adjustment |
| Reports | GET /api/reports/summary, GET /api/reports/export |
| Users | GET /api/users, POST /api/users |
| Dashboard | GET /api/dashboard |
📊 Reports
The system generates professional PDF reports:
| Report | Description |
|---|---|
| 📈 Weekly Revenue | By category, day, hour with charts |
| 🏆 Top Products | By quantity & revenue |
| 💳 Payment Methods | Breakdown by type |
| 👥 Staff Performance | Sales & ratings per staff |
| 📄 Restaurant POS Report | Professional PDF template with charts |
# Download restaurant POS report (PDF)
curl -H "Authorization: Bearer <token>" \
http://localhost:3000/api/reports/export/restaurant-pos \
-o restaurant-report.pdf
📁 Project Structure
POSv/
├── apps/
│ ├── api/ # NestJS API
│ │ ├── src/
│ │ ├── prisma/ # Database schema
│ │ └── Dockerfile
│ └── web/ # React + Vite
│ ├── src/
│ └── Dockerfile
├── docker-compose.yml
├── docker-compose.dev.yml
├── docker-compose.prod.yml
<<<<<<< HEAD
=======
├── docker-compose.synology.yml # Synology Container Manager
>>>>>>> 9d41116 (feat: initial POS system with Docker & Synology support)
├── nginx.conf
└── package.json
🧪 Development Commands
| Command | Description |
|---|---|
bun run dev |
Start API in watch mode |
cd apps/web && bun run dev |
Start web dev server |
bun run db:push |
Push Prisma schema to DB |
bun run db:studio |
Prisma Studio |
bun run seed |
Seed demo data |
bun run seed:mock |
Generate 30-day mock data |
bun run raw:phela |
Generate 90-day Phê La raw data |
bun run import:raw |
Import raw data into DB |
bun run test |
Run unit tests |
bun run test:e2e |
Run E2E tests |
🌱 Seed Data
The system includes realistic Phê La mock data:
| Entity | Details |
|---|---|
| Stores | 4 locations (Phê La Mới, Trung Tâm, Sài Gòn, Vườn Đào) |
| Products | 26 items (Cà Phê, Moka Pot, French Press, Syphon, Cold Brew, Trà Ô Long, Ô Long Matcha, Toppings) |
| Staff | 13 members with PIN login |
| Sales | 30/90-day realistic patterns |
| Pricing | Realistic VND pricing |