Initial commit (unpacked platform)

This commit is contained in:
Sven (AAMOS AI)
2026-08-05 19:21:11 +07:00
commit ac5340195a
314 changed files with 57584 additions and 0 deletions
+81
View File
@@ -0,0 +1,81 @@
import {
boolean,
date,
doublePrecision,
index,
integer,
jsonb,
pgTable,
text,
timestamp,
uuid,
} from "drizzle-orm/pg-core";
import type { NutritionValues } from "@app/shared-types";
import { createdAt, mealLogSourceEnum, mealTypeEnum } from "./_shared.js";
import { households, storageLocations } from "./households.js";
import { recipes } from "./recipes.js";
import { users } from "./users.js";
/**
* Måltidslogg (spec §23). Näringsvärden är alltid deterministiskt härledda
* (recept/produkt/användarinmatning) aldrig påhittade av AI (spec §61.1).
*/
export const meals = pgTable(
"meals",
{
id: uuid("id").primaryKey().defaultRandom(),
userId: uuid("user_id")
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
householdId: uuid("household_id").references(() => households.id, { onDelete: "set null" }),
date: date("date").notNull(),
mealType: mealTypeEnum("meal_type").notNull(),
source: mealLogSourceEnum("source").notNull(),
recipeId: uuid("recipe_id").references(() => recipes.id, { onDelete: "set null" }),
titleSv: text("title_sv").notNull(),
portionFraction: doublePrecision("portion_fraction").notNull().default(1),
nutrition: jsonb("nutrition").$type<NutritionValues>().notNull(),
nutritionIsEstimate: boolean("nutrition_is_estimate").notNull().default(false),
estimateMinKcal: doublePrecision("estimate_min_kcal"),
estimateMaxKcal: doublePrecision("estimate_max_kcal"),
items: jsonb("items"),
photoUrl: text("photo_url"),
scanJobId: uuid("scan_job_id"),
loggedAt: timestamp("logged_at", { withTimezone: true }).notNull().defaultNow(),
},
(t) => [
index("meals_user_date_idx").on(t.userId, t.date),
index("meals_household_idx").on(t.householdId),
],
);
/** Matlådor (spec §24) rekommenderas före ny matlagning när rimligt. */
export const mealBoxes = pgTable(
"meal_boxes",
{
id: uuid("id").primaryKey().defaultRandom(),
householdId: uuid("household_id")
.notNull()
.references(() => households.id, { onDelete: "cascade" }),
recipeId: uuid("recipe_id").references(() => recipes.id, { onDelete: "set null" }),
titleSv: text("title_sv").notNull(),
portions: integer("portions").notNull(),
portionsRemaining: integer("portions_remaining").notNull(),
nutritionPerPortion: jsonb("nutrition_per_portion").$type<NutritionValues>(),
cookedAt: date("cooked_at").notNull(),
storageLocationId: uuid("storage_location_id")
.notNull()
.references(() => storageLocations.id),
frozen: boolean("frozen").notNull().default(false),
recommendedUseBy: date("recommended_use_by").notNull(),
reservedForUserId: uuid("reserved_for_user_id").references(() => users.id, {
onDelete: "set null",
}),
status: text("status").notNull().default("available"),
createdAt: createdAt(),
},
(t) => [
index("meal_boxes_household_idx").on(t.householdId),
index("meal_boxes_use_by_idx").on(t.householdId, t.recommendedUseBy),
],
);