Files
member-console/internal/integration/migrations/00002_integration_tables.sql
Christian Galo f23a84999c sqlc: standardize generated type names across all modules
Drop redundant schema prefixes from all sqlc-generated Go types. Since
each module generates into its own package, the package already provides
the namespace — billing.Account is unambiguous without
billing.BillingAccount.

Changes:
- Add rename: blocks to all 6 sqlc.yaml files mapping schema-prefixed
  names to clean idiomatic names (e.g. BillingBillingAccount → Account,
  IdentityPerson → Person, OrganizationOrganization → Organization)
- Rename billing.billing_accounts → billing.accounts (table name
  repeated
  the schema; the schema already provides that context)
- Rename integration.integration_outbox → integration.outbox (same
  reason)
- Regenerate all sqlc output across billing, identity, organization,
  entitlements, stripe, and fedwiki modules
- Update all calling code (server, workflows, provisioning, tests) to
  use
  the new names
- Add internal/db/sqlc_schemas.sql — sqlc-only schema declarations so
  every module can resolve schema-qualified names without including the
  full db migrations
- Update docs/database-management.md with the naming convention and
  standard sqlc.yaml template

Convention going forward: table names must not repeat the schema name;
generated types carry no schema prefix; the Go package provides the
namespace (like http.Request, not http.HttpRequest).
2026-04-05 02:35:36 -05:00

74 lines
3.1 KiB
SQL

-- +goose Up
-- +goose StatementBegin
-- webhook_events: idempotent inbound webhook capture, partitioned monthly.
-- Processors poll by status; partitioning keeps old data manageable.
CREATE TABLE integration.webhook_events (
id BIGINT GENERATED ALWAYS AS IDENTITY,
provider TEXT NOT NULL, -- e.g. 'stripe'
provider_event_id TEXT NOT NULL, -- Stripe event ID (evt_…)
event_type TEXT NOT NULL, -- e.g. 'invoice.paid'
payload JSONB NOT NULL DEFAULT '{}',
status TEXT NOT NULL DEFAULT 'received', -- received | processing | completed | skipped | failed
retry_count INT NOT NULL DEFAULT 0,
error_message TEXT,
received_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
processed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT webhook_events_pkey PRIMARY KEY (id, received_at),
CONSTRAINT webhook_events_provider_event_uniq UNIQUE (provider, provider_event_id, received_at)
) PARTITION BY RANGE (received_at);
-- Create initial partitions: current month + next 2 months.
-- Future partitions are created by application boot or a scheduler.
DO $$
DECLARE
m_start DATE;
m_end DATE;
part TEXT;
BEGIN
FOR i IN 0..2 LOOP
m_start := DATE_TRUNC('month', NOW()) + (i || ' months')::INTERVAL;
m_end := m_start + '1 month'::INTERVAL;
part := 'integration.webhook_events_' || TO_CHAR(m_start, 'YYYY_MM');
EXECUTE FORMAT(
'CREATE TABLE IF NOT EXISTS %s PARTITION OF integration.webhook_events
FOR VALUES FROM (%L) TO (%L)',
part, m_start, m_end
);
END LOOP;
END$$;
CREATE INDEX idx_webhook_events_status_received
ON integration.webhook_events (status, received_at)
WHERE status IN ('received', 'failed');
CREATE INDEX idx_webhook_events_provider_event
ON integration.webhook_events (provider, provider_event_id);
-- outbox: transactional outbound actions with retry + dead-letter.
CREATE TABLE integration.outbox (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
provider TEXT NOT NULL, -- e.g. 'stripe'
action_type TEXT NOT NULL, -- e.g. 'create_customer'
payload JSONB NOT NULL DEFAULT '{}',
status TEXT NOT NULL DEFAULT 'pending', -- pending | processing | completed | failed | dead_letter
attempts INT NOT NULL DEFAULT 0,
max_attempts INT NOT NULL DEFAULT 5,
next_attempt_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
error_message TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_outbox_pending
ON integration.outbox (status, next_attempt_at)
WHERE status IN ('pending', 'failed');
-- +goose StatementEnd
-- +goose Down
DROP TABLE IF EXISTS integration.outbox;
DROP TABLE IF EXISTS integration.webhook_events;