-- +goose Up -- Audit H6 follow-up. The Apple/Google webhook handler now fails CLOSED on a -- deduplication-store error: if it cannot consult webhook_event_log it returns -- 500 rather than risk processing a replayed event. That makes the presence of -- the webhook_event_log table mandatory. -- -- Like audit_log, this table was never created by a goose migration — only by -- GORM AutoMigrate in tests — so a from-scratch redeploy would come up without -- it and 500 every subscription webhook. CREATE TABLE IF NOT EXISTS brings it -- under migration control: a no-op where the table already exists, and a -- correct build (matching repositories.WebhookEvent) on a fresh database. CREATE TABLE IF NOT EXISTS webhook_event_log ( id BIGSERIAL PRIMARY KEY, event_id VARCHAR(255) NOT NULL, provider VARCHAR(20) NOT NULL, event_type VARCHAR(100) NOT NULL, processed_at TIMESTAMPTZ NOT NULL DEFAULT now(), payload_hash VARCHAR(64) ); -- (provider, event_id) is the dedup key — matches the -- uniqueIndex:idx_provider_event_id GORM tags on repositories.WebhookEvent. CREATE UNIQUE INDEX IF NOT EXISTS idx_provider_event_id ON webhook_event_log (provider, event_id); -- +goose Down -- The table is intentionally NOT dropped — it may hold deduplication history -- that predates this migration, and dropping it would let already-processed -- webhook events be replayed. Down is a documented no-op. SELECT 1;