feat(db): Drizzle ORM schema and migrations

Schema domains: users/auth, recipes, social, meal-planning, tiers/usage, webhooks.
Includes Better Auth tables, audit_logs, site_settings, push_subscriptions,
user_model_prefs, user_nutrition_goals. Migrations 0000–0008 applied.
This commit is contained in:
Arnaud
2026-07-01 08:08:44 +02:00
parent ae7c5d943e
commit add9365250
39 changed files with 25552 additions and 0 deletions
+83
View File
@@ -0,0 +1,83 @@
import {
pgTable,
text,
timestamp,
integer,
boolean,
date,
decimal,
pgEnum,
} from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
import { users } from "./users";
import { recipes } from "./recipes";
import { ingredients } from "./recipes";
export const mealTypeEnum = pgEnum("meal_type", ["breakfast", "lunch", "dinner", "snack"]);
export const weekdayEnum = pgEnum("weekday", ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]);
export const mealPlans = pgTable("meal_plans", {
id: text("id").primaryKey(),
userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
weekStart: date("week_start").notNull(),
createdAt: timestamp("created_at").notNull().defaultNow(),
});
export const mealPlanEntries = pgTable("meal_plan_entries", {
id: text("id").primaryKey(),
mealPlanId: text("meal_plan_id").notNull().references(() => mealPlans.id, { onDelete: "cascade" }),
day: weekdayEnum("day").notNull(),
mealType: mealTypeEnum("meal_type").notNull(),
recipeId: text("recipe_id").references(() => recipes.id, { onDelete: "set null" }),
servings: integer("servings").notNull().default(2),
note: text("note"),
});
export const pantryItems = pgTable("pantry_items", {
id: text("id").primaryKey(),
userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
ingredientId: text("ingredient_id").references(() => ingredients.id, { onDelete: "set null" }),
rawName: text("raw_name").notNull(),
quantity: decimal("quantity", { precision: 10, scale: 4 }),
unit: text("unit"),
expiresAt: timestamp("expires_at"),
createdAt: timestamp("created_at").notNull().defaultNow(),
});
export const shoppingLists = pgTable("shopping_lists", {
id: text("id").primaryKey(),
userId: text("user_id").references(() => users.id, { onDelete: "cascade" }),
name: text("name").notNull(),
generatedAt: timestamp("generated_at"),
createdAt: timestamp("created_at").notNull().defaultNow(),
});
export const shoppingListItems = pgTable("shopping_list_items", {
id: text("id").primaryKey(),
listId: text("list_id").notNull().references(() => shoppingLists.id, { onDelete: "cascade" }),
ingredientId: text("ingredient_id").references(() => ingredients.id, { onDelete: "set null" }),
rawName: text("raw_name").notNull(),
quantity: decimal("quantity", { precision: 10, scale: 4 }),
unit: text("unit"),
aisle: text("aisle"),
checked: boolean("checked").notNull().default(false),
});
export const mealPlansRelations = relations(mealPlans, ({ one, many }) => ({
user: one(users, { fields: [mealPlans.userId], references: [users.id] }),
entries: many(mealPlanEntries),
}));
export const mealPlanEntriesRelations = relations(mealPlanEntries, ({ one }) => ({
mealPlan: one(mealPlans, { fields: [mealPlanEntries.mealPlanId], references: [mealPlans.id] }),
recipe: one(recipes, { fields: [mealPlanEntries.recipeId], references: [recipes.id] }),
}));
export const shoppingListsRelations = relations(shoppingLists, ({ one, many }) => ({
user: one(users, { fields: [shoppingLists.userId], references: [users.id] }),
items: many(shoppingListItems),
}));
export const shoppingListItemsRelations = relations(shoppingListItems, ({ one }) => ({
list: one(shoppingLists, { fields: [shoppingListItems.listId], references: [shoppingLists.id] }),
}));