5.9 KiB
5.9 KiB
Copilot instructions for infoscreen_2025
Use this as your shared context when proposing changes. Keep edits minimal and match existing patterns referenced below.
Big picture
- Multi-service app orchestrated by Docker Compose.
- API: Flask + SQLAlchemy (MariaDB), in
server/exposed on :8000 (health:/health). - Dashboard: React + Vite in
dashboard/, dev on :5173, served via Nginx in prod. - MQTT broker: Eclipse Mosquitto, config in
mosquitto/config/mosquitto.conf. - Listener: MQTT consumer handling discovery + heartbeats in
listener/listener.py. - Scheduler: Publishes active events (per group) to MQTT retained topics in
scheduler/scheduler.py. - Nginx: Reverse proxy routes
/api/*and/screenshots/*to API; everything else to dashboard (nginx.conf).
- API: Flask + SQLAlchemy (MariaDB), in
Service boundaries & data flow
- Database connection string is passed as
DB_CONN(mysql+pymysql) to Python services.- API builds its engine in
server/database.py(loads.envonly in development). - Scheduler loads
DB_CONNinscheduler/db_utils.py. - Listener also creates its own engine for writes to
clients.
- API builds its engine in
- MQTT topics (paho-mqtt v2, use Callback API v2):
- Discovery:
infoscreen/discovery(JSON includesuuid, hw/ip data). ACK toinfoscreen/{uuid}/discovery_ack. Seelistener/listener.py. - Heartbeat:
infoscreen/{uuid}/heartbeatupdatesClient.last_alive(UTC). - Event lists (retained):
infoscreen/events/{group_id}fromscheduler/scheduler.py. - Per-client group assignment (retained):
infoscreen/{uuid}/group_idviaserver/mqtt_helper.py.
- Discovery:
- Screenshots: server-side folders
server/received_screenshots/andserver/screenshots/; Nginx exposes/screenshots/{uuid}.jpgviaserver/wsgi.pyroute.
Data model highlights (see models/models.py)
- Enums:
EventType(presentation, website, video, message, webuntis) andMediaType(file/website types). - Tables:
clients,client_groups,events,event_media,users. - Times are stored as timezone-aware; treat comparisons in UTC (see scheduler and routes/events).
API patterns
- Blueprints live in
server/routes/*and are registered inserver/wsgi.pywith/api/...prefixes. - Session usage: instantiate
Session()per request, commit when mutating, and alwayssession.close()before returning. - Examples:
- Clients:
server/routes/clients.pyincludes bulk group updates and MQTT sync (publish_multiple_client_groups). - Groups:
server/routes/groups.pycomputes “alive” using a grace period that varies byENV. - Events:
server/routes/events.pyserializes enum values to strings and normalizes times to UTC. - Media:
server/routes/eventmedia.pyimplements a simple file manager API rooted atserver/media/.
- Clients:
Frontend patterns (dashboard)
- Vite React app; proxies
/apiand/screenshotsto API in dev (vite.config.ts). - Uses Syncfusion components; Vite config pre-bundles specific packages to avoid alias issues.
- Environment:
VITE_API_URLprovided at build/run; in dev compose, proxy handles/apiso local fetches can use relative/api/...paths.
Local development
- Compose: development is
docker-compose.yml+docker-compose.override.yml.- API (dev):
server/Dockerfile.devwith debugpy on 5678, Flask appwsgi:appon :8000. - Dashboard (dev):
dashboard/Dockerfile.devexposes :5173 and waits for API viadashboard/wait-for-backend.sh. - Mosquitto: allows anonymous in dev; WebSocket on :9001.
- API (dev):
- Common env vars:
DB_CONN,DB_USER,DB_PASSWORD,DB_HOST=db,DB_NAME,ENV,MQTT_USER,MQTT_PASSWORD. - Alembic: prod compose runs
alembic ... upgrade headandserver/init_defaults.pybefore gunicorn.
Production
docker-compose.prod.ymluses prebuilt images (ghcr.io/robbstarkaustria/*).- Nginx serves dashboard and proxies API; TLS certs expected in
certs/and mounted to/etc/nginx/certs.
Environment variables (reference)
- DB_CONN — Preferred DB URL for services. Example:
mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME} - DB_USER, DB_PASSWORD, DB_NAME, DB_HOST — Used to assemble DB_CONN in dev if missing; inside containers
DB_HOST=db. - ENV —
developmentorproduction; in development,server/database.pyloads.env. - MQTT_BROKER_HOST, MQTT_BROKER_PORT — Defaults
mqttand1883; MQTT_USER/MQTT_PASSWORD optional (dev often anonymous per Mosquitto config). - VITE_API_URL — Dashboard build-time base URL (prod); in dev the Vite proxy serves
/apitoserver:8000. - HEARTBEAT_GRACE_PERIOD_DEV / HEARTBEAT_GRACE_PERIOD_PROD — Groups “alive” window (defaults ~15s dev / 180s prod).
- REFRESH_SECONDS — Optional scheduler republish interval;
0disables periodic refresh.
Conventions & gotchas
- Always compare datetimes in UTC; some DB values may be naive—normalize before comparing (see
routes/events.py). - Use retained MQTT messages for state that clients must recover after reconnect (events per group, client group_id).
- In-container DB host is
db; do not uselocalhostinside services. - No separate dev vs prod secret conventions: use the same env var keys across environments (e.g.,
DB_CONN,MQTT_USER,MQTT_PASSWORD). - When adding a new route:
- Create a Blueprint in
server/routes/..., - Register it in
server/wsgi.py, - Manage
Session()lifecycle, and - Return JSON-safe values (serialize enums and datetimes).
- Create a Blueprint in
- When extending media types, update
MediaTypeand any logic ineventmediaand dashboard that depends on it.
Quick examples
- Add client description persists to DB and publishes group via MQTT: see
PUT /api/clients/<uuid>/descriptioninroutes/clients.py. - Bulk group assignment emits retained messages for each client:
PUT /api/clients/group. - Listener heartbeat path:
infoscreen/<uuid>/heartbeat→ setsclients.last_alive.
Questions or unclear areas? Tell us if you need: exact devcontainer debugging steps, stricter Alembic workflow, or a seed dataset beyond init_defaults.py.