# DDL SPECIFICATION: Schema Compliance (INFONAVIT)

**Version:** 1.0.0
**Fecha:** 2025-12-05
**Schema:** `compliance`
**Modulos:** MAI-011 (INFONAVIT Cumplimiento)

---

## Resumen

| Metrica | Valor |
|---------|-------|
| Total Tablas | 10 |
| ENUMs | 6 |
| Funciones | 4 |
| Triggers | 3 |
| Indices | 25+ |

---

## 1. ENUMs

```sql
-- Tipos de programa INFONAVIT
CREATE TYPE compliance.program_type AS ENUM (
  'evc',              -- Esquemas de Valor Compartido
  'traditional',      -- Credito tradicional
  'cofinavit',        -- Credito mixto INFONAVIT + bancario
  'infonavit_total',  -- Credito con subsidio
  'apoyo_infonavit',  -- Solo subsidio
  'mejoravit',        -- Mejora de vivienda
  'unamos_creditos'   -- Creditos combinados
);

-- Categorias de requisito
CREATE TYPE compliance.requirement_category AS ENUM (
  'technical',       -- Requisitos tecnicos
  'urban',           -- Requisitos urbanos
  'services',        -- Requisitos de servicios
  'legal',           -- Requisitos legales
  'environmental'    -- Requisitos ambientales
);

-- Estados de requisito
CREATE TYPE compliance.requirement_status AS ENUM (
  'pending',         -- Pendiente
  'in_progress',     -- En proceso
  'compliant',       -- Cumple
  'non_compliant',   -- No cumple
  'not_applicable'   -- No aplica
);

-- Tipos de auditoria
CREATE TYPE compliance.audit_type AS ENUM (
  'initial',         -- Inicial
  'progress',        -- Avance
  'final',           -- Final
  'special',         -- Especial
  'random'           -- Aleatoria
);

-- Estados de auditoria
CREATE TYPE compliance.audit_status AS ENUM (
  'scheduled',       -- Programada
  'in_progress',     -- En curso
  'completed',       -- Completada
  'follow_up',       -- En seguimiento
  'cancelled'        -- Cancelada
);

-- Severidad de hallazgo
CREATE TYPE compliance.finding_severity AS ENUM (
  'minor',           -- Menor (30 dias para corregir)
  'major',           -- Mayor (15 dias para corregir)
  'critical'         -- Critico (7 dias para corregir)
);
```

---

## 2. Tablas

### 2.1 infonavit_programs (Programas INFONAVIT)

```sql
CREATE TABLE compliance.infonavit_programs (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES core.tenants(id),

  -- Identificacion
  code VARCHAR(20) NOT NULL,
  name VARCHAR(200) NOT NULL,
  description TEXT,
  program_type compliance.program_type NOT NULL,

  -- Vigencia
  valid_from DATE,
  valid_to DATE,

  -- Estado
  is_active BOOLEAN DEFAULT true,

  -- Metadata
  requirements_count INTEGER DEFAULT 0,

  -- Auditoria
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID REFERENCES core.users(id),
  updated_at TIMESTAMP,
  updated_by UUID REFERENCES core.users(id),
  deleted_at TIMESTAMP,

  CONSTRAINT uq_programs_code UNIQUE (tenant_id, code)
);

CREATE INDEX idx_programs_tenant ON compliance.infonavit_programs(tenant_id);
CREATE INDEX idx_programs_type ON compliance.infonavit_programs(program_type);
CREATE INDEX idx_programs_active ON compliance.infonavit_programs(tenant_id) WHERE is_active = true;
```

### 2.2 program_requirements (Requisitos por Programa)

```sql
CREATE TABLE compliance.program_requirements (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES core.tenants(id),
  program_id UUID NOT NULL REFERENCES compliance.infonavit_programs(id),

  -- Identificacion
  code VARCHAR(30) NOT NULL,
  name VARCHAR(300) NOT NULL,
  description TEXT,

  -- Clasificacion
  category compliance.requirement_category NOT NULL,
  subcategory VARCHAR(100),

  -- Evidencia requerida
  evidence_required TEXT[],  -- Lista de tipos de evidencia
  evidence_description TEXT,

  -- Orden y jerarquia
  sort_order INTEGER DEFAULT 0,
  parent_id UUID REFERENCES compliance.program_requirements(id),

  -- Estado
  is_mandatory BOOLEAN DEFAULT true,
  is_active BOOLEAN DEFAULT true,

  -- Auditoria
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID REFERENCES core.users(id),
  updated_at TIMESTAMP,
  updated_by UUID REFERENCES core.users(id),

  CONSTRAINT uq_requirements_code UNIQUE (program_id, code)
);

CREATE INDEX idx_requirements_program ON compliance.program_requirements(program_id);
CREATE INDEX idx_requirements_category ON compliance.program_requirements(category);
CREATE INDEX idx_requirements_parent ON compliance.program_requirements(parent_id);
```

### 2.3 project_programs (Proyectos en Programas)

```sql
CREATE TABLE compliance.project_programs (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES core.tenants(id),
  project_id UUID NOT NULL REFERENCES construction.projects(id),
  program_id UUID NOT NULL REFERENCES compliance.infonavit_programs(id),

  -- Registro
  registration_number VARCHAR(50),
  registration_date DATE,

  -- Vigencia
  valid_from DATE,
  valid_to DATE,

  -- Estado de cumplimiento
  compliance_percentage DECIMAL(5,2) DEFAULT 0,
  total_requirements INTEGER DEFAULT 0,
  compliant_count INTEGER DEFAULT 0,
  non_compliant_count INTEGER DEFAULT 0,
  pending_count INTEGER DEFAULT 0,

  -- Estado
  status VARCHAR(20) DEFAULT 'active',

  -- Auditoria
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID REFERENCES core.users(id),
  updated_at TIMESTAMP,
  updated_by UUID REFERENCES core.users(id),
  deleted_at TIMESTAMP,

  CONSTRAINT uq_project_program UNIQUE (project_id, program_id)
);

CREATE INDEX idx_project_programs_project ON compliance.project_programs(project_id);
CREATE INDEX idx_project_programs_program ON compliance.project_programs(program_id);
```

### 2.4 compliance_items (Items de Cumplimiento)

```sql
CREATE TABLE compliance.compliance_items (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES core.tenants(id),
  project_program_id UUID NOT NULL REFERENCES compliance.project_programs(id),
  requirement_id UUID NOT NULL REFERENCES compliance.program_requirements(id),

  -- Estado
  status compliance.requirement_status NOT NULL DEFAULT 'pending',
  previous_status compliance.requirement_status,

  -- Verificacion
  verified_by UUID REFERENCES core.users(id),
  verified_at TIMESTAMP,
  verification_notes TEXT,

  -- Fechas limite
  due_date DATE,
  completed_date DATE,

  -- Notas
  notes TEXT,
  is_not_applicable BOOLEAN DEFAULT false,
  na_reason TEXT,

  -- Auditoria
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID REFERENCES core.users(id),
  updated_at TIMESTAMP,
  updated_by UUID REFERENCES core.users(id),

  CONSTRAINT uq_compliance_item UNIQUE (project_program_id, requirement_id)
);

CREATE INDEX idx_compliance_items_project_program ON compliance.compliance_items(project_program_id);
CREATE INDEX idx_compliance_items_requirement ON compliance.compliance_items(requirement_id);
CREATE INDEX idx_compliance_items_status ON compliance.compliance_items(status);
CREATE INDEX idx_compliance_items_pending ON compliance.compliance_items(project_program_id)
  WHERE status IN ('pending', 'in_progress');
```

### 2.5 compliance_evidence (Evidencias)

```sql
CREATE TABLE compliance.compliance_evidence (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES core.tenants(id),
  compliance_item_id UUID NOT NULL REFERENCES compliance.compliance_items(id),

  -- Archivo
  file_url TEXT NOT NULL,
  file_name VARCHAR(255) NOT NULL,
  file_size INTEGER,
  mime_type VARCHAR(100),
  thumbnail_url TEXT,

  -- Tipo de evidencia
  evidence_type VARCHAR(50),  -- document, photo, video, certificate
  description TEXT,

  -- Metadata
  taken_at TIMESTAMP,
  location GEOGRAPHY(POINT, 4326),
  metadata JSONB,

  -- Estado
  status VARCHAR(20) DEFAULT 'active',  -- active, replaced, rejected

  -- Revision
  reviewed_by UUID REFERENCES core.users(id),
  reviewed_at TIMESTAMP,
  review_notes TEXT,

  -- Auditoria
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID REFERENCES core.users(id),
  updated_at TIMESTAMP,
  updated_by UUID REFERENCES core.users(id),
  deleted_at TIMESTAMP
);

CREATE INDEX idx_evidence_compliance_item ON compliance.compliance_evidence(compliance_item_id);
CREATE INDEX idx_evidence_type ON compliance.compliance_evidence(evidence_type);
CREATE INDEX idx_evidence_status ON compliance.compliance_evidence(status);
```

### 2.6 audits (Auditorias)

```sql
CREATE TABLE compliance.audits (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES core.tenants(id),
  project_id UUID NOT NULL REFERENCES construction.projects(id),

  -- Identificacion
  audit_number VARCHAR(30) NOT NULL,
  audit_type compliance.audit_type NOT NULL,

  -- Programacion
  scheduled_date DATE NOT NULL,
  scheduled_time TIME,
  actual_date DATE,

  -- Auditor
  auditor_name VARCHAR(200),
  auditor_company VARCHAR(200),
  auditor_contact TEXT,

  -- Estado
  status compliance.audit_status NOT NULL DEFAULT 'scheduled',

  -- Resultados
  overall_compliance_percentage DECIMAL(5,2),
  findings_count INTEGER DEFAULT 0,
  critical_findings INTEGER DEFAULT 0,
  major_findings INTEGER DEFAULT 0,
  minor_findings INTEGER DEFAULT 0,

  -- Documentacion
  report_url TEXT,
  notes TEXT,

  -- Cierre
  closed_at TIMESTAMP,
  closed_by UUID REFERENCES core.users(id),

  -- Auditoria
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID REFERENCES core.users(id),
  updated_at TIMESTAMP,
  updated_by UUID REFERENCES core.users(id),
  deleted_at TIMESTAMP,

  CONSTRAINT uq_audits_number UNIQUE (tenant_id, audit_number)
);

CREATE INDEX idx_audits_project ON compliance.audits(project_id);
CREATE INDEX idx_audits_status ON compliance.audits(status);
CREATE INDEX idx_audits_date ON compliance.audits(scheduled_date);
CREATE INDEX idx_audits_type ON compliance.audits(audit_type);
```

### 2.7 audit_findings (Hallazgos de Auditoria)

```sql
CREATE TABLE compliance.audit_findings (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES core.tenants(id),
  audit_id UUID NOT NULL REFERENCES compliance.audits(id),
  compliance_item_id UUID REFERENCES compliance.compliance_items(id),

  -- Identificacion
  finding_number VARCHAR(30) NOT NULL,
  severity compliance.finding_severity NOT NULL,

  -- Descripcion
  title VARCHAR(300) NOT NULL,
  description TEXT NOT NULL,
  evidence_refs TEXT[],  -- Referencias a evidencias

  -- Requisito incumplido
  requirement_code VARCHAR(30),
  requirement_name VARCHAR(300),

  -- Responsable
  responsible_name VARCHAR(200),
  responsible_area VARCHAR(100),

  -- Fechas
  due_date DATE NOT NULL,
  resolution_date DATE,

  -- Estado
  status VARCHAR(20) DEFAULT 'open',  -- open, in_progress, resolved, verified, closed

  -- Auditoria
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID REFERENCES core.users(id),
  updated_at TIMESTAMP,
  updated_by UUID REFERENCES core.users(id),

  CONSTRAINT uq_findings_number UNIQUE (audit_id, finding_number)
);

CREATE INDEX idx_findings_audit ON compliance.audit_findings(audit_id);
CREATE INDEX idx_findings_compliance_item ON compliance.audit_findings(compliance_item_id);
CREATE INDEX idx_findings_severity ON compliance.audit_findings(severity);
CREATE INDEX idx_findings_status ON compliance.audit_findings(status);
CREATE INDEX idx_findings_open ON compliance.audit_findings(audit_id) WHERE status NOT IN ('verified', 'closed');
```

### 2.8 corrective_actions (Acciones Correctivas)

```sql
CREATE TABLE compliance.corrective_actions (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES core.tenants(id),
  finding_id UUID NOT NULL REFERENCES compliance.audit_findings(id),

  -- Identificacion
  action_number VARCHAR(30) NOT NULL,

  -- Accion
  description TEXT NOT NULL,
  action_type VARCHAR(50),  -- correction, prevention, improvement

  -- Asignacion
  assigned_to UUID REFERENCES core.users(id),
  assigned_to_name VARCHAR(200),
  assigned_at TIMESTAMP,

  -- Fechas
  due_date DATE NOT NULL,
  completed_date DATE,

  -- Estado
  status VARCHAR(20) DEFAULT 'pending',  -- pending, in_progress, completed, verified

  -- Verificacion
  verified_by UUID REFERENCES core.users(id),
  verified_at TIMESTAMP,
  verification_notes TEXT,

  -- Auditoria
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID REFERENCES core.users(id),
  updated_at TIMESTAMP,
  updated_by UUID REFERENCES core.users(id)
);

CREATE INDEX idx_corrective_finding ON compliance.corrective_actions(finding_id);
CREATE INDEX idx_corrective_assigned ON compliance.corrective_actions(assigned_to);
CREATE INDEX idx_corrective_status ON compliance.corrective_actions(status);
CREATE INDEX idx_corrective_due ON compliance.corrective_actions(due_date) WHERE status NOT IN ('completed', 'verified');
```

### 2.9 compliance_alerts (Alertas de Cumplimiento)

```sql
CREATE TABLE compliance.compliance_alerts (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES core.tenants(id),
  project_id UUID NOT NULL REFERENCES construction.projects(id),

  -- Tipo de alerta
  alert_type VARCHAR(50) NOT NULL,  -- requirement_due, audit_scheduled, finding_due, low_compliance
  severity VARCHAR(20) NOT NULL,    -- info, warning, critical

  -- Referencia
  reference_type VARCHAR(50),       -- compliance_item, audit, finding
  reference_id UUID,

  -- Contenido
  title VARCHAR(300) NOT NULL,
  message TEXT NOT NULL,

  -- Destinatarios
  recipients UUID[],

  -- Estado
  status VARCHAR(20) DEFAULT 'active',  -- active, acknowledged, dismissed
  acknowledged_by UUID REFERENCES core.users(id),
  acknowledged_at TIMESTAMP,

  -- Vigencia
  expires_at TIMESTAMP,

  -- Auditoria
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID REFERENCES core.users(id)
);

CREATE INDEX idx_alerts_project ON compliance.compliance_alerts(project_id);
CREATE INDEX idx_alerts_type ON compliance.compliance_alerts(alert_type);
CREATE INDEX idx_alerts_status ON compliance.compliance_alerts(status);
CREATE INDEX idx_alerts_active ON compliance.compliance_alerts(project_id) WHERE status = 'active';
```

### 2.10 compliance_history (Historial de Cambios)

```sql
CREATE TABLE compliance.compliance_history (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES core.tenants(id),

  -- Referencia
  entity_type VARCHAR(50) NOT NULL,  -- compliance_item, finding, corrective_action
  entity_id UUID NOT NULL,

  -- Cambio
  action VARCHAR(50) NOT NULL,       -- status_change, evidence_added, verified, etc
  previous_value JSONB,
  new_value JSONB,
  change_reason TEXT,

  -- Auditoria
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_by UUID REFERENCES core.users(id)
);

CREATE INDEX idx_history_entity ON compliance.compliance_history(entity_type, entity_id);
CREATE INDEX idx_history_date ON compliance.compliance_history(created_at);
```

---

## 3. Funciones

### 3.1 Calcular Porcentaje de Cumplimiento

```sql
CREATE OR REPLACE FUNCTION compliance.calculate_compliance_percentage(p_project_program_id UUID)
RETURNS VOID AS $$
DECLARE
  v_total INTEGER;
  v_compliant INTEGER;
  v_non_compliant INTEGER;
  v_pending INTEGER;
  v_percentage DECIMAL(5,2);
BEGIN
  -- Contar por estado
  SELECT
    COUNT(*) FILTER (WHERE status != 'not_applicable'),
    COUNT(*) FILTER (WHERE status = 'compliant'),
    COUNT(*) FILTER (WHERE status = 'non_compliant'),
    COUNT(*) FILTER (WHERE status IN ('pending', 'in_progress'))
  INTO v_total, v_compliant, v_non_compliant, v_pending
  FROM compliance.compliance_items
  WHERE project_program_id = p_project_program_id;

  -- Calcular porcentaje
  IF v_total > 0 THEN
    v_percentage := (v_compliant::DECIMAL / v_total) * 100;
  ELSE
    v_percentage := 0;
  END IF;

  -- Actualizar project_program
  UPDATE compliance.project_programs
  SET
    total_requirements = v_total,
    compliant_count = v_compliant,
    non_compliant_count = v_non_compliant,
    pending_count = v_pending,
    compliance_percentage = v_percentage,
    updated_at = CURRENT_TIMESTAMP
  WHERE id = p_project_program_id;
END;
$$ LANGUAGE plpgsql;
```

### 3.2 Crear Items de Cumplimiento al Registrar Proyecto

```sql
CREATE OR REPLACE FUNCTION compliance.create_compliance_items_for_project()
RETURNS TRIGGER AS $$
BEGIN
  -- Crear items para cada requisito del programa
  INSERT INTO compliance.compliance_items (
    tenant_id, project_program_id, requirement_id, status, created_by
  )
  SELECT
    NEW.tenant_id,
    NEW.id,
    pr.id,
    'pending',
    NEW.created_by
  FROM compliance.program_requirements pr
  WHERE pr.program_id = NEW.program_id
    AND pr.is_active = true;

  -- Calcular porcentaje inicial
  PERFORM compliance.calculate_compliance_percentage(NEW.id);

  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_create_compliance_items
AFTER INSERT ON compliance.project_programs
FOR EACH ROW
EXECUTE FUNCTION compliance.create_compliance_items_for_project();
```

### 3.3 Actualizar Porcentaje al Cambiar Estado

```sql
CREATE OR REPLACE FUNCTION compliance.on_compliance_item_change()
RETURNS TRIGGER AS $$
BEGIN
  -- Registrar historial
  INSERT INTO compliance.compliance_history (
    tenant_id, entity_type, entity_id, action,
    previous_value, new_value, created_by
  )
  VALUES (
    NEW.tenant_id,
    'compliance_item',
    NEW.id,
    'status_change',
    jsonb_build_object('status', OLD.status),
    jsonb_build_object('status', NEW.status),
    NEW.updated_by
  );

  -- Recalcular porcentaje
  PERFORM compliance.calculate_compliance_percentage(NEW.project_program_id);

  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_compliance_item_change
AFTER UPDATE OF status ON compliance.compliance_items
FOR EACH ROW
WHEN (OLD.status IS DISTINCT FROM NEW.status)
EXECUTE FUNCTION compliance.on_compliance_item_change();
```

### 3.4 Generar Alertas de Vencimiento

```sql
CREATE OR REPLACE FUNCTION compliance.generate_due_date_alerts()
RETURNS INTEGER AS $$
DECLARE
  v_count INTEGER := 0;
BEGIN
  -- Alertas para requisitos proximos a vencer (7 dias)
  INSERT INTO compliance.compliance_alerts (
    tenant_id, project_id, alert_type, severity,
    reference_type, reference_id, title, message, expires_at
  )
  SELECT
    ci.tenant_id,
    pp.project_id,
    'requirement_due',
    CASE
      WHEN ci.due_date < CURRENT_DATE THEN 'critical'
      WHEN ci.due_date <= CURRENT_DATE + INTERVAL '3 days' THEN 'warning'
      ELSE 'info'
    END,
    'compliance_item',
    ci.id,
    'Requisito proximo a vencer: ' || pr.name,
    format('El requisito %s vence el %s', pr.code, ci.due_date::TEXT),
    ci.due_date + INTERVAL '1 day'
  FROM compliance.compliance_items ci
  JOIN compliance.project_programs pp ON pp.id = ci.project_program_id
  JOIN compliance.program_requirements pr ON pr.id = ci.requirement_id
  WHERE ci.status IN ('pending', 'in_progress')
    AND ci.due_date IS NOT NULL
    AND ci.due_date <= CURRENT_DATE + INTERVAL '7 days'
    AND NOT EXISTS (
      SELECT 1 FROM compliance.compliance_alerts ca
      WHERE ca.reference_id = ci.id
        AND ca.alert_type = 'requirement_due'
        AND ca.status = 'active'
    );

  GET DIAGNOSTICS v_count = ROW_COUNT;
  RETURN v_count;
END;
$$ LANGUAGE plpgsql;
```

---

## 4. Row Level Security

```sql
-- Habilitar RLS en todas las tablas
ALTER TABLE compliance.infonavit_programs ENABLE ROW LEVEL SECURITY;
ALTER TABLE compliance.program_requirements ENABLE ROW LEVEL SECURITY;
ALTER TABLE compliance.project_programs ENABLE ROW LEVEL SECURITY;
ALTER TABLE compliance.compliance_items ENABLE ROW LEVEL SECURITY;
ALTER TABLE compliance.compliance_evidence ENABLE ROW LEVEL SECURITY;
ALTER TABLE compliance.audits ENABLE ROW LEVEL SECURITY;
ALTER TABLE compliance.audit_findings ENABLE ROW LEVEL SECURITY;
ALTER TABLE compliance.corrective_actions ENABLE ROW LEVEL SECURITY;
ALTER TABLE compliance.compliance_alerts ENABLE ROW LEVEL SECURITY;
ALTER TABLE compliance.compliance_history ENABLE ROW LEVEL SECURITY;

-- Crear politicas de aislamiento por tenant
DO $$
DECLARE
  t TEXT;
BEGIN
  FOR t IN SELECT tablename FROM pg_tables WHERE schemaname = 'compliance'
  LOOP
    EXECUTE format('
      CREATE POLICY tenant_isolation ON compliance.%I
      USING (tenant_id = current_setting(''app.current_tenant_id'')::uuid)
    ', t);
  END LOOP;
END $$;
```

---

## 5. Seeds Iniciales

```sql
-- Programas INFONAVIT base
INSERT INTO compliance.infonavit_programs (tenant_id, code, name, program_type, is_active)
VALUES
  ('{{TENANT_ID}}', 'EVC', 'Esquemas de Valor Compartido', 'evc', true),
  ('{{TENANT_ID}}', 'TRAD', 'Credito Tradicional', 'traditional', true),
  ('{{TENANT_ID}}', 'COFI', 'Cofinavit', 'cofinavit', true),
  ('{{TENANT_ID}}', 'TOTAL', 'INFONAVIT Total', 'infonavit_total', true),
  ('{{TENANT_ID}}', 'APOYO', 'Apoyo INFONAVIT', 'apoyo_infonavit', true);

-- Requisitos tecnicos base (ejemplo para EVC)
INSERT INTO compliance.program_requirements (tenant_id, program_id, code, name, category, is_mandatory)
SELECT
  '{{TENANT_ID}}',
  p.id,
  code,
  name,
  'technical'::compliance.requirement_category,
  true
FROM compliance.infonavit_programs p
CROSS JOIN (VALUES
  ('TEC-001', 'Superficie construida minima 38 m2'),
  ('TEC-002', 'Altura minima de entrepiso 2.30 m'),
  ('TEC-003', 'Recamara principal minimo 7 m2'),
  ('TEC-004', 'Bano completo con regadera'),
  ('TEC-005', 'Cocina con espacio para estufa y refrigerador'),
  ('TEC-006', 'Sistema electrico con centro de carga'),
  ('TEC-007', 'Sistema hidraulico con tinaco'),
  ('TEC-008', 'Sistema sanitario conectado a drenaje'),
  ('TEC-009', 'Canceleria completa en ventanas'),
  ('TEC-010', 'Puertas de acceso con chapa de seguridad')
) AS reqs(code, name)
WHERE p.code = 'EVC';
```

---

## Referencias

- [MAI-011: INFONAVIT Cumplimiento](../../02-definicion-modulos/MAI-011-infonavit-cumplimiento/)
- [EPIC-MAI-011](../../08-epicas/EPIC-MAI-011-infonavit.md)
- [ADR-007: Database Design](../../97-adr/ADR-007-database-design.md)

---

*Ultima actualizacion: 2025-12-05*
