← back to NationalPaperHangers

db/migrations/001_claim_columns.sql

52 lines

-- 001 · Claim columns + provenance + opt-out
-- Adds the columns the option-C "scrape lite + claim flow" needs.
-- Idempotent: re-runnable, all ADD COLUMN guarded by IF NOT EXISTS.

BEGIN;

ALTER TABLE installers
  ADD COLUMN IF NOT EXISTS claim_status      TEXT DEFAULT 'self',  -- self | unclaimed | pending_claim | claimed
  ADD COLUMN IF NOT EXISTS claim_token       TEXT,                 -- one-shot verification token
  ADD COLUMN IF NOT EXISTS claim_token_at    TIMESTAMPTZ,
  ADD COLUMN IF NOT EXISTS claimed_at        TIMESTAMPTZ,
  ADD COLUMN IF NOT EXISTS instagram_handle  TEXT,                 -- e.g. "atelierbond" — no @, no URL
  ADD COLUMN IF NOT EXISTS source_name       TEXT,                 -- e.g. "wia" | "self_signup" | "manual"
  ADD COLUMN IF NOT EXISTS source_url        TEXT,                 -- exact URL we scraped from
  ADD COLUMN IF NOT EXISTS source_scraped_at TIMESTAMPTZ;

CREATE INDEX IF NOT EXISTS idx_installers_claim_status ON installers(claim_status);
CREATE INDEX IF NOT EXISTS idx_installers_source_url ON installers(source_url);

-- Self-signed-up installers default to 'self'
-- (existing rows that came in via signup will get 'self' by default)
UPDATE installers SET claim_status = 'self' WHERE claim_status IS NULL;

-- ----------------------------------------------------------------------
-- Opt-out registry: domains that have asked to be delisted and never
-- re-scraped, no matter what source they show up on.
-- ----------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS directory_optout (
  id          SERIAL PRIMARY KEY,
  domain      TEXT UNIQUE NOT NULL,
  reason      TEXT,
  requested_by_email TEXT,
  created_at  TIMESTAMPTZ DEFAULT now()
);

-- ----------------------------------------------------------------------
-- Scrape audit: per-request log so we can prove crawl etiquette later.
-- ----------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS scrape_log (
  id          SERIAL PRIMARY KEY,
  source      TEXT NOT NULL,        -- e.g. 'wia', 'studio_site'
  url         TEXT NOT NULL,
  http_status INTEGER,
  bytes       INTEGER,
  duration_ms INTEGER,
  error       TEXT,
  created_at  TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_scrape_log_source_created ON scrape_log(source, created_at DESC);

COMMIT;