feat(events): reliable holiday skipping for recurrences + UI badge; clean logs

Backend: generate EventException on create/update when skip_holidays or recurrence changes; emit RecurrenceException (EXDATE) with exact occurrence start time (UTC)
API: return master events with RecurrenceRule + RecurrenceException
Frontend: map RecurrenceException → recurrenceException; ensure SkipHolidays instances never render on holidays; place TentTree icon (black) next to main event icon via template
Docs: update README and Copilot instructions for recurrence/holiday behavior
Cleanup: remove dataSource and debug console logs
This commit is contained in:
RobbStarkAustria
2025-10-12 12:00:43 +00:00
parent 7ab4ea14c4
commit 773628c324
15 changed files with 698 additions and 122 deletions

View File

@@ -69,6 +69,11 @@ Use this as your shared context when proposing changes. Keep edits minimal and m
- Holidays present in the current view (count)
- Period label (display_name or name) with a badge indicating whether any holidays exist in that period (overlap check)
- Recurrence & holidays (latest):
- Backend stores holiday skips in `EventException` and emits `RecurrenceException` (EXDATE) for master events in `GET /api/events`. EXDATE timestamps match each occurrence start time (UTC) so Syncfusion excludes instances on holidays reliably.
- Frontend maps `RecurrenceException` to `recurrenceException` and relies on Syncfusion to expand recurrences. Additionally, `eventRendered` cancels rendering for any instance with `SkipHolidays=true` falling within holiday ranges, independent of the “Termine an Ferientagen erlauben” toggle.
- UI: Events with `SkipHolidays` render a TentTree icon directly after the main event icon in the scheduler event template. Icon color: black.
- Program info page (`dashboard/src/programminfo.tsx`):
- Loads data from `dashboard/public/program-info.json` (app name, version, build info, tech stack, changelog).
- Uses Syncfusion card classes (`e-card`, `e-card-header`, `e-card-title`, `e-card-content`) for consistent styling.
@@ -117,6 +122,11 @@ Note: Syncfusion usage in the dashboard is already documented above; if a UI for
- Academic periods: Events/media can be optionally associated with periods for educational organization. Only one period should be active at a time (`is_active=True`).
- Initialization scripts: legacy DB init scripts were removed; use Alembic and `initialize_database.py` going forward.
### Recurrence & holidays: conventions
- Do not pre-expand recurrences on the backend. Always send master event with `RecurrenceRule` + `RecurrenceException`.
- Ensure EXDATE tokens include the occurrence start time (HH:mm:ss) in UTC to match Syncfusions expansion.
- When `skip_holidays` or recurrence changes, regenerate `EventException` rows so `RecurrenceException` stays in sync.
## Quick examples
- Add client description persists to DB and publishes group via MQTT: see `PUT /api/clients/<uuid>/description` in `routes/clients.py`.
- Bulk group assignment emits retained messages for each client: `PUT /api/clients/group`.