# Architektur ## Datenmodell ### Phase 9a — Kalender-Stammdaten | Tabelle | Inhalt | Owner | |---------|--------|-------| | `cal_public_event` | Ferien + Feiertage (region, type, name, start, end) | global (alle Bundeslaender) | | `cal_school_config` | Bundesland-Auswahl + Schuljahr-Daten | 1 row per user_id | ### Phase 9b — Schul-Events | Tabelle | Inhalt | Owner | |---------|--------|-------| | `cal_school_event` | Titel + Typ + Datum/Zeit + affected_class_ids + Notification-Flags | created_by_user_id | Event-Typen (CHECK constraint): `fortbildung`, `schulfeier`, `klassenfahrt`, `projekttag`, `eltern_info`, `andere`. ### Phase 9c — Parent-Accounts | Tabelle | Inhalt | |---------|--------| | `parent_account` | Email + preferred_language, UNIQUE pro (Lehrer, Email) | | `parent_child` | Vorname/Nachname + FK auf tt_class | | `parent_magic_link` | Einmal-Token (SHA-256 in DB), expires_at 7 Tage | | `parent_session` | Browser-Session-Token (SHA-256 in DB), expires_at 30 Tage | ### Phase 9d — Notifications | Tabelle | Inhalt | |---------|--------| | `notification_log` | Idempotenz: UNIQUE(event_id, lead_days, audience, channel) | ## Auth-Modell **Zwei voneinander unabhaengige Auth-Wege:** 1. **Lehrer:** JWT in Authorization-Header (oder Dev-Bypass mit Default-User wenn `ENVIRONMENT != "production"`). Routen unter `/api/v1/school/...`. 2. **Eltern:** Session-Cookie `bp_parent_session` (HttpOnly, SameSite=Lax), gesetzt vom `/api/v1/parent/auth/redeem` Endpoint. ParentSessionMiddleware resolved Cookie → parent_account. Eltern sehen **nie** Daten anderer Eltern. Privacy-Check via `ChildBelongsToParent` in jedem GET, Plus Filterung der Lessons gegen tt_solution des einladenden Lehrers. ## Bundesland-Wizard Erster Aufruf von `/schulkalender` → kein `cal_school_config` → `BundeslandWizard` UI → POST `/calendar/config` mit `{bundesland: "DE-NI"}` → MonthView lädt für die naechsten ~6 Wochen. ## Schuljahres-Rollover POST `/calendar/school-year-rollover` (optional `{new_year_start, new_year_end}`): 1. `DELETE FROM tt_class WHERE grade_level >= 13` (Abschlusskohorte) 2. `UPDATE tt_class SET grade_level = grade_level + 1` 3. `UPDATE cal_school_config SET school_year_start/end = ...` Alles in einer Transaction. Stundenplan-Lehrer-Faecher-Raum-Bestand bleibt unangetastet. ## Auth + Messaging outsourced Production-Auth, Matrix-Bridge und Email-Gateway werden vom Kollegen gepflegt — siehe globale Memory `stundenplan_auth_and_messaging.md`. Wir definieren nur: - Dispatch-Payload-Struct (siehe [notifications.md](notifications.md)) - Env-Vars `MATRIX_SERVICE_URL`, `EMAIL_SERVICE_URL` (leer = Stub-Mode) - Endpoint-Vertrag (POST mit JSON-Body, HTTP 2xx = sent)