Files
Sauci/apps/api/drizzle/0007_billing_redemption.sql
jjbrunton 006761d3b0 feat(backend): add standalone data plane
Replace the Supabase application data plane with the Node/PostgreSQL API, migrate mobile, admin, web, and MCP callers, add controlled cutover tooling, and define hardened Dokploy infrastructure.
2026-08-28 14:42:11 +01:00

63 lines
2.5 KiB
SQL

CREATE TABLE IF NOT EXISTS subscriptions (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
revenuecat_app_user_id text NOT NULL,
product_id text NOT NULL,
status text NOT NULL DEFAULT 'active'
CHECK (status IN ('active', 'cancelled', 'expired', 'billing_issue', 'paused')),
entitlement_ids text[] NOT NULL DEFAULT '{}',
purchased_at timestamptz NOT NULL,
expires_at timestamptz,
original_transaction_id text,
store text NOT NULL DEFAULT 'APP_STORE',
is_sandbox boolean NOT NULL DEFAULT false,
cancel_reason text,
grace_period_expires_at timestamptz,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (user_id, original_transaction_id)
);
--> statement-breakpoint
CREATE INDEX IF NOT EXISTS subscriptions_user_id_idx ON subscriptions(user_id);
--> statement-breakpoint
CREATE INDEX IF NOT EXISTS subscriptions_status_idx ON subscriptions(status);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS revenuecat_webhook_events (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
event_id text NOT NULL UNIQUE,
event_type text NOT NULL,
app_user_id text NOT NULL,
processed_at timestamptz NOT NULL DEFAULT now(),
payload jsonb NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS redemption_codes (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
code text NOT NULL,
description text,
max_uses integer DEFAULT 1 CHECK (max_uses IS NULL OR max_uses >= 0),
current_uses integer NOT NULL DEFAULT 0 CHECK (current_uses >= 0),
expires_at timestamptz,
is_active boolean NOT NULL DEFAULT true,
created_by uuid REFERENCES profiles(id) ON DELETE SET NULL,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
--> statement-breakpoint
CREATE UNIQUE INDEX IF NOT EXISTS redemption_codes_upper_code_idx ON redemption_codes(upper(code));
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS code_redemptions (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
code_id uuid NOT NULL REFERENCES redemption_codes(id) ON DELETE CASCADE,
user_id uuid NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
redeemed_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (code_id, user_id)
);
--> statement-breakpoint
CREATE INDEX IF NOT EXISTS code_redemptions_user_id_idx ON code_redemptions(user_id);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS redemption_rate_limits (
bucket timestamptz PRIMARY KEY,
attempts integer NOT NULL CHECK (attempts >= 0)
);