# 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)

1. Ändra schema i `packages/database/src/schema/` → `pnpm db:generate` → granska SQL:en.
2. Ingen destruktiv ändring utan: backup (deploy.sh tar dump), migration, dokumenterad
   rollback, kontroll efteråt.
3. 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_code` char(3) NOT NULL DEFAULT 'SEK' – pengagränsen går vid hushållet.
- Alla pengakolumner är `integer` i 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.
