Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cloud-service — VPS Pack
Everything that runs on the developer's VPS and serves all client sites.
This folder is its own git repo, nested inside the xenia-pos parent repo.
Read the global rules first: ../../docs/README.md. This file adds only the rules specific to this pack. The feature catalog, the local ↔ cloud contract, known issues and site records all live in the parent's
docs/.
Services
| Service | Stack | Host port | Audience |
|---|---|---|---|
cloud_backend |
FastAPI + SQLAlchemy + SQLite (${BACKEND_DATA}) |
8001 | local sites (heartbeat/sync), sysadmin, connect apps |
sysadmin_panel |
React + Vite (VITE_CLOUD_URL baked in at build) |
5175 | the developer only |
connect_frontend |
nginx serving two SPAs: menu-app at /menu/, manager-app at /manage/ |
3100 | restaurant customers (QR menu), remote managers |
TLS and domains are handled in front of these ports on the VPS (e.g. xenia-admin.bonamin.gr → cloud_backend).
Routers (cloud_backend/routers/)
| Prefix | File | Auth | Used by |
|---|---|---|---|
/api/auth |
auth.py |
admin login | sysadmin panel |
/api/sites |
sites.py |
admin bearer | sysadmin panel |
/api/heartbeat |
heartbeat.py |
X-Site-ID + X-Site-Key |
local sites |
/api/menu |
menu.py |
public GET; site headers for sync | menu-app, local sites |
/api/orders |
orders.py |
public create/status; site headers for pending/synced/status | menu-app, local sites |
/api/manager |
manager_auth.py |
manager bearer | manager-app, sysadmin |
/api/remote |
remote_dashboard.py |
manager bearer; site headers for POST /snapshot |
manager-app, local sites |
Pack-specific rules
CL-1. Old sites are always talking to you. Sites upgrade slowly, and some may be several versions behind. Every endpoint a site calls (the contract, C-1 … C-7) must stay backward compatible:
- add optional fields only
- never rename, remove or retype fields
- never make a new request field required
Any change to one of these endpoints updates the parent's docs/reference/cloud-contract.md (global Rule 6).
CL-2. Schema changes go through _run_migrations() in cloud_backend/main.py: additive ALTER TABLE ... ADD COLUMN only, and never drop columns. Superseded columns stay, with a comment (e.g. menu_hours_en).
CL-3. The cloud is never on the service-critical path. If the cloud is down, restaurants must keep taking orders (global Rule 8). Don't design features where the local site blocks while waiting on the cloud.
CL-4. Public endpoints are hostile territory.
menu-app endpoints are reachable by anyone on the internet. Validate everything, rate-limit where it makes sense, and never return data from another site. Site secrets (SITE_KEY) are shown once, at registration.
CL-5. Frontend URLs are baked in at build time.
VITE_CLOUD_URL is a build arg, so changing it means rebuilding the image, not restarting it.
Common commands
# Deploy on the VPS
cd ~/stacks/xenia-pos-cloud && docker compose up -d --build
# Dev
cd cloud_backend && uvicorn main:app --reload --port 8001
cd sysadmin_panel && npm run dev
cd connect_frontend/menu-app && npm run dev
cd connect_frontend/manager-app && npm run dev
Releasing a new client version also means bumping LATEST_VERSION in cloud_backend/.env and redeploying. See the parent's DEPLOYMENT_GUIDE.md.