8.4 KiB
8.4 KiB
Del 7 – Datamodell
Källa: packages/database/src/schema/ (Drizzle). Genererad SQL:
infrastructure/migrations/0000_*.sql – 54 tabeller, 38 enums, FK:er och index.
Kör: pnpm db:generate (ny migration ur schemat), pnpm db:migrate, pnpm db:seed.
Domänöversikt (tabeller per fil)
| Fil | Tabeller | Nyckelidéer |
|---|---|---|
| users.ts | users, user_credentials, refresh_tokens, user_health_profiles, user_preferences, user_consents | Hälsodata i EGEN tabell, exponeras aldrig via hushålls-API (§7/§56). Refresh-tokens hashade med familje-id → stöldskydd. Samtycken som (user, kind)-PK med tidsstämplar (§33). |
| households.ts | households, household_members, storage_locations | invite_code unik. portion_factor per medlem (§7). Platser = kyl/frys/skafferi/…/custom med sublocations[] (§8). |
| ingredients.ts | canonical_ingredients, substitutions | Navet för normalisering (§9). Näring per 100 med provenance-JSON (aldrig AI-påhitt). Diet-/allergiflaggor för deterministisk filtrering. shelf_life_guidance per platstyp (§13). |
| products.ts | products | Versionshantering: (gtin, version) unik, aktuell rad = valid_to IS NULL (§11, §61.12). |
| inventory.ts | inventory_items, inventory_transactions | Transaktioner är sanningen (§8): typade (+purchase/−cook_use/−discard/…), value_minor på discard → svinnvärde (§26). Saldo cachas på posten. Index på (household, best_before). |
| recipes.ts | recipe_source_registry, recipes, recipe_ingredients, recipe_steps, recipe_ratings, recipe_favorites, recipe_cooks, recipe_similarities | Source registry för juridik (§15). DNA som jsonb (§16). variant_of/forked_from (§16/§35). Status-flöde §35. Similarity-klassning §36. Steg med timer/temperatur för Cooking Mode. |
| meals.ts | meals, meal_boxes | Näring som snapshot-jsonb (historik ändras inte när recept ändras). Estimatintervall för tallriksfoto (§22). Matlådor med portions_remaining + recommended_use_by (§24). |
| planning.ts | week_plans, week_plan_entries, shopping_lists, shopping_list_items | Planpost kan peka på recept ELLER matlåda. reschedule_reason_sv för dynamisk omplanering (§25). Lista: store_section, origin (plan/manual/…) (§27). |
| receipts.ts | receipts, receipt_lines, price_observations | Kvittorader med confidence + verified (§12). Prishistorik → budget/prognoser. |
| scans.ts | scan_jobs, ai_corrections | Jobbstatus inkl. awaiting_confirmation. Korrigeringar med consent_snapshot → träningsdata endast med samtycke (§33). model/prompt_version på allt (§9). |
| memory.ts | memory_items, taste_signals, food_memories | Minnestyper §32, origin user_stated/observed/ai_inferred (§30), paused/verified per post. |
| seasons.ts | season_events | Datadrivna datumregler (fixed/range/computed: midsommar/påsk/advent) (§28). |
| subscriptions.ts | subscriptions, subscription_events, store_transactions, store_notifications, trials, ai_usage_counters | Backend source of truth (§47). (provider, original_transaction_id) unik → idempotent verifiering. Månadskvot för fair use (§45–46). |
| platform.ts | domain_events, feature_flags, audit_logs, idempotency_keys, notifications, push_tokens, creator_stats, creator_follows, ai_eval_cases, ai_eval_runs, waste_summaries | Outbox-mönster (§55). Flaggor med rollout-procent. Audit (§56). Evals (§34). |
Viktiga constraints & index (urval)
Unika: users.email; households.invite_code; recipes.slug; (recipe,user) i ratings; (provider, original_transaction_id) i subscriptions (partial, NOT NULL); (gtin, version) i products (partial); (user, month) i ai_usage_counters; refresh_tokens.token_hash. Prestanda: inventory(household, best_before) för utgångslistan; meals(user, date) för Min dag; domain_events(published_at, occurred_at) för outbox; scan_jobs(status); recipes(status), (cuisine), (total_time).
Regler för ändringar (spec §63)
- Ändra schema i
packages/database/src/schema/→pnpm db:generate→ granska SQL:en. - Ingen destruktiv ändring utan: backup (deploy.sh tar dump), migration, dokumenterad rollback, kontroll efteråt.
- Logga varje migration i tabellen nedan.
Migrationslogg
| # | Fil | Datum | Innehåll | Rollback |
|---|---|---|---|---|
| 0000 | 0000_dusty_lady_deathstrike.sql | 2026-08-02 | Initialt schema: 54 tabeller, 38 enums, samtliga index/FK | Drop databasen (pre-launch) |
i18n-tillägg (M1–M6)
households.currency_codechar(3) NOT NULL DEFAULT 'SEK' – pengagränsen går vid hushållet.- Alla pengakolumner är
integeri minor units (*_minor). ingredient_translations(ingredient_id, language_tag, name, aliases[], source, status) – unik per (ingrediens, språk).unit_translations(unit_code, language_tag, abbreviation, name) – PK (kod, språk).recipe_translations(recipe_id, language_tag, title, description, storage_guidance, status draft_ai|in_review|published, source, verification jsonb).recipe_step_translations(recipe_id, language_tag, step_number, instruction, tip) – PK (recept, språk, steg).nutrition_display_profiles(region_code PK, energy_display kcal|kj|both, salt_display salt|sodium, energy_label_key).allergen_market_rules(region_code, allergen, must_highlight) – PK (region, allergen).- Trigramindex (pg_trgm) på canonical_ingredients.name_sv, ingredient_translations.name, recipes.title_sv; unaccent för accentokänslig sök.