- Add GET /api/clients/crashed endpoint (process_status=crashed or stale heartbeat) - Add restart_app command action with same lifecycle + lockout as reboot_host - Scheduler: crash auto-recovery loop (CRASH_RECOVERY_ENABLED flag, lockout, MQTT publish) - Scheduler: unconditional command expiry sweep per poll cycle (sweep_expired_commands) - Listener: subscribe to infoscreen/+/service_failed; persist service_failed_at + unit - Listener: extract broker_connection block from health payload; persist reconnect_count + last_disconnect_at - DB migration b1c2d3e4f5a6: service_failed_at, service_failed_unit, mqtt_reconnect_count, mqtt_last_disconnect_at on clients - Add GET /api/clients/service_failed and POST /api/clients/<uuid>/clear_service_failed - Monitoring overview API: include mqtt_reconnect_count + mqtt_last_disconnect_at per client - Frontend: orange service-failed alert panel (hidden when empty, auto-refresh, quittieren action) - Frontend: MQTT reconnect count + last disconnect in client detail panel - MQTT auth hardening: listener/scheduler/server use env credentials; broker enforces allow_anonymous false - Client command lifecycle foundation: ClientCommand model, reboot_host/shutdown_host, full ACK lifecycle - Docs: TECH-CHANGELOG, DEV-CHANGELOG, MQTT_EVENT_PAYLOAD_GUIDE, copilot-instructions updated - Add implementation-plans/, RESTART_VALIDATION_CHECKLIST.md, TODO.md
6.2 KiB
6.2 KiB
Copilot instructions for infoscreen_2025
Purpose
This file is a concise, high-signal brief for coding agents. It is not a changelog and not a full architecture handbook.
TL;DR
- Stack: Flask API + MariaDB, React/Vite dashboard, MQTT listener, scheduler, worker.
- Main areas:
- API logic in
server/ - Scheduler logic in
scheduler/ - UI logic in
dashboard/src/
- API logic in
- Keep changes minimal, match existing patterns, and update docs in the same commit when behavior changes.
Fast file map
scheduler/scheduler.py- scheduler loop, MQTT event publishing, TV power intent publishing, crash auto-recovery, command expiry sweepscheduler/db_utils.py- event formatting, power-intent helpers, crash recovery helpers, command expiry sweeplistener/listener.py- discovery/heartbeat/log/screenshot/service_failed MQTT consumptionserver/init_academic_periods.py- idempotent academic-period seeding + auto-activation for current dateserver/initialize_database.py- migration + bootstrap orchestration for local/manual setupserver/routes/events.py- event CRUD, recurrence handling, UTC normalizationserver/routes/eventmedia.py- file manager, media upload/stream endpointsserver/routes/groups.py- group lifecycle, alive status, order persistenceserver/routes/system_settings.py- system settings CRUD and supplement-table endpointserver/routes/clients.py- client metadata, restart/shutdown/restart_app command issuing, command status, crashed/service_failed alert endpointsdashboard/src/settings.tsx- settings UX and system-defaults integrationdashboard/src/components/CustomEventModal.tsx- event creation/editing UXdashboard/src/monitoring.tsx- superadmin monitoring pageTV_POWER_INTENT_SERVER_CONTRACT_V1.md- Phase 1 TV power contract
Service picture
- API:
server/on:8000(health:/health) - Dashboard:
dashboard/(dev:5173, proxied API calls) - MQTT broker: Mosquitto (
mosquitto/config/mosquitto.conf) - Listener: MQTT consumer that updates server-side state
- Scheduler: publishes active events and group-level TV power intents
- Nginx: routes
/api/*and/screenshots/*to API, dashboard otherwise - Prod bootstrap:
docker-compose.prod.ymlserver command runs migrations, defaults init, and academic-period init before Gunicorn start
Non-negotiable conventions
- Datetime:
- Store/compare in UTC.
- API returns ISO strings without
Zin many routes. - Frontend must append
Zbefore parsing if needed.
- JSON naming:
- Backend internals use snake_case.
- API responses use camelCase (via
server/serializers.py).
- DB host in containers:
db(not localhost). - Never put secrets in docs.
MQTT contracts
- Event list topic (retained):
infoscreen/events/{group_id} - Group assignment topic (retained):
infoscreen/{uuid}/group_id - Heartbeat topic:
infoscreen/{uuid}/heartbeat - Logs topic family:
infoscreen/{uuid}/logs/{error|warn|info} - Health topic:
infoscreen/{uuid}/health - Dashboard screenshot topic:
infoscreen/{uuid}/dashboard - Client command topic (QoS1, non-retained):
infoscreen/{uuid}/commands(compat alias:infoscreen/{uuid}/command) - Client command ack topic (QoS1, non-retained):
infoscreen/{uuid}/commands/ack(compat alias:infoscreen/{uuid}/command/ack) - Service-failed topic (retained, client→server):
infoscreen/{uuid}/service_failed - TV power intent Phase 1 topic (retained, QoS1):
infoscreen/groups/{group_id}/power/intent
TV power intent Phase 1 rules:
- Schema version is
"1.0". - Group-only scope in Phase 1.
- Heartbeat publish keeps
intent_id; semantic transition rotatesintent_id. - Expiry rule:
expires_at = issued_at + max(3 x poll_interval_sec, 90s). - Canonical contract is
TV_POWER_INTENT_SERVER_CONTRACT_V1.md.
Backend patterns
- Routes in
server/routes/*, registered inserver/wsgi.py. - Use one request-scoped DB session, commit on mutation, always close session.
- Keep enum/datetime serialization JSON-safe.
- Maintain UTC-safe comparisons in scheduler and routes.
- Keep recurrence handling backend-driven and consistent with exceptions.
- Academic periods bootstrap is idempotent and should auto-activate period covering
date.today()when available.
Frontend patterns
- Use Syncfusion-based patterns already present in dashboard.
- Keep API requests relative (
/api/...) to use Vite proxy in dev. - Respect
FRONTEND_DESIGN_RULES.mdfor component and styling conventions. - Keep role-gated UI behavior aligned with backend authorization.
- Holiday status banner in dashboard should render from computed state and avoid stale message reuse in 3rd-party UI components.
Environment variables (high-value)
- Scheduler:
POLL_INTERVAL_SECONDS,REFRESH_SECONDS - Power intent:
POWER_INTENT_PUBLISH_ENABLED,POWER_INTENT_HEARTBEAT_ENABLED,POWER_INTENT_EXPIRY_MULTIPLIER,POWER_INTENT_MIN_EXPIRY_SECONDS - Monitoring:
PRIORITY_SCREENSHOT_TTL_SECONDS - Crash recovery:
CRASH_RECOVERY_ENABLED,CRASH_RECOVERY_GRACE_SECONDS,CRASH_RECOVERY_LOCKOUT_MINUTES,CRASH_RECOVERY_COMMAND_EXPIRY_SECONDS - Core:
DB_CONN,DB_USER,DB_PASSWORD,DB_HOST,DB_NAME,ENV - MQTT auth/connectivity:
MQTT_BROKER_HOST,MQTT_BROKER_PORT,MQTT_USER,MQTT_PASSWORD(listener/scheduler/server should use authenticated broker access)
Edit guardrails
- Do not edit generated assets in
dashboard/dist/. - Do not change CI/build outputs unless explicitly intended.
- Preserve existing API behavior unless task explicitly requires a change.
- Prefer links to canonical docs instead of embedding long historical notes here.
Documentation sync rule
When services/MQTT/API/UTC/env behavior changes:
- Update this file (concise deltas only).
- Update canonical docs where details live.
- Update changelogs separately (
TECH-CHANGELOG.md,DEV-CHANGELOG.md,dashboard/public/program-info.jsonas appropriate).
Canonical docs map
- Repo entry:
README.md - Instruction governance:
AI-INSTRUCTIONS-MAINTENANCE.md - Technical release details:
TECH-CHANGELOG.md - Workspace/development notes:
DEV-CHANGELOG.md - MQTT payload details:
MQTT_EVENT_PAYLOAD_GUIDE.md - TV power contract:
TV_POWER_INTENT_SERVER_CONTRACT_V1.md - Frontend patterns:
FRONTEND_DESIGN_RULES.md - Archived historical docs:
docs/archive/