
# TECH-CHANGELOG



This changelog documents technical and developer-relevant changes included in public releases. For development workspace changes, see DEV-CHANGELOG.md. Not all changes here are reflected in the user-facing changelog (`program-info.json`), and not all UI/feature changes are repeated here. Some changes (e.g., backend refactoring, API adjustments, infrastructure, developer tooling, or internal logic) may only appear in TECH-CHANGELOG.md. For UI/feature changes, see `dashboard/public/program-info.json`.

## 2026.1.0-alpha.15 (2026-03-31)
- 🗃️ **Holiday data model scoping to academic periods**:
	- Added period scoping for holidays via `SchoolHoliday.academic_period_id` (FK to academic periods) in `models/models.py`.
	- Added Alembic migration `f3c4d5e6a7b8_scope_school_holidays_to_academic_.py` to introduce FK/index/constraint updates for period-aware holiday storage.
	- Updated uniqueness semantics and indexing so holiday identity is evaluated in the selected academic period context.
- 🔌 **Holiday API hardening (`server/routes/holidays.py`)**:
	- Extended to period-scoped workflows for list/import/manual CRUD.
	- Added manual CRUD endpoints and behavior:
		- `POST /api/holidays`
		- `PUT /api/holidays/<id>`
		- `DELETE /api/holidays/<id>`
	- Enforced date-range validation against selected academic period for both import and manual writes.
	- Added duplicate prevention (normalized name/region matching with null-safe handling).
	- Implemented overlap policy:
		- Same normalized `name+region` overlaps (including adjacent ranges) are merged.
		- Different-identity overlaps are treated as conflicts (manual blocked, import skipped with details).
	- Import responses now include richer counters/details (inserted/updated/merged/skipped/conflicts).
- 🔁 **Recurrence integration updates**:
	- Event holiday-skip exception regeneration now resolves holidays by `academic_period_id` instead of global holiday sets.
	- Updated event-side recurrence handling (`server/routes/events.py`) to keep EXDATE behavior in sync with period-scoped holidays.
- 🖥️ **Frontend integration (technical)**:
	- Updated holiday API client (`dashboard/src/apiHolidays.ts`) for period-aware list/upload and manual CRUD operations.
	- Settings holiday management (`dashboard/src/settings.tsx`) now binds import/list/manual CRUD to selected academic period and surfaces conflict/merge outcomes.
	- Dashboard and appointments holiday data loading updated to active-period context.
- 📖 **Documentation & release alignment**:
	- Updated `.github/copilot-instructions.md` with period-scoped holiday conventions, overlap policy, and settings behavior.
	- Refactored root `README.md` to index-style documentation and archived historical implementation docs under `docs/archive/`.
	- Synchronized release line with user-facing version `2026.1.0-alpha.15` in `dashboard/public/program-info.json`.

Notes for integrators:
- Holiday operations now require a clear academic period context; archived periods should be treated as read-only for holiday mutation flows.
- Existing recurrence flows depend on period-scoped holiday sets; verify period assignment for recurring master events when validating skip-holidays behavior.

## 2026.1.0-alpha.14 (2026-01-28)
- 🗓️ **Ressourcen Page (Timeline View)**:
	- New frontend page: `dashboard/src/ressourcen.tsx` (357 lines) – Parallel timeline view showing active events for all room groups
	- Uses Syncfusion ScheduleComponent with TimelineViews module for resource-based scheduling
	- Compact visualization: 65px row height per group, dynamically calculated total container height
	- Real-time event loading: Fetches events per group for current date range on mount and view/date changes
	- Timeline modes: Day (default) and Week views with date range calculation
	- Color-coded event bars: Uses `getGroupColor()` from `groupColors.ts` for group theme matching
	- Displays first active event per group with type, title, and time window
	- Filters out "Nicht zugeordnet" group from timeline display
	- Resource mapping: Each group becomes a timeline resource row, events mapped via `ResourceId`
	- Syncfusion modules: TimelineViews, Resize, DragAndDrop injected for rich interaction
- 🎨 **Ressourcen Styling**:
	- New CSS file: `dashboard/src/ressourcen.css` (178 lines) with modern Material 3 design
	- Fixed CSS lint errors: Converted `rgba()` to modern `rgb()` notation with percentage alpha values (`rgb(0 0 0 / 10%)`)
	- Removed unnecessary quotes from font-family names (Roboto, Oxygen, Ubuntu, Cantarell)
	- Fixed CSS selector specificity ordering (`.e-schedule` before `.ressourcen-timeline-wrapper .e-schedule`)
	- Card-based controls layout with shadow and rounded corners
	- Group ordering panel with scrollable list and action buttons
	- Responsive timeline wrapper with flex layout
- 🔌 **Group Order API**:
	- New backend endpoints in `server/routes/groups.py`:
		- `GET /api/groups/order` – Retrieve saved group display order (returns JSON with `order` array of group IDs)
		- `POST /api/groups/order` – Persist group display order (accepts JSON with `order` array)
	- Order persistence: Stored in `system_settings` table with key `group_display_order` (JSON array of integers)
	- Automatic synchronization: Missing group IDs added to order, removed IDs filtered out
	- Frontend integration: Group order panel with drag up/down buttons, real-time reordering with backend sync
- 🖥️ **Frontend Technical**:
	- State management: React hooks with unused setters removed (setTimelineView, setViewDate) to resolve lint warnings
	- TypeScript: Changed `let` to `const` for immutable end date calculation
	- UTC date parsing: Uses parseUTCDate callback to append 'Z' and ensure UTC interpretation
	- Event formatting: Capitalizes first letter of event type for display (e.g., "Website - Title")
	- Loading state: Shows loading indicator while fetching group/event data
	- Schedule height: Dynamic calculation based on `groups.length * 65px + 100px` for header
- 📖 **Documentation**:
	- Updated `.github/copilot-instructions.md`:
		- Added Ressourcen page to "Recent changes" section (January 2026)
		- Added `ressourcen.tsx` and `ressourcen.css` to "Important files" list
		- Added Groups API order endpoints documentation
		- Added comprehensive Ressourcen page section to "Frontend patterns"
	- Updated `README.md`:
		- Added Ressourcen page to "Pages Overview" section with feature details
		- Added `GET/POST /api/groups/order` to Core Resources API section
	- Bumped version in `dashboard/public/program-info.json` to `2026.1.0-alpha.14` with user-facing changelog

Notes for integrators:
- Group order API returns JSON with `{ "order": [1, 2, 3, ...] }` structure (array of group IDs)
- Timeline view automatically filters "Nicht zugeordnet" group for cleaner display
- CSS follows modern Material 3 color-function notation (`rgb(r g b / alpha%)`)
- Syncfusion ScheduleComponent requires TimelineViews, Resize, and DragAndDrop modules injected

Backend technical work (post-release notes; no version bump):
- 📊 **Client Monitoring Infrastructure (Server-Side) (2026-03-10)**:
	- Database schema: New Alembic migration `c1d2e3f4g5h6_add_client_monitoring.py` (idempotent) adds:
		- `client_logs` table: Stores centralized logs with columns (id, client_uuid, timestamp, level, message, context, created_at)
		- Foreign key: `client_logs.client_uuid` → `clients.uuid` (ON DELETE CASCADE)
		- Health monitoring columns added to `clients` table: `current_event_id`, `current_process`, `process_status`, `process_pid`, `last_screenshot_analyzed`, `screen_health_status`, `last_screenshot_hash`
		- Indexes for performance: (client_uuid, timestamp DESC), (level, timestamp DESC), (created_at DESC)
	- Data models (`models/models.py`):
		- New enums: `LogLevel` (ERROR, WARN, INFO, DEBUG), `ProcessStatus` (running, crashed, starting, stopped), `ScreenHealthStatus` (OK, BLACK, FROZEN, UNKNOWN)
		- New model: `ClientLog` with foreign key to `Client` (CASCADE on delete)
		- Extended `Client` model with 7 health monitoring fields
	- MQTT listener extensions (`listener/listener.py`):
		- New topic subscriptions: `infoscreen/+/logs/error`, `infoscreen/+/logs/warn`, `infoscreen/+/logs/info`, `infoscreen/+/health`
		- Log handler: Parses JSON payloads, creates `ClientLog` entries, validates client UUID exists (FK constraint)
		- Health handler: Updates client state from MQTT health messages
		- Enhanced heartbeat handler: Captures `process_status`, `current_process`, `process_pid`, `current_event_id` from payload
	- API endpoints (`server/routes/client_logs.py`):
		- `GET /api/client-logs/<uuid>/logs` – Retrieve client logs with filters (level, limit, since); authenticated (admin_or_higher)
		- `GET /api/client-logs/summary` – Get log counts by level per client for last 24h; authenticated (admin_or_higher)
		- `GET /api/client-logs/monitoring-overview` – Aggregated monitoring overview for dashboard clients/statuses; authenticated (admin_or_higher)
		- `GET /api/client-logs/recent-errors` – System-wide error monitoring; authenticated (admin_or_higher)
		- `GET /api/client-logs/test` – Infrastructure validation endpoint (no auth required)
		- Blueprint registered in `server/wsgi.py` as `client_logs_bp`
	- Dev environment fix: Updated `docker-compose.override.yml` listener service to use `working_dir: /workspace` and direct command path for live code reload
- 🖥️ **Monitoring Dashboard Integration (2026-03-24)**:
	- Frontend monitoring dashboard (`dashboard/src/monitoring.tsx`) is active and wired to monitoring APIs
	- Superadmin-only route/menu integration completed in `dashboard/src/App.tsx`
	- Added dashboard monitoring API client (`dashboard/src/apiClientMonitoring.ts`) for overview and recent errors
- 🐛 **Presentation Flags Persistence Fix (2026-03-24)**:
	- Fixed persistence for presentation flags `page_progress` and `auto_progress` across create/update and detached-occurrence flows
	- API serialization now reliably returns stored values for presentation behavior fields
- 📡 **MQTT Protocol Extensions**:
	- New log topics: `infoscreen/{uuid}/logs/{error|warn|info}` with JSON payload (timestamp, message, context)
	- New health topic: `infoscreen/{uuid}/health` with metrics (expected_state, actual_state, health_metrics)
	- Enhanced heartbeat: `infoscreen/{uuid}/heartbeat` now includes `current_process`, `process_pid`, `process_status`, `current_event_id`
	- QoS levels: ERROR/WARN logs use QoS 1 (at least once), INFO/health use QoS 0 (fire and forget)
- 📖 **Documentation**:
	- New file: `CLIENT_MONITORING_SPECIFICATION.md` – Comprehensive 20-section technical spec for client-side implementation (MQTT protocol, process monitoring, auto-recovery, payload formats, testing guide)
	- New file: `CLIENT_MONITORING_IMPLEMENTATION_GUIDE.md` – 5-phase implementation guide (database, backend, client watchdog, dashboard UI, testing)
	- Updated `.github/copilot-instructions.md`: Added MQTT topics section, client monitoring integration notes
- ✅ **Validation**:
	- End-to-end testing completed: MQTT message → listener → database → API confirmed working
	- Test flow: Published message to `infoscreen/{real-uuid}/logs/error` → listener logs showed receipt → database stored entry → test API returned log data
	- Known client UUIDs validated: 9b8d1856-ff34-4864-a726-12de072d0f77, 7f65c615-5827-4ada-9ac8-4727c2e8ee55, bdbfff95-0b2b-4265-8cc7-b0284509540a

Notes for integrators:
- Tiered logging strategy: ERROR/WARN always centralized (QoS 1), INFO dev-only (QoS 0), DEBUG local-only
- Monitoring dashboard is implemented and consumes `/api/client-logs/monitoring-overview`, `/api/client-logs/recent-errors`, and `/api/client-logs/<uuid>/logs`
- Foreign key constraint prevents logging for non-existent clients (data integrity enforced)
- Migration is idempotent and can be safely rerun after interruption
- Use `GET /api/client-logs/test` for quick infrastructure validation without authentication

## 2025.1.0-beta.1 (TBD)
- 🔐 **User Management & Role-Based Access Control**:
	- Backend: Implemented comprehensive user management API (`server/routes/users.py`) with 6 endpoints (GET, POST, PUT, DELETE users + password reset).
	- Data model: Extended `User` with 7 audit/security fields via Alembic migration (`4f0b8a3e5c20_add_user_audit_fields.py`):
		- `last_login_at`, `last_password_change_at`: TIMESTAMP (UTC) for auth event tracking
		- `failed_login_attempts`, `last_failed_login_at`: Security monitoring for brute-force detection
		- `locked_until`: TIMESTAMP placeholder for account lockout (infrastructure in place, not yet enforced)
		- `deactivated_at`, `deactivated_by`: Soft-delete audit trail (FK self-reference)
	- Role hierarchy: 4-tier privilege escalation (user → editor → admin → superadmin) enforced at API and UI levels:
		- Admin cannot see, create, or manage superadmin accounts
		- Admin can manage user/editor/admin roles only
		- Superadmin can manage all roles including other superadmins
	- Auth routes enhanced (`server/routes/auth.py`):
		- Login: Sets `last_login_at`, resets `failed_login_attempts` on success; increments `failed_login_attempts` and `last_failed_login_at` on failure
		- Password change: Sets `last_password_change_at` on both self-service and admin reset
		- New endpoint: `PUT /api/auth/change-password` for self-service password change (all authenticated users; requires current password verification)
	- User API security:
		- Admin cannot reset superadmin passwords
		- Self-account protections: cannot change own role/status, cannot delete self
		- Admin cannot use password reset endpoint for their own account (backend check enforces self-service requirement)
		- All user responses include audit fields in camelCase (lastLoginAt, lastPasswordChangeAt, failedLoginAttempts, deactivatedAt, deactivatedBy)
	- Soft-delete pattern: Deactivation by default (sets `deactivated_at` and `deactivated_by`); hard-delete superadmin-only
- 🖥️ **Frontend User Management**:
	- New page: `dashboard/src/users.tsx` – Full CRUD interface (820 lines) with Syncfusion components
	- GridComponent: 20 per page (configurable), sortable columns (ID, username, role), custom action button template with role-based visibility
	- Statistics cards: Total users, active (non-deactivated), inactive (deactivated) counts
	- Dialogs: Create (username/password/role/status), Edit (with self-edit protections), Password Reset (admin only, no current password required), Delete (superadmin only, self-check), Details (read-only audit info with formatted timestamps)
	- Role badges: Color-coded display (user: gray, editor: blue, admin: green, superadmin: red)
	- Audit information display: last login, password change, last failed login, deactivation timestamps and deactivating user
	- Self-protection: Delete button hidden for current user (prevents accidental self-deletion)
	- Menu visibility: "Benutzer" sidebar item only visible to admin+ (role-gated in App.tsx)
- 💬 **Header User Menu**:
	- Enhanced top-right dropdown with "Passwort ändern" (lock icon), "Profil", and "Abmelden"
	- Self-service password change dialog: Available to all authenticated users; requires current password verification, new password min 6 chars, must match confirm field
	- Implemented with Syncfusion DropDownButton (`@syncfusion/ej2-react-splitbuttons`)
- 🔌 **API Client**:
	- New file: `dashboard/src/apiUsers.ts` – Type-safe TypeScript client (143 lines) for user operations
	- Functions: listUsers(), getUser(), createUser(), updateUser(), resetUserPassword(), deleteUser()
	- All functions include proper error handling and camelCase JSON mapping
- 📖 **Documentation**:
	- Updated `.github/copilot-instructions.md`: Added comprehensive sections on user model audit fields, user management API routes, auth routes, header menu, and user management page implementation
	- Updated `README.md`: Added user management to Key Features, API endpoints (User Management + Authentication sections), Pages Overview, and Security & Authentication sections with RBAC details
	- Updated `TECH-CHANGELOG.md`: Documented all technical changes and integration notes

Notes for integrators:
- User CRUD endpoints accept/return all audit fields in camelCase
- Admin password reset (`PUT /api/users/<id>/password`) cannot be used for admin's own account; users must use self-service endpoint
- Frontend enforces role-gated menu visibility; backend validates all role transitions to prevent privilege escalation
- Soft-delete is default; hard-delete (superadmin-only) requires explicit confirmation
- Audit fields populated automatically on login/logout/password-change/deactivation events



Backend rework (post-release notes; no version bump):
- 🧩 Dev Container hygiene: Remote Containers runs on UI (`remote.extensionKind`), removed in-container install to prevent reappearance loops; switched `postCreateCommand` to `npm ci` for reproducible dashboard installs; `postStartCommand` aliases made idempotent.
- 🔄 Serialization: Consolidated snake_case→camelCase via `server/serializers.py` for all JSON outputs; ensured enums/UTC datetimes serialize consistently across routes.
- 🕒 Time handling: Normalized naive timestamps to UTC in all back-end comparisons (events, scheduler, groups) and kept ISO strings without `Z` in API responses; frontend appends `Z`.
- 📡 Streaming: Stabilized range-capable endpoint (`/api/eventmedia/stream/<media_id>/<filename>`), clarified client handling; scheduler emits basic HEAD-probe metadata (`mime_type`, `size`, `accept_ranges`).
- 📅 Recurrence/exceptions: Ensured EXDATE tokens (RFC 5545 UTC) align with occurrence start; detached-occurrence flow confirmed via `POST /api/events/<id>/occurrences/<date>/detach`.
- 🧰 Routes cleanup: Applied `dict_to_camel_case()` before `jsonify()` uniformly; verified Session lifecycle consistency (open/commit/close) across blueprints.
- 🔄 **API Naming Convention Standardization**:
	- Created `server/serializers.py` with `dict_to_camel_case()` and `dict_to_snake_case()` utilities for consistent JSON serialization
	- Events API refactored: `GET /api/events` and `GET /api/events/<id>` now return camelCase JSON (`id`, `subject`, `startTime`, `endTime`, `type`, `groupId`, etc.) instead of PascalCase
	- Internal event dictionaries use snake_case keys, then converted to camelCase via `dict_to_camel_case()` before `jsonify()`
	- **Breaking**: External API consumers must update field names from PascalCase to camelCase
- ⏰ **UTC Time Handling**:
	- Standardized datetime handling: Database stores timestamps in UTC (naive timestamps normalized by backend)
	- API returns ISO strings without 'Z' suffix: `"2025-11-27T20:03:00"`
	- Frontend appends 'Z' to parse as UTC and displays in user's local timezone via `toLocaleTimeString('de-DE')`
	- All time comparisons use UTC; `date.toISOString()` sends UTC back to API
- 🖥️ **Dashboard Major Redesign**:
	- Completely redesigned dashboard with card-based layout for Raumgruppen (room groups)
	- Global statistics summary card: total infoscreens, online/offline counts, warning groups
	- Filter buttons with dynamic counts: All, Online, Offline, Warnings
	- Active event display per group: shows currently playing content with type icon, title, date ("Heute"/"Morgen"/date), and time range
	- Health visualization: color-coded progress bars showing online/offline ratio per group
	- Expandable client details: shows last alive timestamps with human-readable format ("vor X Min.", "vor X Std.", "vor X Tagen")
	- Bulk restart functionality: restart all offline clients in a group
	- Manual refresh button with toast notifications
	- 15-second auto-refresh interval
	- "Nicht zugeordnet" group always appears last in sorted list
- 🎨 **Frontend Technical**:
	- Dashboard (`dashboard/src/dashboard.tsx`): Uses Syncfusion ButtonComponent, ToastComponent, and card CSS classes
	- Appointments page updated to map camelCase API responses to internal PascalCase for Syncfusion compatibility
	- Time formatting functions (`formatEventTime`, `formatEventDate`) handle UTC string parsing with 'Z' appending
	- TypeScript lint errors resolved: unused error variables removed, null safety checks added with optional chaining
- 📖 **Documentation**:
	- Updated `.github/copilot-instructions.md` with comprehensive sections on:
		- API patterns: JSON serialization, datetime handling conventions
		- Frontend patterns: API response format, UTC time parsing
		- Dashboard page overview with features
		- Conventions & gotchas: datetime and JSON naming guidelines
	- Updated `README.md` with recent changes, API response format section, and dashboard page details

Notes for integrators:
- **Breaking change**: All Events API endpoints now return camelCase field names. Update client code accordingly.
- Frontend must append 'Z' to API datetime strings before parsing: `const utcStr = dateStr.endsWith('Z') ? dateStr : dateStr + 'Z'; new Date(utcStr);`
- Use `dict_to_camel_case()` from `server/serializers.py` for any new API endpoints returning JSON
 - Dev container: prefer `npm ci` and UI-only Remote Containers to avoid extension drift in-container.

---

### Component build metadata template (for traceability)
Record component builds under the unified app version when releasing:

```
Component builds for this release
- API: image tag `ghcr.io/robbstarkaustria/api:<short-sha>` (commit `<sha>`)
- Dashboard: image tag `ghcr.io/robbstarkaustria/dashboard:<short-sha>` (commit `<sha>`)
- Scheduler: image tag `ghcr.io/robbstarkaustria/scheduler:<short-sha>` (commit `<sha>`)
- Listener: image tag `ghcr.io/robbstarkaustria/listener:<short-sha>` (commit `<sha>`)
- Worker: image tag `ghcr.io/robbstarkaustria/worker:<short-sha>` (commit `<sha>`)
```

This is informational (build metadata) and does not change the user-facing version number.

## 2025.1.0-alpha.11 (2025-11-05)
- 🗃️ Data model & API:
	- Added `muted` (Boolean) to `Event` with Alembic migration; create/update and GET endpoints now accept, persist, and return `muted` alongside `autoplay`, `loop`, and `volume` for video events.
	- Video event fields consolidated: `event_media_id`, `autoplay`, `loop`, `volume`, `muted`.
- 🔗 Streaming:
	- Added range-capable streaming endpoint: `GET /api/eventmedia/stream/<media_id>/<filename>` (supports byte-range requests 206 for seeking).
	- Scheduler: Performs a best-effort HEAD probe for video stream URLs and includes basic metadata in the emitted payload (`mime_type`, `size`, `accept_ranges`). Placeholders added for `duration`, `resolution`, `bitrate`, `qualities`, `thumbnails`, `checksum`.
- 🖥️ Frontend/Dashboard:
	- Settings page refactored to nested tabs with controlled tab selection (`selectedItem`) to prevent sub-tab jumps.
	- Settings → Events → Videos: Added system-wide defaults with load/save via system settings keys: `video_autoplay`, `video_loop`, `video_volume`, `video_muted`.
	- Event modal (CustomEventModal): Exposes per-event video options including “Ton aus” (`muted`) and initializes all video fields from system defaults when creating new events.
	- Academic Calendar (Settings): Merged “Schulferien Import” and “Liste” into a single sub-tab “📥 Import & Liste”.
- 📖 Documentation:
	- Updated `README.md` and `.github/copilot-instructions.md` for video payload (incl. `muted`), streaming endpoint (206), nested Settings tabs, and video defaults keys; clarified client handling of `video` payloads.
	- Updated `dashboard/public/program-info.json` (user-facing changelog) and bumped version to `2025.1.0-alpha.11` with corresponding UI/UX notes.

Notes for integrators:
- Clients should parse `event_type` and handle the nested `video` payload, honoring `autoplay`, `loop`, `volume`, and `muted`. Use the streaming endpoint with HTTP Range for seeking.
- System settings keys for video defaults: `video_autoplay`, `video_loop`, `video_volume`, `video_muted`.

## 2025.1.0-alpha.10 (2025-10-25)
- No new developer-facing changes in this release.
- UI/UX updates are documented in `dashboard/public/program-info.json`:
	- Event modal: Surfaced video options (Autoplay, Loop, Volume).
	- FileManager: Increased upload limits (Full-HD); client-side duration validation (max 10 minutes).

## 2025.1.0-alpha.9 (2025-10-19)
- 🗓️ Events/API:
	- Implemented new `webuntis` event type. Event creation now resolves the URL from the system setting `supplement_table_url`; returns 400 if unset.
	- Removed obsolete `webuntis-url` settings endpoints. Use `GET/POST /api/system-settings/supplement-table` for URL and enabled state (shared for WebUntis/Vertretungsplan).
	- Initialization defaults: dropped `webuntis_url`; updated `supplement_table_url` description to “Vertretungsplan / WebUntis”.
- 🚦 Scheduler payloads:
	- Unified Website/WebUntis payload: both emit a nested `website` object `{ "type": "browser", "url": "…" }`; `event_type` remains either `website` or `webuntis` for dispatch.
	- Payloads now include a top-level `event_type` string for all events to aid client dispatch.
- 🖥️ Frontend/Dashboard:
	- Program info updated to `2025.1.0-alpha.13` with release notes.
	- Settings → Events: WebUntis now uses the existing Supplement-Table URL; no separate WebUntis URL field.
	- Event modal: WebUntis type behaves like Website (no per-event URL input).
- 📖 Documentation:
	- Added `MQTT_EVENT_PAYLOAD_GUIDE.md` (message structure, client best practices, versioning).
	- Added `WEBUNTIS_EVENT_IMPLEMENTATION.md` (design notes, admin setup, testing checklist).
	- Updated `.github/copilot-instructions.md` and `README.md` for the unified Website/WebUntis handling and settings usage.

Notes for integrators:
- If you previously integrated against `/api/system-settings/webuntis-url`, migrate to `/api/system-settings/supplement-table`.
- Clients should now parse `event_type` and use the corresponding nested payload (`presentation`, `website`, …). `webuntis` and `website` should be handled identically (nested `website` payload).


## 2025.1.0-alpha.8 (2025-10-18)
- 🛠️ Backend: Seeded presentation defaults (`presentation_interval`, `presentation_page_progress`, `presentation_auto_progress`) in system settings; applied on event creation.
- 🗃️ Data model: Added `page_progress` and `auto_progress` fields to `Event` (with Alembic migration).
- 🗓️ Scheduler: Now publishes only currently active events per group (at "now"); clears retained topics by publishing `[]` for groups with no active events; normalizes naive timestamps and compares times in UTC; presentation payloads include `page_progress` and `auto_progress`.
- 🖥️ Dashboard: Settings → Events tab now includes Presentations defaults (interval, page-progress, auto-progress) with load/save via API; event modal applies defaults on create and persists per-event values on edit.
- 📖 Docs: Updated README and Copilot instructions for new scheduler behavior, UTC handling, presentation defaults, and per-event flags.

---

## 2025.1.0-alpha.11 (2025-10-16)
- ✨ Settings page: New tab layout (Syncfusion) with role-based visibility – Tabs: 📅 Academic Calendar, 🖥️ Display & Clients, 🎬 Media & Files, 🗓️ Events, ⚙️ System.
- 🛠️ Settings (Technical): API calls now use relative /api paths via the Vite proxy (prevents CORS and double /api).
- 📖 Docs: README updated for settings page (tabs) and system settings API.

## 2025.1.0-alpha.10 (2025-10-15)
- 🔐 Auth: Login and user management implemented (role-based, persistent sessions).
- 🧩 Frontend: Syncfusion SplitButtons integrated (react-splitbuttons) and Vite config updated for pre-bundling.
- 🐛 Fix: Import error ‘@syncfusion/ej2-react-splitbuttons’ – instructions added to README (optimizeDeps + volume reset).

## 2025.1.0-alpha.9 (2025-10-14)
- ✨ UI: Unified deletion workflow for appointments – all types (single, single instance, entire series) handled with custom dialogs.
- 🔧 Frontend: Syncfusion RecurrenceAlert and DeleteAlert intercepted and replaced with custom dialogs (including final confirmation for series deletion).
- 📖 Docs: README and Copilot instructions expanded for deletion workflow and dialog handling.

## 2025.1.0-alpha.8 (2025-10-11)
- 🎨 Theme: Migrated to Syncfusion Material 3; centralized CSS imports in main.tsx
- 🧹 Cleanup: Tailwind CSS completely removed (packages, PostCSS, Stylelint, config files)
- 🧩 Group management: "infoscreen_groups" migrated to Syncfusion components (Buttons, Dialogs, DropDownList, TextBox); improved spacing
- 🔔 Notifications: Unified toast/dialog wording; last alert usage replaced
- 📖 Docs: README and Copilot instructions updated (Material 3, centralized styles, no Tailwind)

## 2025.1.0-alpha.7 (2025-09-21)
- 🧭 UI: Period selection (Syncfusion) next to group selection; compact layout
- ✅ Display: Badge for existing holiday plan + counter ‘Holidays in view’
- 🛠️ API: Endpoints for academic periods (list, active GET/POST, for_date)
- 📅 Scheduler: By default, no scheduling during holidays; block display like all-day event; black text color
- 📤 Holidays: Upload from TXT/CSV (headless TXT uses columns 2–4)
- 🔧 UX: Switches in a row; dropdown widths optimized

## 2025.1.0-alpha.6 (2025-09-20)
- 🗓️ NEW: Academic periods system – support for school years, semesters, trimesters
- 🏗️ DATABASE: New 'academic_periods' table for time-based organization
- 🔗 EXTENDED: Events and media can now optionally be linked to an academic period
- 📊 ARCHITECTURE: Fully backward-compatible implementation for gradual rollout
- ⚙️ TOOLS: Automatic creation of standard school years for Austrian schools

## 2025.1.0-alpha.5 (2025-09-14)
- Backend: Complete redesign of backend handling for group assignments of new clients and steps for changing group assignment.

## 2025.1.0-alpha.4 (2025-09-01)
- Deployment: Base structure for deployment tested and optimized.
- FIX: Program error when switching view on media page fixed.

## 2025.1.0-alpha.3 (2025-08-30)
- NEW: Program info page with dynamic data, build info, and changelog.
- NEW: Logout functionality implemented.
- FIX: Sidebar width corrected in collapsed state.

## 2025.1.0-alpha.2 (2025-08-29)
- INFO: Analysis and display of used open-source libraries.

## 2025.1.0-alpha.1 (2025-08-28)
- Initial project setup and base structure.
