template-saas-database-v2/ddl/schemas/tenants/tables/01-tenants.sql
rckrdmrd 3ce06fbce4 Initial commit - Database de template-saas migrado desde monorepo
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>
2026-01-16 08:07:11 -06:00

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';