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