Document Stundenplan + Schulkalender end-of-session state
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
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
- 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>
This commit is contained in:
@@ -243,6 +243,35 @@ ssh macmini "cd /Users/benjaminadmin/Projekte/breakpilot-lehrer && git push all
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Stundenplan + Schulkalender (Mai 2026, alle Phasen deployed)
|
||||||
|
|
||||||
|
Zwei groesse Feature-Strange, vollstaendig live auf Mac Mini:
|
||||||
|
|
||||||
|
| Pfad | Beschreibung |
|
||||||
|
|------|--------------|
|
||||||
|
| `/stundenplan` (studio-v2) | Lehrer-UI mit 9 Tabs (Plan + 7 Stammdaten + Regeln), 15 Constraint-Editoren, Pin/Unpin im Wochengrid |
|
||||||
|
| `/schulkalender` (studio-v2) | Bundesland-Wizard, Monatsansicht mit Ferien (16 BL × 3 Jahre), Schul-Events, Schuljahres-Rollover, Eltern-Manager |
|
||||||
|
| `/eltern` (studio-v2) | Eltern-Sicht: Wochengrid des eigenen Kindes in Eltern-Sprache, Magic-Link-Login |
|
||||||
|
| `school-service` (Go, :8084) | Beide Backends — 30+ Tabellen, JWT-Auth (Dev-Bypass aktiv), Cron fuer Notifications |
|
||||||
|
| `timetable-solver-service` (Python+JVM, :8095) | Timefold-basierter Solver, 14 Constraints implementiert |
|
||||||
|
|
||||||
|
**Wichtigste Memo-Dateien fuer Wiedereinstieg:**
|
||||||
|
- `~/.claude/projects/-Users-benjaminadmin-Projekte-breakpilot-lehrer/memory/session_summary_2026_05_22.md` — vollstaendiges Inventar
|
||||||
|
- `~/.claude/projects/-Users-benjaminadmin/memory/project_timetable_scheduler.md` — Stundenplan-Status
|
||||||
|
- `~/.claude/projects/-Users-benjaminadmin-Projekte-breakpilot-lehrer/memory/project_schulkalender.md` — Schulkalender-Status
|
||||||
|
|
||||||
|
**Pitfalls (vermeidet diese):**
|
||||||
|
- Timefold Python-Package heisst `timefold` (NICHT `timefold-solver`), v1.24.0b0
|
||||||
|
- Production-Auth + Matrix/Email-Services baut Kollege — Frontend-Hooks nutzen, kein eigener Service-Code
|
||||||
|
- JSX-Attribute mit deutschen Quotes `„X"` brechen, Loesung: `description={"..."}` Expression-Form
|
||||||
|
- LOC-Budget 500 pro File — bei specs mit shared Helpers arbeiten (`e2e/_helpers.ts`)
|
||||||
|
|
||||||
|
**Test-Status (Stand 2026-05-22):** 89 Go + 21 Playwright im Schulkalender + 42 Playwright im Stundenplan = **152 grun**
|
||||||
|
|
||||||
|
**Offen:** Seed-Daten fuer Demo-Schule, Vollschuljahr-ICS mit RRULE+EXDATE, Untis-Import (Phase 4 geparkt).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Wichtige Dateien (Referenz)
|
## Wichtige Dateien (Referenz)
|
||||||
|
|
||||||
| Datei | Beschreibung |
|
| Datei | Beschreibung |
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
# 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)
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
# Ferien + Feiertage
|
||||||
|
|
||||||
|
## Quelle
|
||||||
|
|
||||||
|
[openholidaysapi.org](https://openholidaysapi.org) — EU-Initiative, MIT-Lizenz
|
||||||
|
fuer den API-Code, ODbL fuer die Daten. Liefert sowohl `PublicHolidays` als
|
||||||
|
auch `SchoolHolidays` je Bundesland mit ISO-Codes `DE-BW`, `DE-BY`, ...
|
||||||
|
|
||||||
|
## Build-Time-Snapshot
|
||||||
|
|
||||||
|
Statt zur Laufzeit zu pollen wird ein JSON-Snapshot committed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/calendar-snapshot.sh 2026 2030
|
||||||
|
```
|
||||||
|
|
||||||
|
Schreibt nach `school-service/internal/seed/calendar_holidays.json`. Das
|
||||||
|
Dockerfile kopiert die Datei ins Image; bei jedem Container-Start importiert
|
||||||
|
`CalendarService.SeedFromSnapshot()` die Eintraege idempotent (UNIQUE auf
|
||||||
|
region, event_type, name_de, start_date).
|
||||||
|
|
||||||
|
**Stand 2026-05-22:** 854 Events fuer alle 16 Bundeslaender × 3 Schuljahre.
|
||||||
|
|
||||||
|
## Aktualisierungs-Workflow
|
||||||
|
|
||||||
|
1. Jaehrlich (z.B. im Mai vor neuem Schuljahr):
|
||||||
|
```bash
|
||||||
|
bash scripts/calendar-snapshot.sh 2027 2031
|
||||||
|
```
|
||||||
|
2. Diff im Git pruefen — sollte nur neue Eintraege haben, nicht alte ueberschreiben.
|
||||||
|
3. Commit + push + Container-Rebuild.
|
||||||
|
4. Beim ersten Boot werden neue Eintraege in `cal_public_event` eingefuegt; bestehende bleiben.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /api/v1/school/calendar/holidays?region=DE-NI&from=2026-08-01&to=2027-07-31
|
||||||
|
```
|
||||||
|
|
||||||
|
Liefert Array sortiert nach `start_date`. Beispiel-Antwort:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{"id":"…","region":"DE-NI","event_type":"school_holiday","name_de":"Sommerferien","start_date":"2026-07-02","end_date":"2026-08-12"},
|
||||||
|
{"id":"…","region":"DE-NI","event_type":"public_holiday","name_de":"Tag der Deutschen Einheit","start_date":"2026-10-03","end_date":"2026-10-03"},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Format-Mapping (Snapshot-Script)
|
||||||
|
|
||||||
|
OpenHolidaysAPI gibt:
|
||||||
|
```json
|
||||||
|
{"id":"...","startDate":"2026-10-03","endDate":"2026-10-03","type":"Public",
|
||||||
|
"name":[{"language":"DE","text":"Tag der Deutschen Einheit"}]}
|
||||||
|
```
|
||||||
|
|
||||||
|
`scripts/calendar-snapshot.sh` normalisiert via jq:
|
||||||
|
```json
|
||||||
|
{"region":"DE-NI","event_type":"public_holiday","name_de":"Tag der Deutschen Einheit",
|
||||||
|
"name_en":null,"start_date":"2026-10-03","end_date":"2026-10-03"}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Lizenz-Compliance
|
||||||
|
|
||||||
|
- API-Code: MIT
|
||||||
|
- Daten: ODbL (Open Database License)
|
||||||
|
|
||||||
|
Beides ist fuer kommerzielle Nutzung erlaubt. Die Quelle muss in einer
|
||||||
|
Lizenz-Aufstellung (SBOM) genannt werden — bereits in
|
||||||
|
`sbom/stundenplan/README.md` dokumentiert.
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# Schulkalender
|
||||||
|
|
||||||
|
Bundeslandweit kalibrierter Schulkalender mit Ferien, Feiertagen, Schul-
|
||||||
|
Events, Eltern-Sicht und mehrsprachigen Benachrichtigungen.
|
||||||
|
|
||||||
|
## Auf einen Blick
|
||||||
|
|
||||||
|
```
|
||||||
|
studio-v2 /schulkalender → Lehrer-Sicht (CRUD Events, Eltern einladen, Rollover)
|
||||||
|
studio-v2 /eltern → Eltern-Sicht (Wochengrid des Kindes in eigener Sprache)
|
||||||
|
│
|
||||||
|
│ HTTP /api/school/* und /api/parent/* (zwei separate Auth-Gruppen)
|
||||||
|
▼
|
||||||
|
school-service (Go, :8084)
|
||||||
|
├── cal_public_event — Ferien/Feiertage-Snapshot (OpenHolidaysAPI)
|
||||||
|
├── cal_school_config — Bundesland pro Rektor
|
||||||
|
├── cal_school_event — Schulfeier, Fortbildung, Klassenfahrt etc.
|
||||||
|
├── parent_account/_child/_magic_link/_session — Eltern-Auth
|
||||||
|
└── notification_log — Idempotenter Versand-Log
|
||||||
|
│
|
||||||
|
▼ POST DispatchPayload
|
||||||
|
Matrix-Bridge + Email-Gateway (vom Kollegen gepflegt, nicht in diesem Repo)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Module
|
||||||
|
|
||||||
|
| Bereich | Doku |
|
||||||
|
|---------|------|
|
||||||
|
| [Architektur](architecture.md) | DB-Modell, Auth-Ablauf, Phase-Reihenfolge |
|
||||||
|
| [Ferien-Snapshot](holidays.md) | OpenHolidaysAPI-Pipeline, jaehrliche Aktualisierung |
|
||||||
|
| [Eltern-Workflow](parent-flow.md) | Magic-Link, Cookie-Session, i18n-Fachnamen |
|
||||||
|
| [Notifications](notifications.md) | Cron, Templates, Dispatcher-Vertrag |
|
||||||
|
|
||||||
|
## Phasen-Stand
|
||||||
|
|
||||||
|
**Alle vier Phasen abgeschlossen (2026-05-22):**
|
||||||
|
|
||||||
|
- 9a — Bundesland-Wizard + Monatsansicht
|
||||||
|
- 9b — Schul-Events + Schuljahres-Rollover
|
||||||
|
- 9c — Parent-Accounts + Magic-Link + Wochengrid in 8 Sprachen
|
||||||
|
- 9d — Notification-Cron + Templates + Status-Badges
|
||||||
|
|
||||||
|
**Offen:** Vollschuljahr-ICS, Seed-Daten fuer Demo-Schule.
|
||||||
|
|
||||||
|
## Test-Status
|
||||||
|
|
||||||
|
| Suite | Tests |
|
||||||
|
|------|-------|
|
||||||
|
| Go (services + notifications) | 89 / 89 |
|
||||||
|
| Playwright Schulkalender | 16 / 16 |
|
||||||
|
| Playwright Eltern | 7 / 7 |
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# Notifications
|
||||||
|
|
||||||
|
## Pipeline
|
||||||
|
|
||||||
|
```
|
||||||
|
06:00 Uhr (Berlin-Zeit, Container TZ=Europe/Berlin)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
NotificationService.RunForDate(today)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
dueEvents() findet cal_school_event mit
|
||||||
|
(start_date - today) ∈ notification_lead_days
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Pro Event: fuer jede Audience (parents/students) und jeden Channel
|
||||||
|
(matrix für alle, email zusaetzlich nur fuer parents):
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
dispatchOne()
|
||||||
|
1. Idempotenz-Check (UNIQUE notification_log)
|
||||||
|
2. recipientsFor() — JOIN parent_account+parent_child fuer
|
||||||
|
betroffene Klassen, gibt Email-Liste + bevorzugte Sprache zurueck
|
||||||
|
3. Render-Template (templates.go, 8 Sprachen)
|
||||||
|
4. POST {MATRIX,EMAIL}_SERVICE_URL mit DispatchPayload
|
||||||
|
5. notification_log writeLog (sent/failed/skipped)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cron-Mechanik
|
||||||
|
|
||||||
|
`main.go` startet einen Goroutine-Ticker mit 1h-Intervall. Sobald `time.Now().Hour() == 6` wird `RunForDate` aufgerufen. Idempotent — die UNIQUE auf notification_log filtert Doppel-Calls am selben Tag.
|
||||||
|
|
||||||
|
Bei Container-Restart vor 06:00 läuft trotzdem alles korrekt: der naechste 06-Tick fired bis spaetestens 06:59:59. Bei Restart nach 06:00: erste Notification erst am Folgetag (acceptable trade-off gegen einen 1-Min-Ticker).
|
||||||
|
|
||||||
|
## Manueller Trigger
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Heute jetzt scannen
|
||||||
|
curl -X POST http://localhost:8084/api/v1/school/calendar/notifications/run-now
|
||||||
|
|
||||||
|
# Backfill (z.B. nach langem Container-Down)
|
||||||
|
curl -X POST 'http://localhost:8084/api/v1/school/calendar/notifications/run-now?date=2026-05-20'
|
||||||
|
```
|
||||||
|
|
||||||
|
Antwort: `{"date":"2026-05-22","sent":N,"failed":N,"skipped":N,"already_logged":N}`.
|
||||||
|
|
||||||
|
## Template-Engine
|
||||||
|
|
||||||
|
Datei: `school-service/internal/notifications/templates.go`. Schema:
|
||||||
|
|
||||||
|
```
|
||||||
|
templates[lang][event_type][audience][bucket] → {Subject, Body}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `lang` ∈ de/en/tr/ar/uk/ru/pl/fr (Fallback `de`)
|
||||||
|
- `event_type` ∈ fortbildung/schulfeier/klassenfahrt/projekttag/eltern_info/andere (Fallback `andere`)
|
||||||
|
- `audience` ∈ parents/students (Fallback `parents`)
|
||||||
|
- `bucket` ∈ today/tomorrow/days (Fallback `days`)
|
||||||
|
|
||||||
|
Placeholders: `{{title}}`, `{{date}}`, `{{date_pretty}}`, `{{class_name}}`, `{{class_suffix}}`, `{{teacher_name}}`, `{{lead}}`.
|
||||||
|
|
||||||
|
Beispiel-Render (TR / schulfeier / parents / 1-Tag-Vorlauf):
|
||||||
|
```
|
||||||
|
Subject: Yarın: Sommerfest (5a)
|
||||||
|
Body: Sayın veliler, yarın (15.06.2026) Sommerfest gerçekleşiyor (5a).
|
||||||
|
```
|
||||||
|
|
||||||
|
## DispatchPayload (Endpoint-Vertrag mit Matrix/Email Service)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"channel": "matrix",
|
||||||
|
"recipient": "mama@example.de",
|
||||||
|
"language": "tr",
|
||||||
|
"subject": "Yarın: Sommerfest",
|
||||||
|
"body": "Sayın veliler, ...",
|
||||||
|
"event_id": "uuid-…",
|
||||||
|
"lead_days": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Erwartete Antwort vom Upstream: HTTP 2xx = sent. 4xx/5xx = failed. Wir leiten **keine** Empfaenger-Identifier-Aufloesung weiter ans Upstream — die Matrix-Bridge mapt Email → Matrix-Handle in der eigenen Logik.
|
||||||
|
|
||||||
|
Bei `MATRIX_SERVICE_URL` oder `EMAIL_SERVICE_URL` leer: status='skipped', kein Versandversuch. Erlaubt lokales Testen ohne Upstream.
|
||||||
|
|
||||||
|
## Status-Anzeige im Lehrer-UI
|
||||||
|
|
||||||
|
`DayDetail` mountet `NotificationStatus` fuer jedes Event mit `notify_parents` oder `notify_students`. Lädt `GET /api/v1/school/calendar/events/:id/notifications` und zeigt Badges:
|
||||||
|
|
||||||
|
- ✓ gruen = sent
|
||||||
|
- ✗ rot = failed (Hover zeigt error_message)
|
||||||
|
- ⏱ amber = skipped (Upstream noch nicht konfiguriert)
|
||||||
|
|
||||||
|
## Privacy
|
||||||
|
|
||||||
|
`notification_log` ist nur über JOIN cal_school_event sichtbar — Lehrer sieht nur Logs seiner eigenen Events. Eltern haben gar keine UI fuer Logs.
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# Eltern-Workflow
|
||||||
|
|
||||||
|
## Einladung (Lehrer)
|
||||||
|
|
||||||
|
1. Lehrer offnet `/schulkalender`, scrollt zu `ParentManager`.
|
||||||
|
2. Klick "+ Eltern einladen" → Form mit Email, Vorname/Nachname Kind, Klasse, Sprache.
|
||||||
|
3. `POST /api/v1/school/calendar/parents/invite` legt parent_account (upsert), parent_child + parent_magic_link an, gibt Klartext-Token + voll qualifizierten Link zurueck.
|
||||||
|
4. Lehrer kopiert Link aus der UI und schickt ihn ueber Matrix oder Email (Versand-Automation kommt mit Phase 9d Notification-Pipeline).
|
||||||
|
|
||||||
|
## Login (Eltern)
|
||||||
|
|
||||||
|
1. Eltern klicken den Link `https://app/eltern/login?token=…`.
|
||||||
|
2. Browser laedt die Login-Page, sendet `POST /api/v1/parent/auth/redeem {token}`.
|
||||||
|
3. school-service validiert Token (Hash-Lookup + expires_at + used_at), markiert used_at, mintet Session-Token (32-Byte URL-safe Base64), setzt HttpOnly Cookie `bp_parent_session`.
|
||||||
|
4. Redirect auf `/eltern`. Folgende API-Calls senden Cookie automatisch.
|
||||||
|
|
||||||
|
## Wochengrid
|
||||||
|
|
||||||
|
`/eltern` ruft:
|
||||||
|
|
||||||
|
- `GET /api/v1/parent/me` → Account + Kinder-Liste (Name, Klasse via JOIN tt_class)
|
||||||
|
- `GET /api/v1/parent/me/timetable?class_id=…` → letzte completed tt_solution der Klasse
|
||||||
|
|
||||||
|
Filter laeuft strikt: ParentService prueft `ChildBelongsToParent(parent_id, class_id)` vor jeder Timetable-Query.
|
||||||
|
|
||||||
|
## Fach-Uebersetzung
|
||||||
|
|
||||||
|
`lib/calendar/subject-i18n.ts` hat 22 Standardfaecher in 8 Sprachen:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
mathematik: { de: 'Mathematik', en: 'Mathematics', tr: 'Matematik',
|
||||||
|
ar: 'الرياضيات', uk: 'Математика', ru: 'Математика',
|
||||||
|
pl: 'Matematyka', fr: 'Mathématiques' }
|
||||||
|
```
|
||||||
|
|
||||||
|
`translateSubject(germanName, lang)`:
|
||||||
|
|
||||||
|
1. Lowercase + trim → `key`
|
||||||
|
2. `SUBJECTS[key]` lookup
|
||||||
|
3. Wenn key nicht in Map: Original-Deutsch zurueck (z.B. "Imkern AG")
|
||||||
|
4. Wenn lang nicht in Sprachen: `de`-Fallback
|
||||||
|
|
||||||
|
## Logout
|
||||||
|
|
||||||
|
`POST /api/v1/parent/auth/logout` setzt Cookie auf max-age=-1. Session-Row bleibt in DB (laeuft selber ab nach 30 Tagen) — vereinfacht Tracking.
|
||||||
|
|
||||||
|
## Was die Eltern NICHT sehen
|
||||||
|
|
||||||
|
- Andere Eltern oder Kinder
|
||||||
|
- Stundenplan-Versionen die nicht "completed" sind
|
||||||
|
- Schul-Events mit `visible_to_parents=false`
|
||||||
|
- Lehrer-internes wie Stundentafel oder Lehrauftrag-Konfiguration
|
||||||
|
|
||||||
|
Privacy-Garantien sind auf SQL-Ebene durchgesetzt (JOIN-Pfade + WHERE-Klauseln), nicht nur im Application-Layer.
|
||||||
@@ -88,6 +88,12 @@ nav:
|
|||||||
- Constraints: services/stundenplan/constraints.md
|
- Constraints: services/stundenplan/constraints.md
|
||||||
- Solver-Tuning: services/stundenplan/solver-tuning.md
|
- Solver-Tuning: services/stundenplan/solver-tuning.md
|
||||||
- Export: services/stundenplan/export.md
|
- Export: services/stundenplan/export.md
|
||||||
|
- Schulkalender:
|
||||||
|
- Uebersicht: services/schulkalender/index.md
|
||||||
|
- Architektur: services/schulkalender/architecture.md
|
||||||
|
- Ferien-Snapshot: services/schulkalender/holidays.md
|
||||||
|
- Eltern-Workflow: services/schulkalender/parent-flow.md
|
||||||
|
- Notifications: services/schulkalender/notifications.md
|
||||||
- Architektur:
|
- Architektur:
|
||||||
- Multi-Agent System: architecture/multi-agent.md
|
- Multi-Agent System: architecture/multi-agent.md
|
||||||
- Zeugnis-System: architecture/zeugnis-system.md
|
- Zeugnis-System: architecture/zeugnis-system.md
|
||||||
|
|||||||
Reference in New Issue
Block a user