← back to Ventura Claw Leads

db/migrations/004_business_users_and_claims.sql

31 lines

-- Admin/claim infrastructure for businesses to claim their directory listing,
-- log into a dashboard, see leads, edit profile, and manage subscription.

CREATE TABLE IF NOT EXISTS business_users (
  id              BIGSERIAL PRIMARY KEY,
  email           TEXT UNIQUE NOT NULL,
  password_hash   TEXT,                                            -- nullable until first password set; magic-link login still works
  business_id     BIGINT NOT NULL REFERENCES businesses(id) ON DELETE CASCADE,
  display_name    TEXT,
  email_verified  BOOLEAN NOT NULL DEFAULT false,
  last_login_at   TIMESTAMPTZ,
  created_at      TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (business_id, email)
);
CREATE INDEX IF NOT EXISTS business_users_business_idx ON business_users (business_id);

-- One-shot claim tokens. The email→business_id mapping is in the row, so a
-- compromised token only unlocks that one specific listing.
CREATE TABLE IF NOT EXISTS claim_tokens (
  id              BIGSERIAL PRIMARY KEY,
  token           TEXT UNIQUE NOT NULL,                            -- HMAC-derived, 32 chars
  business_id     BIGINT NOT NULL REFERENCES businesses(id) ON DELETE CASCADE,
  email           TEXT NOT NULL,                                   -- the recipient who'll claim
  issued_at       TIMESTAMPTZ NOT NULL DEFAULT now(),
  expires_at      TIMESTAMPTZ NOT NULL,
  consumed_at     TIMESTAMPTZ,
  ip_hash         TEXT
);
CREATE INDEX IF NOT EXISTS claim_tokens_business_idx ON claim_tokens (business_id);
CREATE INDEX IF NOT EXISTS claim_tokens_active_idx ON claim_tokens (token) WHERE consumed_at IS NULL;