← back to Ventura Corridor

db/migrations/011_pitch_daily_snapshot.sql

39 lines

-- Migration 011 — daily activity snapshot
-- Captures (snap_date, dimension_key, dimension_value, count) once a day so
-- /today.html can plot a 30-day trend chart of corridor velocity.
--
-- A single table holds three "dimensions" — status, outreach_channel, dw_proximity —
-- so we can render multiple sparklines from one source.

CREATE TABLE IF NOT EXISTS pitch_daily_snapshot (
  snap_date     DATE        NOT NULL,
  dim           TEXT        NOT NULL,    -- 'status' | 'outreach_channel' | 'dw_proximity' | 'totals'
  bucket        TEXT        NOT NULL,    -- e.g. 'draft', 'walk-in', 'same_block', 'all'
  count         INTEGER     NOT NULL DEFAULT 0,
  captured_at   TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  PRIMARY KEY (snap_date, dim, bucket)
);

CREATE INDEX IF NOT EXISTS idx_snapshot_dim ON pitch_daily_snapshot (dim, snap_date);

-- Snapshot helper view so the snapshot script is a one-liner UPSERT
CREATE OR REPLACE VIEW v_pitch_today_status AS
SELECT 'status'::text AS dim, status AS bucket, count(*)::int AS count
FROM pitches GROUP BY status
UNION ALL
SELECT 'outreach_channel'::text, COALESCE(outreach_channel, 'unspecified'), count(*)::int
FROM pitches GROUP BY outreach_channel
UNION ALL
SELECT 'dw_proximity'::text, COALESCE(dw_proximity, 'unknown'), count(*)::int
FROM pitches GROUP BY dw_proximity
UNION ALL
SELECT 'totals'::text, 'all', count(*)::int FROM pitches
UNION ALL
SELECT 'totals'::text, 'sent', count(*)::int FROM pitches WHERE sent_at IS NOT NULL
UNION ALL
SELECT 'totals'::text, 'replied', count(*)::int FROM pitches WHERE replied_at IS NOT NULL
UNION ALL
SELECT 'totals'::text, 'won', count(*)::int FROM pitches WHERE status = 'won'
UNION ALL
SELECT 'totals'::text, 'walked', count(*)::int FROM pitches WHERE outreach_channel = 'walk-in' AND sent_at IS NOT NULL;