← back to AbramsOS

db/migrations/0010_savings.sql

57 lines

-- 0010_savings.sql
-- The "life optimizer" layer: turn what Steve actually buys into money-saving /
-- quality-improving suggestions, plus coupon leads at the places he shops.
--   savings_suggestion — one actionable idea (cheaper/better substitute, reorder timing,
--                        price drop, or a coupon) generated from purchase + reorder_item data.
--   merchant_coupon    — a discount/coupon lead tied to a merchant Steve buys from.
-- Both feed the /savings dashboard. Local-LLM ($0) generated; nothing is auto-purchased.
-- Idempotent. Safe to re-run.

BEGIN;

CREATE TABLE IF NOT EXISTS savings_suggestion (
  id               text PRIMARY KEY,
  user_id          text NOT NULL REFERENCES user_account(id) ON DELETE CASCADE,
  kind             text NOT NULL DEFAULT 'substitute',  -- substitute|upgrade|coupon|reorder-timing|price-drop|bundle
  title            text NOT NULL,
  current_item     text,                                 -- what Steve buys today
  current_price    numeric(12,2),
  suggested_item   text,                                 -- the cheaper/better alternative
  suggested_price  numeric(12,2),
  est_savings      numeric(12,2),                         -- estimated $ saved
  savings_basis    text,                                  -- "per order" | "per year" | "one-time"
  quality_note     text,                                  -- quality tradeoff or upgrade rationale
  merchant         text,                                  -- where to buy the suggestion
  source_url       text,                                  -- link to verify (never auto-buy)
  rationale        text,                                  -- why this suggestion
  confidence       numeric(4,3) NOT NULL DEFAULT 0.5,     -- 0..1
  reorder_item_id  text REFERENCES reorder_item(id) ON DELETE SET NULL,
  status           text NOT NULL DEFAULT 'new',           -- new|saved|dismissed|done
  metadata_jsonb   jsonb NOT NULL DEFAULT '{}'::jsonb,
  created_at       timestamptz NOT NULL DEFAULT now(),
  updated_at       timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS savings_user_status_idx ON savings_suggestion (user_id, status, created_at DESC);
CREATE INDEX IF NOT EXISTS savings_kind_idx        ON savings_suggestion (user_id, kind);

CREATE TABLE IF NOT EXISTS merchant_coupon (
  id              text PRIMARY KEY,
  user_id         text NOT NULL REFERENCES user_account(id) ON DELETE CASCADE,
  merchant        text NOT NULL,                          -- e.g. "Amazon", "Costco", "Nespresso"
  merchant_domain text,
  title           text NOT NULL,
  code            text,                                   -- promo code, if any
  discount_text   text,                                   -- "15% off", "$10 off $50"
  description      text,
  url             text,
  expires_on      date,
  source          text,                                   -- where the lead came from
  status          text NOT NULL DEFAULT 'active',         -- active|expired|dismissed
  metadata_jsonb  jsonb NOT NULL DEFAULT '{}'::jsonb,
  created_at      timestamptz NOT NULL DEFAULT now(),
  updated_at      timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS coupon_user_merchant_idx ON merchant_coupon (user_id, merchant, status);

COMMIT;