7.2 KiB
7.2 KiB
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 ladenGET /api/mealplan/{weekStart}— Plan für bestimmte WochePUT /api/mealplan/{id}/entry/{date}— Gericht für einen Tag austauschenPOST /api/mealplan/{id}/entry/{date}/reroll— Neues zufälliges Gericht für Tag
Rezepte
GET /api/recipes— Eigene Rezepte auflistenGET /api/recipes/{id}— RezeptdetailsPOST /api/recipes— Eigenes Rezept anlegenPUT /api/recipes/{id}— Eigenes Rezept bearbeitenDELETE /api/recipes/{id}— Eigenes Rezept löschenGET /api/recipes/search?q=— Suche (eigene + TheMealDB)
Einkaufsliste
GET /api/shoppinglist/{mealPlanId}— Aggregierte Einkaufsliste für WochenplanPUT /api/shoppinglist/{mealPlanId}/check/{itemId}— Item abhaken/enthaken
Einstellungen
GET /api/settings— User-Einstellungen ladenPUT /api/settings— User-Einstellungen speichern
Wochenplan-Generierung
- Alle verfügbaren Rezepte sammeln (eigene + TheMealDB Random)
- 7 zufällige, unterschiedliche Gerichte auswählen
- Montag bis Sonntag zuweisen
- In DB speichern
Reroll: Einzelnes Gericht durch neues zufälliges ersetzen (nicht doppelt im Plan).
Einkaufslisten-Logik
- Alle Rezepte des Wochenplans laden
- Zutaten sammeln, gleiche Zutaten zusammenfassen (Name-Match, Mengen addieren)
- Mengen × Haushaltsgröße skalieren
- Nach Kategorie gruppieren (Gemüse, Fleisch, Milchprodukte, Gewürze, Sonstiges)
- 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
- Wochenplan (Startseite) — 7 Cards (Mo-So), je mit Gerichtname + Bild. Buttons: "Austauschen" (Rezeptsuche), "Neu würfeln" (Random). Button oben: "Neue Woche generieren".
- Einkaufsliste — Gruppiert nach Kategorie, Checkboxen zum Abhaken. Badge mit Anzahl offener Items.
- Rezepte — Eigene Rezepte CRUD. Karten-Ansicht. Formular zum Anlegen/Bearbeiten mit dynamischer Zutatenliste.
- 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:
mealplannerauf 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ötigrandom.php— Zufälliges Rezeptsearch.php?s=— Suchelookup.php?i=— Details per ID
- Rezepte auf Englisch — akzeptabel für MVP