feat: period-scoped holiday management, archive lifecycle, and docs/release sync
- add period-scoped holiday architecture end-to-end - model: scope `SchoolHoliday` to `academic_period_id` - migrations: add holiday-period scoping, academic-period archive lifecycle, and merge migration head - API: extend holidays with manual CRUD, period validation, duplicate prevention, and overlap merge/conflict handling - recurrence: regenerate holiday exceptions using period-scoped holiday sets - improve frontend settings and holiday workflows - bind holiday import/list/manual CRUD to selected academic period - show detailed import outcomes (inserted/updated/merged/skipped/conflicts) - fix file-picker UX (visible selected filename) - align settings controls/dialogs with defined frontend design rules - scope appointments/dashboard holiday loading to active period - add shared date formatting utility - strengthen academic period lifecycle handling - add archive/restore/delete flow and backend validations/blocker checks - extend API client support for lifecycle operations - release/docs updates and cleanup - bump user-facing version to `2026.1.0-alpha.15` with new changelog entry - add tech changelog entry for alpha.15 backend changes - refactor README to concise index and archive historical implementation docs - fix Copilot instruction link diagnostics via local `.github` design-rules reference
This commit is contained in:
774
README.md
774
README.md
@@ -6,643 +6,181 @@
|
||||
[](https://mariadb.org/)
|
||||
[](https://mosquitto.org/)
|
||||
|
||||
A comprehensive multi-service digital signage solution for educational institutions, featuring client management, event scheduling, presentation conversion, and real-time MQTT communication.
|
||||
Multi-service digital signage platform for educational institutions.
|
||||
|
||||
## 🏗️ Architecture Overview
|
||||
Core stack:
|
||||
- Dashboard: React + Vite + Syncfusion
|
||||
- API: Flask + SQLAlchemy + Alembic
|
||||
- DB: MariaDB
|
||||
- Messaging: MQTT (Mosquitto)
|
||||
- Background jobs: Redis + RQ + Gotenberg
|
||||
|
||||
```
|
||||
┌───────────────┐ ┌──────────────────────────┐ ┌───────────────┐
|
||||
│ Dashboard │◄──────►│ API Server │◄──────►│ Worker │
|
||||
│ (React/Vite) │ │ (Flask) │ │ (Conversions) │
|
||||
└───────────────┘ └──────────────────────────┘ └───────────────┘
|
||||
▲ ▲
|
||||
│ │
|
||||
┌───────────────┐ │
|
||||
│ MariaDB │ │
|
||||
│ (Database) │ │
|
||||
└───────────────┘ │
|
||||
│ direct commands/results
|
||||
## Architecture (Short)
|
||||
|
||||
Reads events ▲ Interacts with API ▲
|
||||
│ ┌────┘
|
||||
┌───────────────┐ │ │ ┌───────────────┐
|
||||
│ Scheduler │──┘ └──│ Listener │
|
||||
│ (Events) │ │ (MQTT Client) │
|
||||
└───────────────┘ └───────────────┘
|
||||
│ Publishes events ▲ Consumes discovery/heartbeats
|
||||
▼ │ and forwards to API
|
||||
┌─────────────────┐◄─────────────────────────────────────────────────────────────────┘
|
||||
│ MQTT Broker │────────────────────────────────────────────────────────► Clients
|
||||
│ (Mosquitto) │ Sends events to clients (send discovery/heartbeats)
|
||||
└─────────────────┘
|
||||
```
|
||||
- Dashboard talks only to API (`/api/...` via Vite proxy in dev).
|
||||
- API is the single writer to MariaDB.
|
||||
- Listener consumes MQTT discovery/heartbeat/log/screenshot topics and updates API state.
|
||||
- Scheduler expands recurring events, applies exceptions, and publishes active content to retained MQTT topics.
|
||||
- Worker handles document conversions asynchronously.
|
||||
|
||||
Data flow summary:
|
||||
- Listener: consumes discovery and heartbeat messages from the MQTT Broker and updates the API Server (client registration/heartbeats).
|
||||
- Listener screenshot flow: consumes `infoscreen/{uuid}/screenshot` and `infoscreen/{uuid}/dashboard`. Dashboard messages use grouped v2 schema (`message`, `content`, `runtime`, `metadata`); screenshot data is read from `content.screenshot`, capture type from `metadata.capture.type`, and forwarded to `POST /api/clients/{uuid}/screenshot`.
|
||||
- Scheduler: reads events from the API Server and publishes only currently active content to the MQTT Broker (retained topics per group). When a group has no active events, the scheduler clears its retained topic by publishing an empty list. All time comparisons are done in UTC; any naive timestamps are normalized.
|
||||
- Clients: send discovery/heartbeat via the MQTT Broker (handled by the Listener) and receive content from the Scheduler via MQTT.
|
||||
- Worker: receives conversion commands directly from the API Server and reports results/status back to the API (no MQTT involved).
|
||||
- MariaDB: is accessed exclusively by the API Server. The Dashboard never talks to the database directly; it only communicates with the API.
|
||||
|
||||
## 🌟 Key Features
|
||||
|
||||
- **User Management**: Comprehensive role-based access control (user → editor → admin → superadmin)
|
||||
- Admin panel for user CRUD operations with audit tracking
|
||||
- Self-service password change available to all users
|
||||
- Audit trail: login times, password changes, deactivation history
|
||||
- Soft-delete by default, hard-delete superadmin-only
|
||||
- Modern React-based web interface with Syncfusion components
|
||||
- Real-time client monitoring and group management
|
||||
- Event scheduling with academic period support
|
||||
- Media management with presentation conversion
|
||||
- Holiday calendar integration
|
||||
- Visual indicators: TentTree icon next to the main event icon marks events that skip holidays (icon color: black)
|
||||
|
||||
- **Event Deletion**: All event types (single, single-in-series, entire series) are handled with custom dialogs. The frontend intercepts Syncfusion's built-in RecurrenceAlert and DeleteAlert popups to provide a unified, user-friendly deletion flow:
|
||||
- Single (non-recurring) event: deleted directly after confirmation.
|
||||
- Single occurrence of a recurring series: user can delete just that instance.
|
||||
- Entire recurring series: user can delete all occurrences after a final custom confirmation dialog.
|
||||
- Detached occurrences (edited/broken out): treated as single events.
|
||||
|
||||
### 🎯 **Event System**
|
||||
- **Presentations**: PowerPoint/LibreOffice → PDF conversion via Gotenberg
|
||||
- **Websites**: URL-based content display
|
||||
- **Videos**: Media file streaming with per-event playback settings (`autoplay`, `loop`, `volume`, `muted`); system-wide defaults configurable under Settings → Events → Videos
|
||||
- **Messages**: Text announcements
|
||||
- **WebUntis**: Educational schedule integration
|
||||
- Uses the system-wide Vertretungsplan/Supplement-Table URL (`supplement_table_url`) configured under Settings → Events. No separate per-event URL is required; WebUntis events display the same as Website events.
|
||||
- **Recurrence & Holidays**: Recurring events can be configured to skip holidays. The backend generates EXDATEs (RecurrenceException) for holiday occurrences using RFC 5545 timestamps (yyyyMMddTHHmmssZ), so the calendar never shows those instances. The scheduler queries a 7-day window to expand recurring events and applies event exceptions, but only publishes events that are active at the current time (UTC). The "Termine an Ferientagen erlauben" toggle does not affect these events.
|
||||
- **Single Occurrence Editing**: Users can edit individual occurrences of recurring events without affecting the master series. The system provides a confirmation dialog to choose between editing a single occurrence or the entire series.
|
||||
|
||||
### 🏫 **Academic Period Management**
|
||||
- Support for school years, semesters, and trimesters
|
||||
- Austrian school system integration
|
||||
- Holiday calendar synchronization
|
||||
- Period-based event organization
|
||||
|
||||
### 📡 **Real-time Communication**
|
||||
- MQTT-based client discovery and heartbeat monitoring
|
||||
- Retained topics for reliable state synchronization
|
||||
- WebSocket support for browser clients
|
||||
- Automatic client group assignment
|
||||
|
||||
### 🔄 **Background Processing**
|
||||
- Redis-based job queues for presentation conversion
|
||||
- Gotenberg integration for LibreOffice/PowerPoint processing
|
||||
- Asynchronous file processing with status tracking
|
||||
- RQ (Redis Queue) worker management
|
||||
|
||||
## 🚀 Quick Start
|
||||
## Quick Start
|
||||
|
||||
### Prerequisites
|
||||
- Docker & Docker Compose
|
||||
- Docker + Docker Compose
|
||||
- Git
|
||||
- SSL certificates (for production)
|
||||
|
||||
### Development Setup
|
||||
|
||||
1. **Clone the repository**
|
||||
```bash
|
||||
git clone https://github.com/RobbStarkAustria/infoscreen_2025.git
|
||||
cd infoscreen_2025
|
||||
```
|
||||
|
||||
2. **Environment Configuration**
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# Edit .env with your configuration
|
||||
```
|
||||
|
||||
3. **Start the development stack**
|
||||
```bash
|
||||
make up
|
||||
# or: docker compose up -d --build
|
||||
```
|
||||
|
||||
Before running the dashboard dev server you may need to install Syncfusion packages used by the UI. Example (install only the packages you use):
|
||||
|
||||
```bash
|
||||
# from the repository root
|
||||
cd dashboard
|
||||
npm install --save @syncfusion/ej2-react-splitbuttons @syncfusion/ej2-splitbuttons \
|
||||
@syncfusion/ej2-react-grids @syncfusion/ej2-react-schedule @syncfusion/ej2-react-filemanager
|
||||
```
|
||||
|
||||
License note: Syncfusion distributes components under a commercial license with a free community license for qualifying users. Verify licensing for your organization before using Syncfusion in production and document any license keys or compliance steps in this repository.
|
||||
|
||||
4. **Initialize the database (first run only)**
|
||||
```bash
|
||||
# One-shot: runs all Alembic migrations, creates default admin/group, and seeds academic periods
|
||||
python server/initialize_database.py
|
||||
```
|
||||
|
||||
5. **Access the services**
|
||||
- Dashboard: http://localhost:5173
|
||||
- API: http://localhost:8000
|
||||
- Database: localhost:3306
|
||||
- MQTT: localhost:1883 (WebSocket: 9001)
|
||||
|
||||
### Production Deployment
|
||||
|
||||
1. **Build and push images**
|
||||
```bash
|
||||
make build
|
||||
make push
|
||||
```
|
||||
|
||||
2. **Deploy on server**
|
||||
```bash
|
||||
make pull-prod
|
||||
make up-prod
|
||||
```
|
||||
|
||||
For detailed deployment instructions, see:
|
||||
- [Debian Deployment Guide](deployment-debian.md)
|
||||
- [Ubuntu Deployment Guide](deployment-ubuntu.md)
|
||||
|
||||
## 🛠️ Services
|
||||
|
||||
### 🖥️ **Dashboard** (`dashboard/`)
|
||||
- **Technology**: React 19 + TypeScript + Vite
|
||||
- **UI Framework**: Syncfusion components (Material 3 theme)
|
||||
- **Styling**: Centralized Syncfusion Material 3 CSS imports in `dashboard/src/main.tsx`
|
||||
- **Features**: Responsive design, real-time updates, file management
|
||||
- **Port**: 5173 (dev), served via Nginx (prod)
|
||||
- **Data access**: No direct database connection; communicates with the API Server only via HTTP.
|
||||
- **Dev proxy tip**: In development, use relative paths like `/api/...` in the frontend to route through Vite's proxy to the API. Avoid absolute URLs with an extra `/api` segment to prevent CORS or double-path issues.
|
||||
|
||||
### 🔧 **API Server** (`server/`)
|
||||
- **Technology**: Flask + SQLAlchemy + Alembic
|
||||
- **Database**: MariaDB with timezone-aware timestamps
|
||||
- **Features**: RESTful API, file uploads, MQTT integration
|
||||
- Recurrence/holidays: returns only master events with `RecurrenceRule` and `RecurrenceException` (EXDATEs) so clients render recurrences and skip holiday instances reliably.
|
||||
- Recurring events are only deactivated after their recurrence_end (UNTIL); non-recurring events deactivate after their end time. Event exceptions are respected and rendered in scheduler output.
|
||||
- Single occurrence detach: `POST /api/events/<id>/occurrences/<date>/detach` creates standalone events from recurring series without modifying the master event.
|
||||
- **Port**: 8000
|
||||
- **Health Check**: `/health`
|
||||
|
||||
### 👂 **Listener** (`listener/`)
|
||||
|
||||
### ⏰ **Scheduler** (`scheduler/`)
|
||||
**Technology**: Python + SQLAlchemy
|
||||
**Purpose**: Event publishing, group-based content distribution
|
||||
**Features**:
|
||||
- Queries a future window (default: 7 days) to expand recurring events
|
||||
- Expands recurrences using RFC 5545 rules
|
||||
- Applies event exceptions (skipped dates, detached occurrences)
|
||||
- Only deactivates recurring events after their recurrence_end (UNTIL)
|
||||
- Publishes only currently active events to MQTT (per group)
|
||||
- Clears retained topics by publishing an empty list when a group has no active events
|
||||
- Normalizes naive timestamps and compares times in UTC
|
||||
- Logging is concise; conversion lookups are cached and logged only once per media
|
||||
|
||||
### 🔄 **Worker** (Conversion Service)
|
||||
- **Technology**: RQ (Redis Queue) + Gotenberg
|
||||
- **Purpose**: Background presentation conversion
|
||||
- **Features**: PPT/PPTX/ODP → PDF conversion, status tracking
|
||||
|
||||
### 🗄️ **Database** (MariaDB 11.2)
|
||||
- **Features**: Health checks, automatic initialization
|
||||
- **Migrations**: Alembic-based schema management
|
||||
- **Timezone**: UTC-aware timestamps
|
||||
|
||||
### 📡 **MQTT Broker** (Eclipse Mosquitto 2.0.21)
|
||||
- **Features**: WebSocket support, health monitoring
|
||||
- **Topics**:
|
||||
- `infoscreen/discovery` - Client registration
|
||||
- `infoscreen/{uuid}/heartbeat` - Client alive status
|
||||
- `infoscreen/events/{group_id}` - Event distribution
|
||||
## 🔗 Scheduler Event Payloads
|
||||
|
||||
- Presentations include a `presentation` object with `files`, `slide_interval`, `page_progress`, and `auto_progress`.
|
||||
- Website and WebUntis events share a unified payload:
|
||||
- `website`: `{ "type": "browser", "url": "https://..." }`
|
||||
- The `event_type` field remains specific (e.g., `presentation`, `website`, `webuntis`) so clients can dispatch appropriately; however, `website` and `webuntis` should be handled identically in clients.
|
||||
- Videos include a `video` payload with a stream URL and playback flags:
|
||||
- `video`: includes `url` (streaming endpoint) and `autoplay`, `loop`, `volume`, `muted`
|
||||
- Streaming endpoint supports byte-range requests (206) to enable seeking: `/api/eventmedia/stream/<media_id>/<filename>`
|
||||
- Server-side UTC: All backend comparisons are performed in UTC; API returns ISO strings without `Z`. Frontend appends `Z` before parsing.
|
||||
|
||||
## Recent changes since last commit
|
||||
|
||||
- Monitoring system: End-to-end monitoring is now implemented. The listener ingests `logs/*` and `health` MQTT topics, the API exposes monitoring endpoints (`/api/client-logs/monitoring-overview`, `/api/client-logs/recent-errors`, `/api/client-logs/<uuid>/logs`), and the superadmin dashboard page shows live client status, screenshots, and recent errors.
|
||||
- Screenshot priority flow: Screenshot payloads now support `screenshot_type` (`periodic`, `event_start`, `event_stop`). `event_start` and `event_stop` are treated as high-priority screenshots; the API stores typed screenshots, maintains priority metadata, and serves active priority screenshots through `/screenshots/{uuid}/priority`.
|
||||
- MQTT dashboard payload v2 cutover: Listener parsing is now v2-only for dashboard JSON payloads (`message/content/runtime/metadata`). Legacy top-level dashboard fallback has been removed after migration completion; parser observability tracks `v2_success` and `parse_failures`.
|
||||
- Presentation persistence fix: Fixed persistence of presentation flags so `page_progress` and `auto_progress` are reliably stored and returned for create/update flows and detached occurrences.
|
||||
- Additional improvements: Video/streaming, scheduler metadata, settings defaults, and UI refinements remain documented in the detailed sections below.
|
||||
|
||||
These changes are designed to be safe if metadata extraction or probes fail — clients should still attempt playback using the provided `url` and fall back to requesting/resolving richer metadata when available.
|
||||
|
||||
See `MQTT_EVENT_PAYLOAD_GUIDE.md` for details.
|
||||
|
||||
## 🧩 Developer Environment Notes (Dev Container)
|
||||
- Extensions: UI-only `Dev Containers` runs on the host UI; not installed inside the container to avoid reinstallation loops. See `/.devcontainer/devcontainer.json` (`remote.extensionKind`).
|
||||
- Installs: Dashboard uses `npm ci` on `postCreateCommand` for reproducible installs.
|
||||
- Aliases: `postStartCommand` appends shell aliases idempotently to prevent duplicates across restarts.
|
||||
|
||||
## 📦 Versioning
|
||||
- Unified app version: Use a single SemVer for the product (e.g., `2025.1.0-beta.3`) — simplest for users and release management.
|
||||
- Pre-releases: Use identifiers like `-alpha.N`, `-beta.N`, `-rc.N` for stage tracking.
|
||||
- Build metadata: Optionally include component build info (non-ordering) e.g., `+api.abcd123,dash.efgh456,sch.jkl789,wkr.mno012`.
|
||||
- Component traceability: Document component SHAs or image tags under each TECH-CHANGELOG release entry rather than exposing separate user-facing versions.
|
||||
- Hotfixes: For backend-only fixes, prefer a patch bump or pre-release increment, and record component metadata under the unified version.
|
||||
|
||||
## 📁 Project Structure
|
||||
|
||||
```
|
||||
infoscreen_2025/
|
||||
├── dashboard/ # React frontend
|
||||
│ ├── src/ # React components and logic
|
||||
│ ├── public/ # Static assets
|
||||
│ └── Dockerfile # Production build
|
||||
├── server/ # Flask API backend
|
||||
│ ├── routes/ # API endpoints
|
||||
│ ├── alembic/ # Database migrations
|
||||
│ ├── media/ # File storage
|
||||
│ ├── initialize_database.py # All-in-one DB initialization (dev)
|
||||
│ └── worker.py # Background jobs
|
||||
├── listener/ # MQTT listener service
|
||||
├── scheduler/ # Event scheduling service
|
||||
├── models/ # Shared database models
|
||||
├── mosquitto/ # MQTT broker configuration
|
||||
├── certs/ # SSL certificates
|
||||
├── docker-compose.yml # Development setup
|
||||
├── docker-compose.prod.yml # Production setup
|
||||
└── Makefile # Development shortcuts
|
||||
```
|
||||
|
||||
## 🔧 Development
|
||||
|
||||
### Available Commands
|
||||
|
||||
```bash
|
||||
# Development
|
||||
make up # Start dev stack
|
||||
make down # Stop dev stack
|
||||
make logs # View all logs
|
||||
make logs-server # View specific service logs
|
||||
|
||||
# Building & Deployment
|
||||
make build # Build all images
|
||||
make push # Push to registry
|
||||
make pull-prod # Pull production images
|
||||
make up-prod # Start production stack
|
||||
|
||||
# Maintenance
|
||||
make health # Health checks
|
||||
make fix-perms # Fix file permissions
|
||||
```
|
||||
|
||||
### Database Management
|
||||
|
||||
```bash
|
||||
# One-shot initialization (schema + defaults + academic periods)
|
||||
python server/initialize_database.py
|
||||
|
||||
# Access database directly
|
||||
docker exec -it infoscreen-db mysql -u${DB_USER} -p${DB_PASSWORD} ${DB_NAME}
|
||||
|
||||
# Run migrations
|
||||
docker exec -it infoscreen-api alembic upgrade head
|
||||
|
||||
# Initialize academic periods (Austrian school system)
|
||||
docker exec -it infoscreen-api python init_academic_periods.py
|
||||
```
|
||||
|
||||
### MQTT Testing
|
||||
|
||||
```bash
|
||||
# Subscribe to all topics
|
||||
mosquitto_sub -h localhost -t "infoscreen/#" -v
|
||||
|
||||
# Publish test message
|
||||
mosquitto_pub -h localhost -t "infoscreen/test" -m "Hello World"
|
||||
|
||||
# Monitor client heartbeats
|
||||
mosquitto_sub -h localhost -t "infoscreen/+/heartbeat" -v
|
||||
```
|
||||
|
||||
## 🌐 API Endpoints
|
||||
|
||||
### Core Resources
|
||||
- `GET /api/clients` - List all registered clients
|
||||
- `PUT /api/clients/{uuid}/group` - Assign client to group
|
||||
- `GET /api/groups` - List client groups with alive status
|
||||
- `GET /api/groups/order` - Get saved group display order
|
||||
- `POST /api/groups/order` - Save group display order (array of group IDs)
|
||||
- `GET /api/events` - List events with filtering
|
||||
- `POST /api/events` - Create new event
|
||||
- `POST /api/events/{id}/occurrences/{date}/detach` - Detach single occurrence from recurring series
|
||||
- `GET /api/academic_periods` - List academic periods
|
||||
- `POST /api/academic_periods/active` - Set active period
|
||||
|
||||
### File Management
|
||||
- `POST /api/files` - Upload media files
|
||||
- `GET /api/files/{path}` - Download files
|
||||
- `GET /api/files/converted/{path}` - Download converted PDFs
|
||||
- `POST /api/conversions/{media_id}/pdf` - Request conversion
|
||||
- `GET /api/conversions/{media_id}/status` - Check conversion status
|
||||
- `GET /api/eventmedia/stream/<media_id>/<filename>` - Stream media with byte-range support (206) for seeking
|
||||
- `POST /api/clients/{uuid}/screenshot` - Upload screenshot for client (base64 JPEG, optional `timestamp`, optional `screenshot_type` = `periodic|event_start|event_stop`)
|
||||
- **Screenshot retention:** The API stores `{uuid}.jpg` as latest plus the last 20 timestamped screenshots per client; older timestamped files are deleted automatically.
|
||||
- **Priority screenshots:** For `event_start`/`event_stop`, the API also keeps `{uuid}_priority.jpg` and metadata (`{uuid}_meta.json`) used by monitoring priority selection.
|
||||
|
||||
### System Settings
|
||||
- `GET /api/system-settings` - List all system settings (admin+)
|
||||
- `GET /api/system-settings/{key}` - Get a specific setting (admin+)
|
||||
- `POST /api/system-settings/{key}` - Create or update a setting (admin+)
|
||||
- `DELETE /api/system-settings/{key}` - Delete a setting (admin+)
|
||||
- `GET /api/system-settings/supplement-table` - Get WebUntis/Vertretungsplan settings (enabled, url)
|
||||
- `POST /api/system-settings/supplement-table` - Update WebUntis/Vertretungsplan settings
|
||||
- Presentation defaults stored as keys:
|
||||
- `presentation_interval` (seconds, default "10")
|
||||
- `presentation_page_progress` ("true"/"false", default "true")
|
||||
- `presentation_auto_progress` ("true"/"false", default "true")
|
||||
- Video defaults stored as keys:
|
||||
- `video_autoplay` ("true"/"false", default "true")
|
||||
- `video_loop` ("true"/"false", default "true")
|
||||
- `video_volume` (0.0–1.0, default "0.8")
|
||||
- `video_muted` ("true"/"false", default "false")
|
||||
|
||||
### User Management (Admin+)
|
||||
- `GET /api/users` - List all users (role-filtered by user's role)
|
||||
- `POST /api/users` - Create new user with username, password (min 6 chars), role, and status
|
||||
- `GET /api/users/<id>` - Get user details including audit information (login times, password changes, deactivation)
|
||||
- `PUT /api/users/<id>` - Update user (cannot change own role or account status)
|
||||
- `PUT /api/users/<id>/password` - Admin password reset (cannot reset own password this way; use `/api/auth/change-password` instead)
|
||||
- `DELETE /api/users/<id>` - Delete user permanently (superadmin only; cannot delete self)
|
||||
|
||||
### Authentication
|
||||
- `POST /api/auth/login` - User login (tracks last login time and failed attempts)
|
||||
- `POST /api/auth/logout` - User logout
|
||||
- `PUT /api/auth/change-password` - Self-service password change (all authenticated users; requires current password verification)
|
||||
|
||||
### Health & Monitoring
|
||||
- `GET /health` - Service health check
|
||||
- `GET /screenshots/{uuid}.jpg` - Latest client screenshot
|
||||
- `GET /screenshots/{uuid}/priority` - Active high-priority screenshot (falls back to latest)
|
||||
- `GET /api/client-logs/monitoring-overview` - Aggregated monitoring overview for dashboard (superadmin)
|
||||
- `GET /api/client-logs/recent-errors` - Recent error feed across clients (admin+)
|
||||
- `GET /api/client-logs/{uuid}/logs` - Filtered per-client logs (admin+)
|
||||
|
||||
## 🎨 Frontend Features
|
||||
|
||||
> UI implementation conventions (component choices, layout, buttons, dialogs, badge colors, toast patterns, locale) are documented in [FRONTEND_DESIGN_RULES.md](FRONTEND_DESIGN_RULES.md).
|
||||
|
||||
### API Response Format
|
||||
- **JSON Convention**: All API endpoints return camelCase JSON (e.g., `startTime`, `endTime`, `groupId`). Frontend consumes camelCase directly.
|
||||
- **UTC Time Parsing**: API returns ISO strings without 'Z' suffix. Frontend appends 'Z' before parsing to ensure UTC interpretation: `const utcString = dateStr.endsWith('Z') ? dateStr : dateStr + 'Z'; new Date(utcString);`. Display uses `toLocaleTimeString('de-DE')` for German format.
|
||||
|
||||
### Recurrence & holidays
|
||||
- Recurrence is handled natively by Syncfusion. The API returns master events with `RecurrenceRule` and `RecurrenceException` (EXDATE) in RFC 5545 format (yyyyMMddTHHmmssZ, UTC) so the Scheduler excludes holiday instances reliably.
|
||||
- Events with "skip holidays" display a TentTree icon next to the main event icon (icon color: black). The Scheduler’s native lower-right recurrence badge indicates series membership.
|
||||
- Single occurrence editing: Users can edit either a single occurrence or the entire series. The UI persists changes using `onActionCompleted (requestType='eventChanged')`:
|
||||
- Single occurrence → `POST /api/events/<id>/occurrences/<date>/detach` (creates standalone event and adds EXDATE to master)
|
||||
- Series/single event → `PUT /api/events/<id>`
|
||||
|
||||
### Syncfusion Components Used (Material 3)
|
||||
- **Schedule**: Event calendar with drag-drop support
|
||||
- **Grid**: Data tables with filtering and sorting
|
||||
- **DropDownList**: Group and period selectors
|
||||
- **FileManager**: Media upload and organization
|
||||
- **Kanban**: Task management views
|
||||
- **Notifications**: Toast messages and alerts
|
||||
- **Pager**: Used on Programinfo changelog for pagination
|
||||
- **Cards (layouts)**: Programinfo sections styled with Syncfusion card classes
|
||||
- **SplitButtons**: Header user menu (top-right) using Syncfusion DropDownButton to show current user and role, with actions "Passwort ändern", "Profil", and "Abmelden".
|
||||
|
||||
### Pages Overview
|
||||
- **Dashboard**: Card-based overview of all Raumgruppen (room groups) with real-time status monitoring. Features include:
|
||||
- Global statistics: total infoscreens, online/offline counts, warning groups
|
||||
- Filter buttons: All / Online / Offline / Warnings with dynamic counts
|
||||
- Per-group cards showing currently active event (title, type, date/time in local timezone)
|
||||
- Health bar with online/offline ratio and color-coded status
|
||||
- Expandable client list with last alive timestamps
|
||||
- Bulk restart button for offline clients
|
||||
- Auto-refresh every 15 seconds; manual refresh button available
|
||||
- **Clients**: Device management and monitoring
|
||||
- **Groups**: Client group organization
|
||||
- **Events**: Schedule management
|
||||
- **Media**: File upload and conversion
|
||||
- **Users**: Comprehensive user management (admin+ only in menu)
|
||||
- Full CRUD interface with sortable GridComponent (20 per page)
|
||||
- Statistics cards: total, active, inactive user counts
|
||||
- Create, edit, delete, and password reset dialogs
|
||||
- User details modal showing audit information (login times, password changes, deactivation)
|
||||
- Role badges with color coding (user: gray, editor: blue, admin: green, superadmin: red)
|
||||
- Self-protection: cannot modify own account (cannot change role/status or delete self)
|
||||
- Superadmin-only hard delete; other users soft-deactivate
|
||||
- **Settings**: Central configuration (tabbed)
|
||||
- 📅 Academic Calendar (all users):
|
||||
- 📥 Import & Liste: CSV/TXT import combined with holidays list
|
||||
- 🗂️ Perioden: Academic Periods (set active period)
|
||||
- 🖥️ Display & Clients (admin+): Defaults placeholders and quick links to Clients/Groups
|
||||
- 🎬 Media & Files (admin+): Upload settings placeholders and Conversion status overview
|
||||
- 🗓️ Events (admin+): WebUntis/Vertretungsplan URL enable/disable, save, preview. Presentations: general defaults for slideshow interval, page-progress, and auto-progress; persisted via `/api/system-settings` keys and applied on create in the event modal. Videos: system-wide defaults for `autoplay`, `loop`, `volume`, and `muted`; persisted via `/api/system-settings` keys and applied on create in the event modal.
|
||||
- ⚙️ System (superadmin): Organization info and Advanced configuration placeholders
|
||||
- **Holidays**: Academic calendar management
|
||||
- **Ressourcen**: Timeline view of active events across all room groups
|
||||
- Parallel timeline display showing all groups and their current events simultaneously
|
||||
- Compact visualization: 65px row height per group with color-coded event bars
|
||||
- Day and week views for flexible time range inspection
|
||||
- Customizable group ordering with visual drag controls (order persisted to backend)
|
||||
- Real-time event status: shows currently running events with type, title, and time window
|
||||
- Filters out unassigned groups for focused view
|
||||
- Resource-based Syncfusion timeline scheduler with resize and drag-drop support
|
||||
- **Monitoring**: Superadmin-only monitoring dashboard
|
||||
- Live client health states (`healthy`, `warning`, `critical`, `offline`) from heartbeat/process/log data
|
||||
- Latest screenshot preview with screenshot-type badges (`periodic`, `event_start`, `event_stop`) and process metadata per client
|
||||
- Active priority screenshots are surfaced immediately and polled faster while priority items are active
|
||||
- System-wide recent error stream and per-client log drill-down
|
||||
- **Program info**: Version, build info, tech stack and paginated changelog (reads `dashboard/public/program-info.json`)
|
||||
|
||||
## 🔒 Security & Authentication
|
||||
|
||||
- **Role-Based Access Control (RBAC)**: 4-tier hierarchy (user → editor → admin → superadmin) with privilege escalation protection
|
||||
- Admin cannot see, manage, or create superadmin accounts
|
||||
- Admin can create and manage user/editor/admin roles only
|
||||
- Superadmin can manage all roles including other superadmins
|
||||
- Role-gated menu visibility: users only see menu items they have permission for
|
||||
- **Account Management**:
|
||||
- Soft-delete by default (deactivated_at, deactivated_by timestamps)
|
||||
- Hard-delete superadmin-only (permanent removal from database)
|
||||
- Self-account protections: cannot change own role/status, cannot delete self via admin panel
|
||||
- Self-service password change available to all authenticated users (requires current password verification)
|
||||
- Admin password reset available for other users (no current password required)
|
||||
- **Audit Tracking**: All user accounts track login times, password changes, failed login attempts, and deactivation history
|
||||
- **Environment Variables**: Sensitive data via `.env`
|
||||
- **SSL/TLS**: HTTPS support with custom certificates
|
||||
- **MQTT Security**: Username/password authentication
|
||||
- **Database**: Parameterized queries, connection pooling
|
||||
- **File Uploads**: Type validation, size limits
|
||||
- **CORS**: Configured for production deployment
|
||||
|
||||
## 📊 Monitoring & Logging
|
||||
|
||||
### Health Checks
|
||||
- Database: Connection and initialization status
|
||||
- MQTT: Pub/sub functionality test
|
||||
- Dashboard: Nginx availability
|
||||
- **Scheduler**: Logging is concise; conversion lookups are cached and logged only once per media.
|
||||
- Monitoring API: `/api/client-logs/monitoring-overview` and `/api/client-logs/recent-errors` for live diagnostics
|
||||
- Monitoring overview includes screenshot priority state (`latestScreenshotType`, `priorityScreenshotType`, `priorityScreenshotReceivedAt`, `hasActivePriorityScreenshot`) and `summary.activePriorityScreenshots`
|
||||
|
||||
### Logging Strategy
|
||||
- **Development**: Docker Compose logs with service prefixes
|
||||
- **Production**: Centralized logging via Docker log drivers
|
||||
- **MQTT**: Message-level debugging available
|
||||
- **Database**: Query logging in development mode
|
||||
|
||||
## 🌍 Deployment Options
|
||||
|
||||
### Development
|
||||
- **Hot Reload**: Vite dev server + Flask debug mode
|
||||
- **Volume Mounts**: Live code editing
|
||||
- **Debug Ports**: Python debugger support (port 5678)
|
||||
- **Local Certificates**: Self-signed SSL for testing
|
||||
|
||||
### Production
|
||||
- **Optimized Builds**: Multi-stage Dockerfiles
|
||||
- **Reverse Proxy**: Nginx with SSL termination
|
||||
- **Health Monitoring**: Comprehensive healthchecks
|
||||
- **Registry**: GitHub Container Registry integration
|
||||
- **Scaling**: Docker Compose for single-node deployment
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch: `git checkout -b feature/amazing-feature`
|
||||
3. Commit your changes: `git commit -m 'Add amazing feature'`
|
||||
4. Push to the branch: `git push origin feature/amazing-feature`
|
||||
5. Open a Pull Request
|
||||
|
||||
### Development Guidelines
|
||||
- Follow existing code patterns and naming conventions
|
||||
- Add appropriate tests for new features
|
||||
- Update documentation for API changes
|
||||
- Use TypeScript for frontend development
|
||||
- Follow Python PEP 8 for backend code
|
||||
|
||||
## 📋 Requirements
|
||||
|
||||
### System Requirements
|
||||
- **CPU**: 2+ cores recommended
|
||||
- **RAM**: 4GB minimum, 8GB recommended
|
||||
- **Storage**: 20GB+ for media files and database
|
||||
- **Network**: Reliable internet for client communication
|
||||
|
||||
### Software Dependencies
|
||||
- Docker 24.0+
|
||||
- Docker Compose 2.0+
|
||||
- Git 2.30+
|
||||
- Modern web browser (Chrome, Firefox, Safari, Edge)
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Services won't start**
|
||||
1. Clone
|
||||
```bash
|
||||
# Check service health
|
||||
git clone https://github.com/RobbStarkAustria/infoscreen_2025.git
|
||||
cd infoscreen_2025
|
||||
```
|
||||
|
||||
2. Configure environment
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# edit values as needed
|
||||
```
|
||||
|
||||
3. Start stack
|
||||
```bash
|
||||
make up
|
||||
# or: docker compose up -d --build
|
||||
```
|
||||
|
||||
4. Initialize DB (first run)
|
||||
```bash
|
||||
python server/initialize_database.py
|
||||
```
|
||||
|
||||
5. Open services
|
||||
- Dashboard: http://localhost:5173
|
||||
- API: http://localhost:8000
|
||||
- MariaDB: localhost:3306
|
||||
- MQTT: localhost:1883 (WS: 9001)
|
||||
|
||||
## Holiday Calendar (Quick Usage)
|
||||
|
||||
Settings path:
|
||||
- `Settings` -> `Academic Calendar` -> `Ferienkalender: Import/Anzeige`
|
||||
|
||||
Workflow summary:
|
||||
1. Select target academic period (archived periods are read-only/not selectable).
|
||||
2. Import CSV/TXT or add/edit holidays manually.
|
||||
3. Validation is period-scoped (out-of-period ranges are blocked).
|
||||
4. Duplicate/overlap policy:
|
||||
- exact duplicates: skipped/prevented
|
||||
- same normalized `name+region` overlaps (including adjacent ranges): merged
|
||||
- different-identity overlaps: conflict (manual blocked, import skipped with details)
|
||||
5. Recurring events with `skip_holidays` are recalculated automatically after holiday changes.
|
||||
|
||||
## Common Commands
|
||||
|
||||
```bash
|
||||
# Start/stop
|
||||
make up
|
||||
make down
|
||||
|
||||
# Logs
|
||||
make logs
|
||||
make logs-server
|
||||
|
||||
# Health
|
||||
make health
|
||||
|
||||
# View specific service logs
|
||||
make logs-server
|
||||
make logs-db
|
||||
# Build/push/deploy
|
||||
make build
|
||||
make push
|
||||
make pull-prod
|
||||
make up-prod
|
||||
```
|
||||
|
||||
**Database connection errors**
|
||||
```bash
|
||||
# Verify database is running
|
||||
docker exec -it infoscreen-db mysqladmin ping
|
||||
## Documentation Map
|
||||
|
||||
# Check credentials in .env file
|
||||
# Restart dependent services
|
||||
### Deployment
|
||||
- [deployment-debian.md](deployment-debian.md)
|
||||
- [deployment-ubuntu.md](deployment-ubuntu.md)
|
||||
- [setup-deployment.sh](setup-deployment.sh)
|
||||
|
||||
### Backend & Database
|
||||
- [DATABASE_GUIDE.md](DATABASE_GUIDE.md)
|
||||
- [TECH-CHANGELOG.md](TECH-CHANGELOG.md)
|
||||
- [server/alembic](server/alembic)
|
||||
|
||||
### Authentication & Authorization
|
||||
- [AUTH_SYSTEM.md](AUTH_SYSTEM.md)
|
||||
- [AUTH_QUICKREF.md](AUTH_QUICKREF.md)
|
||||
- [userrole-management.md](userrole-management.md)
|
||||
- [SUPERADMIN_SETUP.md](SUPERADMIN_SETUP.md)
|
||||
|
||||
### Monitoring, Screenshots, Health
|
||||
- [CLIENT_MONITORING_IMPLEMENTATION_GUIDE.md](CLIENT_MONITORING_IMPLEMENTATION_GUIDE.md)
|
||||
- [CLIENT_MONITORING_SPECIFICATION.md](CLIENT_MONITORING_SPECIFICATION.md)
|
||||
- [SCREENSHOT_IMPLEMENTATION.md](SCREENSHOT_IMPLEMENTATION.md)
|
||||
|
||||
### MQTT & Payloads
|
||||
- [MQTT_EVENT_PAYLOAD_GUIDE.md](MQTT_EVENT_PAYLOAD_GUIDE.md)
|
||||
- [MQTT_PAYLOAD_MIGRATION_GUIDE.md](MQTT_PAYLOAD_MIGRATION_GUIDE.md)
|
||||
|
||||
### Events, Calendar, WebUntis
|
||||
- [WEBUNTIS_EVENT_IMPLEMENTATION.md](WEBUNTIS_EVENT_IMPLEMENTATION.md)
|
||||
|
||||
### Historical Background
|
||||
- [docs/archive/ACADEMIC_PERIODS_IMPLEMENTATION_SUMMARY.md](docs/archive/ACADEMIC_PERIODS_IMPLEMENTATION_SUMMARY.md)
|
||||
- [docs/archive/ACADEMIC_PERIODS_CRUD_BUILD_PLAN.md](docs/archive/ACADEMIC_PERIODS_CRUD_BUILD_PLAN.md)
|
||||
- [docs/archive/PHASE_3_CLIENT_MONITORING_IMPLEMENTATION.md](docs/archive/PHASE_3_CLIENT_MONITORING_IMPLEMENTATION.md)
|
||||
- [docs/archive/CLEANUP_SUMMARY.md](docs/archive/CLEANUP_SUMMARY.md)
|
||||
|
||||
### Conversion / Media
|
||||
- [pptx_conversion_guide.md](pptx_conversion_guide.md)
|
||||
- [pptx_conversion_guide_gotenberg.md](pptx_conversion_guide_gotenberg.md)
|
||||
|
||||
### Frontend
|
||||
- [FRONTEND_DESIGN_RULES.md](FRONTEND_DESIGN_RULES.md)
|
||||
- [dashboard/README.md](dashboard/README.md)
|
||||
|
||||
### Project / Contributor Guidance
|
||||
- [.github/copilot-instructions.md](.github/copilot-instructions.md)
|
||||
- [AI-INSTRUCTIONS-MAINTENANCE.md](AI-INSTRUCTIONS-MAINTENANCE.md)
|
||||
- [DEV-CHANGELOG.md](DEV-CHANGELOG.md)
|
||||
|
||||
## API Highlights
|
||||
|
||||
- Core resources: clients, groups, events, academic periods
|
||||
- Holidays: `GET/POST /api/holidays`, `POST /api/holidays/upload`, `PUT/DELETE /api/holidays/<id>`
|
||||
- Media: upload/download/stream + conversion status
|
||||
- Auth: login/logout/change-password
|
||||
- Monitoring: logs and monitoring overview endpoints
|
||||
|
||||
For full endpoint details, use source route files under `server/routes/` and the docs listed above.
|
||||
|
||||
## Project Structure (Top Level)
|
||||
|
||||
```text
|
||||
infoscreen_2025/
|
||||
├── dashboard/ # React frontend
|
||||
├── server/ # Flask API + migrations + worker
|
||||
├── listener/ # MQTT listener
|
||||
├── scheduler/ # Event scheduler/publisher
|
||||
├── models/ # Shared SQLAlchemy models
|
||||
├── mosquitto/ # MQTT broker config
|
||||
├── certs/ # TLS certs (prod)
|
||||
└── docker-compose*.yml
|
||||
```
|
||||
|
||||
**Vite import-analysis errors (Syncfusion splitbuttons)**
|
||||
```bash
|
||||
# Symptom
|
||||
[plugin:vite:import-analysis] Failed to resolve import "@syncfusion/ej2-react-splitbuttons"
|
||||
## Contributing
|
||||
|
||||
# Fix
|
||||
# 1) Ensure dependencies are added in dashboard/package.json:
|
||||
# - @syncfusion/ej2-react-splitbuttons, @syncfusion/ej2-splitbuttons
|
||||
# 2) In dashboard/vite.config.ts, add to optimizeDeps.include:
|
||||
# '@syncfusion/ej2-react-splitbuttons', '@syncfusion/ej2-splitbuttons'
|
||||
# 3) If dashboard uses a named node_modules volume, recreate it so npm ci runs inside the container:
|
||||
docker compose rm -sf dashboard
|
||||
docker volume rm <project>_dashboard-node-modules <project>_dashboard-vite-cache || true
|
||||
docker compose up -d --build dashboard
|
||||
```
|
||||
1. Create branch
|
||||
2. Implement change + tests
|
||||
3. Update relevant docs
|
||||
4. Open PR
|
||||
|
||||
**MQTT communication issues**
|
||||
```bash
|
||||
# Test MQTT broker
|
||||
mosquitto_pub -h localhost -t test -m "hello"
|
||||
Guidelines:
|
||||
- Match existing architecture and naming conventions
|
||||
- Keep frontend aligned with [FRONTEND_DESIGN_RULES.md](FRONTEND_DESIGN_RULES.md)
|
||||
- Keep service/API behavior aligned with [.github/copilot-instructions.md](.github/copilot-instructions.md)
|
||||
|
||||
# Check client certificates and credentials
|
||||
# Verify firewall settings for ports 1883/9001
|
||||
```
|
||||
## License
|
||||
|
||||
**File conversion problems**
|
||||
```bash
|
||||
# Check Gotenberg service
|
||||
curl http://localhost:3000/health
|
||||
|
||||
# Monitor worker logs
|
||||
make logs-worker
|
||||
|
||||
# Check Redis queue status
|
||||
docker exec -it infoscreen-redis redis-cli LLEN conversions
|
||||
```
|
||||
|
||||
## 📄 License
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
## 🙏 Acknowledgments
|
||||
|
||||
- **Syncfusion**: UI components for React dashboard
|
||||
- **Eclipse Mosquitto**: MQTT broker implementation
|
||||
- **Gotenberg**: Document conversion service
|
||||
- **MariaDB**: Reliable database engine
|
||||
- **Flask**: Python web framework
|
||||
- **React**: Frontend user interface library
|
||||
|
||||
---
|
||||
|
||||
For detailed technical documentation, deployment guides, and API specifications, please refer to the additional documentation files in this repository.
|
||||
|
||||
Notes:
|
||||
- Tailwind CSS was removed. Styling is managed via Syncfusion Material 3 theme imports in `dashboard/src/main.tsx`.
|
||||
|
||||
## 🧭 Changelog Style Guide
|
||||
|
||||
When adding entries to `dashboard/public/program-info.json` (displayed on the Program info page):
|
||||
|
||||
- Structure per release
|
||||
- `version` (e.g., `2025.1.0-alpha.8`)
|
||||
- `date` in `YYYY-MM-DD` (ISO format)
|
||||
- `changes`: array of short bullet strings
|
||||
|
||||
- Categories (Keep a Changelog inspired)
|
||||
- Prefer starting bullets with an implicit category or an emoji, e.g.:
|
||||
- Added (🆕/✨), Changed (🔧/🛠️), Fixed (🐛/✅), Removed (🗑️), Security (🔒), Deprecated (⚠️)
|
||||
|
||||
- Writing rules
|
||||
- Keep bullets concise (ideally one line) and user-facing; avoid internal IDs or jargon
|
||||
- Put the affected area first when helpful (e.g., “UI: …”, “API: …”, “Scheduler: …”)
|
||||
- Highlight breaking changes with “BREAKING:”
|
||||
- Prefer German wording consistently; dates are localized at runtime for display
|
||||
|
||||
- Ordering and size
|
||||
- Newest release first in the array
|
||||
- Aim for ≤ 8–10 bullets per release; group or summarize if longer
|
||||
|
||||
- JSON hygiene
|
||||
- Valid JSON only (no trailing commas); escape quotes as needed
|
||||
- One release object per version; do not modify historical entries unless to correct typos
|
||||
|
||||
The Program info page paginates older entries (default page size 5). Keep highlights at the top of each release for scanability.
|
||||
MIT License. See [LICENSE](LICENSE).
|
||||
|
||||
Reference in New Issue
Block a user