Doku: Anforderungen + ADRs (Symfony, htmx, SQLite, HA-Consumer)
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
# Anforderungen – svc-essensplanung
|
||||
|
||||
> Stand: 13.09.2026 · Status: **Agreed Draft** (noch nicht in Code umgesetzt)
|
||||
|
||||
Kurzes Mittagessen-Planer-Werkzeug: Gericht anlegen, „fertig/gegessen" abhaken,
|
||||
Reihenfolge anpassen, Wochentage markieren und bei Bedarf aus dem Archiv
|
||||
inspirieren lassen. Ein einzelner Nutzer, läuft im eigenen Homelab, mobil via Browser.
|
||||
|
||||
## 1. Kern-Entities
|
||||
|
||||
### Gericht (Eintrag)
|
||||
Ein Gericht ist die zentrale Dateneinheit. Felder:
|
||||
|
||||
| Feld | Typ | Pflicht | Beschreibung |
|
||||
|------|-----|---------|--------------|
|
||||
| `id` | int (PK) | ja | Autogeneriert |
|
||||
| `name` | text | ja | z. B. „Spaghetti Bolognese" |
|
||||
| `notiz` | text | nein | Freie Anmerkung, z. B. „mit mehr Soße" |
|
||||
| `menge` | int/smallint | nein | Portionen oder Stückzahl, falls nützlich |
|
||||
| `wochentage` | set (Mo–So) | nein | Beliebig viele, optional. **Nur zur Markierung/Gruppierung**, keine Automatik. |
|
||||
| `sort_order` | int | ja | Position in der Planungsliste (manuell per Drag & Drop) |
|
||||
| `status` | enum: `geplant` / `gegessen` | ja | `geplant` = aktiv in der Liste, `gegessen` = abgehakt → Archiv |
|
||||
| `gegessen_am` | date | nein | Setzt sich automatisch, wenn auf `gegessen` gesetzt |
|
||||
| `erstellt_am` | timestamp | ja | |
|
||||
| `aktualisiert_am` | timestamp | ja | |
|
||||
|
||||
> **Wiederholungen über mehrere Tage** (z. B. Reste Mo+Di) werden **nicht** als
|
||||
> automische Dauer modelliert. Stattdessen decken die `wochentage`-Markierungen und
|
||||
> ggf. mehrere Einträge ab. „Erforderlich, dass jeder Tag abgedeckt ist" gilt **nicht** –
|
||||
> Tage dürfen frei stehen bleiben.
|
||||
|
||||
### Archiv
|
||||
- Das Archiv ist **keine eigene Tabelle**: Es ist die Sicht auf Einträge mit
|
||||
`status = gegessen`, geordnet nach `gegessen_am` (neueste zuerst).
|
||||
- Abhaken (`geplant → gegessen`) verschiebt den Eintrag automatisch in die Archivsicht.
|
||||
- Aufheben / „wieder einplanen" (`gegessen → geplant`) setzt `gegessen_am` zurück und
|
||||
fügt ihn der Planungsliste wieder hinzu.
|
||||
|
||||
## 2. Features (MVP)
|
||||
|
||||
### 2.1 Gericht verwalten
|
||||
- **Anlegen** (name, notiz, menge, wochentage).
|
||||
- **Bearbeiten** (alle Felder).
|
||||
- **Löschen** (hart, mit Bestätigung).
|
||||
- **Reihenfolge ändern**: Drag & Drop in der Planungsliste → persistiert in `sort_order`.
|
||||
|
||||
### 2.2 Abhaken / Archiv
|
||||
- Pro Eintrag ein „Abhaken"-Aktion (Checkbox oder Button).
|
||||
- Abhaken: `status → gegessen`, `gegessen_am = heute`, Eintrag verschwindet aus der
|
||||
Planungsliste in die **Archivansicht**.
|
||||
- In der Archivansicht: Eintrag wieder in die Planung zurückstellen oder Löschen.
|
||||
|
||||
### 2.3 Inspiration
|
||||
- **Inspiration-Panel**, das **jeweils 5 Vorschläge** aus dem Archiv anzeigt.
|
||||
- Button „Weitere 5" → nächste 5, die noch nicht vorgeschlagen wurden.
|
||||
- **Auswahlkriterium (gewichteter Mix):**
|
||||
1. **Lange nicht** gekocht (älteste `gegessen_am`) – primär,
|
||||
2. **Seltene** (wenigste Auftritte insgesamt) – sekundär,
|
||||
3. **Häufige** (beliebt) – drittens.
|
||||
Genauere Gewichtung bei der Implementierung festlegen (siehe ADR-005, offen).
|
||||
- Jeder Vorschlag hat einen **1-Klick-Button** → übernimmt das Gericht als **neuen
|
||||
`geplant`-Eintrag** in die Planungsliste (Kopie, `gegessen_am` wird leer).
|
||||
|
||||
### 2.4 Ansichten
|
||||
- **Planung** (Liste der `geplant`-Einträge, sortiert nach `sort_order`).
|
||||
- **Archiv** (Liste der `gegessen`-Einträge, sortiert nach `gegessen_am` absteigend).
|
||||
- **Inspiration** (Panel / eigener Bereich, siehe 2.3).
|
||||
- Wochentage werden je Eintrag **als Markierung** angezeigt (kein Filter nötig, aber
|
||||
optional als Gruppierung möglich).
|
||||
|
||||
## 3. Technische Vorgaben (aus der Diskussion)
|
||||
|
||||
- **Backend:** PHP / **Symfony 7**, eigene JSON-Controller (keine ApiPlatform-Magie),
|
||||
als **API** nutzbar.
|
||||
- **Frontend:** Serverseitiges Rendering + **htmx** (CRUD + Listen + Formulare).
|
||||
Sortierbarkeit via **SortableJS** (~20 kB). **Kein Build-Step, kein Node im Runtime.**
|
||||
- **Datenbank:** **SQLite** (einfach, leicht zu backupn).
|
||||
- **Mobile:** Responsive + **PWA-Manifest** („Zum Homescreen hinzufügen").
|
||||
- **Deployment:** Docker-Stack `svc-essensplanung` im Homelab, hängend an das
|
||||
bestehende Traefik-`infra-traefik_traefik-net`; **Domain:** `essen.ljh31.de`
|
||||
(ACME `letsencrypt`). Gleiche Deploy-Muster wie die anderen `svc-*`-Stacks.
|
||||
- **Auth:** Single User → **kein Login**. Optionaler Shared-Token, falls später von
|
||||
elsewhere (z. B. Home-Assistant) genutzt.
|
||||
|
||||
### 3.1 Home-Assistant-Integration (Phase 2, optional)
|
||||
- HA holt **„Was steht heute an?"** über dieselbe API.
|
||||
- Ziel: 1 Zeile im HA-Dashboard + ggf. Benachrichtigung „Heute: Bolognese".
|
||||
- Ist ein z**Add-on**, kein Teil des MVP. Siehe ADR-004 (offen, Phase 2).
|
||||
|
||||
## 4. Ausdrücklich NICHT im MVP
|
||||
- Mehrere Nutzer / Rechte.
|
||||
- Automatische Wiederholung pro Wochentag (Wochentag ist nur Label).
|
||||
- Einkaufslisten, Kalorien, Portionen-Logik.
|
||||
- Offline-First / lokale Sync (htmx braucht die API).
|
||||
- Export/import (vorerst).
|
||||
|
||||
## 5. Offene Punkte (bevor Code)
|
||||
- [ ] Genaue **Gewichtung** der Inspiration (s. ADR-005).
|
||||
- [ ] `menge`: reine Zahl oder Zahl + Einheit (Portionen)?
|
||||
- [ ] Soll **Löschen** hart sein oder auch auf archiviert? (vorerst: hart)
|
||||
- [ ] PWA: nur Add-to-Home, oder auch Push (braucht SW + Service-Worker)?
|
||||
- [ ] HA-Integration: konkret als Sensor (REST-Poll) via `rest`-Integration in HA —
|
||||
dazu braucht die API einen sauberen `GET /api/today`-Endpunkt.
|
||||
|
||||
## 6. Abnahmekriterien (Definition of Done, MVP)
|
||||
- [ ] Gericht anlegen/bearbeiten/löschen läuft via UI.
|
||||
- [ ] Reihenfolge per Drag & Drop persisted (übersteht Reload).
|
||||
- [ ] Abhaken verschiebt Eintrag in Archiv, Wiederherstellen bringt ihn zurück.
|
||||
- [ ] Inspiration zeigt 5, „Weitere 5" liefert neue 5, 1-Klick übernimmt.
|
||||
- [ ] Läuft auf `essen.ljh31.de` (https, ACME) und ist mobil + add-to-home.
|
||||
- [ ] Daten in SQLite, kein Build-Step im Deployment.
|
||||
Reference in New Issue
Block a user