# POS System — End-to-End Testing Checklist Work through this top-to-bottom. Each section depends on the one above it. Mark `[x]` as you go. Note failures with a short comment. --- ## 0. Prerequisites - [ ] Docker Desktop is running - [ ] You are in the project root: `c:\development\simple-pos-system` - [ ] All `.env` files are filled in correctly (see below) ### .env quick reference **`cloud_backend/.env`** ``` SECRET_KEY= DATABASE_URL=sqlite:////app/data/cloud.db ACCESS_TOKEN_EXPIRE_MINUTES=60 ADMIN_USERNAME=sysadmin ADMIN_PASSWORD= ``` **`local_backend/.env`** ``` SITE_ID= SITE_KEY= CLOUD_URL=http://cloud_backend:8001 SECRET_KEY= LICENSE_GRACE_HOURS=24 ``` **`sysadmin_panel/.env`** ``` VITE_CLOUD_URL=http://localhost:8001 ``` **`waiter_pwa/.env`** ``` VITE_API_URL=http://:8000 ``` **`manager_dashboard/.env`** ``` VITE_API_URL=http://:8000 ``` --- ## 1. Cloud Backend ### 1.1 Start ```bash docker compose up cloud_backend -d ``` - [ ] Container starts without errors (`docker compose logs cloud_backend`) ### 1.2 Health check ``` GET http://localhost:8001/health ``` - [ ] Returns `{"status": "ok"}` ### 1.3 Sysadmin login ``` POST http://localhost:8001/api/auth/login Body: { "username": "sysadmin", "password": "changeme" } ``` - [ ] Returns a JWT `access_token` - [ ] Save token for next steps ### 1.4 List sites (empty) ``` GET http://localhost:8001/api/sites/ Header: Authorization: Bearer ``` - [ ] Returns `[]` (empty list) --- ## 2. Sysadmin Panel ### 2.1 Start ```bash docker compose up sysadmin_panel -d ``` - [ ] Container starts, `npm install` completes, dev server on port 5175 ### 2.2 Open in browser ``` http://localhost:5175 ``` - [ ] Redirects to `/login` - [ ] Login form appears (username + password, NOT pin pad) ### 2.3 Login - [ ] Enter `sysadmin` / `changeme` → redirects to `/sites` - [ ] Sites page shows "0 registered", "Register New Site" button visible - [ ] Summary counts (Active / Locked / Expired) visible ### 2.4 Register a site - Click "Register New Site" - [ ] Form fields: Restaurant Name, Owner Name, Contact Email, License Expiry - [ ] Fill in test data, set expiry date to at least 1 year from now - [ ] Submit → success screen shows - [ ] **Site ID** and **Secret Key** are displayed - [ ] Warning banner "Copy this secret key now" is visible - [ ] "Copy .env vars" button works (copies to clipboard) - Copy the `SITE_ID` and `SITE_SECRET` values - Paste them into `local_backend/.env` as `SITE_ID=` and `SITE_KEY=` ### 2.5 Verify site in list - [ ] Navigate to `/sites` → new site card appears - [ ] Status shows yellow "No Heartbeat" (expected — local backend hasn't connected yet) - [ ] Click site card → SiteDetailPage shows correct name, owner, expiry - [ ] Lock/Unlock/Extend License buttons are visible --- ## 3. Local Backend ### 3.1 Start ```bash docker compose up backend -d ``` - [ ] Container starts without errors - [ ] Logs show: `Application startup complete` - [ ] Logs show cloud sync attempt: either `Cloud sync OK` or `Cloud sync failed` (if cloud URL not yet reachable from inside Docker — check `CLOUD_URL=http://cloud_backend:8001`) ### 3.2 Health check ``` GET http://localhost:8000/api/system/health ``` - [ ] Returns `{"status": "ok"}` (this endpoint is exempt from license check) ### 3.3 Heartbeat appears in sysadmin panel - [ ] In Sysadmin Panel → SiteDetailPage: "Last seen" updates to recent timestamp - [ ] Status indicator turns green "Active" - [ ] Last IP field shows the Docker container IP > Note: Cloud sync runs immediately on startup, so this should update within seconds. ### 3.4 Auth — create initial manager If no manager user exists in the DB yet, seed one via the seed script or direct API call: ```bash docker compose exec backend python seed.py ``` - [ ] Seed runs without errors (or manager already exists) ### 3.5 Auth — login as manager ``` POST http://localhost:8000/api/auth/login Body: { "username": "manager", "pin": "1234" } ``` - [ ] Returns `{ access_token, user: { id, username, role: "manager" } }` ### 3.6 Auth — login as waiter ``` POST http://localhost:8000/api/auth/login Body: { "username": "", "pin": "" } ``` - [ ] Returns token with `role: "waiter"` ### 3.7 Tables endpoint ``` GET http://localhost:8000/api/tables/ Header: Authorization: Bearer ``` - [ ] Returns list of tables (may be empty if not seeded) ### 3.8 Products endpoint ``` GET http://localhost:8000/api/products/ Header: Authorization: Bearer ``` - [ ] Returns list of products and categories --- ## 4. Manager Dashboard ### 4.1 Start ```bash docker compose up manager_dashboard -d ``` - [ ] Dev server starts on port 5174 ### 4.2 Open in browser ``` http://localhost:5174 ``` - [ ] Redirects to `/login` - [ ] PIN pad + username field visible ### 4.3 Login - [ ] Enter manager username + PIN → redirects to `/dashboard` - [ ] Dashboard shows table grid (empty or with existing tables) - [ ] No console errors ### 4.4 Tables page - [ ] Navigate to Tables → existing tables shown - [ ] Create a new table (e.g. Table 10) → appears in list - [ ] Table groups section visible ### 4.5 Products page - [ ] Navigate to Products → existing products shown - [ ] Create a new category - [ ] Create a new product in that category, assign a price - [ ] Toggle product availability → greyed out when unavailable - [ ] Assign a printer zone to a product (if printer is configured) - [ ] Product image upload works on an existing product ### 4.6 Waiters page - [ ] Navigate to Waiters → existing waiters shown - [ ] Create a new waiter (username + PIN) - [ ] Block/unblock a waiter works - [ ] Reset PIN works ### 4.7 Dashboard live grid - [ ] Open an order from the Waiter PWA (step 5 below), then return here - [ ] Table card updates within 30 seconds (polling interval) - [ ] Click table → OrderDetailPage loads with correct items ### 4.8 Reports page - [ ] Navigate to Reports → no crash - [ ] Date picker works, summary loads (may be empty) ### 4.9 Settings page - [ ] Navigate to Settings → no crash - [ ] Printer config visible --- ## 5. Waiter PWA ### 5.1 Open on phone (or browser) ``` http://:5173 ``` - [ ] App loads, redirects to `/login` - [ ] Username field + PIN pad visible ### 5.2 Login as waiter - [ ] Enter waiter credentials → redirects to table list - [ ] Only active tables visible (not deactivated ones) ### 5.3 Open a table order - [ ] Tap a table → if no open order, "Open Order" button appears - [ ] Tap "Open Order" → order is created, table turns active ### 5.4 Add items - [ ] Category tabs visible at top - [ ] Tap a product → added to order - [ ] Products with options show option selector - [ ] Products with removable ingredients show toggle list - [ ] Item with note field → can add freetext note ### 5.5 Verify print routing - [ ] After adding items: check printer (if connected) received the ticket - [ ] If no physical printer: check `docker compose logs backend` — should show print attempt log (success or failure, NOT a crash) ### 5.6 View order total - [ ] Order total shows correct sum (base price + selected option deltas) - [ ] Individual item prices shown ### 5.7 Partial payment - [ ] Select some items → "Mark as Paid" → those items turn grey/paid - [ ] Order status changes to "partially_paid" - [ ] Remaining total updates ### 5.8 Full payment and close - [ ] Mark all items as paid → order status = "paid" - [ ] "Close Order" button becomes active - [ ] Tap "Close Order" → confirmation prompt - [ ] Confirm → order closes, table returns to "available" ### 5.9 Multi-waiter scenario - [ ] From Manager Dashboard, add a second waiter to the order - [ ] Second waiter can see and manage the table in their PWA ### 5.10 Blocked waiter - [ ] From Manager Dashboard, block a waiter - [ ] That waiter is immediately redirected to login on their next PWA request (401 interceptor) --- ## 6. License / Lock Testing ### 6.1 Lock site from sysadmin panel - [ ] In Sysadmin Panel → SiteDetailPage → Lock Site → enter reason → confirm - [ ] Site shows "Locked" status with red indicator - [ ] Within the next sync cycle (or restart local backend to force immediate sync): - Local backend logs show lock status received - All local backend endpoints return HTTP 423 (except `/api/system/health`) - Waiter PWA shows error / cannot load data - Manager Dashboard shows error ### 6.2 Unlock - [ ] In Sysadmin Panel → Unlock Site - [ ] After next sync: local backend resumes normal operation ### 6.3 Expired license - [ ] In Sysadmin Panel → Extend License → set expiry date in the PAST → save - [ ] After local backend sync: returns HTTP 402 on all endpoints - [ ] Restore to future date → normal operation resumes ### 6.4 Cloud unreachable (grace period) - [ ] Stop cloud backend: `docker compose stop cloud_backend` - [ ] Local backend continues to serve requests (last known state + 24h grace) - [ ] Logs show repeated `Cloud sync failed` warnings - [ ] Restart cloud backend → next sync succeeds --- ## 7. Known Issues to Watch For - Product image upload only works on existing products (not at creation time) - Printer zone must be assigned via Manager Dashboard before items will route to a printer - Some manager/PWA interactions have rough edges (noted in CLAUDE_CODE_INSTRUCTIONS.md) - `SITE_KEY` in `local_backend/.env` must match the secret generated at site registration (copy it immediately, it's shown only once) --- ## Done? All steps checked → the system is fully operational end-to-end. Log any failures as GitHub issues or in `CLAUDE_CODE_INSTRUCTIONS.md` under a new "Phase 5 Known Issues" section.