DDL schemas for Trading Platform: - User management - Authentication - Payments - Education - ML predictions - Trading data Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
108 lines
4.8 KiB
SQL
108 lines
4.8 KiB
SQL
-- =====================================================
|
|
-- ORBIQUANT IA - SUBSCRIPTIONS TABLE
|
|
-- =====================================================
|
|
-- Description: User subscription management with Stripe integration
|
|
-- Schema: financial
|
|
-- =====================================================
|
|
-- DECISION: Planes en USD como moneda base
|
|
-- =====================================================
|
|
|
|
CREATE TABLE financial.subscriptions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE RESTRICT,
|
|
|
|
-- Plan y estado
|
|
plan financial.subscription_plan NOT NULL,
|
|
status financial.subscription_status NOT NULL DEFAULT 'incomplete',
|
|
|
|
-- Stripe integration
|
|
stripe_subscription_id VARCHAR(255) UNIQUE,
|
|
stripe_customer_id VARCHAR(255),
|
|
stripe_price_id VARCHAR(255),
|
|
stripe_product_id VARCHAR(255),
|
|
|
|
-- Pricing
|
|
price DECIMAL(10,2) NOT NULL,
|
|
currency financial.currency_code NOT NULL DEFAULT 'USD',
|
|
billing_interval VARCHAR(20) NOT NULL DEFAULT 'month', -- month, year
|
|
|
|
-- Billing periods
|
|
current_period_start TIMESTAMPTZ,
|
|
current_period_end TIMESTAMPTZ,
|
|
trial_start TIMESTAMPTZ,
|
|
trial_end TIMESTAMPTZ,
|
|
|
|
-- Cancelación
|
|
cancelled_at TIMESTAMPTZ,
|
|
cancel_at_period_end BOOLEAN DEFAULT false,
|
|
cancellation_reason TEXT,
|
|
cancellation_feedback JSONB,
|
|
|
|
-- Downgrade/Upgrade tracking
|
|
previous_plan financial.subscription_plan,
|
|
scheduled_plan financial.subscription_plan,
|
|
scheduled_plan_effective_at TIMESTAMPTZ,
|
|
|
|
-- Payment tracking
|
|
last_payment_at TIMESTAMPTZ,
|
|
next_payment_at TIMESTAMPTZ,
|
|
failed_payment_count INTEGER DEFAULT 0,
|
|
|
|
-- Features/Quotas (se pueden mover a tabla separada si crece)
|
|
metadata JSONB DEFAULT '{}',
|
|
|
|
-- Timestamps
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
ended_at TIMESTAMPTZ,
|
|
|
|
-- Constraints
|
|
CONSTRAINT positive_price CHECK (price >= 0),
|
|
CONSTRAINT valid_billing_interval CHECK (billing_interval IN ('month', 'year')),
|
|
CONSTRAINT trial_dates_order CHECK (
|
|
(trial_start IS NULL AND trial_end IS NULL) OR
|
|
(trial_start IS NOT NULL AND trial_end IS NOT NULL AND trial_start < trial_end)
|
|
),
|
|
CONSTRAINT period_dates_order CHECK (
|
|
(current_period_start IS NULL AND current_period_end IS NULL) OR
|
|
(current_period_start IS NOT NULL AND current_period_end IS NOT NULL AND current_period_start < current_period_end)
|
|
),
|
|
CONSTRAINT cancel_date_valid CHECK (
|
|
(cancelled_at IS NULL) OR
|
|
(cancelled_at >= created_at)
|
|
),
|
|
CONSTRAINT ended_when_cancelled CHECK (
|
|
(ended_at IS NULL) OR
|
|
(cancelled_at IS NOT NULL AND ended_at >= cancelled_at)
|
|
),
|
|
CONSTRAINT scheduled_plan_different CHECK (
|
|
scheduled_plan IS NULL OR scheduled_plan != plan
|
|
)
|
|
);
|
|
|
|
-- Indexes
|
|
CREATE INDEX idx_subscriptions_user_id ON financial.subscriptions(user_id);
|
|
CREATE INDEX idx_subscriptions_status ON financial.subscriptions(status);
|
|
CREATE INDEX idx_subscriptions_plan ON financial.subscriptions(plan);
|
|
CREATE INDEX idx_subscriptions_stripe_sub ON financial.subscriptions(stripe_subscription_id) WHERE stripe_subscription_id IS NOT NULL;
|
|
CREATE INDEX idx_subscriptions_stripe_customer ON financial.subscriptions(stripe_customer_id) WHERE stripe_customer_id IS NOT NULL;
|
|
CREATE INDEX idx_subscriptions_active ON financial.subscriptions(user_id, status) WHERE status = 'active';
|
|
CREATE INDEX idx_subscriptions_period_end ON financial.subscriptions(current_period_end) WHERE status = 'active';
|
|
CREATE INDEX idx_subscriptions_trial_end ON financial.subscriptions(trial_end) WHERE status = 'trialing';
|
|
CREATE INDEX idx_subscriptions_next_payment ON financial.subscriptions(next_payment_at) WHERE next_payment_at IS NOT NULL;
|
|
|
|
-- Unique constraint: un usuario solo puede tener una suscripción activa a la vez
|
|
CREATE UNIQUE INDEX idx_subscriptions_user_active ON financial.subscriptions(user_id)
|
|
WHERE status IN ('active', 'trialing', 'past_due');
|
|
|
|
-- Comments
|
|
COMMENT ON TABLE financial.subscriptions IS 'User subscription management with Stripe integration';
|
|
COMMENT ON COLUMN financial.subscriptions.plan IS 'Subscription plan tier';
|
|
COMMENT ON COLUMN financial.subscriptions.status IS 'Subscription status (Stripe-compatible states)';
|
|
COMMENT ON COLUMN financial.subscriptions.price IS 'Subscription price in specified currency';
|
|
COMMENT ON COLUMN financial.subscriptions.billing_interval IS 'Billing frequency: month or year';
|
|
COMMENT ON COLUMN financial.subscriptions.cancel_at_period_end IS 'If true, subscription will cancel at end of current period';
|
|
COMMENT ON COLUMN financial.subscriptions.scheduled_plan IS 'Plan to switch to at scheduled_plan_effective_at';
|
|
COMMENT ON COLUMN financial.subscriptions.failed_payment_count IS 'Number of consecutive failed payment attempts';
|
|
COMMENT ON COLUMN financial.subscriptions.metadata IS 'Plan features, quotas, and additional configuration';
|