diff --git a/Doku/plan.md b/Doku/plan.md new file mode 100644 index 0000000..c50c55d --- /dev/null +++ b/Doku/plan.md @@ -0,0 +1,80 @@ +# 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, security, doctrine/SQLite, twig, routing), `public/index.php` +- Struktur laut `architektur.md` leergelegt (`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` + (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 | diff --git a/README.md b/README.md index b7ec2b4..06addd5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,20 @@ # svc-essensplanung -Essens-Planer: Mittagessen planen, abhaken, archivieren. Symfony-API + htmx-PWA. \ No newline at end of file +Single-User-Essensplanung: CRUD + Wochentage + Status (aktiv/gecheckt/archiv) ++ Reordering + htxm-Inspiration, mit optionaler HA-/Smartphone-Sicht. + +Einzelner Docker-Stack (FrankenPHP/SQLite), deployt parallel zu anderen +`svc-*`-Stacks unter `~/Projekte/Homelab/`. + +> Status: in Umsetzung – siehe [Doku/plan.md](Doku/plan.md) + +## Doku (kanonisch) + +- [`Doku/anforderungen.md`](Doku/anforderungen.md) – Requirements & Definition of Done +- [`Doku/architektur.md`](Doku/architektur.md) – 3-Layer-Architektur (UI/Logic/Data), Patterns, Testing +- [`Doku/plan.md`](Doku/plan.md) – Implementierungsplan M0–M5, Abnahme-Historie +- [`Doku/adr/README.md`](Doku/adr/README.md) – Entscheidungen (ADR-Index) + +## Tech + +Symfony 7.4 LTS · PHP 8.4 · FrankenPHP · SQLite · htmx + SortableJS · Keycloak-OIDC