Files
Benjamin Admin 77c720e2df
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 50s
CI / test-go-edu-search (push) Successful in 45s
CI / test-python-klausur (push) Failing after 3m50s
CI / test-python-agent-core (push) Successful in 36s
CI / test-nodejs-website (push) Successful in 49s
Document Stundenplan + Schulkalender end-of-session state
- CLAUDE.md gets a new section summarising the two feature strands,
  pitfalls (Timefold name, JSX quotes, LOC budget), the auth/messaging
  outsourcing, and pointers to the three memory files for next session.
- docs-src/services/schulkalender/ — 5 MkDocs pages mirroring the
  stundenplan structure: index, architecture, holidays, parent-flow,
  notifications. Each with DB tables, endpoints, and the dispatch
  payload contract for the colleague's Matrix/Email services.
- mkdocs.yml gains the Schulkalender nav entry under Services.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 18:41:31 +02:00

65 lines
2.7 KiB
Markdown

# 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)