-- SaaS hardening schema additions CREATE TABLE IF NOT EXISTS plan_limits ( id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), plan_code varchar(64) NOT NULL, resource varchar(64) NOT NULL, hard_limit integer NOT NULL, soft_limit integer NULL, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), UNIQUE (plan_code, resource) ); CREATE TABLE IF NOT EXISTS usage_counters ( id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), tenant_id uuid NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, resource varchar(64) NOT NULL, usage_value bigint NOT NULL DEFAULT 0, period_start timestamptz NOT NULL, period_end timestamptz NOT NULL, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), UNIQUE (tenant_id, resource, period_start, period_end) ); CREATE TABLE IF NOT EXISTS webhook_endpoints ( id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), tenant_id uuid NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, url text NOT NULL, secret_encrypted text NOT NULL, events jsonb NOT NULL DEFAULT '[]'::jsonb, status varchar(32) NOT NULL DEFAULT 'active', created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS webhook_deliveries ( id bigserial PRIMARY KEY, tenant_id uuid NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, webhook_endpoint_id uuid NOT NULL REFERENCES webhook_endpoints(id) ON DELETE CASCADE, event_type varchar(64) NOT NULL, payload jsonb NOT NULL DEFAULT '{}'::jsonb, status varchar(32) NOT NULL DEFAULT 'queued', response_code integer NULL, attempts integer NOT NULL DEFAULT 0, delivered_at timestamptz NULL, created_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS public_api_tokens ( id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), tenant_id uuid NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, name varchar(120) NOT NULL, token_hash varchar(255) NOT NULL UNIQUE, scopes jsonb NOT NULL DEFAULT '[]'::jsonb, expires_at timestamptz NULL, revoked_at timestamptz NULL, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now() );