-- Cumulative usage quotas + self-service user registration for the public API. -- -- The free anonymous tier is capped at a lifetime number of calls (enforced in -- Redis, keyed by client IP). To keep calling beyond the free quota a caller -- registers an account and self-issues an API key with a higher quota. -- quota_total = 0 means unlimited. -- -- Registration is the one place the public server writes to PostgreSQL (it -- inserts an app_user and its api_key); every other public route stays -- read-only. Request counting still lives entirely in Redis. ALTER TABLE api_key ADD COLUMN IF NOT EXISTS quota_total BIGINT NOT NULL DEFAULT 0; ALTER TABLE api_key DROP CONSTRAINT IF EXISTS api_key_tier_chk; ALTER TABLE api_key ADD CONSTRAINT api_key_tier_chk CHECK (tier IN ('free', 'registered', 'partner', 'internal')); CREATE TABLE IF NOT EXISTS app_user ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email TEXT NOT NULL, password_hash TEXT NOT NULL, api_key_id UUID REFERENCES api_key (id) ON DELETE SET NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- Case-insensitive uniqueness so each email registers at most once. CREATE UNIQUE INDEX IF NOT EXISTS idx_app_user_email ON app_user (lower(email));