docs: add mealplanner design spec
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
208
docs/superpowers/specs/2026-04-14-mealplanner-design.md
Normal file
208
docs/superpowers/specs/2026-04-14-mealplanner-design.md
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
# Mealplanner — Design Spec
|
||||||
|
|
||||||
|
**Datum:** 2026-04-14
|
||||||
|
**Domain:** `essen.kuns.dev`
|
||||||
|
**Repo:** `kuns/mealplanner`
|
||||||
|
|
||||||
|
## Zusammenfassung
|
||||||
|
|
||||||
|
Webapp zur Wochenplanung von Mahlzeiten. Generiert automatisch einen Wochenplan (7 Tage, je 1 Hauptmahlzeit), der bearbeitbar ist. Aus dem Plan wird eine intelligente Einkaufsliste generiert (Zutaten zusammengefasst, abhakbar). Rezepte kommen aus einer externen API + eigene Rezepte.
|
||||||
|
|
||||||
|
## Anforderungen
|
||||||
|
|
||||||
|
- **Haushalt:** Feste Personenzahl in Einstellungen (Standard: 2)
|
||||||
|
- **Mahlzeiten:** 1 pro Tag (Abendessen)
|
||||||
|
- **Wochenplan:** Auto-generiert, voll editierbar (Gericht austauschen, neu generieren)
|
||||||
|
- **Rezepte:** Externe DB (TheMealDB, kostenlos, kein API-Key nötig) + eigene Rezepte
|
||||||
|
- **Einkaufsliste:** Zutaten aggregiert, nach Kategorie gruppiert, abhakbar
|
||||||
|
- **Ernährungspräferenzen:** Keine
|
||||||
|
- **Auth:** Zitadel (manueller OIDC PKCE Flow, kein oidc-client-ts)
|
||||||
|
|
||||||
|
## Architektur
|
||||||
|
|
||||||
|
```
|
||||||
|
Vue 3 SPA (Tailwind 4, Bun, Vite)
|
||||||
|
↓ REST API (/api/*)
|
||||||
|
.NET 8 Web API
|
||||||
|
├── Auth (Zitadel JWT Bearer + NuGet-Paket)
|
||||||
|
├── RecipeService (TheMealDB Client + eigene Rezepte CRUD)
|
||||||
|
├── MealPlanService (Generierung + CRUD)
|
||||||
|
└── ShoppingListService (Aggregation aus Wochenplan)
|
||||||
|
↓
|
||||||
|
Shared PostgreSQL (DB: mealplanner)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Projektstruktur
|
||||||
|
|
||||||
|
```
|
||||||
|
mealplanner/
|
||||||
|
├── backend/
|
||||||
|
│ ├── Controllers/
|
||||||
|
│ │ ├── RecipeController.cs
|
||||||
|
│ │ ├── MealPlanController.cs
|
||||||
|
│ │ ├── ShoppingListController.cs
|
||||||
|
│ │ └── SettingsController.cs
|
||||||
|
│ ├── Models/
|
||||||
|
│ │ ├── Recipe.cs
|
||||||
|
│ │ ├── MealPlan.cs
|
||||||
|
│ │ ├── MealPlanEntry.cs
|
||||||
|
│ │ ├── ShoppingItem.cs
|
||||||
|
│ │ └── UserSettings.cs
|
||||||
|
│ ├── Services/
|
||||||
|
│ │ ├── TheMealDbClient.cs
|
||||||
|
│ │ ├── RecipeService.cs
|
||||||
|
│ │ ├── MealPlanService.cs
|
||||||
|
│ │ └── ShoppingListService.cs
|
||||||
|
│ ├── Data/
|
||||||
|
│ │ └── AppDbContext.cs
|
||||||
|
│ ├── Program.cs
|
||||||
|
│ └── backend.csproj
|
||||||
|
├── frontend/
|
||||||
|
│ ├── src/
|
||||||
|
│ │ ├── views/
|
||||||
|
│ │ │ ├── WeekPlanView.vue (Hauptansicht)
|
||||||
|
│ │ │ ├── ShoppingListView.vue
|
||||||
|
│ │ │ ├── RecipesView.vue (Eigene Rezepte verwalten)
|
||||||
|
│ │ │ └── SettingsView.vue
|
||||||
|
│ │ ├── components/
|
||||||
|
│ │ │ ├── MealCard.vue
|
||||||
|
│ │ │ ├── RecipeDetail.vue
|
||||||
|
│ │ │ ├── ShoppingItem.vue
|
||||||
|
│ │ │ └── WeekDay.vue
|
||||||
|
│ │ ├── composables/
|
||||||
|
│ │ │ └── useApi.ts
|
||||||
|
│ │ ├── auth.ts (Manueller OIDC PKCE Flow)
|
||||||
|
│ │ ├── router.ts
|
||||||
|
│ │ ├── App.vue
|
||||||
|
│ │ └── main.ts
|
||||||
|
│ ├── index.html
|
||||||
|
│ └── package.json
|
||||||
|
├── Dockerfile
|
||||||
|
├── docker-compose.yml
|
||||||
|
└── docs/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Datenmodell
|
||||||
|
|
||||||
|
### Recipe
|
||||||
|
| Feld | Typ | Beschreibung |
|
||||||
|
|------|-----|-------------|
|
||||||
|
| id | UUID | PK |
|
||||||
|
| user_id | string | Zitadel User ID (null = extern) |
|
||||||
|
| external_id | string? | TheMealDB ID |
|
||||||
|
| title | string | Name des Gerichts |
|
||||||
|
| instructions | text | Zubereitungsanleitung |
|
||||||
|
| image_url | string? | Bild-URL |
|
||||||
|
| source | enum | `own`, `themealdb` |
|
||||||
|
| created_at | timestamp | |
|
||||||
|
|
||||||
|
### RecipeIngredient
|
||||||
|
| Feld | Typ | Beschreibung |
|
||||||
|
|------|-----|-------------|
|
||||||
|
| id | UUID | PK |
|
||||||
|
| recipe_id | UUID | FK → Recipe |
|
||||||
|
| name | string | Zutat |
|
||||||
|
| amount | decimal? | Menge |
|
||||||
|
| unit | string? | Einheit (g, ml, Stück, etc.) |
|
||||||
|
| category | string? | Gemüse, Fleisch, Milch, etc. |
|
||||||
|
|
||||||
|
### MealPlan
|
||||||
|
| Feld | Typ | Beschreibung |
|
||||||
|
|------|-----|-------------|
|
||||||
|
| id | UUID | PK |
|
||||||
|
| user_id | string | Zitadel User ID |
|
||||||
|
| week_start | date | Montag der Woche |
|
||||||
|
| created_at | timestamp | |
|
||||||
|
|
||||||
|
### MealPlanEntry
|
||||||
|
| Feld | Typ | Beschreibung |
|
||||||
|
|------|-----|-------------|
|
||||||
|
| id | UUID | PK |
|
||||||
|
| meal_plan_id | UUID | FK → MealPlan |
|
||||||
|
| date | date | Tag |
|
||||||
|
| recipe_id | UUID | FK → Recipe |
|
||||||
|
|
||||||
|
### UserSettings
|
||||||
|
| Feld | Typ | Beschreibung |
|
||||||
|
|------|-----|-------------|
|
||||||
|
| user_id | string | PK, Zitadel User ID |
|
||||||
|
| household_size | int | Anzahl Personen (Default: 2) |
|
||||||
|
|
||||||
|
## API Endpoints
|
||||||
|
|
||||||
|
### Wochenplan
|
||||||
|
- `POST /api/mealplan/generate` — Neuen Wochenplan generieren (ab nächstem Montag)
|
||||||
|
- `GET /api/mealplan/current` — Aktuellen Wochenplan laden
|
||||||
|
- `GET /api/mealplan/{weekStart}` — Plan für bestimmte Woche
|
||||||
|
- `PUT /api/mealplan/{id}/entry/{date}` — Gericht für einen Tag austauschen
|
||||||
|
- `POST /api/mealplan/{id}/entry/{date}/reroll` — Neues zufälliges Gericht für Tag
|
||||||
|
|
||||||
|
### Rezepte
|
||||||
|
- `GET /api/recipes` — Eigene Rezepte auflisten
|
||||||
|
- `GET /api/recipes/{id}` — Rezeptdetails
|
||||||
|
- `POST /api/recipes` — Eigenes Rezept anlegen
|
||||||
|
- `PUT /api/recipes/{id}` — Eigenes Rezept bearbeiten
|
||||||
|
- `DELETE /api/recipes/{id}` — Eigenes Rezept löschen
|
||||||
|
- `GET /api/recipes/search?q=` — Suche (eigene + TheMealDB)
|
||||||
|
|
||||||
|
### Einkaufsliste
|
||||||
|
- `GET /api/shoppinglist/{mealPlanId}` — Aggregierte Einkaufsliste für Wochenplan
|
||||||
|
- `PUT /api/shoppinglist/{mealPlanId}/check/{itemId}` — Item abhaken/enthaken
|
||||||
|
|
||||||
|
### Einstellungen
|
||||||
|
- `GET /api/settings` — User-Einstellungen laden
|
||||||
|
- `PUT /api/settings` — User-Einstellungen speichern
|
||||||
|
|
||||||
|
## Wochenplan-Generierung
|
||||||
|
|
||||||
|
1. Alle verfügbaren Rezepte sammeln (eigene + TheMealDB Random)
|
||||||
|
2. 7 zufällige, unterschiedliche Gerichte auswählen
|
||||||
|
3. Montag bis Sonntag zuweisen
|
||||||
|
4. In DB speichern
|
||||||
|
|
||||||
|
**Reroll:** Einzelnes Gericht durch neues zufälliges ersetzen (nicht doppelt im Plan).
|
||||||
|
|
||||||
|
## Einkaufslisten-Logik
|
||||||
|
|
||||||
|
1. Alle Rezepte des Wochenplans laden
|
||||||
|
2. Zutaten sammeln, gleiche Zutaten zusammenfassen (Name-Match, Mengen addieren)
|
||||||
|
3. Mengen × Haushaltsgröße skalieren
|
||||||
|
4. Nach Kategorie gruppieren (Gemüse, Fleisch, Milchprodukte, Gewürze, Sonstiges)
|
||||||
|
5. Check-Status pro User in DB persistieren
|
||||||
|
|
||||||
|
## Frontend Design
|
||||||
|
|
||||||
|
**Theme:** Dark Mode (wie task-scheduler-v2)
|
||||||
|
- **Hintergrund:** zinc-950 (#09090b)
|
||||||
|
- **Cards:** zinc-900 (#18181b)
|
||||||
|
- **Borders:** zinc-800 (#27272a)
|
||||||
|
- **Primary Text:** zinc-100 (#f5f5f5)
|
||||||
|
- **Secondary Text:** zinc-500 (#71717a)
|
||||||
|
- **Accent:** emerald (#10b981)
|
||||||
|
- **Accent Hover:** #059669
|
||||||
|
|
||||||
|
### Hauptansichten
|
||||||
|
|
||||||
|
1. **Wochenplan** (Startseite) — 7 Cards (Mo-So), je mit Gerichtname + Bild. Buttons: "Austauschen" (Rezeptsuche), "Neu würfeln" (Random). Button oben: "Neue Woche generieren".
|
||||||
|
2. **Einkaufsliste** — Gruppiert nach Kategorie, Checkboxen zum Abhaken. Badge mit Anzahl offener Items.
|
||||||
|
3. **Rezepte** — Eigene Rezepte CRUD. Karten-Ansicht. Formular zum Anlegen/Bearbeiten mit dynamischer Zutatenliste.
|
||||||
|
4. **Einstellungen** — Haushaltsgröße anpassen.
|
||||||
|
|
||||||
|
### Navigation
|
||||||
|
Sidebar oder Bottom-Nav mit 4 Tabs: Wochenplan, Einkaufsliste, Rezepte, Einstellungen.
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
- **Coolify** via Git Push (wie alle anderen Projekte)
|
||||||
|
- **Dockerfile:** Multi-stage (Bun Frontend Build → .NET Publish → Runtime)
|
||||||
|
- **DB:** `mealplanner` auf Shared PostgreSQL
|
||||||
|
- **Domain:** `essen.kuns.dev`
|
||||||
|
- **Env-Vars in Coolify:** `DATABASE_URL`, `ZITADEL_ISSUER`, `ZITADEL_CLIENT_ID`
|
||||||
|
|
||||||
|
## Externe Abhängigkeiten
|
||||||
|
|
||||||
|
- **TheMealDB API** (`www.themealdb.com/api/json/v1/1/`) — kostenlos, kein Key nötig
|
||||||
|
- `random.php` — Zufälliges Rezept
|
||||||
|
- `search.php?s=` — Suche
|
||||||
|
- `lookup.php?i=` — Details per ID
|
||||||
|
- Rezepte auf Englisch — akzeptabel für MVP
|
||||||
Reference in New Issue
Block a user