150 lines
7.9 KiB
Markdown
150 lines
7.9 KiB
Markdown
# Claude Code — Session Instructions
|
||
|
||
This file is your starting point for every Claude Code session on this project.
|
||
Paste it (or reference it) at the start of each session to give Claude Code full context.
|
||
|
||
---
|
||
|
||
## Project Summary
|
||
We are building a local-first restaurant POS system. Full architecture and specs live in the `PLANS AND STRATEGIES/` folder. Always read the relevant guide file before starting work on any component. For a complete picture of the entire system read `PROJECT_REFERENCE.md`.
|
||
|
||
## Guide Files
|
||
- `00_PROJECT_OVERVIEW.md` — Architecture, stack, build order
|
||
- `01_LOCAL_BACKEND.md` — FastAPI backend spec
|
||
- `02_WAITER_PWA.md` — Waiter-facing PWA spec
|
||
- `03_MANAGER_DASHBOARD.md` — Manager web app spec
|
||
- `04_CLOUD_BACKEND.md` — Cloud licensing backend spec
|
||
- `05_SYSADMIN_PANEL.md` — Sysadmin cloud panel spec
|
||
- `TESTING_CHECKLIST.md` — End-to-end testing guide (step-by-step)
|
||
- `PROJECT_REFERENCE.md` — Master reference: full system description, wiring, all env vars
|
||
|
||
## Git Workflow
|
||
- The project uses git. **Commit after every meaningful milestone** (e.g. after scaffolding a phase, after a feature is working, after a bug fix).
|
||
- Always commit before starting a new phase or major refactor.
|
||
- Keep commit messages short and descriptive. No co-author lines needed.
|
||
- Never commit `.env`, `*.db`, or `license_state.json` — they are in `.gitignore`.
|
||
|
||
## Ground Rules for Claude Code
|
||
1. **Read the guide before writing code.** Each guide has schema, endpoints, and UX specs. Follow them.
|
||
2. **Local backend first.** Nothing else can be built or tested without it.
|
||
3. **Ask before deviating.** If something in the spec seems wrong or ambiguous, ask — don't invent.
|
||
4. **Keep business logic in the backend.** Frontends are display + interaction only.
|
||
5. **Never store sensitive data in frontend localStorage beyond token + username.**
|
||
6. **All prices are stored and calculated on the backend.** Frontend only displays them.
|
||
7. **The `unit_price` on `order_items` is a snapshot** — it must be copied from the product price at the time of ordering, not referenced dynamically.
|
||
8. **Printer failures must never block order saves.** Log and continue.
|
||
|
||
---
|
||
|
||
## Current Build Phase
|
||
> All 5 phases are built. Now in testing / polish.
|
||
> Phase 1: Local Backend — [x] Complete. Smoke tested.
|
||
> Phase 2: Waiter PWA — [x] Complete. Smoke tested end-to-end.
|
||
> Phase 3: Manager Dashboard — [x] Complete. Scaffolded and smoke tested. Known rough edges remain.
|
||
> Phase 4: Cloud Backend — [x] Complete. Built, not yet smoke tested end-to-end with a real site.
|
||
> Phase 5: Sysadmin Panel — [x] Complete. Built, not yet smoke tested.
|
||
|
||
---
|
||
|
||
## Phase 2 Known Issues & Fixes Applied
|
||
- `OrderItemOut` schema now includes `product { id, name }` via `ProductNameOut` — required for item names to show correctly in the PWA.
|
||
- `OrderOut` schema now includes `waiters: List[OrderWaiterOut]` — required for `isMyOrder` check on the frontend.
|
||
- Close order button is enabled when there are zero active items (not just when all are paid) — allows closing an empty order.
|
||
- Printing silently skips items with no `printer_zone_id` — **expected**. Printer zones are assigned in Phase 3 (Manager Dashboard). No code change needed.
|
||
- `selected_options` and `removed_ingredients` on `OrderItemInput` now accept `List[dict]` from the PWA (name+price_delta objects and name strings respectively), stored as JSON in the DB. The printer service reads them as raw JSON — modifier names print correctly.
|
||
|
||
## Phase 3 — What Was Built
|
||
- Manager Dashboard: React+Vite, TailwindCSS, React Query, react-hot-toast. Port 5174.
|
||
- Pages: Login (PIN pad, manager/sysadmin only), Dashboard (live table grid, 30s polling), OrderDetailPage (full actions), ProductsPage, WaitersPage, TablesPage, ReportsPage, SettingsPage.
|
||
- Docker Compose service added.
|
||
|
||
## Phase 3 Known Issues & Fixes Applied
|
||
- `isMyOrder` was always false after page reload — fixed: `AuthRehydrator` fetches `/auth/me` on app load to rehydrate user from token.
|
||
- `OrderItemInput` schema mismatch fixed: backend now accepts `selected_options` as `List[{id, name, price_delta}]` objects (not int IDs).
|
||
- Blocked waiter now force-logged out of PWA on next request (401 interceptor).
|
||
- `opt.price_delta` fixed to read `opt.extra_cost` from backend schema.
|
||
- `GET /api/products/?all=true` added for manager to see unavailable products (greyed out, not hidden).
|
||
- `PUT /api/products/{id}` now replaces options, ingredients, and preference_sets.
|
||
- New: ProductPreferenceSet + ProductPreferenceChoice models (exclusive-choice per product).
|
||
- New: Product image upload — POST `/api/products/{id}/image`, stored at `/app/data/product_images`, served as static files. Docker volume: `./data/product_images:/app/data/product_images`.
|
||
- New: TableGroup model + endpoints (`/api/tables/groups`). Tables have `group_id` FK.
|
||
- New: `DELETE /api/tables/{id}?hard=true` for permanent delete vs deactivate.
|
||
- New: `POST /api/tables/batch` for bulk table creation with prefix + count.
|
||
- New: `POST /api/auth/me` endpoint.
|
||
- Auto-migration on startup adds new columns to existing SQLite DB without dropping data.
|
||
|
||
## Phase 3 Known Remaining Issues (to revisit)
|
||
- Some PWA/manager interactions still have rough edges — to be addressed in a dedicated polish pass.
|
||
- Product image upload requires the product to already exist (no upload on creation, only on edit).
|
||
|
||
## Phase 4 — What Was Built
|
||
- Cloud Backend: FastAPI, SQLite (dev) / PostgreSQL (prod), JWT auth. Port 8001.
|
||
- Endpoints: `POST /api/auth/login`, `GET|POST|PUT|DELETE /api/sites/:id`, lock/unlock actions, `POST /api/heartbeat/`.
|
||
- Admin account seeded from env vars on first startup (`ADMIN_USERNAME`, `ADMIN_PASSWORD`).
|
||
- Heartbeat: local backend posts every 6 hours with `X-Site-ID` + `X-Site-Key` headers; cloud returns license status.
|
||
- `cloud_sync.py` in local backend runs as background asyncio task, persists state to `license_state.json`.
|
||
- Grace period: if cloud unreachable, local backend continues operating for `LICENSE_GRACE_HOURS` (default 24h).
|
||
- Docker Compose service: `cloud_backend`, depends on nothing, data volume at `./data/cloud`.
|
||
|
||
## Phase 5 — What Was Built
|
||
- Sysadmin Panel: React+Vite, TailwindCSS, dark theme, cyan accent. Port 5175.
|
||
- Points to cloud backend (`VITE_CLOUD_URL`), NOT the local backend.
|
||
- Pages: LoginPage (username+password), SitesPage (card grid, 30s polling, summary counts), SiteDetailPage (lock/unlock/extend license/delete with confirmation modals), RegisterSitePage (form + one-time secret key display with copy button).
|
||
- Token stored as `sysadmin_token` in localStorage (separate key from manager dashboard).
|
||
- Docker Compose service: `sysadmin_panel`, depends on `cloud_backend`.
|
||
|
||
## Dev Data (seeded / created during development)
|
||
- Tables 1–6 exist in local DB
|
||
- Category "food" (id=1) + arakas product from Phase 1 smoke test
|
||
- Categories: Ποτά, Σαλάτες, Κυρίως — 3 products each
|
||
- Printer zones assignable via ProductsPage in Manager Dashboard
|
||
- Cloud DB: admin `sysadmin` / `changeme` seeded on first startup
|
||
|
||
---
|
||
|
||
## Environment Variables (current actual values)
|
||
|
||
### Local Backend (`local_backend/.env`)
|
||
```
|
||
SITE_ID=<from sysadmin panel site registration>
|
||
SITE_KEY=<secret key shown once at registration>
|
||
CLOUD_URL=http://cloud_backend:8001
|
||
SECRET_KEY=<long random string>
|
||
LICENSE_GRACE_HOURS=24
|
||
```
|
||
|
||
### Waiter PWA (`waiter_pwa/.env`)
|
||
```
|
||
VITE_API_URL=http://<local-machine-ip>:8000
|
||
```
|
||
|
||
### Manager Dashboard (`manager_dashboard/.env`)
|
||
```
|
||
VITE_API_URL=http://<local-machine-ip>:8000
|
||
```
|
||
|
||
### Cloud Backend (`cloud_backend/.env`)
|
||
```
|
||
SECRET_KEY=<long random string — different from local>
|
||
DATABASE_URL=sqlite:////app/data/cloud.db
|
||
ACCESS_TOKEN_EXPIRE_MINUTES=60
|
||
ADMIN_USERNAME=sysadmin
|
||
ADMIN_PASSWORD=<your password>
|
||
```
|
||
|
||
### Sysadmin Panel (`sysadmin_panel/.env`)
|
||
```
|
||
VITE_CLOUD_URL=http://localhost:8001
|
||
```
|
||
|
||
---
|
||
|
||
## Ports
|
||
| Service | Port |
|
||
|---|---|
|
||
| Local Backend | 8000 |
|
||
| Cloud Backend | 8001 |
|
||
| Waiter PWA | 5173 |
|
||
| Manager Dashboard | 5174 |
|
||
| Sysadmin Panel | 5175 |
|