erp-core/docs/02-fase-core-business/MGN-006-settings/especificaciones/ET-SETTINGS-database.md

13 KiB

DDL-SPEC: Schema core_settings

Identificacion

Campo Valor
Schema core_settings
Modulo MGN-006
Version 1.0
Estado En Diseno
Autor Requirements-Analyst
Fecha 2025-12-05

Descripcion General

El schema core_settings gestiona configuraciones del sistema, por tenant, preferencias de usuario y feature flags. Implementa herencia de configuraciones y evaluacion eficiente de flags.

RF Cubiertos

RF Titulo Tablas
RF-SETTINGS-001 Configuraciones Sistema system_settings
RF-SETTINGS-002 Configuraciones Tenant tenant_settings, plan_settings
RF-SETTINGS-003 Preferencias Usuario user_preferences
RF-SETTINGS-004 Feature Flags feature_flags, feature_flag_overrides

Diagrama ER

erDiagram
    system_settings {
        uuid id PK
        varchar key UK
        jsonb value
        varchar data_type
        varchar category
        text description
        boolean is_public
        boolean is_editable
        jsonb default_value
        jsonb validation_rules
    }

    plan_settings {
        uuid id PK
        uuid plan_id FK
        varchar key
        jsonb value
    }

    tenant_settings {
        uuid id PK
        uuid tenant_id FK
        varchar key
        jsonb value
        varchar inherited_from
        boolean is_overridden
    }

    user_preferences {
        uuid id PK
        uuid user_id FK
        varchar key
        jsonb value
        timestamptz synced_at
    }

    feature_flags {
        uuid id PK
        varchar key UK
        varchar name
        text description
        varchar flag_type
        jsonb default_value
        jsonb rollout_config
        boolean is_active
        timestamptz expires_at
    }

    feature_flag_overrides {
        uuid id PK
        uuid feature_flag_id FK
        varchar level
        uuid level_id
        jsonb value
        boolean is_active
    }

    plan_settings }o--|| subscription_plans : "plan"
    tenant_settings }o--|| tenants : "tenant"
    user_preferences }o--|| users : "user"
    feature_flag_overrides }o--|| feature_flags : "flag"

Tablas

1. system_settings

Configuraciones globales del sistema.

Columna Tipo Nullable Default Descripcion
id UUID NOT NULL gen_random_uuid() PK
key VARCHAR(100) NOT NULL - Clave unica
value JSONB NOT NULL - Valor actual
data_type VARCHAR(20) NOT NULL 'string' Tipo de dato
category VARCHAR(50) NOT NULL - Categoria
description TEXT NULL - Descripcion UI
is_public BOOLEAN NOT NULL false Visible a tenants
is_editable BOOLEAN NOT NULL true Modificable runtime
default_value JSONB NULL - Valor por defecto
validation_rules JSONB NULL '{}' Reglas validacion
created_at TIMESTAMPTZ NOT NULL NOW() Fecha creacion
updated_at TIMESTAMPTZ NOT NULL NOW() Fecha actualizacion
updated_by UUID NULL - Usuario modificador
CONSTRAINT pk_system_settings PRIMARY KEY (id),
CONSTRAINT uk_system_settings_key UNIQUE (key),
CONSTRAINT chk_system_settings_data_type
    CHECK (data_type IN ('string', 'number', 'boolean', 'json', 'array', 'secret'))
CREATE INDEX idx_system_settings_category ON core_settings.system_settings(category);
CREATE INDEX idx_system_settings_public ON core_settings.system_settings(is_public) WHERE is_public = true;

2. plan_settings

Configuraciones por defecto por plan de suscripcion.

Columna Tipo Nullable Default Descripcion
id UUID NOT NULL gen_random_uuid() PK
plan_id UUID NOT NULL - FK a subscription_plans
key VARCHAR(100) NOT NULL - Clave de setting
value JSONB NOT NULL - Valor para el plan
created_at TIMESTAMPTZ NOT NULL NOW() Fecha creacion
updated_at TIMESTAMPTZ NOT NULL NOW() Fecha actualizacion
CONSTRAINT pk_plan_settings PRIMARY KEY (id),
CONSTRAINT uk_plan_settings_plan_key UNIQUE (plan_id, key),
CONSTRAINT fk_plan_settings_plan
    FOREIGN KEY (plan_id) REFERENCES core_tenants.subscription_plans(id) ON DELETE CASCADE

3. tenant_settings

Configuraciones personalizadas por tenant.

Columna Tipo Nullable Default Descripcion
id UUID NOT NULL gen_random_uuid() PK
tenant_id UUID NOT NULL - FK a tenants
key VARCHAR(100) NOT NULL - Clave de setting
value JSONB NOT NULL - Valor personalizado
inherited_from VARCHAR(20) NOT NULL 'custom' system/plan/custom
is_overridden BOOLEAN NOT NULL true Sobreescribe herencia
created_at TIMESTAMPTZ NOT NULL NOW() Fecha creacion
updated_at TIMESTAMPTZ NOT NULL NOW() Fecha actualizacion
CONSTRAINT pk_tenant_settings PRIMARY KEY (id),
CONSTRAINT uk_tenant_settings_tenant_key UNIQUE (tenant_id, key),
CONSTRAINT fk_tenant_settings_tenant
    FOREIGN KEY (tenant_id) REFERENCES core_tenants.tenants(id) ON DELETE CASCADE,
CONSTRAINT chk_tenant_settings_inherited
    CHECK (inherited_from IN ('system', 'plan', 'custom'))
-- RLS
ALTER TABLE core_settings.tenant_settings ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON core_settings.tenant_settings
    FOR ALL USING (tenant_id = current_setting('app.current_tenant_id')::uuid);

4. user_preferences

Preferencias personales de usuario.

Columna Tipo Nullable Default Descripcion
id UUID NOT NULL gen_random_uuid() PK
user_id UUID NOT NULL - FK a users
key VARCHAR(100) NOT NULL - Clave de preferencia
value JSONB NOT NULL - Valor
synced_at TIMESTAMPTZ NOT NULL NOW() Ultima sync
created_at TIMESTAMPTZ NOT NULL NOW() Fecha creacion
updated_at TIMESTAMPTZ NOT NULL NOW() Fecha actualizacion
CONSTRAINT pk_user_preferences PRIMARY KEY (id),
CONSTRAINT uk_user_preferences_user_key UNIQUE (user_id, key),
CONSTRAINT fk_user_preferences_user
    FOREIGN KEY (user_id) REFERENCES core_users.users(id) ON DELETE CASCADE

5. feature_flags

Definicion de feature flags.

Columna Tipo Nullable Default Descripcion
id UUID NOT NULL gen_random_uuid() PK
key VARCHAR(100) NOT NULL - Clave unica
name VARCHAR(255) NOT NULL - Nombre descriptivo
description TEXT NULL - Descripcion
flag_type VARCHAR(20) NOT NULL 'boolean' boolean/percentage/variant
default_value JSONB NOT NULL 'false' Valor por defecto
rollout_config JSONB NULL '{}' Config de rollout
is_active BOOLEAN NOT NULL true Flag activo
expires_at TIMESTAMPTZ NULL - Expiracion
created_at TIMESTAMPTZ NOT NULL NOW() Fecha creacion
updated_at TIMESTAMPTZ NOT NULL NOW() Fecha actualizacion
created_by UUID NULL - Usuario creador
CONSTRAINT pk_feature_flags PRIMARY KEY (id),
CONSTRAINT uk_feature_flags_key UNIQUE (key),
CONSTRAINT chk_feature_flags_type
    CHECK (flag_type IN ('boolean', 'percentage', 'variant'))

6. feature_flag_overrides

Overrides de flags por nivel.

Columna Tipo Nullable Default Descripcion
id UUID NOT NULL gen_random_uuid() PK
feature_flag_id UUID NOT NULL - FK a feature_flags
level VARCHAR(20) NOT NULL - plan/tenant/user
level_id UUID NOT NULL - ID del nivel
value JSONB NOT NULL - Valor override
is_active BOOLEAN NOT NULL true Override activo
created_at TIMESTAMPTZ NOT NULL NOW() Fecha creacion
created_by UUID NULL - Usuario creador
CONSTRAINT pk_feature_flag_overrides PRIMARY KEY (id),
CONSTRAINT uk_feature_flag_overrides UNIQUE (feature_flag_id, level, level_id),
CONSTRAINT fk_feature_flag_overrides_flag
    FOREIGN KEY (feature_flag_id) REFERENCES core_settings.feature_flags(id) ON DELETE CASCADE,
CONSTRAINT chk_feature_flag_overrides_level
    CHECK (level IN ('plan', 'tenant', 'user'))
CREATE INDEX idx_feature_flag_overrides_lookup
    ON core_settings.feature_flag_overrides(feature_flag_id, level, level_id);

Funciones de Utilidad

Obtener Setting Efectivo del Tenant

CREATE OR REPLACE FUNCTION core_settings.get_tenant_setting(
    p_tenant_id UUID,
    p_key VARCHAR
) RETURNS JSONB AS $$
DECLARE
    v_value JSONB;
    v_plan_id UUID;
BEGIN
    -- 1. Buscar en tenant_settings
    SELECT value INTO v_value
    FROM core_settings.tenant_settings
    WHERE tenant_id = p_tenant_id AND key = p_key AND is_overridden = true;

    IF v_value IS NOT NULL THEN
        RETURN v_value;
    END IF;

    -- 2. Buscar en plan_settings
    SELECT t.plan_id INTO v_plan_id
    FROM core_tenants.tenants t WHERE t.id = p_tenant_id;

    SELECT value INTO v_value
    FROM core_settings.plan_settings
    WHERE plan_id = v_plan_id AND key = p_key;

    IF v_value IS NOT NULL THEN
        RETURN v_value;
    END IF;

    -- 3. Retornar system default
    SELECT COALESCE(value, default_value) INTO v_value
    FROM core_settings.system_settings
    WHERE key = p_key;

    RETURN v_value;
END;
$$ LANGUAGE plpgsql STABLE;

Evaluar Feature Flag

CREATE OR REPLACE FUNCTION core_settings.evaluate_feature_flag(
    p_key VARCHAR,
    p_tenant_id UUID DEFAULT NULL,
    p_user_id UUID DEFAULT NULL
) RETURNS JSONB AS $$
DECLARE
    v_flag RECORD;
    v_override JSONB;
    v_result JSONB;
BEGIN
    -- Obtener flag base
    SELECT * INTO v_flag
    FROM core_settings.feature_flags
    WHERE key = p_key AND is_active = true
    AND (expires_at IS NULL OR expires_at > NOW());

    IF v_flag IS NULL THEN
        RETURN jsonb_build_object('enabled', false, 'source', 'not_found');
    END IF;

    -- Buscar override por user
    IF p_user_id IS NOT NULL THEN
        SELECT value INTO v_override
        FROM core_settings.feature_flag_overrides
        WHERE feature_flag_id = v_flag.id AND level = 'user' AND level_id = p_user_id AND is_active = true;

        IF v_override IS NOT NULL THEN
            RETURN jsonb_build_object('enabled', v_override, 'source', 'user_override');
        END IF;
    END IF;

    -- Buscar override por tenant
    IF p_tenant_id IS NOT NULL THEN
        SELECT value INTO v_override
        FROM core_settings.feature_flag_overrides
        WHERE feature_flag_id = v_flag.id AND level = 'tenant' AND level_id = p_tenant_id AND is_active = true;

        IF v_override IS NOT NULL THEN
            RETURN jsonb_build_object('enabled', v_override, 'source', 'tenant_override');
        END IF;
    END IF;

    -- Retornar default
    RETURN jsonb_build_object('enabled', v_flag.default_value, 'source', 'default');
END;
$$ LANGUAGE plpgsql STABLE;

Seed Data

System Settings

INSERT INTO core_settings.system_settings (key, value, data_type, category, description, is_editable) VALUES
('security.max_login_attempts', '5', 'number', 'security', 'Intentos maximos de login', true),
('security.lockout_duration_minutes', '15', 'number', 'security', 'Duracion bloqueo en minutos', true),
('security.token_expiry_hours', '24', 'number', 'security', 'Expiracion token en horas', true),
('security.password_min_length', '8', 'number', 'security', 'Longitud minima password', true),
('email.smtp_host', '""', 'string', 'email', 'Host SMTP', true),
('email.smtp_port', '587', 'number', 'email', 'Puerto SMTP', true),
('storage.max_file_size_mb', '10', 'number', 'storage', 'Tamano maximo archivo MB', true),
('storage.allowed_extensions', '["pdf","jpg","png","xlsx"]', 'array', 'storage', 'Extensiones permitidas', true),
('performance.cache_ttl_seconds', '300', 'number', 'performance', 'TTL cache segundos', true),
('performance.pagination_max_limit', '100', 'number', 'performance', 'Max items por pagina', false);

Feature Flags

INSERT INTO core_settings.feature_flags (key, name, flag_type, default_value, description) VALUES
('feature.oauth_login', 'Login con OAuth', 'boolean', 'true', 'Habilita login con proveedores OAuth'),
('feature.dark_mode', 'Modo Oscuro', 'boolean', 'true', 'Habilita tema oscuro'),
('feature.export_excel', 'Exportar Excel', 'boolean', 'true', 'Permite exportar a Excel'),
('feature.bulk_operations', 'Operaciones Masivas', 'boolean', 'true', 'Permite operaciones en lote'),
('feature.ai_suggestions', 'Sugerencias IA', 'boolean', 'false', 'Sugerencias con IA');

Historial

Version Fecha Autor Cambios
1.0 2025-12-05 Requirements-Analyst Creacion inicial