tenant-engine/migrations/postgres/0001_tenant_store.sql
tegwick 749461b97b
All checks were successful
Build and Publish Container Image / build-and-push (push) Successful in 41s
Implement PostgreSQL production store path
Add the PostgreSQL backend, migration and stopped-write transfer tools, lease-aware deployment manifests, tenancy declarations, and shared conformance coverage. Persist grouping mutations in durable stores and separate process liveness from database readiness.
2026-08-19 14:43:08 +02:00

82 lines
2.4 KiB
PL/PgSQL

BEGIN;
CREATE TABLE IF NOT EXISTS tenants (
tenant_id TEXT PRIMARY KEY,
identifier TEXT UNIQUE NOT NULL,
grouping_name TEXT NOT NULL,
display_name TEXT,
contact_email TEXT,
lifecycle TEXT NOT NULL DEFAULT 'active'
CHECK (lifecycle IN ('active', 'retired')),
version BIGINT NOT NULL DEFAULT 1 CHECK (version > 0),
-- Pre-lifecycle SQLite rows legitimately carry no timestamp. Nullable here
-- preserves them exactly during the store move; new domain writes set both.
created_at TIMESTAMPTZ,
updated_at TIMESTAMPTZ,
retired_at TIMESTAMPTZ,
reactivated_at TIMESTAMPTZ
);
CREATE TABLE IF NOT EXISTS grants (
grant_id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL REFERENCES tenants(tenant_id),
role TEXT NOT NULL,
grant_reason TEXT NOT NULL,
plan_id TEXT,
granted_by TEXT NOT NULL,
granted_at TIMESTAMPTZ NOT NULL,
correlation_id TEXT NOT NULL,
revoked_at TIMESTAMPTZ
);
CREATE INDEX IF NOT EXISTS grants_tenant_active_idx
ON grants (tenant_id) WHERE revoked_at IS NULL;
CREATE TABLE IF NOT EXISTS plans (
tenant_id TEXT PRIMARY KEY REFERENCES tenants(tenant_id),
plan_id TEXT NOT NULL,
assigned_at TIMESTAMPTZ NOT NULL
);
CREATE TABLE IF NOT EXISTS events (
seq BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
event_type TEXT NOT NULL,
tenant_id TEXT NOT NULL REFERENCES tenants(tenant_id),
at TIMESTAMPTZ NOT NULL,
payload JSONB NOT NULL
);
CREATE INDEX IF NOT EXISTS events_tenant_seq_idx ON events (tenant_id, seq);
CREATE TABLE IF NOT EXISTS idempotency_receipts (
tenant_id TEXT NOT NULL REFERENCES tenants(tenant_id),
idempotency_key TEXT NOT NULL,
request_fingerprint TEXT NOT NULL,
result JSONB NOT NULL,
recorded_at TIMESTAMPTZ NOT NULL,
PRIMARY KEY (tenant_id, idempotency_key)
);
CREATE TABLE IF NOT EXISTS guardrail_overrides (
tenant_id TEXT NOT NULL REFERENCES tenants(tenant_id),
limit_key TEXT NOT NULL,
kind TEXT NOT NULL,
amount TEXT NOT NULL,
currency TEXT,
period TEXT,
PRIMARY KEY (tenant_id, limit_key)
);
CREATE TABLE IF NOT EXISTS guardrail_changes (
change_id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL REFERENCES tenants(tenant_id),
limit_key TEXT NOT NULL,
previous JSONB,
current JSONB,
changed_by TEXT NOT NULL,
reason TEXT NOT NULL,
correlation_id TEXT NOT NULL,
changed_at TIMESTAMPTZ NOT NULL
);
CREATE INDEX IF NOT EXISTS guardrail_changes_tenant_time_idx
ON guardrail_changes (tenant_id, changed_at, change_id);
COMMIT;