31 KiB
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)
- 🔌 TV Power Intent Phase 1 (server-side):
- Scheduler now publishes retained QoS1 group-level intents to
infoscreen/groups/{group_id}/power/intent. - Implemented deterministic intent computation helpers in
scheduler/db_utils.py(compute_group_power_intent_basis,build_group_power_intent_body,compute_group_power_intent_fingerprint). - Implemented transition + heartbeat semantics in
scheduler/scheduler.py: stableintent_idon heartbeat; newintent_idonly on semantic transition. - Added startup publish and MQTT reconnect republish behavior for retained intent continuity.
- Added poll-based expiry rule:
expires_at = issued_at + max(3 × poll_interval_sec, 90s). - Added scheduler tests and canary validation artifacts:
scheduler/test_power_intent_utils.py,scheduler/test_power_intent_scheduler.py,test_power_intent_canary.py, andTV_POWER_CANARY_VALIDATION_CHECKLIST.md.
- Scheduler now publishes retained QoS1 group-level intents to
- 🗃️ Holiday data model scoping to academic periods:
- Added period scoping for holidays via
SchoolHoliday.academic_period_id(FK to academic periods) inmodels/models.py. - Added Alembic migration
f3c4d5e6a7b8_scope_school_holidays_to_academic_.pyto 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.
- Added period scoping for holidays via
- 🔌 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/holidaysPUT /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+regionoverlaps (including adjacent ranges) are merged. - Different-identity overlaps are treated as conflicts (manual blocked, import skipped with details).
- Same normalized
- 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_idinstead of global holiday sets. - Updated event-side recurrence handling (
server/routes/events.py) to keep EXDATE behavior in sync with period-scoped holidays.
- Event holiday-skip exception regeneration now resolves holidays by
- 🖥️ 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.
- Updated holiday API client (
- 📖 Documentation & release alignment:
- Updated
.github/copilot-instructions.mdwith period-scoped holiday conventions, overlap policy, and settings behavior. - Refactored root
README.mdto index-style documentation and archived historical implementation docs underdocs/archive/. - Synchronized release line with user-facing version
2026.1.0-alpha.15indashboard/public/program-info.json.
- Updated
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()fromgroupColors.tsfor 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
- New frontend page:
- 🎨 Ressourcen Styling:
- New CSS file:
dashboard/src/ressourcen.css(178 lines) with modern Material 3 design - Fixed CSS lint errors: Converted
rgba()to modernrgb()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-schedulebefore.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
- New CSS file:
- 🔌 Group Order API:
- New backend endpoints in
server/routes/groups.py:GET /api/groups/order– Retrieve saved group display order (returns JSON withorderarray of group IDs)POST /api/groups/order– Persist group display order (accepts JSON withorderarray)
- Order persistence: Stored in
system_settingstable with keygroup_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
- New backend endpoints in
- 🖥️ Frontend Technical:
- State management: React hooks with unused setters removed (setTimelineView, setViewDate) to resolve lint warnings
- TypeScript: Changed
lettoconstfor 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 + 100pxfor header
- 📖 Documentation:
- Updated
.github/copilot-instructions.md:- Added Ressourcen page to "Recent changes" section (January 2026)
- Added
ressourcen.tsxandressourcen.cssto "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/orderto Core Resources API section
- Bumped version in
dashboard/public/program-info.jsonto2026.1.0-alpha.14with user-facing changelog
- Updated
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_logstable: 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
clientstable: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:
ClientLogwith foreign key toClient(CASCADE on delete) - Extended
Clientmodel with 7 health monitoring fields
- New enums:
- 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
ClientLogentries, 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_idfrom payload
- New topic subscriptions:
- 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.pyasclient_logs_bp
- Dev environment fix: Updated
docker-compose.override.ymllistener service to useworking_dir: /workspaceand direct command path for live code reload
- Database schema: New Alembic migration
- 🖥️ 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
- Frontend monitoring dashboard (
- 🐛 Presentation Flags Persistence Fix (2026-03-24):
- Fixed persistence for presentation flags
page_progressandauto_progressacross create/update and detached-occurrence flows - API serialization now reliably returns stored values for presentation behavior fields
- Fixed persistence for presentation flags
- 📡 MQTT Protocol Extensions:
- New log topics:
infoscreen/{uuid}/logs/{error|warn|info}with JSON payload (timestamp, message, context) - New health topic:
infoscreen/{uuid}/healthwith metrics (expected_state, actual_state, health_metrics) - Enhanced heartbeat:
infoscreen/{uuid}/heartbeatnow includescurrent_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)
- New log topics:
- 📖 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
- New file:
- ✅ 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/testfor 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
Userwith 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 trackingfailed_login_attempts,last_failed_login_at: Security monitoring for brute-force detectionlocked_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, resetsfailed_login_attemptson success; incrementsfailed_login_attemptsandlast_failed_login_aton failure - Password change: Sets
last_password_change_aton both self-service and admin reset - New endpoint:
PUT /api/auth/change-passwordfor self-service password change (all authenticated users; requires current password verification)
- Login: Sets
- 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_atanddeactivated_by); hard-delete superadmin-only
- Backend: Implemented comprehensive user management API (
- 🖥️ 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)
- New page:
- 💬 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
- New file:
- 📖 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
- Updated
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; switchedpostCreateCommandtonpm cifor reproducible dashboard installs;postStartCommandaliases made idempotent. - 🔄 Serialization: Consolidated snake_case→camelCase via
server/serializers.pyfor 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
Zin API responses; frontend appendsZ. - 📡 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()beforejsonify()uniformly; verified Session lifecycle consistency (open/commit/close) across blueprints. - 🔄 API Naming Convention Standardization:
- Created
server/serializers.pywithdict_to_camel_case()anddict_to_snake_case()utilities for consistent JSON serialization - Events API refactored:
GET /api/eventsandGET /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()beforejsonify() - Breaking: External API consumers must update field names from PascalCase to camelCase
- Created
- ⏰ 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
- Dashboard (
- 📖 Documentation:
- Updated
.github/copilot-instructions.mdwith 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.mdwith recent changes, API response format section, and dashboard page details
- Updated
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()fromserver/serializers.pyfor any new API endpoints returning JSON - Dev container: prefer
npm ciand 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) toEventwith Alembic migration; create/update and GET endpoints now accept, persist, and returnmutedalongsideautoplay,loop, andvolumefor video events. - Video event fields consolidated:
event_media_id,autoplay,loop,volume,muted.
- Added
- 🔗 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 forduration,resolution,bitrate,qualities,thumbnails,checksum.
- Added range-capable streaming endpoint:
- 🖥️ 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”.
- Settings page refactored to nested tabs with controlled tab selection (
- 📖 Documentation:
- Updated
README.mdand.github/copilot-instructions.mdfor video payload (incl.muted), streaming endpoint (206), nested Settings tabs, and video defaults keys; clarified client handling ofvideopayloads. - Updated
dashboard/public/program-info.json(user-facing changelog) and bumped version to2025.1.0-alpha.11with corresponding UI/UX notes.
- Updated
Notes for integrators:
- Clients should parse
event_typeand handle the nestedvideopayload, honoringautoplay,loop,volume, andmuted. 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
webuntisevent type. Event creation now resolves the URL from the system settingsupplement_table_url; returns 400 if unset. - Removed obsolete
webuntis-urlsettings endpoints. UseGET/POST /api/system-settings/supplement-tablefor URL and enabled state (shared for WebUntis/Vertretungsplan). - Initialization defaults: dropped
webuntis_url; updatedsupplement_table_urldescription to “Vertretungsplan / WebUntis”.
- Implemented new
- 🚦 Scheduler payloads:
- Unified Website/WebUntis payload: both emit a nested
websiteobject{ "type": "browser", "url": "…" };event_typeremains eitherwebsiteorwebuntisfor dispatch. - Payloads now include a top-level
event_typestring for all events to aid client dispatch.
- Unified Website/WebUntis payload: both emit a nested
- 🖥️ Frontend/Dashboard:
- Program info updated to
2025.1.0-alpha.13with 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).
- Program info updated to
- 📖 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.mdandREADME.mdfor the unified Website/WebUntis handling and settings usage.
- Added
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_typeand use the corresponding nested payload (presentation,website, …).webuntisandwebsiteshould be handled identically (nestedwebsitepayload).
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_progressandauto_progressfields toEvent(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 includepage_progressandauto_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.