d9858084ddb3902f8dadf87e2faf733bb9617da8
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
d9858084dd |
Phase 9c: Parent accounts, magic-link login + parent timetable view
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 31s
CI / test-go-edu-search (push) Successful in 30s
CI / test-python-klausur (push) Failing after 2m36s
CI / test-python-agent-core (push) Successful in 21s
CI / test-nodejs-website (push) Successful in 26s
Backend (school-service):
- parent_account, parent_child, parent_magic_link, parent_session
tables. Tokens are sha256-hashed in DB; raw goes back exactly
once to the inviting teacher.
- InviteParent upserts the parent account, links a child to a tt_
class, mints a 7-day magic link. Returns the link path so the
teacher can paste it into Matrix/Email.
- RedeemMagicLink validates + marks used + mints a 30-day session,
sets HttpOnly bp_parent_session cookie.
- ParentSessionMiddleware reads the cookie and resolves the parent.
Lives in its own router group /api/v1/parent — totally separate
from the teacher JWT path.
- ParentMe returns the account + list of children (with class name).
- ParentTimetable returns the latest completed tt_solution's lessons
for the requested child's class, with full authorization check
(parent must own a child in that class).
Frontend (studio-v2):
- lib/calendar/subject-i18n.ts maps 22 German subject names to 8
parent locales (de/en/tr/ar/uk/ru/pl/fr). Falls back to German
for custom subjects.
- ParentManager component on the Schulkalender page lets the teacher
invite parents via email + child name + class + language. Newly
minted magic-link is shown with a copy-to-clipboard button.
- app/api/parent/[...path]/route.ts proxies parent-side endpoints
via the cookie so HttpOnly survives the Next.js round-trip.
- /eltern/login?token=… redeems and redirects to /eltern.
- /eltern shows a Wochengrid with German days + translated subject
names in the parent's preferred language. Headings and weekday
labels also localised (de/en/tr/ar/uk/ru/pl/fr).
Tests:
- 3 new Go unit tests (random token, hash stability, invite-request
validator). 83 subtests gesamt.
- studio-v2: e2e/eltern.spec.ts mit 7 tests across ParentManager,
/eltern/login, /eltern overview, subject-i18n end-to-end.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
97e37837ee |
Phase 9a: Schulkalender — Bundesland-Auswahl + Monatsansicht mit Ferien
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 29s
CI / test-go-edu-search (push) Successful in 27s
CI / test-python-klausur (push) Failing after 2m50s
CI / test-python-agent-core (push) Successful in 18s
CI / test-nodejs-website (push) Successful in 21s
Backend (school-service):
- cal_public_event (region, event_type, name_de, name_en, start/end,
UNIQUE(region, event_type, name_de, start_date)) — global snapshot.
- cal_school_config (user_id PRIMARY KEY, bundesland, school year dates).
- cal_school_event — Schul-eigene Termine; CRUD folgt in 9b.
- GET /calendar/holidays?region=&from=&to= — Range-Query against
cal_public_event, ordered by start_date.
- GET / PUT /calendar/config — upsert Bundesland per User.
- SeedFromSnapshot reads internal/seed/calendar_holidays.json on every
boot; idempotent via the unique constraint. Async goroutine so the
HTTP server starts immediately even if the seed file is large.
Data source:
- scripts/calendar-snapshot.sh ruft openholidaysapi.org fuer alle 16
Bundeslaender x 3 Schuljahre und schreibt
school-service/internal/seed/calendar_holidays.json (854 Events,
Stand Schuljahre 2026-2028).
- Dockerfile kopiert das seed/-Verzeichnis ins Image, damit die
Container-Datenbank beim ersten Start gefuellt wird.
Frontend (studio-v2):
- /schulkalender Page mit Gradient + Blobs wie /stundenplan und
/korrektur — gleicher Visual-Style.
- BundeslandWizard: zeigt alle 16 Laender als Dropdown, speichert
bei Klick die Config und switcht zur Monatsansicht.
- MonthView: 6-Wochen-Grid Mo-So, Feiertage rose-toned, Schulferien
amber-toned, heutiges Datum mit Indigo-Ring. Prev/Next/Heute
Navigation.
- lib/schulkalender/api.ts re-uses the stundenplan JWT helper so
auth-mode wechselt nicht.
- Sidebar bekommt einen Schulkalender-Eintrag (Icon mit Datum-Dots,
Pfad /schulkalender) in allen 26 Sprachen.
Tests:
- Go: 3 neue Validator-Tests (Bundesland len=5, EventType oneof,
Pflichtfelder). 77 Tests gesamt, alle gruen.
- Playwright: e2e/schulkalender.spec.ts mit Wizard, Save-Flow,
MonthView-Render, Heute-Button, Sidebar-Link. Hermetisch via
mockCalendarApi.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
f042f2896b |
Phase 5: Timefold timetable-solver-service + solution persistence
school-service additions:
- tt_solution + tt_lesson migration. tt_lesson carries three UNIQUEs
(solution+class, solution+teacher, solution+room per slot) so the
DB itself rejects any double-booking the solver might emit by
mistake.
- Solution CRUD + GET solutions/:id/lessons endpoint with joined
class/subject/teacher/room names for display.
- POST /timetable/solutions creates the row then fires off the
solver-service via HTTP (5s timeout, mark failed if unreachable).
- SOLVER_SERVICE_URL config wired through main.go/handlers.
New service timetable-solver-service:
- Python 3.11 + FastAPI + Timefold Solver 1.21 (Apache-2.0). Dockerfile
bundles OpenJDK 17 since Timefold for Python is a JPype bridge.
- app/domain.py — Timefold @planning_entity Lesson with timeslot+room
as PlanningVariables; @planning_solution Timetable holds problem
facts (rooms/teachers/etc.) AND rule-fact collections.
- app/rules.py — frozen dataclasses mirroring 6 of the 15 tt_
constraint_* tables initially.
- app/constraints.py — ConstraintProvider with 3 universal hard
constraints (no double-booking) + 5 DB-driven constraints
(teacher_unavailable_day/window, teacher_excluded_room,
room_unavailable, room_requires_type) + 1 quality soft constraint
(subject_preferred_period). Remaining 9 constraint types ready to
plug in via the same join pattern.
- app/repository.py — async loaders for stammdaten + rules; builds
one Lesson per (curriculum row × weekly_hours), skipping rows
without a tt_assignment teacher.
- app/runner.py — runs solver in ThreadPoolExecutor so the FastAPI
event loop stays responsive. Updates tt_solution status
pending→running→completed|infeasible|failed.
- app/main.py — POST /api/v1/solve (202 Accepted, background task),
GET /api/v1/jobs/{id}, /health. School-service polls tt_solution
directly instead of GET /jobs for the typical case.
- docker-compose.yml adds the service on port 8095, depending on
core-health-check.
Tests:
- school-service: validator test for CreateTimetableSolutionRequest
(allows empty name).
- solver-service: tests/test_domain.py + tests/test_rules.py cover
construction + hashability of the planning facts. Full solve flow
deferred to Phase 8 integration with seed data.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
e958f88a2d |
Add timetable scheduler Phases 1 + 2 to school-service
Phase 1 — Stammdaten (7 tables):
tt_class, tt_period, tt_room, tt_subject, tt_teacher,
tt_curriculum, tt_assignment with CRUD endpoints.
Phase 2 — Constraints (15 typed tables):
Teacher (6): unavailable_day, unavailable_window, max_hours_day,
max_hours_week, excluded_subject, excluded_room
Subject (5): min_day_gap, max_consecutive, contiguous_when_repeated,
preferred_period, double_lesson
Class (2): max_hours_day, no_gaps
Room (2): requires_type, unavailable
Each constraint row carries is_hard / weight / active / note /
created_by_user_id; ownership enforced via WHERE EXISTS against the
parent tt_teacher/tt_class/tt_subject/tt_room row.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
5a31f52310 |
Initial commit: breakpilot-lehrer - Lehrer KI Platform
Services: Admin-Lehrer, Backend-Lehrer, Studio v2, Website, Klausur-Service, School-Service, Voice-Service, Geo-Service, BreakPilot Drive, Agent-Core Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |