Migración desde workspace-v2/projects/template-saas/apps/database Este repositorio es parte del estándar multi-repo v2 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
80 lines
2.5 KiB
PL/PgSQL
80 lines
2.5 KiB
PL/PgSQL
-- ============================================
|
|
-- TEMPLATE-SAAS: Tenants Table
|
|
-- Schema: tenants
|
|
-- Version: 1.0.0
|
|
-- ============================================
|
|
|
|
CREATE TABLE tenants.tenants (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Basic info
|
|
name VARCHAR(255) NOT NULL,
|
|
slug VARCHAR(100) UNIQUE NOT NULL,
|
|
domain VARCHAR(255) UNIQUE,
|
|
logo_url VARCHAR(500),
|
|
|
|
-- Status
|
|
status tenants.tenant_status DEFAULT 'pending' NOT NULL,
|
|
|
|
-- Subscription
|
|
plan_id UUID, -- FK to plans.plans
|
|
subscription_status tenants.subscription_status DEFAULT 'trialing',
|
|
trial_ends_at TIMESTAMPTZ,
|
|
subscription_ends_at TIMESTAMPTZ,
|
|
|
|
-- Stripe integration
|
|
stripe_customer_id VARCHAR(255) UNIQUE,
|
|
stripe_subscription_id VARCHAR(255) UNIQUE,
|
|
|
|
-- Settings (JSONB for flexibility)
|
|
settings JSONB DEFAULT '{}'::jsonb,
|
|
-- Example settings:
|
|
-- {
|
|
-- "timezone": "America/Mexico_City",
|
|
-- "locale": "es-MX",
|
|
-- "currency": "MXN",
|
|
-- "date_format": "DD/MM/YYYY",
|
|
-- "features": {}
|
|
-- }
|
|
|
|
-- Metadata
|
|
metadata JSONB DEFAULT '{}'::jsonb,
|
|
|
|
-- Audit fields
|
|
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
|
|
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
|
|
created_by UUID,
|
|
updated_by UUID,
|
|
deleted_at TIMESTAMPTZ,
|
|
|
|
-- Constraints
|
|
CONSTRAINT valid_slug CHECK (slug ~ '^[a-z0-9]([a-z0-9-]*[a-z0-9])?$'),
|
|
CONSTRAINT slug_length CHECK (LENGTH(slug) >= 3 AND LENGTH(slug) <= 50)
|
|
);
|
|
|
|
-- Indexes
|
|
CREATE INDEX idx_tenants_status ON tenants.tenants(status) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_tenants_slug ON tenants.tenants(slug) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_tenants_stripe_customer ON tenants.tenants(stripe_customer_id) WHERE stripe_customer_id IS NOT NULL;
|
|
CREATE INDEX idx_tenants_plan ON tenants.tenants(plan_id) WHERE deleted_at IS NULL;
|
|
|
|
-- Trigger for updated_at
|
|
CREATE OR REPLACE FUNCTION tenants.update_updated_at()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = NOW();
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE TRIGGER trg_tenants_updated_at
|
|
BEFORE UPDATE ON tenants.tenants
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION tenants.update_updated_at();
|
|
|
|
-- Comments
|
|
COMMENT ON TABLE tenants.tenants IS 'Core tenant table for multi-tenancy';
|
|
COMMENT ON COLUMN tenants.tenants.slug IS 'URL-safe identifier, used in subdomains';
|
|
COMMENT ON COLUMN tenants.tenants.settings IS 'Tenant-specific configuration (JSON)';
|
|
COMMENT ON COLUMN tenants.tenants.stripe_customer_id IS 'Stripe Customer ID for billing';
|