mirror of
https://github.com/warmbly/warmbly.git
synced 2026-08-19 08:01:16 +00:00
121 lines
3.7 KiB
SQL
121 lines
3.7 KiB
SQL
CREATE TABLE durations (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
title VARCHAR(100) NOT NULL
|
|
);
|
|
|
|
CREATE TABLE plans (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name VARCHAR(100),
|
|
max_contacts BIGINT NOT NULL,
|
|
daily_emails INT NOT NULL,
|
|
ai_generation BOOLEAN NOT NULL,
|
|
account_limit INT NOT NULL,
|
|
price DECIMAL(10, 2) NOT NULL,
|
|
discounted_price DECIMAL(10, 2) NOT NULL,
|
|
duration_id UUID NOT NULL REFERENCES durations(id) ON DELETE CASCADE,
|
|
savings SMALLINT,
|
|
public BOOLEAN NOT NULL DEFAULT false,
|
|
|
|
-- Stripe integration
|
|
stripe_price_id VARCHAR(255),
|
|
stripe_product_id VARCHAR(255),
|
|
|
|
-- Organization limits
|
|
max_campaigns INT,
|
|
max_active_campaigns INT,
|
|
max_team_members INT,
|
|
max_email_accounts INT,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
|
|
CONSTRAINT valid_savings CHECK (savings BETWEEN 0 AND 100)
|
|
);
|
|
|
|
CREATE INDEX idx_plans_stripe_price ON plans(stripe_price_id);
|
|
|
|
CREATE TABLE offers (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
title VARCHAR(255) NOT NULL,
|
|
description TEXT NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TABLE offer_options (
|
|
offer_id UUID NOT NULL REFERENCES offers(id) ON DELETE CASCADE,
|
|
plan_id UUID NOT NULL REFERENCES plans(id) ON DELETE CASCADE,
|
|
title VARCHAR(255) NOT NULL,
|
|
|
|
PRIMARY KEY (offer_id, plan_id)
|
|
);
|
|
|
|
CREATE TABLE secret_plans (
|
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
plan_id UUID NOT NULL REFERENCES plans(id) ON DELETE CASCADE,
|
|
|
|
PRIMARY KEY (user_id, plan_id)
|
|
);
|
|
|
|
-- Subscription status enum
|
|
CREATE TYPE subscription_status AS ENUM (
|
|
'trialing',
|
|
'active',
|
|
'past_due',
|
|
'canceled',
|
|
'unpaid',
|
|
'incomplete',
|
|
'incomplete_expired',
|
|
'paused'
|
|
);
|
|
|
|
CREATE TABLE subscriptions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
|
|
plan_id UUID NOT NULL REFERENCES plans(id) ON DELETE RESTRICT,
|
|
|
|
-- Stripe identifiers
|
|
stripe_customer_id VARCHAR(255) NOT NULL,
|
|
stripe_subscription_id VARCHAR(255) UNIQUE,
|
|
stripe_price_id VARCHAR(255),
|
|
|
|
-- Subscription state
|
|
status subscription_status NOT NULL DEFAULT 'incomplete',
|
|
|
|
-- Billing period
|
|
current_period_start TIMESTAMPTZ,
|
|
current_period_end TIMESTAMPTZ,
|
|
cancel_at_period_end BOOLEAN NOT NULL DEFAULT FALSE,
|
|
canceled_at TIMESTAMPTZ,
|
|
|
|
-- Trial info
|
|
trial_start TIMESTAMPTZ,
|
|
trial_end TIMESTAMPTZ,
|
|
|
|
-- Enterprise flag - when true, uses user_rate_limits for custom limits
|
|
is_enterprise BOOLEAN NOT NULL DEFAULT FALSE,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
|
|
CONSTRAINT unique_org_subscription UNIQUE (organization_id)
|
|
);
|
|
|
|
CREATE INDEX idx_subscriptions_stripe_customer ON subscriptions(stripe_customer_id);
|
|
CREATE INDEX idx_subscriptions_stripe_subscription ON subscriptions(stripe_subscription_id);
|
|
CREATE INDEX idx_subscriptions_status ON subscriptions(status);
|
|
CREATE INDEX idx_subscriptions_period_end ON subscriptions(current_period_end);
|
|
CREATE INDEX idx_subscriptions_org ON subscriptions(organization_id);
|
|
|
|
-- Stripe webhook events log for idempotency
|
|
CREATE TABLE stripe_webhook_events (
|
|
id VARCHAR(255) PRIMARY KEY,
|
|
event_type VARCHAR(100) NOT NULL,
|
|
processed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
payload JSONB
|
|
);
|
|
|
|
CREATE INDEX idx_stripe_events_type ON stripe_webhook_events(event_type);
|
|
CREATE INDEX idx_stripe_events_processed ON stripe_webhook_events(processed_at);
|