diff --git a/.planning/PROJECT.md b/.planning/PROJECT.md new file mode 100644 index 0000000..ee2a39b --- /dev/null +++ b/.planning/PROJECT.md @@ -0,0 +1,147 @@ +# Recipe (working title) + +## What This Is + +A mobile-first meal planning app for a small household — pick recipes for the week, fill a calendar across five meal slots per day, and watch pantry gaps + shopping lists emerge from the plan. Kotlin Multiplatform targeting iOS primarily, with Android, Desktop, and Wasm as secondary targets. Built for me + my partner (shared household plan) with a handful of family/friends as authorized users on the same self-hosted backend. + +## Core Value + +**"My week is planned."** I pick recipes, the calendar fills up, and I know what we're eating. Everything else — pantry tracking, shopping list, nutrition numbers — exists to reinforce that one moment. + +## Requirements + +### Validated + +(None yet — ship to validate) + +### Active + +**Authentication & identity** +- [ ] Users sign in via the user's self-hosted Authentik instance (OIDC) +- [ ] Sessions persist across app launches; offline access works with cached credentials + +**Household sharing** +- [ ] Two users (me + partner) share one household: one plan, one pantry, one shopping list +- [ ] Changes by either user converge on all devices when online + +**Recipes (browse & detail)** +- [ ] User can browse a curated recipe catalog with a grid view +- [ ] User can filter recipes by meal slot, tags, and cooking time +- [ ] User can search recipes by title/tag +- [ ] User can open a recipe detail view with ingredients, steps, and nutrition per serving + +**Meal planner (hero feature)** +- [ ] User can view a calendar of days and see planned meals per day +- [ ] User can add recipes to any of 5 slots/day (śniadanie, drugie śniadanie, obiad, przekąska, kolacja) +- [ ] User can remove or replace a meal entry +- [ ] User can adjust servings on a meal entry +- [ ] User can customize a meal entry: swap ingredients (substitutions), exclude ingredients, add extras, override amounts +- [ ] User can select a specific product (pack size) for an ingredient in a meal entry +- [ ] User can mark a meal slot as "skipped" for a day +- [ ] User sees daily nutrition totals (kcal, protein, fat, carbs) computed from the plan + +**Pantry** +- [ ] User can view current pantry inventory grouped by category +- [ ] User can add/update quantities manually in the pantry +- [ ] User sees which ingredients fall short over a chosen planning horizon +- [ ] User can filter pantry by category and by shortfall status + +**Shopping list** +- [ ] User can select days from the plan to generate a shopping list +- [ ] Shopping list aggregates ingredient needs across selected days minus pantry +- [ ] Shopping list groups items by category for an efficient store trip +- [ ] User can mark items as bought during a shopping session; marked items are removed from active needs and added to pantry + +**Offline + sync** +- [ ] App is fully usable offline: read and write plans, pantry, shopping list +- [ ] Local changes sync to the backend when connectivity returns, without data loss +- [ ] Conflicts between two household members' concurrent edits resolve deterministically (last-write-wins for MVP; revisit if it hurts) + +**Polish UI foundation** +- [ ] All user-facing strings are externalized into resource files (i18n-ready), even though v1 ships Polish only +- [ ] UI uses a Liquid-Glass-inspired visual language (translucent surfaces, blur, soft depth) implemented in Compose Multiplatform +- [ ] Visual hierarchy is less cramped than the mockup (more breathing room, calmer typography) +- [ ] iOS app feels iOS-idiomatic within Compose's constraints (tab bar placement, navigation patterns, safe areas, dark mode) + +### Out of Scope + +**For v1 (deferred to later phases / milestones):** +- In-app recipe authoring — *v1 seeds the DB manually; authoring in-app comes next phase* +- Recipe sharing between users/households — *future feature; households are isolated in v1* +- Nutrition goal tracking (targets, streaks, deficits) — *v1 shows numbers informationally only* +- English and other language copy — *code is i18n-ready but v1 ships Polish only* +- True native iOS 26 Liquid Glass via SwiftUI interop — *Compose approximation for v1; revisit only if real-device chrome feels clearly inadequate* +- Desktop and Wasm as shipped products — *Desktop useful for hot-reload dev; Wasm is a possible future target, neither is a v1 deliverable* +- Sign in with Apple as a first-class button — *user's Authentik handles auth; Apple can be federated upstream in Authentik if needed later* + +**Permanently out of scope (explicit exclusions):** +- Social features: comments, ratings, recipe feeds, public profiles — *this is a private household app, not a community product* +- Meal-plan marketplaces / paid plans — *personal-use product* +- Grocery delivery integrations (Instacart, etc.) — *Polish market + small scope; not worth the integration cost* +- Barcode scanning / receipt OCR for pantry updates — *manual entry is fine for a 2-person household* +- AI-generated recipes — *curated catalog is the value* + +**Deliberately not carried forward from the mockup:** +- The mockup's seed data (~80 ingredients, ~30 recipes) — *user chose to start the catalog fresh* +- The mockup's visual design — *full visual rebuild; mockup is functional reference only* +- The mockup's localStorage data model — *server-backed with local cache replaces it* + +## Context + +**Codebase state.** The `~/dev/repo/recipe` directory is a freshly-generated Kotlin Multiplatform Compose template from IntelliJ with four modules: `composeApp` (Android + Desktop + iOS shared UI), `iosApp` (iOS bootstrap), `server` (Ktor, not yet written), and `shared` (common code). No app logic exists yet — this is effectively greenfield with the build infra in place. + +**Reference implementation.** The user built a working PWA at `~/dev/repo/recipe-mockup/` (vanilla JS + Tailwind CDN + nginx/Docker). It implements the same four views (Recipe List, Meal Planner, Pantry, Shopping List) and has mature logic worth mining as a *functional* spec — particularly planner entry customization (substitutions, amount overrides, product selection), shortfall computation over a horizon, and shopping-list aggregation with "bought" session tracking. The mockup's UI design is **not** being carried forward; the user is redesigning visuals around a Liquid-Glass-inspired language. + +**Users.** Authorized users only, behind the user's Authentik. Primary user is the author; secondary is their partner (household sharing from day 1); a handful of family/friends may use their own household accounts. Not an App Store public launch — personal / close-circle use. + +**Infra.** User runs a homelab. Authentik is already installed. The Ktor backend will run on the same server (containerized). No managed cloud dependencies planned. + +**Language & platform.** Polish-only UI for v1 (strings externalized for future i18n). iOS is the primary daily driver; Android deployed later for friends; Desktop useful for development (hot reload); Wasm is aspirational. + +**Liquid Glass decision.** True iOS 26 Liquid Glass (refractive material, specular highlights, morphing chrome) is a SwiftUI-native feature that Compose on iOS cannot reproduce exactly (Compose uses Skia, not Metal-native glass material). The v1 plan is: Compose-only approximation (blur + translucency + gradients) everywhere, measure real-device performance and visual quality, and **only** selectively add SwiftUI interop for the chrome (tab bar, nav bar) if the approximation feels insufficient. This avoids upfront interop complexity for 90%+ of the UI. + +## Constraints + +- **Tech stack**: Kotlin Multiplatform + Compose Multiplatform for UI, Ktor for server, Authentik OIDC for auth — Locked; aligns with user's skills + self-hosted infra +- **Primary platform**: iOS — Must feel good here first; other platforms are secondary +- **Hosting**: Self-hosted on user's existing homelab (alongside Authentik) — No managed cloud; implies containerized deploy, self-managed DB, reverse proxy +- **Offline**: Full offline read/write is required — User will use the shopping list in-store where signal is unreliable; online-only is unacceptable +- **Audience size**: ~5–10 authenticated users total — Don't over-engineer multi-tenancy, rate limiting, or horizontal scaling +- **Language**: Polish UI for v1, i18n-ready code — All strings must be externalized from day 1 to avoid costly retrofit later +- **Data seeding**: Catalog starts empty; user will author recipes directly in DB for MVP — Need admin-friendly seeding path (SQL migrations, JSON fixtures, or CLI tool) +- **Visual direction**: Liquid-Glass-inspired (Compose approximation) — Bright mockup palette is being replaced; design needs to be reworked as part of the rebuild + +## Key Decisions + +| Decision | Rationale | Outcome | +|----------|-----------|---------| +| KMP with Compose Multiplatform for UI | iOS-primary + Android secondary + Desktop/Wasm optional; single codebase for 90%+ of UI | — Pending | +| Household-sharing from day 1 (me + partner share one plan) | Core use case is cooking together; per-user + later-sharing would force data-model rewrite | — Pending | +| Authentik OIDC as sole auth provider for MVP | User already runs Authentik; self-hosted == aligned; Apple Sign-in likely not required for App Store since Authentik is user's own IdP, not a third-party social login | — Pending | +| Server lives on user's homelab alongside Authentik | Existing infra, zero managed-cloud cost, same ops surface | — Pending | +| Offline-first with last-write-wins sync | Grocery-store usage demands offline; conflict resolution overkill for a 2-person household | — Pending | +| Compose-only Liquid Glass approximation for v1 | Real iOS 26 Liquid Glass requires SwiftUI interop; approximation keeps single codebase; revisit only if chrome feels inadequate on real device | — Pending | +| Polish-only strings, i18n-ready infrastructure | Single-language content for v1 speed; externalized strings prevent future rewrite | — Pending | +| Start catalog fresh (don't port mockup seed data) | Mockup data is a reference, not production content; user wants to re-curate | — Pending | +| Nutrition is informational only in v1 | Keep scope tight; tracking/goals are a natural v2 if usage patterns justify | — Pending | +| Mockup is functional spec only, not visual spec | Visual direction is changing (Liquid Glass); logic is mature and worth mining | — Pending | + +## Evolution + +This document evolves at phase transitions and milestone boundaries. + +**After each phase transition** (via `/gsd-transition`): +1. Requirements invalidated? → Move to Out of Scope with reason +2. Requirements validated? → Move to Validated with phase reference +3. New requirements emerged? → Add to Active +4. Decisions to log? → Add to Key Decisions +5. "What This Is" still accurate? → Update if drifted + +**After each milestone** (via `/gsd-complete-milestone`): +1. Full review of all sections +2. Core Value check — still the right priority? +3. Audit Out of Scope — reasons still valid? +4. Update Context with current state + +--- +*Last updated: 2026-04-23 after initialization*