Files
snowspeeder 59645e59b5 Add green-bean inventory and cupping features
Ports inventory management and SCA-style cupping scoring from
hope_roaster: lot tracking with audit-logged consumption, cupping
sessions with server-authoritative scoring and a live radar chart,
and links from the planner (draw-from-lot, open-cupping-session).

Also fixes the Blend/Single-origin toggle layout, replaces tooltips
with an in-context "why" teaching layer, and stages the planner UI
into pre-roast vs. post-roast phases.
2026-07-30 14:47:15 -04:00

46 lines
2.1 KiB
SQL

-- Additive only: existing tables, rows, and columns are untouched.
CREATE TABLE green_bean_lots (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
origin text NOT NULL,
variety text NOT NULL DEFAULT '',
process text NOT NULL DEFAULT '',
producer text NOT NULL DEFAULT '',
purchase_date date,
initial_weight_g numeric NOT NULL,
remaining_weight_g numeric NOT NULL,
cost_total numeric,
moisture_pct numeric,
density_g_l numeric,
notes text NOT NULL DEFAULT '',
archived boolean NOT NULL DEFAULT false,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE bean_consumption (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
lot_id uuid NOT NULL REFERENCES green_bean_lots(id) ON DELETE CASCADE,
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
roast_plan_id uuid REFERENCES roast_plans(id) ON DELETE SET NULL,
weight_g numeric NOT NULL CHECK (weight_g > 0),
created_at timestamptz NOT NULL DEFAULT now()
);
-- One draw-down per roast plan, ever (NULLs are distinct in Postgres, so plan-less manual
-- entries remain unlimited). This is the server-side backstop that makes the client's
-- "Draw from lot" button idempotent even if clicked twice or from two devices.
CREATE UNIQUE INDEX bean_consumption_one_per_plan ON bean_consumption(roast_plan_id);
CREATE TABLE cupping_sessions (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
roast_plan_id uuid REFERENCES roast_plans(id) ON DELETE SET NULL,
data jsonb NOT NULL,
total_score numeric NOT NULL DEFAULT 0,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX green_bean_lots_user ON green_bean_lots(user_id, archived, purchase_date DESC);
CREATE INDEX bean_consumption_lot ON bean_consumption(lot_id, created_at DESC);
CREATE INDEX bean_consumption_user ON bean_consumption(user_id);
CREATE INDEX cupping_sessions_user ON cupping_sessions(user_id, updated_at DESC);
CREATE INDEX cupping_sessions_plan ON cupping_sessions(roast_plan_id);