-- Tier 2 Block G — smarter fraud detection. -- -- Four schema additions: -- 1. Per-event tunable thresholds. Defaults match the previous hardcoded -- 30/60/85 band boundaries so existing events behave identically until -- a host tweaks them. -- 2. Geolocation columns on access_logs. The fraud engine fills these -- asynchronously; nullable so logs from before this migration aren't -- retroactively required to have geo data. -- 3. fraud_feedback for the "this was legitimate / actually suspicious" -- hostback. Seeds the future ML model and lets hosts silence specific -- false positives. -- 4. event_allowlists for CIDR-based bypass — the corporate-Wi-Fi and -- family-router escape valve. ALTER TABLE events ADD COLUMN IF NOT EXISTS fraud_medium_threshold SMALLINT NOT NULL DEFAULT 30, ADD COLUMN IF NOT EXISTS fraud_high_threshold SMALLINT NOT NULL DEFAULT 60, ADD COLUMN IF NOT EXISTS fraud_block_threshold SMALLINT NOT NULL DEFAULT 85; ALTER TABLE access_logs ADD COLUMN IF NOT EXISTS geo_country TEXT, ADD COLUMN IF NOT EXISTS geo_city TEXT, ADD COLUMN IF NOT EXISTS geo_lat DOUBLE PRECISION, ADD COLUMN IF NOT EXISTS geo_lon DOUBLE PRECISION; CREATE TABLE IF NOT EXISTS fraud_feedback ( access_log_id UUID PRIMARY KEY REFERENCES access_logs(id) ON DELETE CASCADE, verdict TEXT NOT NULL CHECK (verdict IN ('legitimate', 'suspicious')), marked_by UUID REFERENCES users(id) ON DELETE SET NULL, note TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS event_allowlists ( event_id UUID NOT NULL REFERENCES events(id) ON DELETE CASCADE, ip_cidr INET NOT NULL, label TEXT, created_by UUID REFERENCES users(id) ON DELETE SET NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), PRIMARY KEY (event_id, ip_cidr) ); CREATE INDEX IF NOT EXISTS idx_allowlists_event ON event_allowlists(event_id);