3.8 KiB
3.8 KiB
Implementierungsplan
Status: final (2026-09-13, abgestimmt) · Basis: anforderungen.md, architektur.md, ADR 001–007
Prinzipien
- Vertikal geschnitten: Jedes Milestone ist ein vollständiger UI→Logic→Data-Slice und am Ende lauffähig/testbar (kein Layer-Reihenbau).
- Ein Milestone = ein Review-Pausenpunkt. Jeder MS wird einzeln abgenommen, bevor der nächste startet.
- Kein CI – PHPUnit läuft manuell (
composer test). - Auth: Web-UI über Keycloak-OIDC (realm
family, eigener Clientessens), Auto-Provision des lokalen Users (wiesvc-webui). HA bezieht die Tagesansicht überGET /api/todaymit statischem API-Token (X-Api-Tokenaus.env, kein Keycloak-Refresh für HA). Damit wird ADR-003 in M0 entsprechend überarbeitet. - Deploy (M5) erst nach expliziter Freigabe.
Milestones
M0 – Skelett + Auth-Grundgerüst
- Symfony 7.4 LTS, PHP 8.4, FrankenPHP:
composer.json,config/(framework, security, doctrine/SQLite, twig, routing),public/index.php - Struktur laut
architektur.mdleergelegt (src/UI,src/Logic,src/Data) - Keycloak-OIDC:
league/oauth2-client,security.yaml, Login/Logout auf Keycloak,REMOTE_USER-Claim → lokale User-Zeile (Auto-Provision) - Docker:
Dockerfile(php:8.4-frankenphp),docker-compose.yaml(Volumedata/für SQLite,.env), Networkinfra-traefik_traefik-net(external), Traefik-Labels →essen.ljh31.de+ ACME + redirect-to-https phpunit.xml,tests/, htmx + SortableJS inpublic/js/- ADR-003 überarbeitet (Keycloak statt „kein Login")
- DoD: Container läuft,
GET /→ Keycloak-Login, danach Hello-World-Seite
M1 – CRUD-Slice
- Logic:
Dish-Model,CreateDish/UpdateDish/DeleteDish,ListDishes,DishDto - Data:
DishEntity, Migration 0001, Provider/Processor-Impl, Mapper, Exception-Subscriber - UI:
DishController(htmx-Partials), Formular + Validierung im Controller, Liste - Tests: UseCase-Unit (in-mem SQLite) + 1 Controller-Feature-Test
- DoD: Gericht anlegen/bearbeiten/löschen im Browser (als eingeloggter User)
M2 – Status & Wochentage
CheckOffDish/UncheckDish(Statusaktiv/gecheckt),ArchiveDish- Wochentag-Tags (Mo–So) setzen/ändern, Liste nach Tag gruppier-/filterbar
- DoD: Check-Off via htmx-Toggle, Tagesansicht, Archiv-Tab
M3 – Reorder + Inspiration
ReorderDishes(SortableJS-change→ Position-Ints, persistiert)SuggestDishes-Query: Slow 0.5 / Rarität 0.3 / Hotness 0.2 (ADR-006), 5 Vorschläge + „Weitere 5", 1-Klick-Adopt →CreateDishmit Referenz- DoD: Reorder bleibt nach Reload bestehen; Inspiration klickbar adoptierend
M4 – Härtung & API
X-Api-Token-Guard (optional,.env) fürGET /api/today(HA-ready)- Fehlerseiten, Logging, Backup-Hinweis (SQLite-Datei
data/) - DoD:
curl -H "X-Api-Token: …" /api/todayliefert Tagesgericht-JSON; DoD-Punkte ausanforderungen.mdabgehakt
M5 – Deploy (erst nach Freigabe)
- Stack auf
docker1:/root/stacks/svc-essensplanung,git pull && docker compose up -d - Traefik:
essen.ljh31.de, Let's-Encrypt - Keycloak: Client
essensin realmfamilyanlegen (Redirect-URIhttps://essen.ljh31.de) - DoD: Gesamt-DoD aus
anforderungen.mderfüllt, erreichbar ohne LAN-IP
Test-Strategie (quer)
- PHPUnit je Milestone: UseCase-Unit (in-mem SQLite, Logic-Dependencies als Fakes) + Feature-Tests (HTTP gegen Test-DB)
- Manuell:
docker compose run app composer testbzw.vendor/bin/phpunit - Kein CI (bewusst, s. Prinzipien)
Abnahme-Historie
| MS | Datum | Status |
|---|---|---|
| M0 | offen | |
| M1 | offen | |
| M2 | offen | |
| M3 | offen | |
| M4 | offen | |
| M5 | offen |