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 (xenia-api.bonamin.net → cloud_backend, xenia-admin.bonamin.net → sysadmin panel, registry.bonamin.net → image registry).

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-6. The license signing key is permanent. LICENSE_SIGNING_KEY (cloud .env) signs every site's license. Its public half is built into the site code. Never regenerate or lose it: a new key means every site needs a new image. Keep the backup at %USERPROFILE%\.xenia\license_signing_key.txt safe. Never add fields to the token payload that old sites would misread; bump v for incompatible changes.

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.

S
Description
This this is the Cloud Backend + Sysadmin panel, for the Xenia POS system
Readme
375 KiB
Languages
JavaScript 71.9%
Python 26%
Dockerfile 0.9%
HTML 0.8%
CSS 0.4%