Files
recipe/.planning/REQUIREMENTS.md
ulfrxdev a94f803ca6 docs(02-03): complete common auth seams plan
Tasks completed: 2/2
- Define common OIDC and secure store contracts
- Add JVM and Wasm actuals

SUMMARY: .planning/phases/02-authentication-foundation/02-03-SUMMARY.md
2026-04-28 14:16:47 +02:00

243 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Requirements: Recipe
**Defined:** 2026-04-24
**Core Value:** "My week is planned." I pick recipes, the calendar fills up, and I know what we're eating.
## v1 Requirements
### Authentication & identity
- [x] **AUTH-01**: User can sign in via the self-hosted Authentik instance using OIDC (authorization code flow with PKCE)
- [x] **AUTH-02**: Client stores access + refresh tokens securely (iOS Keychain / Android EncryptedSharedPreferences)
- [x] **AUTH-03**: Ktor server validates incoming access tokens via Authentik's JWKS endpoint (issuer, audience, expiry, signature, clock skew leeway)
- [x] **AUTH-04**: User session persists across app launches without re-authentication (token refresh handled transparently)
- [x] **AUTH-05**: User can sign out, which revokes local tokens and returns to the login screen
- [x] **AUTH-06**: Users are JIT-provisioned in the server database on first successful login (by OIDC `sub` claim)
### Household sharing
- [ ] **HSHD-01**: On first login, user is prompted to create a new household or join an existing one via invite code
- [ ] **HSHD-02**: User can create a new household and become its first member
- [ ] **HSHD-03**: User can generate an invite code for their household (short-lived, single-use)
- [ ] **HSHD-04**: Another user can redeem an invite code to join the household
- [ ] **HSHD-05**: All household members see the same plan, pantry, and shopping list
- [ ] **HSHD-06**: Server-side tenancy is enforced: every household-scoped query filters by `household_id` derived from the authenticated principal, never from the request body
- [ ] **HSHD-07**: Client queries for household data filter locally by active `household_id` (defense in depth)
### Recipes — browse & detail
- [ ] **RCPE-01**: User can view a grid of the household's recipe catalog
- [ ] **RCPE-02**: User can filter recipes by meal slot (śniadanie / drugie śniadanie / obiad / przekąska / kolacja)
- [ ] **RCPE-03**: User can filter recipes by tag (e.g., "szybkie", "wegetariańskie", "wysokobiałkowe")
- [ ] **RCPE-04**: User can filter recipes by cooking time range (minutes)
- [ ] **RCPE-05**: User can search recipes by title or tag text
- [ ] **RCPE-06**: User can open a recipe detail view showing ingredients (with amounts + units), steps, nutrition per serving, and cooking time
- [ ] **RCPE-07**: Recipe detail shows ingredient alternatives (substitutions) where defined in the catalog
- [ ] **RCPE-08**: Recipe catalog is seeded via server-side SQL fixtures or admin CLI (no in-app authoring in v1)
### Meal planner (hero feature)
- [ ] **PLAN-01**: User can view a calendar showing planned meals per day
- [ ] **PLAN-02**: User can navigate between days/weeks/months in the calendar
- [ ] **PLAN-03**: User can add a recipe to any of the 5 slots on any day (śniadanie, drugie śniadanie, obiad, przekąska, kolacja)
- [ ] **PLAN-04**: User can remove a meal entry from a slot
- [ ] **PLAN-05**: User can replace a meal entry by picking a different recipe
- [ ] **PLAN-06**: User can adjust servings on a meal entry (112)
- [ ] **PLAN-07**: User can substitute an ingredient in a meal entry with one of the defined alternatives
- [ ] **PLAN-08**: User can exclude an ingredient from a meal entry (won't appear in shopping/pantry calculations)
- [ ] **PLAN-09**: User can add an extra ingredient to a meal entry (amount + unit from the ingredient catalog)
- [ ] **PLAN-10**: User can override the amount of an ingredient in a meal entry
- [ ] **PLAN-11**: User can select a specific product (pack size) for a given ingredient in a meal entry
- [ ] **PLAN-12**: User can mark a meal slot as skipped for a day
- [ ] **PLAN-13**: User sees daily nutrition totals (kcal, protein, fat, carbs) aggregated from all planned meals that day, respecting customizations
- [ ] **PLAN-14**: Meal entries have stable UUID identity (never composite keys like `date + slot`) to survive concurrent edits
### Pantry
- [ ] **PNTR-01**: User can view pantry inventory grouped by ingredient category (pieczywo, nabiał, mięso i ryby, warzywa, owoce, suche, przyprawy, inne)
- [ ] **PNTR-02**: User can manually add or update the quantity of an ingredient in the pantry (using its pantry unit: g, ml, szt.)
- [ ] **PNTR-03**: User sees which ingredients fall short over a user-selected planning horizon (e.g., next 7 days) based on the plan minus current pantry
- [ ] **PNTR-04**: User can filter pantry view by category
- [ ] **PNTR-05**: User can filter pantry view by shortfall status (needed / sufficient / not in plan)
### Shopping list
- [ ] **SHOP-01**: User can select a date range from the plan to generate a shopping list
- [ ] **SHOP-02**: Shopping list aggregates all ingredient needs across selected days minus current pantry quantities
- [ ] **SHOP-03**: Shopping list groups items by ingredient category for efficient in-store navigation
- [ ] **SHOP-04**: User can mark an item as bought during a shopping session; the item is removed from active needs and added to pantry in its pantry unit
- [ ] **SHOP-05**: User can undo a recently marked-bought item within the same session
- [ ] **SHOP-06**: Session log persists across app restarts until the user explicitly clears it
### Offline + sync
- [ ] **SYNC-01**: Client reads all household data from local SQLDelight without requiring network
- [ ] **SYNC-02**: Client writes all household data locally first (optimistic UI), then queues the change for sync
- [ ] **SYNC-03**: Server assigns `updated_at` (server time, monotonic) on every accepted write; clients never trust their own device clock for sync ordering
- [ ] **SYNC-04**: Client pulls household changes via `GET /sync/pull?since=...` using a lexicographic `(updated_at, id)` cursor to survive same-millisecond writes
- [ ] **SYNC-05**: Client pushes pending writes via `POST /sync/push` (batched); accepted writes come back with server-assigned `updated_at`
- [ ] **SYNC-06**: Deletes are soft deletes (`deleted_at` column); synced as state changes, not as "delete ops"
- [ ] **SYNC-07**: Sync runs on: app foreground, pull-to-refresh, debounced 2s after every local write, and polls every 2030s while foreground
- [ ] **SYNC-08**: Sync failures (network error, 5xx) retry with exponential backoff and do not block the UI
- [ ] **SYNC-09**: Sync engine is implemented as a single Koin singleton owning the outbox queue and pull cursor — features never issue HTTP writes directly
- [ ] **SYNC-10**: When two household members edit the same row, the server-assigned later write wins; no silent data loss because writes use UUID identity, not natural keys
### UI foundation (polish + glass aesthetic)
- [ ] **UI-01**: All user-facing strings are externalized as Compose resources (i18n-ready), even though v1 ships Polish only
- [ ] **UI-02**: App ships with Polish-language copy throughout
- [ ] **UI-03**: Bottom tab navigation with 4 tabs: Przepisy / Planer / Spiżarnia / Zakupy, each preserving its own back stack independently
- [ ] **UI-04**: Tab bar and nav bar use Haze-based glass/blur effects (Liquid Glass approximation)
- [ ] **UI-05**: App supports light and dark color schemes with translucent surfaces working in both
- [ ] **UI-06**: UI is iOS-idiomatic within Compose constraints (safe areas, swipe-back gesture where applicable, keyboard avoidance)
- [ ] **UI-07**: Visual hierarchy is less cramped than the mockup — deliberate spacing, calmer typography, readable at arm's length
- [ ] **UI-08**: Locale-aware date formatting for display (days, months, weekday names in Polish); sync wire-format stays UTC ISO-8601
- [ ] **UI-09**: App starts cleanly on first launch (no blank flash) and shows appropriate empty states when catalog / plan / pantry / shopping are empty
### Infrastructure & build
- [x] **INFRA-01**: Gradle version catalog at `gradle/libs.versions.toml` is the single source of truth for library versions
- [x] **INFRA-02**: `build-logic/` convention plugins centralize Kotlin/Compose/test configuration across modules
- [x] **INFRA-03**: iOS Kotlin/Native binary options set from day 1: `kotlin.native.binary.objcDisposeOnMain=false`, `gc=cms`
- [ ] **INFRA-04**: Server Docker image builds and deploys to user's homelab alongside Authentik
- [ ] **INFRA-05**: Flyway migrations run automatically on server startup in a known order
- [x] **INFRA-06**: `shared/commonMain` contains only domain models + API DTOs — no UI, no HTTP, no DB code
- [ ] **INFRA-07**: App is distributed to partner via TestFlight (iOS) for initial dogfooding
## v2 Requirements
Explicitly acknowledged but deferred. Not in the v1 roadmap.
### In-app recipe authoring
- **AUTHR-01**: User can create a new recipe with ingredients, steps, nutrition, allowed slots, tags
- **AUTHR-02**: User can edit an existing recipe
- **AUTHR-03**: User can archive/delete a recipe they created
### Nutrition goal tracking
- **NUTR-01**: User can set daily macro targets (kcal, protein, fat, carbs)
- **NUTR-02**: Planner shows deficit/surplus vs. targets per day
- **NUTR-03**: User can view weekly nutrition trends
### Additional platforms
- **PLAT-01**: Android app distributed to household members (APK or Play Store)
- **PLAT-02**: Web (Compose for Wasm) as a PWA replacement for the current mockup
- **PLAT-03**: English localization (full copy pass)
### Sync hardening
- **SYNC2-01**: Server-sent events (SSE) for near-realtime sync instead of polling
- **SYNC2-02**: Per-table upgrade path from LWW to operation-log sync if concurrent-edit data loss becomes observable
### iOS Liquid Glass fidelity
- **LG2-01**: Native SwiftUI interop for tab bar and nav bar (real iOS 26 Liquid Glass material) if Compose approximation proves inadequate on real hardware
## Out of Scope
Explicitly excluded. Documented to prevent scope creep.
| Feature | Reason |
|---------|--------|
| Social features (comments, ratings, public profiles, feeds) | Private household app, not a community product |
| Recipe sharing between households | Households are isolated in v1; recipe marketplace is not the point |
| Meal-plan marketplace / paid plans | Personal-use product |
| Grocery-delivery integrations (Instacart, Carrefour Online, etc.) | Polish-market + small scope; integration cost not justified |
| Barcode scanning / receipt OCR for pantry updates | Manual entry is fine for a 2-person household |
| AI-generated recipes | Curated catalog is the value |
| Apple Sign-in as a first-class button | Authentik OIDC is user's IdP, not a third-party social login |
| Port of mockup's vanilla-JS visual design | Visual rebuild around Liquid-Glass language; mockup is functional spec only |
| Port of mockup's ~80 ingredients + ~30 recipes as seed data | User explicitly chose to re-curate catalog fresh |
| Device-clock-based sync timestamps | Silent data loss under drift; server-assigned timestamps mandatory |
| True iOS 26 Liquid Glass native material in v1 | Requires SwiftUI interop; Compose approximation is v1 scope |
## Traceability
Populated during roadmap creation. Each v1 requirement maps to exactly one phase.
| Requirement | Phase | Status |
|-------------|-------|--------|
| AUTH-01 | Phase 2: Authentication Foundation | Complete |
| AUTH-02 | Phase 2: Authentication Foundation | Complete |
| AUTH-03 | Phase 2: Authentication Foundation | Pending |
| AUTH-04 | Phase 2: Authentication Foundation | Complete |
| AUTH-05 | Phase 2: Authentication Foundation | Complete |
| AUTH-06 | Phase 2: Authentication Foundation | Pending |
| HSHD-01 | Phase 3: Households, Membership & Server Data Foundation | Pending |
| HSHD-02 | Phase 3: Households, Membership & Server Data Foundation | Pending |
| HSHD-03 | Phase 3: Households, Membership & Server Data Foundation | Pending |
| HSHD-04 | Phase 3: Households, Membership & Server Data Foundation | Pending |
| HSHD-05 | Phase 3: Households, Membership & Server Data Foundation | Pending |
| HSHD-06 | Phase 3: Households, Membership & Server Data Foundation | Pending |
| HSHD-07 | Phase 3: Households, Membership & Server Data Foundation | Pending |
| RCPE-01 | Phase 5: Recipe Catalog (Read Path) | Pending |
| RCPE-02 | Phase 5: Recipe Catalog (Read Path) | Pending |
| RCPE-03 | Phase 5: Recipe Catalog (Read Path) | Pending |
| RCPE-04 | Phase 5: Recipe Catalog (Read Path) | Pending |
| RCPE-05 | Phase 5: Recipe Catalog (Read Path) | Pending |
| RCPE-06 | Phase 5: Recipe Catalog (Read Path) | Pending |
| RCPE-07 | Phase 5: Recipe Catalog (Read Path) | Pending |
| RCPE-08 | Phase 5: Recipe Catalog (Read Path) | Pending |
| PLAN-01 | Phase 6: Meal Planner — Core Write Path | Pending |
| PLAN-02 | Phase 6: Meal Planner — Core Write Path | Pending |
| PLAN-03 | Phase 6: Meal Planner — Core Write Path | Pending |
| PLAN-04 | Phase 6: Meal Planner — Core Write Path | Pending |
| PLAN-05 | Phase 6: Meal Planner — Core Write Path | Pending |
| PLAN-06 | Phase 6: Meal Planner — Core Write Path | Pending |
| PLAN-07 | Phase 7: Meal Planner — Customization & Nutrition | Pending |
| PLAN-08 | Phase 7: Meal Planner — Customization & Nutrition | Pending |
| PLAN-09 | Phase 7: Meal Planner — Customization & Nutrition | Pending |
| PLAN-10 | Phase 7: Meal Planner — Customization & Nutrition | Pending |
| PLAN-11 | Phase 7: Meal Planner — Customization & Nutrition | Pending |
| PLAN-12 | Phase 6: Meal Planner — Core Write Path | Pending |
| PLAN-13 | Phase 7: Meal Planner — Customization & Nutrition | Pending |
| PLAN-14 | Phase 6: Meal Planner — Core Write Path | Pending |
| PNTR-01 | Phase 8: Pantry | Pending |
| PNTR-02 | Phase 8: Pantry | Pending |
| PNTR-03 | Phase 8: Pantry | Pending |
| PNTR-04 | Phase 8: Pantry | Pending |
| PNTR-05 | Phase 8: Pantry | Pending |
| SHOP-01 | Phase 9: Shopping List & Session Log | Pending |
| SHOP-02 | Phase 9: Shopping List & Session Log | Pending |
| SHOP-03 | Phase 9: Shopping List & Session Log | Pending |
| SHOP-04 | Phase 9: Shopping List & Session Log | Pending |
| SHOP-05 | Phase 9: Shopping List & Session Log | Pending |
| SHOP-06 | Phase 9: Shopping List & Session Log | Pending |
| SYNC-01 | Phase 4: Sync Engine Skeleton | Pending |
| SYNC-02 | Phase 4: Sync Engine Skeleton | Pending |
| SYNC-03 | Phase 4: Sync Engine Skeleton | Pending |
| SYNC-04 | Phase 4: Sync Engine Skeleton | Pending |
| SYNC-05 | Phase 4: Sync Engine Skeleton | Pending |
| SYNC-06 | Phase 4: Sync Engine Skeleton | Pending |
| SYNC-07 | Phase 4: Sync Engine Skeleton | Pending |
| SYNC-08 | Phase 4: Sync Engine Skeleton | Pending |
| SYNC-09 | Phase 4: Sync Engine Skeleton | Pending |
| SYNC-10 | Phase 4: Sync Engine Skeleton | Pending |
| UI-01 | Phase 11: Localization & iOS Deployment | Pending |
| UI-02 | Phase 11: Localization & iOS Deployment | Pending |
| UI-03 | Phase 10: UI Chrome & Haze Liquid-Glass Polish | Pending |
| UI-04 | Phase 10: UI Chrome & Haze Liquid-Glass Polish | Pending |
| UI-05 | Phase 5: Recipe Catalog (Read Path) | Pending |
| UI-06 | Phase 10: UI Chrome & Haze Liquid-Glass Polish | Pending |
| UI-07 | Phase 10: UI Chrome & Haze Liquid-Glass Polish | Pending |
| UI-08 | Phase 5: Recipe Catalog (Read Path) | Pending |
| UI-09 | Phase 10: UI Chrome & Haze Liquid-Glass Polish | Pending |
| INFRA-01 | Phase 1: Project Infrastructure & Module Wiring | Complete |
| INFRA-02 | Phase 1: Project Infrastructure & Module Wiring | Complete |
| INFRA-03 | Phase 1: Project Infrastructure & Module Wiring | Complete |
| INFRA-04 | Phase 11: Localization & iOS Deployment | Pending |
| INFRA-05 | Phase 3: Households, Membership & Server Data Foundation | Pending |
| INFRA-06 | Phase 1: Project Infrastructure & Module Wiring | Complete |
| INFRA-07 | Phase 11: Localization & iOS Deployment | Pending |
**Coverage:**
- v1 requirements: **72 total** (AUTH=6, HSHD=7, RCPE=8, PLAN=14, PNTR=5, SHOP=6, SYNC=10, UI=9, INFRA=7)
- Mapped to phases: **72**
- Unmapped: **0**
---
*Requirements defined: 2026-04-24*
*Last updated: 2026-04-23 after roadmap creation*