feat: presentation defaults + scheduler active-only
Add Settings → Events (Presentations) defaults (interval, page-progress, auto-progress) persisted via /api/system-settings Seed defaults in init_defaults.py (10/true/true) Add Event.page_progress and Event.auto_progress (Alembic applied) CustomEventModal applies defaults on create and saves fields Scheduler publishes only currently active events per group, clears retained topics when none, normalizes times to UTC; include flags in payloads Docs: update README, copilot instructions, and DEV-CHANGELOG If you can split the commit, even better feat(dashboard): add presentation defaults UI feat(api): seed presentation defaults in init_defaults.py feat(model): add Event.page_progress and Event.auto_progress feat(scheduler): publish only active events; clear retained topics; UTC docs: update README and copilot-instructions chore: update DEV-CHANGELOG
This commit is contained in:
22
.github/copilot-instructions.md
vendored
22
.github/copilot-instructions.md
vendored
@@ -12,13 +12,13 @@ Use this as your shared context when proposing changes. Keep edits minimal and m
|
||||
- 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`. Scheduler now queries a future window (default: 7 days), expands recurring events using RFC 5545 rules, applies event exceptions, and publishes all valid occurrences. Logging is concise; conversion lookups are cached and logged only once per media.
|
||||
- Scheduler: Publishes only currently active events (per group, at "now") to MQTT retained topics in `scheduler/scheduler.py`. It queries a future window (default: 7 days) to expand recurring events using RFC 5545 rules and applies event exceptions, but only publishes events that are active at the current time. When a group has no active events, the scheduler clears its retained topic by publishing an empty list. All time comparisons are UTC; any naive timestamps are normalized. Logging is concise; conversion lookups are cached and logged only once per media.
|
||||
- Nginx: Reverse proxy routes `/api/*` and `/screenshots/*` to API; everything else to dashboard (`nginx.conf`).
|
||||
|
||||
## 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 `.env` only in development).
|
||||
- Scheduler loads `DB_CONN` in `scheduler/db_utils.py`. Recurring events are expanded for the next 7 days, and event exceptions (skipped dates, detached occurrences) are respected. Only recurring events with recurrence_end in the future remain active.
|
||||
- Scheduler loads `DB_CONN` in `scheduler/db_utils.py`. Recurring events are expanded for the next 7 days, and event exceptions (skipped dates, detached occurrences) are respected. Only recurring events with recurrence_end in the future remain active. The scheduler publishes only events that are active at the current time and clears retained topics (publishes `[]`) for groups without active events. Time comparisons are UTC and naive timestamps are normalized.
|
||||
- Listener also creates its own engine for writes to `clients`.
|
||||
- MQTT topics (paho-mqtt v2, use Callback API v2):
|
||||
- Discovery: `infoscreen/discovery` (JSON includes `uuid`, hw/ip data). ACK to `infoscreen/{uuid}/discovery_ack`. See `listener/listener.py`.
|
||||
@@ -36,11 +36,13 @@ Use this as your shared context when proposing changes. Keep edits minimal and m
|
||||
- Storage: originals under `server/media/…`, outputs under `server/media/converted/` (prod compose mounts a shared volume for this path).
|
||||
|
||||
## Data model highlights (see `models/models.py`)
|
||||
- Enums: `EventType` (presentation, website, video, message, webuntis), `MediaType` (file/website types), and `AcademicPeriodType` (schuljahr, semester, trimester).
|
||||
- Tables: `clients`, `client_groups`, `events`, `event_media`, `users`, `academic_periods`, `school_holidays`.
|
||||
- System settings: `system_settings` key–value store via `SystemSetting` for global configuration (e.g., WebUntis/Vertretungsplan supplement-table). Managed through routes in `server/routes/system_settings.py`.
|
||||
- Academic periods: `academic_periods` table supports educational institution cycles (school years, semesters). Events and media can be optionally linked via `academic_period_id` (nullable for backward compatibility).
|
||||
- Times are stored as timezone-aware; treat comparisons in UTC (see scheduler and routes/events).
|
||||
- Presentation defaults (system-wide):
|
||||
- `presentation_interval` (seconds, default "10")
|
||||
- `presentation_page_progress` ("true"/"false", default "true")
|
||||
- `presentation_auto_progress` ("true"/"false", default "true")
|
||||
Seeded in `server/init_defaults.py` if missing.
|
||||
- Events: Added `page_progress` (Boolean) and `auto_progress` (Boolean) for presentation behavior per event.
|
||||
|
||||
- Conversions:
|
||||
- Enum `ConversionStatus`: `pending`, `processing`, `ready`, `failed`.
|
||||
@@ -109,7 +111,8 @@ Use this as your shared context when proposing changes. Keep edits minimal and m
|
||||
- Conversion Status: placeholder for conversions overview
|
||||
- 🗓️ Events (admin+)
|
||||
- WebUntis / Vertretungsplan: system-wide supplement table URL with enable/disable, save, and preview; persists via `/api/system-settings/supplement-table`
|
||||
- Other event types (presentation, website, video, message, other): placeholders for defaults
|
||||
- Presentations: general defaults for slideshow interval, page-progress, and auto-progress; persisted via `/api/system-settings` keys (`presentation_interval`, `presentation_page_progress`, `presentation_auto_progress`). These defaults are applied when creating new presentation events (the custom event modal reads them and falls back to per-event values when editing).
|
||||
- Other event types (website, video, message, other): placeholders for defaults
|
||||
- ⚙️ System (superadmin)
|
||||
- Organization Info and Advanced Configuration placeholders
|
||||
- Role gating: Admin/Superadmin tabs are hidden if the user lacks permission; System is superadmin-only
|
||||
@@ -148,7 +151,7 @@ Note: Syncfusion usage in the dashboard is already documented above; if a UI for
|
||||
|
||||
## Conventions & gotchas
|
||||
- Always compare datetimes in UTC; some DB values may be naive—normalize before comparing (see `routes/events.py`).
|
||||
- Scheduler queries a future window (default: 7 days) and expands recurring events using RFC 5545 rules. Event exceptions are respected. Logging is concise and conversion lookups are cached.
|
||||
- Scheduler enforces UTC comparisons and normalizes naive timestamps. It publishes only currently active events and clears retained topics for groups with no active events. It also queries a future window (default: 7 days) and expands recurring events using RFC 5545 rules. Event exceptions are respected. Logging is concise and conversion lookups are cached.
|
||||
- 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 use `localhost` inside services.
|
||||
- No separate dev vs prod secret conventions: use the same env var keys across environments (e.g., `DB_CONN`, `MQTT_USER`, `MQTT_PASSWORD`).
|
||||
@@ -172,6 +175,9 @@ Note: Syncfusion usage in the dashboard is already documented above; if a UI for
|
||||
- Bulk group assignment emits retained messages for each client: `PUT /api/clients/group`.
|
||||
- Listener heartbeat path: `infoscreen/<uuid>/heartbeat` → sets `clients.last_alive`.
|
||||
|
||||
## Scheduler payloads: presentation extras
|
||||
- Presentation event payloads now include `page_progress` and `auto_progress` in addition to `slide_interval` and media files. These are sourced from per-event fields in the database (with system defaults applied on event creation).
|
||||
|
||||
Questions or unclear areas? Tell us if you need: exact devcontainer debugging steps, stricter Alembic workflow, or a seed dataset beyond `init_defaults.py`.
|
||||
|
||||
## Academic Periods System
|
||||
|
||||
Reference in New Issue
Block a user