Files
svc-essensplanung/Doku/plan.md
T
jensandClaude Opus 4.8 cb3cbfb394 M0: Skelett + Auth-Grundgerüst (Keycloak-OIDC + API-Token)
- Symfony 7.4 LTS, PHP 8.4, FrankenPHP, SQLite (3-Layer src/UI|Logic|Data)
- Auth: manueller OidcClient (Authorization-Code) im UI-Layer, kein
  Security-Bundle/league; Session-Gate via SessionAuthSubscriber
- API-Guard via statischem X-Api-Token (ApiTokenSubscriber); ExceptionSubscriber
- UserEntity (Auto-Provision) + Init-Migration
- Docker (php:8.4-frankenphp) + compose (essen.ljh31.de, traefik-net external)
- SmokeTests (7) grün: Redirect-Fälle, API-Token, Auth-Render, Logout

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-13 22:48:24 +02:00

82 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Implementierungsplan
Status: **final** (2026-09-13, abgestimmt) · Basis: [`anforderungen.md`](anforderungen.md), [`architektur.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 Client
`essens`), Auto-Provision des lokalen Users (wie `svc-webui`). HA bezieht die
Tagesansicht über `GET /api/today` mit **statischem API-Token**
(`X-Api-Token` aus `.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, doctrine/SQLite, twig, routing), `public/index.php`
- Struktur laut `architektur.md` leergelegt (`src/UI`, `src/Logic`, `src/Data`)
- Keycloak-OIDC: manueller `OidcClient` (kein `league/oauth2-client`, kein
Security-Bundle; vgl. ADR-003), Login/Callback/Logout im UI-Layer,
`sub`/`email`-Claim → lokale User-Zeile (Auto-Provision)
- Docker: `Dockerfile` (php:8.4-frankenphp), `compose.yaml`
(Volume `data/` für SQLite, `.env`), Network `infra-traefik_traefik-net` (external),
Traefik-Labels → `essen.ljh31.de` + ACME + redirect-to-https
- `phpunit.xml`, `tests/`, htmx + SortableJS in `public/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` (Status `aktiv`/`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 → `CreateDish` mit Referenz
- **DoD:** Reorder bleibt nach Reload bestehen; Inspiration klickbar adoptierend
### M4 – Härtung & API
- `X-Api-Token`-Guard (optional, `.env`) für `GET /api/today` (HA-ready)
- Fehlerseiten, Logging, Backup-Hinweis (SQLite-Datei `data/`)
- **DoD:** `curl -H "X-Api-Token: …" /api/today` liefert Tagesgericht-JSON;
DoD-Punkte aus `anforderungen.md` abgehakt
### 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 `essens` in realm `family` anlegen (Redirect-URI `https://essen.ljh31.de`)
- **DoD:** Gesamt-DoD aus `anforderungen.md` erfü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 test` bzw. `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 |