@@ -0,0 +1,44 @@ |
| 1 | +-- SPDX-License-Identifier: AGPL-3.0-or-later |
| 2 | +-- |
| 3 | +-- PAYMENTS PRO03 — add subject audit columns to billing_webhook_events. |
| 4 | +-- |
| 5 | +-- The webhook idempotency table is already subject-agnostic at the |
| 6 | +-- data-model level: it dedupes by (provider, provider_event_id) and |
| 7 | +-- has no org FK. This migration only adds (subject_kind, subject_id) |
| 8 | +-- audit columns so future operator queries can answer "which user/org |
| 9 | +-- did this event apply to?" without re-parsing the payload. |
| 10 | +-- |
| 11 | +-- Nullable by design: |
| 12 | +-- - Legacy rows (pre-PRO04) have no resolved subject — they predate |
| 13 | +-- the metadata convention. |
| 14 | +-- - Webhook events that fail to resolve a subject (corrupted |
| 15 | +-- metadata, customer-id not found on either side) still get a |
| 16 | +-- receipt row so they aren't replayed forever. Such rows carry |
| 17 | +-- NULL subject and a non-empty process_error. |
| 18 | + |
| 19 | +-- +goose Up |
| 20 | + |
| 21 | +ALTER TABLE billing_webhook_events |
| 22 | + ADD COLUMN subject_kind billing_subject_kind, |
| 23 | + ADD COLUMN subject_id bigint; |
| 24 | + |
| 25 | +-- Both-or-neither: a receipt row either has a resolved subject (both |
| 26 | +-- columns populated) or doesn't (both NULL). Mixed state means a bug |
| 27 | +-- in the resolver. |
| 28 | +ALTER TABLE billing_webhook_events |
| 29 | + ADD CONSTRAINT billing_webhook_events_subject_both_or_neither CHECK ( |
| 30 | + (subject_kind IS NULL AND subject_id IS NULL) |
| 31 | + OR (subject_kind IS NOT NULL AND subject_id IS NOT NULL) |
| 32 | + ); |
| 33 | + |
| 34 | +-- Operator-query index for "events that did resolve a subject." |
| 35 | +CREATE INDEX billing_webhook_events_subject_idx |
| 36 | + ON billing_webhook_events (subject_kind, subject_id, received_at DESC) |
| 37 | + WHERE subject_kind IS NOT NULL; |
| 38 | + |
| 39 | +-- +goose Down |
| 40 | + |
| 41 | +DROP INDEX IF EXISTS billing_webhook_events_subject_idx; |
| 42 | +ALTER TABLE billing_webhook_events DROP CONSTRAINT IF EXISTS billing_webhook_events_subject_both_or_neither; |
| 43 | +ALTER TABLE billing_webhook_events DROP COLUMN IF EXISTS subject_id; |
| 44 | +ALTER TABLE billing_webhook_events DROP COLUMN IF EXISTS subject_kind; |