# Database Initialization and Management Guide ## Quick Start Your database has been successfully initialized! Here's what you need to know: ### ✅ Current Status - **Database**: MariaDB 11.2 running in Docker container `infoscreen-db` - **Schema**: Up to date (check with `alembic current` in `server/`) - **Default Data**: Admin user and client group created - **Academic Periods**: Austrian school years 2024/25 (active), 2025/26, 2026/27 ### 🔐 Default Credentials - **Admin Username**: `infoscreen_admin` - **Admin Password**: Check your `.env` file for `DEFAULT_ADMIN_PASSWORD` - **Database User**: `infoscreen_admin` - **Database Name**: `infoscreen_by_taa` ## Database Management Commands ### Initialize/Reinitialize Database ```bash cd /workspace/server python initialize_database.py ``` ### Check Migration Status ```bash cd /workspace/server alembic current alembic history --verbose ``` ### Run Migrations Manually ```bash cd /workspace/server alembic upgrade head # Apply all pending migrations alembic upgrade +1 # Apply next migration alembic downgrade -1 # Rollback one migration ``` ### Create New Migration ```bash cd /workspace/server alembic revision --autogenerate -m "Description of changes" ``` ### Database Connection Test ```bash cd /workspace/server python -c " from database import Session session = Session() print('✅ Database connection successful') session.close() " ``` ## Initialization Scripts ### Core Scripts (recommended order): 1. **`alembic upgrade head`** - Apply database schema migrations 2. **`init_defaults.py`** - Create default user groups and admin user 3. **`init_academic_periods.py`** - Set up Austrian school year periods ### All-in-One Script: - **`initialize_database.py`** - Complete database initialization (runs all above scripts) ### Development/Testing Scripts: - **`dummy_clients.py`** - Creates test client data for development - **`dummy_events.py`** - Creates test event data for development - **`sync_existing_clients.py`** - One-time MQTT sync for existing clients ## Database Schema Overview ### Main Tables: - **`users`** - User authentication and roles - **`clients`** - Registered client devices - **`client_groups`** - Client organization groups - **`events`** - Scheduled events and presentations - **`event_media`** - Media files for events - **`conversions`** - File conversion jobs (PPT → PDF) - **`academic_periods`** - School year/semester management - **`school_holidays`** - Holiday calendar - **`event_exceptions`** - Overrides and skips for recurring events (per occurrence) - **`system_settings`** - Key–value store for global settings - **`alembic_version`** - Migration tracking ### Key details and relationships - Users (`users`) - Fields: `username` (unique), `password_hash`, `role` (enum: user|editor|admin|superadmin), `is_active` - Client groups (`client_groups`) - Fields: `name` (unique), `description`, `is_active` - Clients (`clients`) - Fields: `uuid` (PK), network/device metadata, `group_id` (FK→client_groups, default 1), `last_alive` (updated on heartbeat), `is_active` - Academic periods (`academic_periods`) - Fields: `name` (unique), optional `display_name`, `start_date`, `end_date`, `period_type` (enum: schuljahr|semester|trimester), `is_active` (at most one should be active) - Indexes: `is_active`, dates - Event media (`event_media`) - Fields: `media_type` (enum, see below), `url`, optional `file_path`, optional `message_content`, optional `academic_period_id` - Used by events of types: presentation, video, website, message, other - Events (`events`) - Core: `group_id` (FK), optional `academic_period_id` (FK), `title`, optional `description`, `start`, `end`, `event_type` (enum), optional `event_media_id` (FK) - Presentation/video extras: `autoplay`, `loop`, `volume`, `slideshow_interval`, `page_progress`, `auto_progress` - Recurrence: `recurrence_rule` (RFC 5545 RRULE), `recurrence_end`, `skip_holidays` (bool) - Audit/state: `created_by` (FK→users), `updated_by` (FK→users), `is_active` - Indexes: `start`, `end`, `recurrence_rule`, `recurrence_end` - Relationships: `event_media`, `academic_period`, `exceptions` (one-to-many to `event_exceptions` with cascade delete) - Event exceptions (`event_exceptions`) - Purpose: track per-occurrence skips or overrides for a recurring master event - Fields: `event_id` (FK→events, ondelete CASCADE), `exception_date` (Date), `is_skipped`, optional overrides (`title`, `description`, `start`, `end`) - School holidays (`school_holidays`) - Unique: (`name`, `start_date`, `end_date`, `region`) - Used in combination with `events.skip_holidays` - Conversions (`conversions`) - Purpose: track PPT/PPTX/ODP → PDF processing - Fields: `source_event_media_id` (FK→event_media, ondelete CASCADE), `target_format`, `target_path`, `status` (enum), `file_hash`, timestamps, `error_message` - Indexes: (`source_event_media_id`, `target_format`), (`status`, `target_format`) - Unique: (`source_event_media_id`, `target_format`, `file_hash`) — idempotency per content - System settings (`system_settings`) - Key–value store: `key` (PK), `value`, optional `description`, `updated_at` - Notable keys used by the app: `presentation_interval`, `presentation_page_progress`, `presentation_auto_progress` ### Enums (reference) - UserRole: `user`, `editor`, `admin`, `superadmin` - AcademicPeriodType: `schuljahr`, `semester`, `trimester` - EventType: `presentation`, `website`, `video`, `message`, `other`, `webuntis` - MediaType: `pdf`, `ppt`, `pptx`, `odp`, `mp4`, `avi`, `mkv`, `mov`, `wmv`, `flv`, `webm`, `mpg`, `mpeg`, `ogv`, `jpg`, `jpeg`, `png`, `gif`, `bmp`, `tiff`, `svg`, `html`, `website` - ConversionStatus: `pending`, `processing`, `ready`, `failed` ### Timezones, recurrence, and holidays - All timestamps are stored/compared as timezone-aware UTC. Any naive datetimes are normalized to UTC before comparisons. - Recurrence is represented on events via `recurrence_rule` (RFC 5545 RRULE) and `recurrence_end`. Do not pre-expand series in the DB. - Per-occurrence exclusions/overrides are stored in `event_exceptions`. The API also emits EXDATE tokens matching occurrence start times (UTC) so the frontend can exclude instances natively. - When `skip_holidays` is true, occurrences that fall on school holidays are excluded via corresponding `event_exceptions`. ### Environment Variables: ```bash DB_CONN=mysql+pymysql://infoscreen_admin:KqtpM7wmNdM1DamFKs@db/infoscreen_by_taa DB_USER=infoscreen_admin DB_PASSWORD=KqtpM7wmNdM1DamFKs DB_NAME=infoscreen_by_taa DB_HOST=db ``` ## Troubleshooting ### Database Connection Issues: ```bash # Check if database container is running docker ps | grep db # Check database logs docker logs infoscreen-db # Test direct connection docker exec -it infoscreen-db mysql -u infoscreen_admin -p infoscreen_by_taa ``` ### Migration Issues: ```bash # Check current state cd /workspace/server && alembic current # Show migration history cd /workspace/server && alembic history # Show pending migrations cd /workspace/server && alembic show head ``` ### Reset Database (⚠️ DESTRUCTIVE): ```bash # Stop services docker-compose down # Remove database volume docker volume rm infoscreen_2025_db-data # Restart and reinitialize docker-compose up -d db cd /workspace/server && python initialize_database.py ``` ## Production Deployment The production setup in `docker-compose.prod.yml` includes automatic database initialization: ```yaml server: command: > bash -c "alembic -c /app/server/alembic.ini upgrade head && python /app/server/init_defaults.py && exec gunicorn server.wsgi:app --bind 0.0.0.0:8000" ``` This ensures the database is properly initialized on every deployment.