← back to Commercialrealestate

scripts/db/sfr-schema.sql

40 lines

-- sfr-schema.sql — single-family-residence FOR-SALE layer for the CRE explorer (local Postgres "cre").
-- Mirrors cre.condo but for detached SFR stock (Redfin uipt=1). Feeds the 'sfr-bankstmt' call segment
-- (self-employed buyers needing bank-statement / P&L income qualification). url is UNIQUE so the
-- gis-csv sweep upserts idempotently across re-runs / price-banded passes.
--
-- HONEST LABELING (same rule as condo): broker_name / firm_name are populated only when the Redfin
-- detail feed exposes a public listing agent. SFRs with a suppressed/absent agent stay NULL — never
-- fabricated. broker_sfr is the residential-agent edge, mirroring broker_condo.

CREATE TABLE IF NOT EXISTS sfr (
  id           text PRIMARY KEY,           -- 'rdf' + MLS# or synthetic addr+zip hash
  address      text,
  city         text,
  zip          text,
  price        bigint,
  beds         numeric,
  baths        numeric,
  sqft         integer,
  year_built   integer,
  listing_text text,                       -- minimal (property type from the feed)
  firm_id      integer REFERENCES firm(id),
  firm_name    text,                        -- listing brokerage when public
  broker_name  text,                        -- lead listing agent when public
  source       text UNIQUE,                 -- Redfin listing URL (idempotent upsert key)
  created_at   timestamptz DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_sfr_zip   ON sfr(zip);
CREATE INDEX IF NOT EXISTS idx_sfr_city  ON sfr(lower(city));
CREATE INDEX IF NOT EXISTS idx_sfr_firm  ON sfr(firm_id);

-- The residential edge: an agent listed an SFR. Mirrors broker_condo for cre.sfr.
CREATE TABLE IF NOT EXISTS broker_sfr (
  broker_id  integer NOT NULL REFERENCES broker(id) ON DELETE CASCADE,
  sfr_id     text    NOT NULL REFERENCES sfr(id)    ON DELETE CASCADE,
  role       text DEFAULT 'listing',       -- listing | co | team
  PRIMARY KEY (broker_id, sfr_id)
);
CREATE INDEX IF NOT EXISTS idx_bs_sfr    ON broker_sfr(sfr_id);
CREATE INDEX IF NOT EXISTS idx_bs_broker ON broker_sfr(broker_id);