← back to Nationalrealestate
db/migrations/008_places_seed.sql
30 lines
-- M-P1: Google Places DISCOVERY seed + free-tier hard-cap counter.
-- No BEGIN/COMMIT here — migrate.ts wraps each file in a transaction.
--
-- ToS posture (Google Maps Platform §3.2.3): place_id is the ONLY Places field
-- we persist. Everything durable (firm name/website/phone) is (re)derived from
-- the firm's OWN public site by the existing crawl pipeline, so Places is a
-- pointer ("where to look next"), never our stored dataset. place_id doubles as
-- the idempotent dedupe key so a seeded office is never re-seeded.
CREATE TABLE places_seed (
place_id TEXT PRIMARY KEY, -- Google's stable id — the only cacheable field
query TEXT, -- the search text that surfaced it (audit)
region_id INT REFERENCES region(id), -- metro/county we were seeding
website_host TEXT, -- host only, for dedupe vs firm_site (not "Places Content")
firm_id INT REFERENCES firm(id), -- the firm row this seed produced/linked (nullable until crawl)
status TEXT NOT NULL DEFAULT 'new', -- new | linked | no_website | crawled | dead
first_seen TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_seen TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_places_seed_region ON places_seed (region_id);
CREATE INDEX idx_places_seed_status ON places_seed (status);
-- Monthly billing guard. One row per YYYY-MM; seed job HARD-STOPS when
-- calls_used >= cap so we never cross the free-tier line into real spend.
CREATE TABLE places_quota (
year_month TEXT PRIMARY KEY, -- 'YYYY-MM'
calls_used INT NOT NULL DEFAULT 0,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);