feat: recipe type (dish/drink) for better cocktail handling (v0.31.0)

Add recipes.recipeType enum (dish|drink, default dish). Recipe form
now shows a Type selector and hides food-only fields for drinks
(prep/cook time, difficulty, batch-cook toggle) instead of forcing
every cocktail through meal-oriented UI. Detail page skips the
meal/drink pairing suggestion buttons on drink recipes (pairing a
drink with a drink doesn't make sense). Recipes list gains a Type
filter facet alongside difficulty/batch-cook.

Scoped deliberately narrow per investigation: no ABV/glass-type/
garnish structured fields, no meal-plan schema changes, and the
existing AI drink-pairing-suggestion feature (ephemeral, never saved
as a recipe) is left as-is rather than wired into recipe creation —
those suggestions are wine/beer/spirit recommendations without
ingredients/steps, not really recipes to save.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Arnaud
2026-07-14 14:16:43 +02:00
parent 894784afda
commit 6f11dc07fd
18 changed files with 5215 additions and 58 deletions
@@ -0,0 +1,3 @@
CREATE TYPE "public"."recipe_type" AS ENUM('dish', 'drink');--> statement-breakpoint
ALTER TABLE "recipes" ADD COLUMN "recipe_type" "recipe_type" DEFAULT 'dish' NOT NULL;--> statement-breakpoint
CREATE INDEX "recipes_type_idx" ON "recipes" USING btree ("recipe_type");
File diff suppressed because it is too large Load Diff
@@ -274,6 +274,13 @@
"when": 1784014063004,
"tag": "0038_peaceful_norrin_radd",
"breakpoints": true
},
{
"idx": 39,
"version": "7",
"when": 1784030221865,
"tag": "0039_sudden_franklin_storm",
"breakpoints": true
}
]
}
+3
View File
@@ -15,6 +15,7 @@ import { users } from "./users";
export const visibilityEnum = pgEnum("visibility", ["private", "unlisted", "public"]);
export const difficultyEnum = pgEnum("difficulty", ["easy", "medium", "hard"]);
export const recipeTypeEnum = pgEnum("recipe_type", ["dish", "drink"]);
export type DietaryTags = {
vegan?: boolean;
@@ -32,6 +33,7 @@ export const recipes = pgTable("recipes", {
title: text("title").notNull(),
description: text("description"),
baseServings: integer("base_servings").notNull().default(4),
recipeType: recipeTypeEnum("recipe_type").notNull().default("dish"),
visibility: visibilityEnum("visibility").notNull().default("private"),
sourceUrl: text("source_url"),
aiGenerated: boolean("ai_generated").notNull().default(false),
@@ -53,6 +55,7 @@ export const recipes = pgTable("recipes", {
index("recipes_visibility_idx").on(t.visibility),
index("recipes_dietary_tags_gin").using("gin", t.dietaryTags),
index("recipes_batch_cook_idx").on(t.isBatchCook),
index("recipes_type_idx").on(t.recipeType),
]);
export const ingredients = pgTable("ingredients", {