← back to Professional Directory

db/migrations/002_data_orders.sql

58 lines

-- Doctor data marketplace: mirror of Counsel & Bar's data_orders for the
-- LA County physician directory. Buyers pick specialties + cities, get a CSV.
-- Two purchase kinds:
--   'one_time'    — single CSV download, snapshot at purchase time
--   'subscription'— monthly recurring, unlimited downloads while active
--
-- Distinct from any future per-doctor upgrade-listing flow (different SKU,
-- different buyer). Stripe is the source of truth on payment status; download_token
-- is the gate (random 32-byte hex, stored as plain text for direct lookup).

CREATE TABLE IF NOT EXISTS data_orders (
  id                      BIGSERIAL PRIMARY KEY,
  kind                    TEXT NOT NULL CHECK (kind IN ('one_time','subscription')),

  -- buyer
  email                   TEXT NOT NULL,
  full_name               TEXT,
  company                 TEXT,
  phone                   TEXT,

  -- product spec — both filter dimensions persist on the row so we can
  -- regenerate the CSV later (snapshot count) or audit what was sold.
  cities                  TEXT[] NOT NULL DEFAULT '{}'::TEXT[],
  specialties             TEXT[] NOT NULL DEFAULT '{}'::TEXT[],
  doctor_count            INT,
  amount_cents            INT NOT NULL,

  -- status
  status                  TEXT NOT NULL DEFAULT 'pending_payment'
                          CHECK (status IN ('pending_payment','paid','refunded','cancelled','sub_cancelled')),

  -- stripe
  stripe_session_id       TEXT,
  stripe_customer_id      TEXT,
  stripe_subscription_id  TEXT,
  payment_link            TEXT,

  -- delivery
  download_token          TEXT NOT NULL UNIQUE,           -- random 32-byte hex
  downloads_count         INT  NOT NULL DEFAULT 0,
  last_downloaded_at      TIMESTAMPTZ,

  -- timestamps
  created_at              TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  paid_at                 TIMESTAMPTZ,
  cancelled_at            TIMESTAMPTZ,

  -- audit
  ip                      TEXT,
  user_agent              TEXT
);

CREATE INDEX IF NOT EXISTS idx_data_orders_email   ON data_orders (LOWER(email));
CREATE INDEX IF NOT EXISTS idx_data_orders_status  ON data_orders (status);
CREATE INDEX IF NOT EXISTS idx_data_orders_created ON data_orders (created_at DESC);

INSERT INTO schema_migrations(filename) VALUES ('002_data_orders.sql') ON CONFLICT DO NOTHING;