77c720e2dfd21caba52fbca0c10359d47a82881b
754 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
77c720e2df |
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
- 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> |
||
|
|
89011d64f7 |
gofmt notification files
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 49s
CI / test-go-edu-search (push) Successful in 45s
CI / test-python-klausur (push) Failing after 3m41s
CI / test-python-agent-core (push) Successful in 38s
CI / test-nodejs-website (push) Successful in 49s
|
||
|
|
8311b33fb3 |
Phase 9d: Notification cron + multilingual templates + status badges
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 1m10s
CI / test-go-edu-search (push) Successful in 43s
CI / test-python-klausur (push) Failing after 4m4s
CI / test-python-agent-core (push) Successful in 44s
CI / test-nodejs-website (push) Successful in 51s
Backend (school-service):
- notification_log table with UNIQUE(event_id, lead_days, audience,
channel) for idempotent re-runs. Status enum sent/failed/skipped.
- internal/notifications/templates.go: per-event-type × audience ×
lead-day-bucket × language templates in 8 languages (de/en/tr/ar/
uk/ru/pl/fr). Fallback chain (lang→de, eventType→andere) so we
never miss a render.
- service.go scans cal_school_event for events whose
(start_date - runDate) appears in notification_lead_days. For each
due (audience, channel) tuple it dispatches via POST to the
Matrix/Email upstreams owned by the colleague's services.
Empty URL → status='skipped', logged for visibility.
- dispatcher.go handles the POST, parent-recipient lookup (joins
parent_account + parent_child + cal_school_event.affected_class_ids),
and writeLog with the unique constraint dropping duplicate runs.
- main.go runs a 1-hour ticker; when time.Hour()==6 it invokes the
scanner for today. Idempotent so transient restarts don't double-
send.
- POST /calendar/notifications/run-now for manual trigger + backfill
(?date=YYYY-MM-DD).
- GET /calendar/events/:id/notifications returns notification_log
rows scoped to the owning teacher.
- MATRIX_SERVICE_URL + EMAIL_SERVICE_URL env vars added (default
empty = stub mode).
Frontend (studio-v2):
- NotificationStatus component fetches /events/:id/notifications and
renders coloured badges per (lead, audience, channel, status).
- DayDetail mounts NotificationStatus inside each event card when
notify_parents or notify_students is set.
Tests:
- 6 new Go unit tests for bucketFor + Render (de/tr/fallback paths)
+ substitute(class_suffix). 89 subtests gesamt.
- 2 new Playwright tests: badge render with mocked log, hidden when
notifications are off.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
85957ed5db |
gofmt parent backend files
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 36s
CI / test-go-edu-search (push) Successful in 33s
CI / test-python-klausur (push) Failing after 2m45s
CI / test-python-agent-core (push) Successful in 23s
CI / test-nodejs-website (push) Successful in 27s
|
||
|
|
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>
|
||
|
|
33409352ee |
Phase 9b: Schul-Events CRUD + Schuljahres-Rollover
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 28s
CI / test-go-edu-search (push) Successful in 28s
CI / test-python-klausur (push) Failing after 2m38s
CI / test-python-agent-core (push) Successful in 20s
CI / test-nodejs-website (push) Successful in 26s
Backend (school-service):
- calendar_events.go — Create/List/Delete on cal_school_event with
UUID[] handling for affected_class_ids. Default lead-days [7,1]
if caller omits the array.
- calendar_rollover.go — single-transaction promotion: graduating
classes (grade >= 13) get deleted first so the +1 update doesn't
bump them to invalid grade 14. defaultSchoolYearDates() picks the
next Aug-Jul pair when the caller doesn't specify.
- Handlers + routes: GET/POST /calendar/events,
DELETE /calendar/events/:id, POST /calendar/school-year-rollover.
Frontend (studio-v2):
- EventModal: form with Title / Typ / Datum/Zeit / unterrichtsfrei /
Beschreibung / Sichtbarkeit + Notification-Checkboxen. Per-Type
Farb-Mapping in types.ts.
- DayDetail: Modal das beim Klick auf einen Kalender-Tag aufgeht und
Feiertage + Schulferien + Schul-Events fuer diesen Tag listet,
inkl. Loeschen-Button pro Event.
- RolloverWizard: zwei-Schritt-Dialog mit Datums-Auswahl + Tipp-
Bestaetigung ("SCHULJAHR WECHSELN") gegen versehentliche Auslo-
sung, danach Ergebnis-Card mit promoted/graduated-Counts.
- MonthView gewinnt onDayClick + onAddEvent + onRollover Props,
rendert farb-codierte Punkte fuer School-Events am Tagesrand.
- Page laed Events parallel mit Holidays und reicht alle Handler
nach unten.
Tests:
- Go: 3 neue Tests fuer defaultSchoolYearDates + parseClassIDs.
Validator-Test fuer CreateSchoolEventRequest existiert bereits.
80 Subtests gesamt, alle gruen.
- Playwright: mockCalendarApi gewinnt Routes fuer events GET/POST/
DELETE und school-year-rollover. 6 neue Tests (EventModal open,
submit, DayDetail open, Rollover-Trigger, Confirm-Schutz,
Ergebnis-Anzeige).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
3b8df0d294 |
Schulkalender test: use exact text for legend assertions
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 29s
CI / test-python-klausur (push) Failing after 2m39s
CI / test-python-agent-core (push) Successful in 19s
CI / test-nodejs-website (push) Successful in 22s
|
||
|
|
09f6f5a5e1 |
gofmt calendar files
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 29s
CI / test-python-klausur (push) Failing after 2m25s
CI / test-python-agent-core (push) Successful in 19s
CI / test-nodejs-website (push) Successful in 21s
|
||
|
|
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>
|
||
|
|
65e7ed94f6 |
gofmt middleware.go
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 40s
CI / test-go-edu-search (push) Successful in 30s
CI / test-python-klausur (push) Failing after 2m27s
CI / test-python-agent-core (push) Successful in 19s
CI / test-nodejs-website (push) Successful in 22s
|
||
|
|
306886a42b |
Phase 8: CSV + ICS export, print view, MkDocs docs, SBOM + dev-mode auth
Auth (Test-Mode):
- middleware.AuthMiddleware now takes a devMode flag. In dev,
requests without Authorization fall back to a deterministic dev
UUID (00000000-...-001) and role=teacher. ENVIRONMENT=production
re-enables the strict 401 path.
- main.go wires devMode = cfg.Environment != "production".
- page.tsx replaces the red 'Anmeldung noch nicht integriert' banner
with a softer Testumgebung notice; the manual-token form moves
behind a nested details block.
Export endpoints (school-service):
- LoadExportLessons joins tt_lesson with tt_period for wall-clock
times; one query feeds both CSV and ICS.
- WriteCSV streams 10 columns including pinned flag.
- WriteICS emits one VEVENT per lesson anchored to a Monday — caller
overridable via ?start=YYYY-MM-DD. RFC 5545 escapes for ',', ';',
'\n' in icsEscape().
- NextMonday helper for the default anchor.
- GET /timetable/solutions/:id/export.{csv,ics} handlers attach
Content-Disposition: attachment so browsers download instead of
rendering.
Frontend:
- lib/stundenplan/api.ts downloadSolutionExport() fetches as blob,
triggers a synthetic <a download> click, and forwards the JWT when
present.
- PlanView gains CSV / ICS / Drucken buttons next to the perspective
selector. The toolbar carries class 'no-print' so window.print()
yields only the grid.
- globals.css @media print rule hides chrome, forces white
background, gives the table proper borders for A4.
Docs:
- docs-src/services/stundenplan/{index,architecture,constraints,
solver-tuning,export}.md with nav entry in mkdocs.yml under
Services → Stundenplaner.
- sbom/stundenplan/README.md lists manually-verified key dependencies
and the policy reference. scripts/stundenplan-sbom.sh generates
full machine-readable inventories via go-licenses + pip-licenses
+ license-checker when those tools are available.
Tests:
- internal/services/timetable_exports_test.go: 4 unit tests covering
CSV column layout + quoting, ICS structure + DTSTART formatting,
icsEscape special chars, NextMonday weekday math.
- studio-v2/e2e/stundenplan-export.spec.ts split out of the main spec
file (LOC budget) — 3 tests for button render, CSV download,
ICS download.
- mockSchoolApi extended with export.csv + export.ics routes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
bf5ea860cc |
Phase 7: pinning, plan versions, solver budget + UX polish
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 37s
CI / test-go-edu-search (push) Successful in 29s
CI / test-python-klausur (push) Failing after 3m56s
CI / test-python-agent-core (push) Successful in 19s
CI / test-nodejs-website (push) Successful in 23s
Backend (school-service):
- tt_solution gains parent_solution_id (self-FK, ON DELETE SET NULL)
and seconds_limit columns via ALTER TABLE IF NOT EXISTS.
- CreateTimetableSolutionRequest accepts optional parent_solution_id
and seconds_limit (5-600s) with binding validation.
- CreateSolution checks parent ownership before INSERT so users can't
fork another tenant's plan.
- New PUT /timetable/lessons/:id/pin endpoint; ownership enforced via
the lesson's solution.created_by_user_id JOIN.
Solver:
- Lesson.pinned now carries @PlanningPin so Timefold leaves locked
cells untouched during the search.
- build_problem() takes optional parent_solution_id; if set, copies
pinned (class_id, subject_id, day, period, room) tuples onto fresh
Lesson objects via greedy first-fit matching. Surplus pinned rows
from curriculum changes are silently dropped.
- _build_factory(seconds) replaces the module-level factory so each
job honours its tt_solution.seconds_limit override.
- persist_solution writes lesson.pinned back so subsequent re-solves
inherit it.
Frontend (studio-v2):
- SolutionList grows three knobs in the create-form: Basieren auf
(parent dropdown, only completed solutions, disabled when none),
Sekunden-Limit (5-600), and the existing Name.
- PlanView cells get a pin/unpin button with optimistic update and
rollback on error. Pinned cells gain an amber ring.
- types.ts + api.ts mirror the new fields; lessonsApi.pin(id, bool).
- HelpPanel: collapsible 6-step Bedienungsanleitung explaining the
setup-to-plan workflow. Anchored at the top of /stundenplan above
the dev token banner.
- page.tsx switches to the same gradient + animated-blob background
used on /korrektur so /stundenplan stops looking like a slate-900
test page.
- JWT dev banner gets a step-by-step explanation of how to grab the
token from DevTools and a non-blocking success indicator (no more
alert()).
Tests:
- school-service: 6 new validator cases for parent_solution_id +
seconds_limit boundaries. 73 subtests total, all green.
- studio-v2: mockSchoolApi adds PUT /lessons/:id/pin route. 5 new
Playwright tests across two suites (parent-selector visibility +
options, seconds-limit input, pin button render, pin-icon flip).
Existing tests adjusted to the new help panel + JWT banner wording.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
612ecec6d9 |
Phase 6: Plan-Ansicht — solution list + weekly grid 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 27s
CI / test-go-edu-search (push) Successful in 29s
CI / test-python-klausur (push) Failing after 3m18s
CI / test-python-agent-core (push) Successful in 20s
CI / test-nodejs-website (push) Successful in 23s
Frontend additions in studio-v2:
- types.ts adds TimetableSolution, TimetableLesson, SolutionStatus,
CreateTimetableSolution mirroring the Go models.
- lib/stundenplan/api.ts adds solutionsApi with list/get/create/remove/
lessons. Solve trigger is POST /timetable/solutions — school-service
forwards to the solver-service over the Docker network.
- _components/plan/SolutionList: table of past solves with status
badges, hard/soft score, Anzeigen + Loeschen buttons, and a
'Neuen Plan generieren' trigger. Auto-polls every 4 s while any
solution is pending/running, clears the interval otherwise.
- _components/plan/PlanView: Mo–Fr × period weekly grid. Three
perspectives (Klasse / Lehrer / Raum) toggleable via test-id'd
buttons; selector below lists every unique resource with at least
one lesson. Cells colour-coded by tt_subject.color.
- _components/plan/PlanHub orchestrates list + view; default tab in
page.tsx switches from 'klassen' to 'plan'.
Tests:
- mockSchoolApi helper extracted to e2e/_helpers.ts so the spec file
stays under 500 LOC. Helper now also mocks /solutions GET/POST/DELETE
and /solutions/:id/lessons; solutions kept in a closure so POST
appears in the next GET.
- 8 new tests across two suites: SolutionList empty state, list
render, completed-vs-failed Anzeigen visibility, solve trigger;
PlanView placeholder when no selection, grid render, perspective
switching.
- Existing Klassen CRUD tests now click the Klassen tab first
(Plan is the new default landing tab).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
0744769d88 |
Split DB-driven constraints into hard + soft variants
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 27s
CI / test-go-edu-search (push) Successful in 29s
CI / test-python-klausur (push) Failing after 2m30s
CI / test-python-agent-core (push) Successful in 17s
CI / test-nodejs-website (push) Successful in 25s
Timefold's penalize() emits one score axis per constraint, so the 'penalize as hard OR soft based on is_hard' pattern needs two constraints. Each rule type now has _hard (filters is_hard=True, penalises HardSoftScore.ONE_HARD) and _soft (filters is_hard=False, penalises ONE_SOFT × max(weight, 1)). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
d3f311a32e |
Wrap score-director config in ScoreDirectorFactoryConfig
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 37s
CI / test-go-edu-search (push) Successful in 29s
CI / test-python-klausur (push) Failing after 2m31s
CI / test-python-agent-core (push) Successful in 17s
CI / test-nodejs-website (push) Successful in 21s
Timefold's SolverConfig expects a typed config object, not a dict — plain dicts hit AttributeError when the wrapper tries to materialise the Java side. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
77650e8092 |
Use 'timefold' (not 'timefold-solver') and revert to ARM platform
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 36s
CI / test-go-edu-search (push) Successful in 29s
CI / test-python-klausur (push) Failing after 2m32s
CI / test-python-agent-core (push) Successful in 18s
CI / test-nodejs-website (push) Successful in 21s
The Python distribution is published on PyPI as 'timefold' — only the Java module is called 'timefold-solver'. With the correct package the ARM64 wheel resolves cleanly, so revert the linux/amd64 workaround. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
22f08a232d |
Pin solver-service to linux/amd64 (no ARM wheels on PyPI)
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 28s
CI / test-go-edu-search (push) Successful in 29s
CI / test-python-klausur (push) Failing after 3m16s
CI / test-python-agent-core (push) Successful in 18s
CI / test-nodejs-website (push) Successful in 25s
timefold-solver only publishes x86_64 wheels — pip resolves to no candidate on linux/arm64. Switch the compose entry to linux/amd64 so the image builds via QEMU/Rosetta on the Mac Mini. The cloud target for this service is x86_64 anyway. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
1f2f304724 |
Use default-jdk-headless on python:slim instead of temurin:alpine
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 36s
CI / test-go-edu-search (push) Successful in 29s
CI / test-python-klausur (push) Failing after 2m34s
CI / test-python-agent-core (push) Successful in 17s
CI / test-nodejs-website (push) Successful in 23s
ARM64 has no eclipse-temurin:17-jdk-alpine manifest. Switch to the Debian-based python:3.11-slim and install OpenJDK via apt so the image builds on both Mac Mini (ARM) and x86_64 hosts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
53cfe9238f |
Apply gofmt to timetable_solution_migrations.go
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 38s
CI / test-go-edu-search (push) Successful in 30s
CI / test-python-klausur (push) Failing after 2m32s
CI / test-python-agent-core (push) Successful in 21s
CI / test-nodejs-website (push) Successful in 28s
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>
|
||
|
|
082a5bb68c |
Strip orphan straight-quote pairings in JSX descriptions
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 30s
CI / test-go-edu-search (push) Successful in 31s
CI / test-python-klausur (push) Failing after 2m35s
CI / test-python-agent-core (push) Successful in 20s
CI / test-nodejs-website (push) Successful in 21s
The German „X" markers in the description prop combined a curly „ (U+201E) with a straight " (U+0022). The straight quote prematurely terminated the JavaScript string inside the JSX expression. Removing both markers around the example text keeps the description readable and unambiguously valid JSX. Test selector for the UnavailableWindow description updated to match the new wording. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
a315db0388 |
Fix JSX attribute syntax in constraint editor descriptions
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 28s
CI / test-go-edu-search (push) Successful in 33s
CI / test-python-klausur (push) Failing after 2m32s
CI / test-python-agent-core (push) Successful in 19s
CI / test-nodejs-website (push) Successful in 24s
German curly quotes („…") combined with a closing straight " inside
JSX attribute values were terminating the attribute prematurely, e.g.
`description="Beispiel: „X" (jugendgerecht)."` lost everything after
the inner straight quote. Switch all such descriptions to the JSX
expression form `description={"…"}` so the inner quotes are part of
a JavaScript string literal and parsed correctly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
7c96d89927 |
Stundenplan Phase 3d: all 15 constraint editors via shared shell
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 30s
CI / test-go-edu-search (push) Successful in 29s
CI / test-python-klausur (push) Failing after 2m38s
CI / test-python-agent-core (push) Successful in 18s
CI / test-nodejs-website (push) Successful in 20s
Backend was already complete in Phase 2; this finishes the UI.
- regeln/_shell.tsx introduces useConstraintCrud (handles list/create/
delete state + reload), ConstraintShell (header, prereq banner,
form toggle, error display, empty/loading/table render), and
useShellStyles for the recurring theme tokens. Each editor now
only carries its schema-specific bits.
- Existing 4 editors (TeacherUnavailableDay/Window, SubjectMax
Consecutive/PreferredPeriod) refactored onto the shell — every
Playwright selector preserved.
- 11 new editors covering the remaining constraint tables:
TeacherMaxHours{Day,Week}, TeacherExcluded{Subject,Room},
Subject{MinDayGap,ContiguousWhenRepeated,DoubleLesson},
Class{MaxHoursDay,NoGaps},
Room{RequiresType,Unavailable}.
- RegelnHub now references all 15 editors directly — no more 'soon'
placeholders. The two duplicate 'Max. Stunden / Tag' entries
(teacher + class) are intentional and disambiguated by group.
Tests:
- e2e/stundenplan.spec.ts: mock routes added for all 11 new constraint
endpoints. RegelnHub suite gains a single test that switches
through 13 uniquely-labelled editors, plus a dedicated test for
the two duplicate 'Max. Stunden / Tag' labels.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
c2c09e1cd9 |
Stundenplan Phase 3c: complete Stammdaten + RegelnHub with 4 editors
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 3m31s
CI / test-python-agent-core (push) Successful in 18s
CI / test-nodejs-website (push) Successful in 22s
Frontend additions in studio-v2:
- PeriodsManager renders the weekly grid as a Mo–So table with one
row per period_index. New entries auto-increment period_index so
the user can hit Anlegen repeatedly for a full day's slots.
- CurriculumManager joins classes + subjects; new entries refuse to
open when either prerequisite list is empty (banner instead).
- AssignmentsManager joins teacher × class × subject with the same
prerequisite-banner pattern.
- regeln/RegelnHub: vertical sidebar grouping all 15 constraint
types by parent entity (Lehrer/Fach/Klasse/Raum). Implemented
editors are clickable, the other 11 are visibly disabled with
a 'soon' tag.
- Three new editors:
TeacherUnavailableWindowEditor (time-window pattern),
SubjectMaxConsecutiveEditor (number-input pattern),
SubjectPreferredPeriodEditor (number range pattern).
- page.tsx wires every tab to its manager; the not-implemented
placeholder is gone (no more empty tabs).
Test coverage:
- e2e/stundenplan.spec.ts rewritten: 23 tests across 7 suites,
covering all 8 tabs, the new managers' prerequisite banners,
sub-tab switching in the RegelnHub, and the disabled state of
not-yet-implemented constraint rules. Each test mocks the
backend via page.route() so the suite stays hermetic.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
4657589b89 |
Fix Playwright selector ambiguities in stundenplan.spec.ts
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 31s
CI / test-python-klausur (push) Failing after 2m36s
CI / test-python-agent-core (push) Successful in 20s
CI / test-nodejs-website (push) Successful in 22s
- 'Lehrer' label collided with a Sidebar entry; scope to <main nav>. - 'Schmidt, Anna' lived in a closed <option>; assert on count via select.locator() instead of toBeVisible(). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
73636f76a2 |
Stundenplan Phase 3b: 3 more Stammdaten managers, first constraint editor, full test coverage
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 30s
CI / test-go-edu-search (push) Successful in 30s
CI / test-python-klausur (push) Failing after 3m6s
CI / test-python-agent-core (push) Successful in 20s
CI / test-nodejs-website (push) Successful in 21s
Frontend additions in studio-v2:
- LehrerManager / FaecherManager / RaeumeManager — same CRUD pattern as
Klassen, with entity-specific form fields and table columns.
- regeln/TeacherUnavailableDayEditor — first constraint editor, joins
against teachersApi to render a readable name in the dropdown and
list. Falls back to a guidance banner when no teachers exist yet.
- page.tsx wires up the new tabs; data-testid attributes added across
managers so the Playwright suite can target them deterministically.
Tests:
- school-service: timetable_constraints_more_test.go fills the
remaining 9 constraint DTOs (TeacherMaxHoursDay/Week,
TeacherExcludedSubject/Room, SubjectMinDayGap,
SubjectContiguousWhenRepeated, SubjectDoubleLesson, ClassNoGaps,
RoomRequiresType). 66 subtests total, all green.
- studio-v2: e2e/stundenplan.spec.ts covers the page shell, tab
navigation, Klassen CRUD with mocked backend, constraint editor's
empty-teacher fallback, sidebar entry. All school-service calls
intercepted via page.route() so the suite is hermetic.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
f21ecf293b |
Add Stundenplan frontend scaffolding in studio-v2
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 29s
CI / test-python-klausur (push) Failing after 2m36s
CI / test-python-agent-core (push) Successful in 20s
CI / test-nodejs-website (push) Successful in 22s
Phase 3 — initial UI for the timetable scheduler:
- app/stundenplan/page.tsx with tab navigation (Klassen / Lehrer /
Faecher / Raeume / Zeitraster / Stundentafel / Lehrauftraege /
Regeln) and a dev-mode JWT entry to authenticate against
school-service until full auth is wired up.
- app/stundenplan/_components/KlassenManager.tsx as the working
prototype for one entity (list / create / delete). Pattern can be
copied for the other 6 stammdaten + 15 constraint editors.
- lib/stundenplan/api.ts exposing typed clients for all 22 endpoints
(7 stammdaten + 15 constraint tables). Constraints use a factory
to keep the file tight.
- app/api/school/[...path]/route.ts proxies the browser through
Next.js to school-service so HTTPS studio-v2 can reach the plain
HTTP backend.
- Sidebar.tsx gains a Stundenplan entry with 26-language labels.
- docker-compose.yml exposes SCHOOL_SERVICE_URL to studio-v2 and
declares the school-service dependency.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
64e7176267 |
Apply gofmt to timetable.go
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 39s
CI / test-go-edu-search (push) Successful in 29s
CI / test-python-klausur (push) Failing after 2m35s
CI / test-python-agent-core (push) Successful in 19s
CI / test-nodejs-website (push) Successful in 21s
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>
|
||
|
|
a1488b2fec |
Fix: enrich non-EN Kaikki search results with translations from EN hub
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 33s
CI / test-go-edu-search (push) Successful in 30s
CI / test-python-klausur (push) Failing after 2m33s
CI / test-python-agent-core (push) Successful in 20s
CI / test-nodejs-website (push) Successful in 24s
When searching for DE/FR/ES/etc. words, the Kaikki entries have empty translations. Now does a reverse lookup to find the EN entry and copies its 24-language translations. This ensures wordInNative() works for all languages, not just the original 7. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
8d53b1f6b9 |
Translate Sidebar nav labels into 26 languages
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 28s
CI / test-go-edu-search (push) Successful in 30s
CI / test-python-klausur (push) Failing after 2m22s
CI / test-python-agent-core (push) Successful in 19s
CI / test-nodejs-website (push) Successful in 20s
- Lernmodule, Eltern, Woerterbuch, Meet, KI-Assistent now translated - Uses NAV_LABELS dict with fallback chain (lang → en → de) - Fixed "nav_eltern" → shows "Eltern"/"Parents"/"Ebeveyn" etc. - Fixed "Lernmodule" hardcoded → uses nav_lernmodule key - Woerterbuch link now points to /vocabulary (not /vocab-worksheet) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
399ab88f5f |
Translate language dropdown tabs + add info box in 26 languages
CI / test-go-edu-search (push) Waiting to run
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 40s
CI / test-python-klausur (push) Failing after 2m35s
CI / test-python-agent-core (push) Successful in 18s
CI / test-nodejs-website (push) Successful in 28s
- Tab labels (Muttersprache/Schulsprache) now translate with selected language e.g. Turkish: "Ana dilim" / "Okul dili" - Info box below tabs explains each setting in the user's native language e.g. "Evde konustunuz dil. Tum menuler bu dilde gorunecektir." - Wider dropdown (w-72) to fit translated text - All 26 European languages covered Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
d52eb43a32 |
Fix: auto-fill target translation with best match (not only single result)
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 30s
CI / test-go-edu-search (push) Successful in 29s
CI / test-python-klausur (push) Failing after 2m18s
CI / test-python-agent-core (push) Successful in 19s
CI / test-nodejs-website (push) Successful in 22s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
bde0d57b5a |
Add Schulsprache (school language) as second language setting
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 27s
CI / test-go-edu-search (push) Successful in 28s
CI / test-python-klausur (push) Failing after 2m21s
CI / test-python-agent-core (push) Successful in 18s
CI / test-nodejs-website (push) Successful in 22s
- LanguageContext: new schoolLanguage + setSchoolLanguage - LanguageDropdown: two tabs (Muttersprache / Schulsprache) with flag selection - UnitBuilder: defaults target language to schoolLanguage - Stored in bp_school_language localStorage (default: de) - Shows school flag badge next to main language when different Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
fc49d87928 |
Add exercise translations for all 26 European languages
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 32s
CI / test-go-edu-search (push) Successful in 29s
CI / test-python-klausur (push) Failing after 2m26s
CI / test-python-agent-core (push) Successful in 34s
CI / test-nodejs-website (push) Successful in 23s
Buttons (Richtig/Falsch/Weiter), instructions, labels — now translated for FR, ES, IT, PT, NL, RO, EL, BG, HR, CS, HU, SV, DA, FI, SK, SL, LT, LV, ET. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
0018076ed5 |
Unify language system: one setting for all modules
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 41s
CI / test-go-edu-search (push) Successful in 30s
CI / test-python-klausur (push) Failing after 2m29s
CI / test-python-agent-core (push) Successful in 19s
CI / test-nodejs-website (push) Successful in 26s
- Merge two separate language systems (bp_language + bp_native_language) into one - NativeLanguageContext now reads from LanguageContext (same localStorage key) - Extend i18n.ts to 26 languages with flags (UI falls back to EN/DE) - Replace LanguageSwitcher with LanguageDropdown (flags) in learn + parent layouts - Migration: old bp_native_language value auto-migrates to bp_language - Onboarding page writes to bp_language (unified key) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
a30f10a467 |
Widen AudioButton lang prop to string for multi-language support
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 43s
CI / test-go-edu-search (push) Successful in 35s
CI / test-python-klausur (push) Failing after 2m30s
CI / test-python-agent-core (push) Successful in 22s
CI / test-nodejs-website (push) Successful in 26s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
a44d360cbc |
Fix useRef initial value for React 19 compatibility
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 39s
CI / test-go-edu-search (push) Successful in 31s
CI / test-python-klausur (push) Failing after 2m33s
CI / test-python-agent-core (push) Successful in 22s
CI / test-nodejs-website (push) Successful in 26s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
52a15b24fe |
Add custom word entry + language pair support for learning units
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 31s
CI / test-python-klausur (push) Failing after 2m29s
CI / test-python-agent-core (push) Successful in 24s
CI / test-nodejs-website (push) Successful in 22s
- New UnitBuilder component with language pair selector (DE⇄EN, ES, FR, etc.) - Manual word entry form with auto-suggest from Kaikki dictionary (6M words) - "No results" prompt to add multi-word terms (e.g. "schottisches Hochland") - New backend endpoint GET /vocabulary/lookup-translation (any→any via EN hub) - Updated POST /vocabulary/units: accepts custom_words + source_lang/target_lang - Split unit endpoints into vocabulary/unit_api.py (500 LOC budget) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
855cc4caf4 |
Fix: make 'Alle zur Unit' button visible — full-width layout below word tags
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 43s
CI / test-go-edu-search (push) Successful in 30s
CI / test-python-klausur (push) Failing after 2m37s
CI / test-python-agent-core (push) Successful in 19s
CI / test-nodejs-website (push) Successful in 26s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
c09fc6c7bc |
Add 'Alle zur Unit' button + fix topic display
Two buttons on topic cards: - "Anzeigen": Shows words in search results (for review) - "Alle zur Unit": Adds all topic words to the unit builder directly Both buttons load from Kaikki and respect selected language. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
387219682d |
Fix: Topic word labels translate to selected language
Topics API now accepts lang= parameter. When lang=de, the word labels are translated from English via Kaikki translations: "eye, pupil, iris" → "Auge, Pupille, Iris" Frontend sends searchLang to /topics endpoint and displays display_words (translated) instead of words (English). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
6f43224fda |
Simplify Sidebar: Remove Woerterbuch, rename to "Lernmodule"
Sidebar: Only "Lernmodule" link (no separate Woerterbuch). /learn page: "Neue Lernunit erstellen" button links to /vocabulary for the word selection flow. Teacher stays in one flow. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
9b96998654 |
Fix: Topic "Alle laden" always searches in EN (topics are English word lists)
When user selects DE and types "Auge", the topic "Eye/Auge" is found correctly. But "Alle laden" must search words with lang=en because the topic word list is English (eye, pupil, iris...). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
91e8b92bdc |
Add topic suggestions: search "banana" → suggests "Fruit/Obst" topic
31 curated topics with 683 words (Fruit, Animals, Body, Eye, Sports, School, Family, Weather, etc.). When user types a word that belongs to a topic, the topic appears as a suggestion with "Alle laden" button. Clicking "Alle laden" fetches all words from that topic via Kaikki and displays them for easy selection into a learning unit. New endpoint: GET /api/vocabulary/topics?q=banana New table: vocabulary_topics (topic, words[], word_count) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
c2efb9934c |
Fix: Vocabulary search sends lang parameter + language dropdown
Search now sends lang= to API (was always defaulting to EN). Users can select any of the 24 languages in the search bar dropdown. Placeholder text changes based on selected language. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
0d2e79da66 |
Fix: Hardcode Kaikki stats (COUNT on 6M rows took 100s, blocked server)
SELECT COUNT(*) FROM vocabulary_kaikki was 100+ seconds without index, blocking the entire backend. Hardcoded to 6,271,749 / 24 languages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
cb4ea8e49a |
Connect frontend to Kaikki dictionary (6.27M words, 24 languages)
Search endpoint now defaults to source=kaikki, searching the vocabulary_kaikki table with 6.27M Wiktionary entries. /filters returns kaikki_total and kaikki_languages count. /vocabulary header shows "6,271,749 Woerter in 24 Sprachen". Manual vocabulary_words (27 entries) still accessible via source=manual. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
d14826b199 |
Fix: Build error + explanation above exercise + aligned columns + impressum link
1. Removed stale 'explanations' export that broke build 2. Explanation banner now spans full width ABOVE the 2/3+1/3 layout so exercise cards and native words start at the same height 3. Both columns use items-start for visual alignment 4. Impressum link added at bottom of learn layout Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
693989c1a6 |
Add exercise explanations in all 26 languages
exerciseExplanations.ts: Match and Flashcard explanations translated into DE, EN, TR, AR, UK, RU, PL, FR, ES, IT, PT, NL, RO, EL, BG, HR, CS, HU, SV, DA, FI, SK, SL, LT, LV, ET. Each exercise type gets a parent-facing explanation in the user's selected language. No more German fallback for unsupported languages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |