erp-construccion-database-v2/docs/POLITICA-CASCADAS-FK.md
Adrian Flores Cortes a9dcf86545 [ST-P3-001,ST-P3-003] docs: Add location fields and FK cascade policies
- ESTANDAR-CAMPOS-UBICACION.md: Standards for location fields (GEOMETRY vs DECIMAL)
- POLITICA-CASCADAS-FK.md: Foreign key cascade policy guide

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 07:48:46 -06:00

5.7 KiB

Política de Cascadas en Foreign Keys - ERP Construcción

Versión: 1.0.0 Fecha: 2026-02-03 Subtarea: ST-P3-003


Resumen

Este documento define la política para configurar acciones de CASCADE, SET NULL, RESTRICT y NO ACTION en foreign keys de la base de datos de ERP Construcción.


Opciones Disponibles

Acción ON DELETE ON UPDATE Descripción
CASCADE Propaga la acción a registros relacionados
SET NULL Establece NULL en la columna FK
SET DEFAULT Establece el valor DEFAULT
RESTRICT Bloquea si hay referencias (antes del commit)
NO ACTION Bloquea si hay referencias (al commit)

Estado Actual

Patrón dominante: ON DELETE CASCADE

El DDL actual usa CASCADE en todas las foreign keys. Esto es apropiado para:

  • Relaciones padre-hijo donde el hijo no tiene sentido sin el padre
  • Multi-tenancy (tenant_id → auth.tenants)
  • Tablas de detalle (items de una orden, líneas de una póliza)

Guía de Decisión

Usar ON DELETE CASCADE cuando:

  1. Relación de composición - El hijo no existe sin el padre

    -- Items de una orden de compra
    order_id UUID NOT NULL REFERENCES purchase.orders(id) ON DELETE CASCADE
    
  2. Multi-tenancy - Todos los datos del tenant se eliminan juntos

    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE
    
  3. Tablas de detalle/líneas

    • estimacion_conceptosestimaciones
    • accounting_entry_linesaccounting_entries
    • approval_stepsapproval_instances
  4. Historial/Logs asociados

    • asset_locationsassets
    • document_versionsdocuments

Usar ON DELETE SET NULL cuando:

  1. Relación opcional - El registro puede existir sin la referencia

    -- Empleado asignado puede irse pero el ticket persiste
    assigned_to UUID REFERENCES hr.employees(id) ON DELETE SET NULL
    
  2. Referencias a usuarios - El usuario se va pero el registro queda

    created_by UUID REFERENCES auth.users(id) ON DELETE SET NULL
    updated_by UUID REFERENCES auth.users(id) ON DELETE SET NULL
    
  3. Referencias a catálogos opcionales

    category_id UUID REFERENCES catalogs.categories(id) ON DELETE SET NULL
    

Usar ON DELETE RESTRICT cuando:

  1. Proteger datos críticos - No permitir borrar si hay referencias

    -- No borrar un proyecto si tiene estimaciones
    proyecto_id UUID NOT NULL REFERENCES construction.proyectos(id) ON DELETE RESTRICT
    
  2. Entidades maestras con dependencias de negocio

    -- No borrar proveedor si tiene órdenes de compra
    supplier_id UUID NOT NULL REFERENCES partners.suppliers(id) ON DELETE RESTRICT
    
  3. Datos contables/legales

    -- No borrar cuenta contable si tiene movimientos
    account_id UUID NOT NULL REFERENCES finance.chart_of_accounts(id) ON DELETE RESTRICT
    

Usar NO ACTION cuando:

Similar a RESTRICT, pero permite verificaciones diferidas dentro de una transacción. Usar cuando se necesita reordenar operaciones dentro de una transacción.


ON UPDATE

Recomendación General: NO especificar

Las primary keys son UUIDs inmutables. No hay necesidad de propagar cambios.

-- UUID nunca cambia, no necesita ON UPDATE
id UUID PRIMARY KEY DEFAULT gen_random_uuid()

Si se usa código natural como PK (no recomendado):

-- Solo si el código puede cambiar
codigo VARCHAR(20) PRIMARY KEY,
-- FK con ON UPDATE CASCADE
producto_codigo VARCHAR(20) REFERENCES productos(codigo) ON UPDATE CASCADE

Tabla de Referencia Rápida

Tipo de Relación ON DELETE Ejemplo
Tenant → Datos CASCADE tenant_id → auth.tenants
Padre → Hijos (composición) CASCADE order → order_items
Referencia opcional SET NULL assigned_to → employees
Auditoría (created_by) SET NULL created_by → users
Entidad maestra protegida RESTRICT proyecto → estimaciones
Catálogo con dependencias RESTRICT account → movements

Aplicación en Schemas Existentes

construction

FK Actual Recomendado Razón
fraccionamientos.tenant_id CASCADE CASCADE Multi-tenant
etapas.fraccionamiento_id CASCADE CASCADE Composición
avances.responsable_id CASCADE SET NULL Usuario puede irse

estimates

FK Actual Recomendado Razón
estimaciones.proyecto_id CASCADE RESTRICT Proteger datos
conceptos_estimacion.estimacion_id CASCADE CASCADE Composición

finance

FK Actual Recomendado Razón
accounting_entries.tenant_id CASCADE CASCADE Multi-tenant
entry_lines.entry_id CASCADE CASCADE Composición
entry_lines.account_id - RESTRICT No borrar cuenta con movimientos

Migración Sugerida

Para FK que deberían usar SET NULL o RESTRICT en lugar de CASCADE:

-- Ejemplo: Cambiar CASCADE a RESTRICT
ALTER TABLE estimates.estimaciones
DROP CONSTRAINT estimaciones_proyecto_id_fkey;

ALTER TABLE estimates.estimaciones
ADD CONSTRAINT estimaciones_proyecto_id_fkey
FOREIGN KEY (proyecto_id) REFERENCES construction.proyectos(id)
ON DELETE RESTRICT;

Nota: Evaluar impacto en lógica de aplicación antes de cambiar.


Referencias


Documentado: 2026-02-03 - ST-P3-003