# TRACEABILITY.yml - MAI-003: Presupuestos y Control de Costos
# Matriz completa de trazabilidad: Requerimientos → Especificaciones → Historias → Implementación

epic_code: MAI-003
epic_name: Presupuestos y Control de Costos
phase: 2
phase_name: Core Business
budget_mxn: 35000
story_points: 46
status: planned
sprint: 7-10
period: "Semanas 13-20"
reused_from_gamilit: 0%

# ============================================================================
# METADATA
# ============================================================================

metadata:
  modulo: MAI-003
  nombre: Presupuestos y Control de Costos
  version: 1.0.0
  fecha: 2025-12-06
  descripcion: Sistema integral de presupuestos de construcción en tres niveles (obra, etapa, prototipo), catálogo de conceptos con precios unitarios, control de costos reales y análisis de rentabilidad
  objetivo_negocio: Incrementar margen de utilidad +2 puntos mediante control preciso de costos, reducción 80% en tiempo de elaboración de presupuestos, y detección temprana de desviaciones
  impacto_esperado:
    - Eficiencia en elaboración de presupuestos (2h vs 10h)
    - Precisión en estimación de costos (<3% desviación vs real)
    - Control en tiempo real de costos
    - Mejora en rentabilidad por proyecto

# ============================================================================
# DOCUMENTACIÓN
# ============================================================================

documentation:
  requirements:
    - id: RF-COST-001
      file: requerimientos/RF-COST-001-catalogo-conceptos-precios.md
      title: Catálogo de Conceptos y Precios Unitarios
      status: planned
      reused_from: null
      adaptations:
        - "Sistema nuevo específico para construcción"
        - "4 tipos de conceptos: material, mano de obra, maquinaria, compuesto"
        - "Catálogo jerárquico por división CMIC (16 capítulos)"
        - "Análisis de precios unitarios (APU) detallado"
        - "Versionado y historial de precios"
        - "Regionalización de precios por plaza"

    - id: RF-COST-002
      file: requerimientos/RF-COST-002-presupuestos-maestros.md
      title: Presupuestos Maestros (Obra, Etapa, Prototipo)
      status: planned
      reused_from: null
      adaptations:
        - "3 niveles jerárquicos de presupuestos"
        - "Generadores automáticos de volumetrías"
        - "Versionado completo (baseline, ajustes, cambios)"
        - "Integración con catálogo de conceptos"
        - "Análisis de rentabilidad integrado"

    - id: RF-COST-003
      file: requerimientos/RF-COST-003-control-costos-reales.md
      title: Control de Costos Reales y Desviaciones
      status: planned
      reused_from: null
      adaptations:
        - "Registro automático desde compras, nómina, subcontratos"
        - "Dashboard con curva S"
        - "Cálculo de desviaciones (precio, cantidad, mixta)"
        - "Proyecciones EAC (3 métodos)"
        - "Alertas automáticas configurables"

    - id: RF-COST-004
      file: requerimientos/RF-COST-004-analisis-rentabilidad.md
      title: Análisis de Rentabilidad y Márgenes
      status: planned
      reused_from: null
      adaptations:
        - "Análisis financiero por proyecto y prototipo"
        - "Punto de equilibrio y margen de seguridad"
        - "Simulador de escenarios"
        - "Matriz de sensibilidad (precio vs costo)"
        - "ROI y TIR proyectados"

  specifications:
    - id: ET-COST-001
      file: especificaciones/ET-COST-001-implementacion-catalogo-conceptos.md
      rf: RF-COST-001
      title: Implementación del Catálogo de Conceptos
      status: planned
      reused_from: null
      adaptations:
        - "Schema budgets en PostgreSQL"
        - "Búsqueda full-text con índices GIN"
        - "Triggers para historial automático de precios"
        - "Cálculo automático de PU compuestos"

    - id: ET-COST-002
      file: especificaciones/ET-COST-002-implementacion-presupuestos.md
      rf: RF-COST-002
      title: Implementación de Presupuestos
      status: planned
      reused_from: null
      adaptations:
        - "Estructura jerárquica de partidas (3 niveles)"
        - "Wizard de creación desde prototipos"
        - "Triggers para cálculo automático de totales"
        - "Versionado con comparación"

    - id: ET-COST-003
      file: especificaciones/ET-COST-003-implementacion-control-costos.md
      rf: RF-COST-003
      title: Implementación de Control de Costos
      status: planned
      reused_from: null
      adaptations:
        - "Integración con módulos de Compras/Nómina/Subcontratos"
        - "Recálculo automático de desviaciones"
        - "Proyección EAC con múltiples métodos"
        - "Cron job diario para actualización (6:00 AM)"

    - id: ET-COST-004
      file: especificaciones/ET-COST-004-implementacion-analisis-rentabilidad.md
      rf: RF-COST-004
      title: Implementación de Análisis de Rentabilidad
      status: planned
      reused_from: null
      adaptations:
        - "Cálculo automático de indicadores financieros"
        - "Simulador interactivo de escenarios"
        - "Matriz de sensibilidad con visualización"
        - "Comparación de prototipos"

  user_stories:
    - id: US-COST-001
      file: historias-usuario/US-COST-001-catalogo-conceptos.md
      title: Catálogo de Conceptos y Búsqueda
      rf: [RF-COST-001]
      et: [ET-COST-001]
      story_points: 5
      status: planned
      sprint: 7
      reused_from: null
      adaptations: ["Nuevo desarrollo completo"]

    - id: US-COST-002
      file: historias-usuario/US-COST-002-precios-compuestos.md
      title: Precios Unitarios Compuestos
      rf: [RF-COST-001]
      et: [ET-COST-001]
      story_points: 5
      status: planned
      sprint: 7
      reused_from: null
      adaptations: ["Cálculo automático de APU"]

    - id: US-COST-003
      file: historias-usuario/US-COST-003-actualizacion-precios.md
      title: Actualización Masiva de Precios
      rf: [RF-COST-001]
      et: [ET-COST-001]
      story_points: 3
      status: planned
      sprint: 7
      reused_from: null
      adaptations: ["Actualización con preview y confirmación"]

    - id: US-COST-004
      file: historias-usuario/US-COST-004-presupuesto-obra.md
      title: Presupuesto de Obra Completo
      rf: [RF-COST-002]
      et: [ET-COST-002]
      story_points: 8
      status: planned
      sprint: 8
      reused_from: null
      adaptations: ["Wizard multi-paso con validaciones"]

    - id: US-COST-005
      file: historias-usuario/US-COST-005-presupuesto-prototipo.md
      title: Presupuesto de Prototipo con Generadores
      rf: [RF-COST-002]
      et: [ET-COST-002]
      story_points: 5
      status: planned
      sprint: 8
      reused_from: null
      adaptations: ["Generadores automáticos de volumetrías"]

    - id: US-COST-006
      file: historias-usuario/US-COST-006-dashboard-control-costos.md
      title: Dashboard de Control de Costos Reales
      rf: [RF-COST-003]
      et: [ET-COST-003]
      story_points: 5
      status: planned
      sprint: 9
      reused_from: null
      adaptations: ["Dashboard con curva S y KPIs"]

    - id: US-COST-007
      file: historias-usuario/US-COST-007-analisis-desviaciones.md
      title: Análisis de Desviaciones y Plan de Acción
      rf: [RF-COST-003]
      et: [ET-COST-003]
      story_points: 5
      status: planned
      sprint: 9
      reused_from: null
      adaptations: ["Análisis de causa raíz con alertas"]

    - id: US-COST-008
      file: historias-usuario/US-COST-008-analisis-rentabilidad.md
      title: Análisis de Rentabilidad y Simulaciones
      rf: [RF-COST-004]
      et: [ET-COST-004]
      story_points: 5
      status: planned
      sprint: 10
      reused_from: null
      adaptations: ["Simulador interactivo con matriz de sensibilidad"]

# ============================================================================
# IMPLEMENTACIÓN - BASE DE DATOS
# ============================================================================

implementation:
  database:
    schemas:
      - name: budgets
        path: apps/database/ddl/schemas/budgets/
        description: Schema para presupuestos, catálogo de conceptos y control de costos
        reused_from_gamilit: false
        note: "Schema completamente nuevo para módulo de construcción"

    enums:
      - name: concept_type
        schema: budgets
        file: apps/database/ddl/schemas/budgets/00-prerequisites.sql
        lines: "10-14"
        values: [material, labor, equipment, composite]
        rf: RF-COST-001
        reused_from: null
        note: "4 tipos de conceptos de obra"

      - name: budget_type
        schema: budgets
        file: apps/database/ddl/schemas/budgets/00-prerequisites.sql
        lines: "16-20"
        values: [project, stage, prototype]
        rf: RF-COST-002
        reused_from: null
        note: "3 niveles de presupuestos"

      - name: budget_status
        schema: budgets
        file: apps/database/ddl/schemas/budgets/00-prerequisites.sql
        lines: "22-26"
        values: [draft, active, approved, closed]
        rf: RF-COST-002
        reused_from: null

      - name: version_type
        schema: budgets
        file: apps/database/ddl/schemas/budgets/00-prerequisites.sql
        lines: "28-32"
        values: [baseline, price_adjustment, scope_change, additional_volume]
        rf: RF-COST-002
        reused_from: null

    tables:
      - name: concept_catalog
        schema: budgets
        file: apps/database/ddl/schemas/budgets/tables/01-concept_catalog.sql
        lines: 150
        description: Catálogo maestro de conceptos de obra con precios unitarios
        rf: RF-COST-001
        reused_from_gamilit: false
        note: "Tabla central del módulo de presupuestos"
        columns:
          - id (UUID, PK)
          - constructora_id (UUID, FK)
          - code (VARCHAR(20), UNIQUE per constructora)
          - name (VARCHAR(255))
          - description (TEXT)
          - concept_type (ENUM)
          - category (VARCHAR(100)) # División CMIC
          - subcategory (VARCHAR(100)) # Grupo CMIC
          - unit (VARCHAR(20)) # m³, m², kg, pza, jornal
          - base_price (DECIMAL(12,2))
          - includes_vat (BOOLEAN)
          - currency (VARCHAR(3))
          - waste_factor (DECIMAL(5,3))
          - components (JSONB) # Para conceptos compuestos
          - labor_crew (JSONB) # Cuadrilla tipo
          - indirect_percentage (DECIMAL(5,2))
          - financing_percentage (DECIMAL(5,2))
          - profit_percentage (DECIMAL(5,2))
          - additional_charges (DECIMAL(5,2))
          - direct_cost (DECIMAL(12,2))
          - unit_price (DECIMAL(12,2))
          - unit_price_with_vat (DECIMAL(12,2))
          - region_id (UUID, FK)
          - preferred_supplier_id (UUID, FK)
          - technical_specs (TEXT)
          - performance (VARCHAR(255))
          - version (INTEGER)
          - status (VARCHAR(20))
          - created_by (UUID)
          - created_at (TIMESTAMP)
          - updated_at (TIMESTAMP)

      - name: concept_price_history
        schema: budgets
        file: apps/database/ddl/schemas/budgets/tables/02-concept_price_history.sql
        lines: 60
        description: Historial de cambios de precios de conceptos
        rf: RF-COST-001
        reused_from_gamilit: false
        columns:
          - id (UUID, PK)
          - concept_id (UUID, FK)
          - price (DECIMAL(12,2))
          - valid_from (DATE)
          - valid_until (DATE)
          - variation_percentage (DECIMAL(6,2))
          - reason (VARCHAR(255))
          - created_by (UUID)
          - created_at (TIMESTAMP)

      - name: regions
        schema: budgets
        file: apps/database/ddl/schemas/budgets/tables/03-regions.sql
        lines: 40
        description: Catálogo de regiones para precios regionalizados
        rf: RF-COST-001
        reused_from_gamilit: false
        columns:
          - id (UUID, PK)
          - constructora_id (UUID, FK)
          - code (VARCHAR(10))
          - name (VARCHAR(100))
          - description (TEXT)
          - is_active (BOOLEAN)
          - created_at (TIMESTAMP)

      - name: budgets
        schema: budgets
        file: apps/database/ddl/schemas/budgets/tables/04-budgets.sql
        lines: 180
        description: Presupuestos maestros (obra, etapa, prototipo)
        rf: RF-COST-002
        reused_from_gamilit: false
        columns:
          - id (UUID, PK)
          - constructora_id (UUID, FK)
          - project_id (UUID, FK nullable)
          - stage_id (UUID, FK nullable)
          - prototype_id (UUID, FK nullable)
          - code (VARCHAR(20), UNIQUE)
          - name (VARCHAR(255))
          - budget_type (ENUM)
          - version (INTEGER)
          - is_baseline (BOOLEAN)
          - status (ENUM)
          - housing_units_count (INTEGER)
          - total_built_area (DECIMAL(12,2))
          - total_land_area (DECIMAL(12,2))
          - direct_cost (DECIMAL(15,2))
          - indirect_percentage (DECIMAL(5,2))
          - indirect_amount (DECIMAL(15,2))
          - financing_percentage (DECIMAL(5,2))
          - financing_amount (DECIMAL(15,2))
          - profit_percentage (DECIMAL(5,2))
          - profit_amount (DECIMAL(15,2))
          - additional_charges (DECIMAL(15,2))
          - total_cost (DECIMAL(15,2))
          - sale_price (DECIMAL(15,2))
          - gross_margin (DECIMAL(15,2))
          - margin_percentage (DECIMAL(5,2))
          - roi (DECIMAL(5,2))
          - cost_per_sqm (DECIMAL(10,2))
          - cost_per_unit (DECIMAL(12,2))
          - approved_by (UUID)
          - approved_at (TIMESTAMP)
          - created_by (UUID)
          - created_at (TIMESTAMP)
          - updated_at (TIMESTAMP)

      - name: budget_items
        schema: budgets
        file: apps/database/ddl/schemas/budgets/tables/05-budget_items.sql
        lines: 120
        description: Partidas jerárquicas del presupuesto (3 niveles)
        rf: RF-COST-002
        reused_from_gamilit: false
        columns:
          - id (UUID, PK)
          - budget_id (UUID, FK)
          - parent_item_id (UUID, FK nullable)
          - level (INTEGER) # 1=División, 2=Grupo, 3=Concepto
          - sort_order (INTEGER)
          - concept_id (UUID, FK nullable)
          - code (VARCHAR(20))
          - name (VARCHAR(255))
          - unit (VARCHAR(20))
          - quantity (DECIMAL(12,4))
          - unit_price (DECIMAL(12,2))
          - amount (DECIMAL(15,2))
          - has_generator (BOOLEAN)
          - generator_formula (TEXT)
          - generator_inputs (JSONB)
          - notes (TEXT)
          - created_at (TIMESTAMP)
          - updated_at (TIMESTAMP)

      - name: budget_versions
        schema: budgets
        file: apps/database/ddl/schemas/budgets/tables/06-budget_versions.sql
        lines: 70
        description: Historial de versiones de presupuestos
        rf: RF-COST-002
        reused_from_gamilit: false
        columns:
          - id (UUID, PK)
          - budget_id (UUID, FK)
          - version (INTEGER)
          - version_type (ENUM)
          - previous_version_id (UUID, FK nullable)
          - total_cost (DECIMAL(15,2))
          - variation_amount (DECIMAL(15,2))
          - variation_percentage (DECIMAL(6,2))
          - reason (TEXT)
          - approved_by (UUID)
          - created_at (TIMESTAMP)

      - name: actual_costs
        schema: budgets
        file: apps/database/ddl/schemas/budgets/tables/07-actual_costs.sql
        lines: 100
        description: Registro de costos reales de construcción
        rf: RF-COST-003
        reused_from_gamilit: false
        columns:
          - id (UUID, PK)
          - constructora_id (UUID, FK)
          - project_id (UUID, FK)
          - stage_id (UUID, FK nullable)
          - budget_item_id (UUID, FK)
          - source_type (ENUM) # purchase, payroll, subcontract, equipment, other
          - source_id (UUID)
          - source_document_number (VARCHAR(50))
          - amount (DECIMAL(15,2))
          - currency (VARCHAR(3))
          - includes_vat (BOOLEAN)
          - transaction_date (DATE)
          - accounting_period (VARCHAR(7)) # 2025-11
          - cost_type (ENUM) # material, labor, equipment, subcontract, indirect
          - notes (TEXT)
          - created_by (UUID)
          - created_at (TIMESTAMP)

      - name: cost_variances
        schema: budgets
        file: apps/database/ddl/schemas/budgets/tables/08-cost_variances.sql
        lines: 90
        description: Análisis de desviaciones presupuesto vs real
        rf: RF-COST-003
        reused_from_gamilit: false
        columns:
          - id (UUID, PK)
          - project_id (UUID, FK)
          - budget_item_id (UUID, FK)
          - analysis_date (DATE)
          - budgeted_amount (DECIMAL(15,2))
          - actual_amount (DECIMAL(15,2))
          - variance (DECIMAL(15,2))
          - variance_percentage (DECIMAL(6,2))
          - price_variance (DECIMAL(15,2))
          - quantity_variance (DECIMAL(15,2))
          - mixed_variance (DECIMAL(15,2))
          - status (ENUM) # within_tolerance, warning, critical
          - root_cause (TEXT)
          - action_plan (TEXT)
          - responsible_user_id (UUID)
          - created_at (TIMESTAMP)

      - name: cost_projections
        schema: budgets
        file: apps/database/ddl/schemas/budgets/tables/09-cost_projections.sql
        lines: 80
        description: Proyecciones de costo final (EAC)
        rf: RF-COST-003
        reused_from_gamilit: false
        columns:
          - id (UUID, PK)
          - project_id (UUID, FK)
          - projection_date (DATE)
          - physical_progress (DECIMAL(5,2))
          - budgeted_total_cost (DECIMAL(15,2))
          - actual_cost_to_date (DECIMAL(15,2))
          - linear_projection (DECIMAL(15,2))
          - cpi_based_projection (DECIMAL(15,2))
          - weighted_projection (DECIMAL(15,2))
          - recommended_eac (DECIMAL(15,2))
          - cpi (DECIMAL(5,3)) # Cost Performance Index
          - spi (DECIMAL(5,3)) # Schedule Performance Index
          - created_at (TIMESTAMP)

      - name: profitability_analysis
        schema: budgets
        file: apps/database/ddl/schemas/budgets/tables/10-profitability_analysis.sql
        lines: 110
        description: Análisis de rentabilidad por proyecto
        rf: RF-COST-004
        reused_from_gamilit: false
        columns:
          - id (UUID, PK)
          - constructora_id (UUID, FK)
          - project_id (UUID, FK)
          - analysis_date (DATE)
          - analysis_type (ENUM) # actual, projected, scenario
          - total_revenue (DECIMAL(15,2))
          - average_sale_price (DECIMAL(12,2))
          - units_to_sell (INTEGER)
          - construction_cost (DECIMAL(15,2))
          - land_cost (DECIMAL(15,2))
          - marketing_cost (DECIMAL(15,2))
          - administrative_cost (DECIMAL(15,2))
          - financial_cost (DECIMAL(15,2))
          - total_costs (DECIMAL(15,2))
          - gross_profit (DECIMAL(15,2))
          - gross_margin (DECIMAL(6,2))
          - net_profit (DECIMAL(15,2))
          - net_margin (DECIMAL(6,2))
          - roi (DECIMAL(6,2))
          - irr (DECIMAL(6,2))
          - payback_months (INTEGER)
          - break_even_units (INTEGER)
          - fixed_costs (DECIMAL(15,2))
          - variable_cost_per_unit (DECIMAL(12,2))
          - contribution_margin (DECIMAL(12,2))
          - created_by (UUID)
          - created_at (TIMESTAMP)

      - name: prototype_profitability
        schema: budgets
        file: apps/database/ddl/schemas/budgets/tables/11-prototype_profitability.sql
        lines: 70
        description: Rentabilidad comparativa por prototipo
        rf: RF-COST-004
        reused_from_gamilit: false
        columns:
          - id (UUID, PK)
          - project_id (UUID, FK)
          - prototype_id (UUID, FK)
          - units_planned (INTEGER)
          - units_sold (INTEGER)
          - units_delivered (INTEGER)
          - sale_price (DECIMAL(12,2))
          - construction_cost (DECIMAL(12,2))
          - land_cost_allocated (DECIMAL(12,2))
          - indirect_costs (DECIMAL(12,2))
          - unit_profit (DECIMAL(12,2))
          - unit_margin (DECIMAL(6,2))
          - total_profit (DECIMAL(15,2))
          - average_construction_days (INTEGER)
          - sales_conversion_rate (DECIMAL(5,2))
          - updated_at (TIMESTAMP)

    functions:
      - name: calculate_composite_price
        schema: budgets
        file: apps/database/ddl/schemas/budgets/functions/calculate_composite_price.sql
        lines: "10-80"
        description: Calcula precio unitario de concepto compuesto (APU)
        rf: RF-COST-001
        reused_from_gamilit: false
        note: "Suma materiales + MO + maquinaria + factores"

      - name: calculate_variances
        schema: budgets
        file: apps/database/ddl/schemas/budgets/functions/calculate_variances.sql
        lines: "10-100"
        description: Genera análisis de desviaciones por partida
        rf: RF-COST-003
        reused_from_gamilit: false
        note: "Descompone en precio, cantidad y mixta"

      - name: calculate_eac
        schema: budgets
        file: apps/database/ddl/schemas/budgets/functions/calculate_eac.sql
        lines: "10-70"
        description: Proyección de costo final (3 métodos)
        rf: RF-COST-003
        reused_from_gamilit: false
        note: "Lineal, CPI-based, ponderado"

      - name: calculate_profitability
        schema: budgets
        file: apps/database/ddl/schemas/budgets/functions/calculate_profitability.sql
        lines: "10-90"
        description: Análisis de rentabilidad del proyecto
        rf: RF-COST-004
        reused_from_gamilit: false
        note: "Margen, ROI, TIR, punto de equilibrio"

    triggers:
      - table: budgets.concept_catalog
        trigger: trigger_concept_updated_at
        description: Actualiza timestamp al modificar concepto
        rf: RF-COST-001
        reused_from_gamilit: false
        sql: |
          CREATE TRIGGER trigger_concept_updated_at
            BEFORE UPDATE ON budgets.concept_catalog
            FOR EACH ROW
            EXECUTE FUNCTION budgets.update_concept_timestamp();

      - table: budgets.concept_catalog
        trigger: trigger_create_price_history
        description: Crea registro en historial al cambiar precio
        rf: RF-COST-001
        reused_from_gamilit: false
        sql: |
          CREATE TRIGGER trigger_create_price_history
            AFTER UPDATE ON budgets.concept_catalog
            FOR EACH ROW
            WHEN (NEW.base_price IS DISTINCT FROM OLD.base_price)
            EXECUTE FUNCTION budgets.create_price_history();

      - table: budgets.budget_items
        trigger: trigger_budget_items_calculate
        description: Recalcula totales del presupuesto al modificar partidas
        rf: RF-COST-002
        reused_from_gamilit: false
        sql: |
          CREATE TRIGGER trigger_budget_items_calculate
            AFTER INSERT OR UPDATE OR DELETE ON budgets.budget_items
            FOR EACH ROW
            EXECUTE FUNCTION budgets.calculate_budget_totals();

      - table: budgets.actual_costs
        trigger: trigger_actual_costs_update_variance
        description: Actualiza desviaciones al registrar costo real
        rf: RF-COST-003
        reused_from_gamilit: false
        sql: |
          CREATE TRIGGER trigger_actual_costs_update_variance
            AFTER INSERT ON budgets.actual_costs
            FOR EACH ROW
            EXECUTE FUNCTION budgets.update_cost_variance();

    rls_policies:
      - table: budgets.concept_catalog
        policy: concept_catalog_select_own
        description: Usuarios solo ven conceptos de su constructora
        rf: RF-COST-001
        reused_from_gamilit: false
        sql: |
          CREATE POLICY "concept_catalog_select_own" ON budgets.concept_catalog
              FOR SELECT
              TO authenticated
              USING (
                  constructora_id = get_current_constructora_id()
              );

      - table: budgets.budgets
        policy: budgets_select_own
        description: Usuarios solo ven presupuestos de su constructora
        rf: RF-COST-002
        reused_from_gamilit: false
        sql: |
          CREATE POLICY "budgets_select_own" ON budgets.budgets
              FOR SELECT
              TO authenticated
              USING (
                  constructora_id = get_current_constructora_id()
              );

      - table: budgets.actual_costs
        policy: actual_costs_select_own
        description: Usuarios solo ven costos de su constructora
        rf: RF-COST-003
        reused_from_gamilit: false
        sql: |
          CREATE POLICY "actual_costs_select_own" ON budgets.actual_costs
              FOR SELECT
              TO authenticated
              USING (
                  constructora_id = get_current_constructora_id()
              );

# ============================================================================
# IMPLEMENTACIÓN - BACKEND
# ============================================================================

  backend:
    modules:
      - name: budgets
        path: apps/backend/src/modules/budgets/
        description: Módulo completo de presupuestos, catálogo y control de costos
        rf: [RF-COST-001, RF-COST-002, RF-COST-003, RF-COST-004]
        reused_from_gamilit: false
        adaptations:
          - "Módulo nuevo completo para construcción"
          - "4 servicios principales (Catalog, Budget, CostControl, Profitability)"

    services:
      - name: ConceptCatalogService
        path: apps/backend/src/modules/budgets/concept-catalog.service.ts
        description: Lógica de gestión del catálogo de conceptos
        rf: [RF-COST-001]
        reused_from_gamilit: false
        methods:
          - create(dto)
          - findAll(filters)
          - findOne(id)
          - update(id, dto)
          - delete(id)
          - calculateCompositePrice(conceptId)
          - massUpdatePrices(categoryId, adjustmentPercentage)
          - exportToExcel()
          - importFromExcel(file)

      - name: BudgetService
        path: apps/backend/src/modules/budgets/budget.service.ts
        description: Lógica de elaboración y gestión de presupuestos
        rf: [RF-COST-002]
        reused_from_gamilit: false
        methods:
          - createBudget(dto)
          - generateFromPrototype(prototypeId)
          - addBudgetItem(budgetId, itemDto)
          - calculateTotals(budgetId)
          - createVersion(budgetId, versionType, reason)
          - compareVersions(budgetId, v1, v2)
          - approveBudget(budgetId)
          - exportToPdf(budgetId)

      - name: CostControlService
        path: apps/backend/src/modules/budgets/cost-control.service.ts
        description: Lógica de control de costos reales y desviaciones
        rf: [RF-COST-003]
        reused_from_gamilit: false
        methods:
          - registerActualCost(dto)
          - calculateVariances(projectId)
          - projectEAC(projectId, method)
          - getCostDashboard(projectId)
          - generateAlerts(projectId)
          - getCurveS(projectId)
          - createActionPlan(varianceId, actionPlan)

      - name: ProfitabilityService
        path: apps/backend/src/modules/budgets/profitability.service.ts
        description: Lógica de análisis de rentabilidad y simulaciones
        rf: [RF-COST-004]
        reused_from_gamilit: false
        methods:
          - analyzeProjectProfitability(projectId)
          - analyzePrototypeProfitability(prototypeId)
          - calculateBreakEven(projectId)
          - simulateScenarios(projectId, scenarios)
          - sensitivityMatrix(projectId, priceRange, costRange)
          - compareProjects(projectIds)
          - calculateROI(projectId)

    controllers:
      - name: ConceptCatalogController
        path: apps/backend/src/modules/budgets/concept-catalog.controller.ts
        description: Endpoints del catálogo de conceptos
        rf: RF-COST-001
        reused_from_gamilit: false
        endpoints:
          - "POST /api/v1/budgets/concepts"
          - "GET /api/v1/budgets/concepts"
          - "GET /api/v1/budgets/concepts/:id"
          - "PATCH /api/v1/budgets/concepts/:id"
          - "DELETE /api/v1/budgets/concepts/:id"
          - "POST /api/v1/budgets/concepts/:id/calculate-price"
          - "POST /api/v1/budgets/concepts/mass-update"
          - "GET /api/v1/budgets/concepts/:id/price-history"
          - "POST /api/v1/budgets/concepts/import"

      - name: BudgetController
        path: apps/backend/src/modules/budgets/budget.controller.ts
        description: Endpoints de presupuestos
        rf: RF-COST-002
        reused_from_gamilit: false
        endpoints:
          - "POST /api/v1/budgets"
          - "GET /api/v1/budgets"
          - "GET /api/v1/budgets/:id"
          - "PATCH /api/v1/budgets/:id"
          - "DELETE /api/v1/budgets/:id"
          - "POST /api/v1/budgets/:id/items"
          - "POST /api/v1/budgets/:id/versions"
          - "GET /api/v1/budgets/:id/versions"
          - "GET /api/v1/budgets/:id/compare/:v1/:v2"
          - "POST /api/v1/budgets/:id/approve"
          - "GET /api/v1/budgets/:id/export/pdf"
          - "POST /api/v1/budgets/generate-from-prototype/:prototypeId"

      - name: CostControlController
        path: apps/backend/src/modules/budgets/cost-control.controller.ts
        description: Endpoints de control de costos
        rf: RF-COST-003
        reused_from_gamilit: false
        endpoints:
          - "POST /api/v1/budgets/actual-costs"
          - "GET /api/v1/budgets/projects/:projectId/cost-control"
          - "GET /api/v1/budgets/projects/:projectId/variances"
          - "GET /api/v1/budgets/projects/:projectId/eac"
          - "GET /api/v1/budgets/projects/:projectId/curve-s"
          - "GET /api/v1/budgets/projects/:projectId/alerts"
          - "POST /api/v1/budgets/variances/:varianceId/action-plan"
          - "GET /api/v1/budgets/projects/:projectId/cost-breakdown"

      - name: ProfitabilityController
        path: apps/backend/src/modules/budgets/profitability.controller.ts
        description: Endpoints de análisis de rentabilidad
        rf: RF-COST-004
        reused_from_gamilit: false
        endpoints:
          - "GET /api/v1/budgets/projects/:projectId/profitability"
          - "GET /api/v1/budgets/prototypes/:prototypeId/profitability"
          - "GET /api/v1/budgets/projects/:projectId/break-even"
          - "POST /api/v1/budgets/projects/:projectId/simulate"
          - "GET /api/v1/budgets/projects/:projectId/sensitivity"
          - "POST /api/v1/budgets/portfolio/compare"

    cron_jobs:
      - name: DailyCostAnalysisTask
        path: apps/backend/src/modules/budgets/tasks/daily-cost-analysis.task.ts
        schedule: "0 6 * * *" # Diario a las 6:00 AM
        description: Análisis diario de costos y generación de alertas
        rf: RF-COST-003
        reused_from_gamilit: false

    enums:
      - name: ConceptType
        path: apps/backend/src/modules/budgets/enums/concept-type.enum.ts
        description: Enum TypeScript de tipos de conceptos
        rf: RF-COST-001
        reused_from: null
        values:
          - MATERIAL = 'material'
          - LABOR = 'labor'
          - EQUIPMENT = 'equipment'
          - COMPOSITE = 'composite'

      - name: BudgetType
        path: apps/backend/src/modules/budgets/enums/budget-type.enum.ts
        description: Enum TypeScript de tipos de presupuestos
        rf: RF-COST-002
        reused_from: null
        values:
          - PROJECT = 'project'
          - STAGE = 'stage'
          - PROTOTYPE = 'prototype'

# ============================================================================
# IMPLEMENTACIÓN - FRONTEND
# ============================================================================

  frontend:
    features:
      - name: budgets
        path: apps/frontend/src/features/budgets/
        description: Feature completo de presupuestos y control de costos
        rf: [RF-COST-001, RF-COST-002, RF-COST-003, RF-COST-004]
        reused_from_gamilit: false
        adaptations: ["Feature nuevo completo para construcción"]

    pages:
      - name: ConceptCatalogPage
        path: apps/frontend/src/features/budgets/pages/ConceptCatalogPage.tsx
        route: /concept-catalog
        description: Página principal del catálogo de conceptos
        rf: RF-COST-001
        reused_from_gamilit: false

      - name: BudgetDetailPage
        path: apps/frontend/src/features/budgets/pages/BudgetDetailPage.tsx
        route: /budgets/:id
        description: Detalle y edición de presupuesto
        rf: RF-COST-002
        reused_from_gamilit: false

      - name: CostControlDashboardPage
        path: apps/frontend/src/features/budgets/pages/CostControlDashboardPage.tsx
        route: /projects/:projectId/cost-control
        description: Dashboard de control de costos
        rf: RF-COST-003
        reused_from_gamilit: false

      - name: ProfitabilityAnalysisPage
        path: apps/frontend/src/features/budgets/pages/ProfitabilityAnalysisPage.tsx
        route: /projects/:projectId/profitability
        description: Análisis de rentabilidad y simulaciones
        rf: RF-COST-004
        reused_from_gamilit: false

    components:
      - name: ConceptCatalogList
        path: apps/frontend/src/features/budgets/components/ConceptCatalogList.tsx
        description: Lista de conceptos con búsqueda y filtros
        rf: RF-COST-001
        reused_from_gamilit: false
        note: "Incluye búsqueda full-text, filtros por tipo/categoría"

      - name: CreateConceptModal
        path: apps/frontend/src/features/budgets/components/CreateConceptModal.tsx
        description: Modal para crear concepto compuesto con APU
        rf: RF-COST-001
        reused_from_gamilit: false
        note: "Formulario multi-sección: materiales, MO, maquinaria, factores"

      - name: BudgetItemsTree
        path: apps/frontend/src/features/budgets/components/BudgetItemsTree.tsx
        description: Árbol jerárquico de partidas presupuestales
        rf: RF-COST-002
        reused_from_gamilit: false
        note: "3 niveles: División, Grupo, Concepto"

      - name: BudgetWizard
        path: apps/frontend/src/features/budgets/components/BudgetWizard.tsx
        description: Wizard multi-paso para crear presupuesto
        rf: RF-COST-002
        reused_from_gamilit: false
        note: "Pasos: Tipo, Alcance, Conceptos, Factores, Resumen"

      - name: CurveSChart
        path: apps/frontend/src/features/budgets/components/CurveSChart.tsx
        description: Gráfica de curva S (Presupuestado vs Real vs Proyectado)
        rf: RF-COST-003
        reused_from_gamilit: false
        note: "Chart.js con 3 líneas de tendencia"

      - name: VarianceAnalysisTable
        path: apps/frontend/src/features/budgets/components/VarianceAnalysisTable.tsx
        description: Tabla de análisis de desviaciones por partida
        rf: RF-COST-003
        reused_from_gamilit: false
        note: "Descompone en precio, cantidad, mixta"

      - name: ProfitabilityDashboard
        path: apps/frontend/src/features/budgets/components/ProfitabilityDashboard.tsx
        description: Dashboard ejecutivo de rentabilidad
        rf: RF-COST-004
        reused_from_gamilit: false
        note: "KPIs: Margen, ROI, TIR, Punto de equilibrio"

      - name: ScenarioSimulator
        path: apps/frontend/src/features/budgets/components/ScenarioSimulator.tsx
        description: Simulador interactivo de escenarios
        rf: RF-COST-004
        reused_from_gamilit: false
        note: "Sliders para precio/costo/volumen, cálculo en vivo"

      - name: SensitivityMatrix
        path: apps/frontend/src/features/budgets/components/SensitivityMatrix.tsx
        description: Matriz de sensibilidad (precio vs costo)
        rf: RF-COST-004
        reused_from_gamilit: false
        note: "Heat map con colores según margen"

    stores:
      - name: useConceptCatalogStore
        path: apps/frontend/src/stores/budgets/conceptCatalogStore.ts
        description: Store de catálogo de conceptos (Zustand)
        rf: RF-COST-001
        reused_from_gamilit: false
        state:
          - concepts (array)
          - filters (object)
          - selectedConcept (object)
          - isLoading (boolean)

      - name: useBudgetStore
        path: apps/frontend/src/stores/budgets/budgetStore.ts
        description: Store de presupuestos (Zustand)
        rf: RF-COST-002
        reused_from_gamilit: false
        state:
          - budgets (array)
          - currentBudget (object)
          - budgetItems (array)
          - versions (array)
          - isLoading (boolean)

      - name: useCostControlStore
        path: apps/frontend/src/stores/budgets/costControlStore.ts
        description: Store de control de costos (Zustand)
        rf: RF-COST-003
        reused_from_gamilit: false
        state:
          - actualCosts (array)
          - variances (array)
          - projections (object)
          - alerts (array)
          - curveSData (object)

      - name: useProfitabilityStore
        path: apps/frontend/src/stores/budgets/profitabilityStore.ts
        description: Store de análisis de rentabilidad (Zustand)
        rf: RF-COST-004
        reused_from_gamilit: false
        state:
          - profitabilityAnalysis (object)
          - scenarios (array)
          - sensitivityMatrix (array)
          - comparativeData (array)

# ============================================================================
# TESTING
# ============================================================================

  testing:
    unit_tests:
      - module: ConceptCatalogService
        file: apps/backend/src/modules/budgets/concept-catalog.service.spec.ts
        coverage_target: 85%
        reused_from_gamilit: false
        key_tests:
          - "create concept simple (material)"
          - "create concept composite (APU calculation)"
          - "mass update prices by category"
          - "calculate composite price with components"

      - module: BudgetService
        file: apps/backend/src/modules/budgets/budget.service.spec.ts
        coverage_target: 85%
        reused_from_gamilit: false
        key_tests:
          - "create budget from prototype"
          - "calculate totals trigger"
          - "create version (baseline, adjustment)"
          - "compare versions"

      - module: CostControlService
        file: apps/backend/src/modules/budgets/cost-control.service.spec.ts
        coverage_target: 85%
        reused_from_gamilit: false
        key_tests:
          - "register actual cost from purchase"
          - "calculate variances (price, quantity, mixed)"
          - "project EAC (3 methods)"
          - "generate alerts on threshold"

      - module: ProfitabilityService
        file: apps/backend/src/modules/budgets/profitability.service.spec.ts
        coverage_target: 85%
        reused_from_gamilit: false
        key_tests:
          - "calculate project profitability"
          - "break-even calculation"
          - "ROI and TIR calculation"
          - "scenario simulation"

    integration_tests:
      - name: Budget Creation Flow
        file: apps/backend/test/integration/budget-creation.spec.ts
        scenarios:
          - Crear concepto compuesto
          - Generar presupuesto desde prototipo
          - Agregar partidas al presupuesto
          - Calcular totales automáticamente
          - Aprobar presupuesto
        reused_from_gamilit: false

      - name: Cost Control Integration
        file: apps/backend/test/integration/cost-control.spec.ts
        scenarios:
          - Registrar costo desde orden de compra
          - Actualizar desviaciones automáticamente
          - Generar alerta si desviación >5%
          - Crear plan de acción
        reused_from_gamilit: false

    e2e_tests:
      - name: Budget E2E
        file: apps/frontend/test/e2e/budgets.e2e.spec.ts
        scenarios:
          - Usuario crea concepto compuesto
          - Usuario genera presupuesto de prototipo
          - Usuario compara versiones de presupuesto
          - Usuario exporta presupuesto a PDF
        reused_from_gamilit: false

      - name: Cost Control E2E
        file: apps/frontend/test/e2e/cost-control.e2e.spec.ts
        scenarios:
          - Usuario ve dashboard de control de costos
          - Usuario investiga desviación crítica
          - Usuario crea plan de acción
          - Usuario simula escenarios de rentabilidad
        reused_from_gamilit: false

# ============================================================================
# MÉTRICAS
# ============================================================================

metrics:
  story_points:
    planned: 46
    completed: 0
    by_sprint:
      sprint_7: 13 # US-COST-001, 002, 003
      sprint_8: 13 # US-COST-004, 005
      sprint_9: 10 # US-COST-006, 007
      sprint_10: 10 # US-COST-008
    variance: 0%

  budget:
    planned: 35000
    actual: 0
    variance: 0%

  reuse_from_gamilit:
    infrastructure: 0%
    database: 0%
    backend: 0%
    frontend: 0%
    overall: 0%
    note: "Módulo completamente nuevo, sin reutilización de GAMILIT"

  performance_targets:
    concept_search: "<200ms"
    composite_price_calculation: "<100ms"
    budget_generation_100_items: "<2s"
    mass_price_update_500_concepts: "<5s"
    dashboard_load: "<1.5s"
    curve_s_rendering: "<800ms"

  quality_targets:
    test_coverage: ">85%"
    budget_accuracy: "<3% deviation vs real"
    eac_projection_accuracy: "<2% error"
    alert_response_time: "<24h"

# ============================================================================
# ROADMAP
# ============================================================================

roadmap:
  sprint_7:
    weeks: "13-14"
    goal: "Catálogo de Conceptos y Precios Unitarios"
    story_points: 13
    tasks:
      - Implementar schema budgets en DB
      - Crear tablas concept_catalog, price_history, regions
      - Desarrollar ConceptCatalogService (CRUD + cálculos)
      - Implementar búsqueda full-text
      - Desarrollar CreateConceptModal (frontend)
      - Implementar actualización masiva de precios
      - Tests unitarios del catálogo
    deliverables:
      - US-COST-001: Catálogo de Conceptos
      - US-COST-002: Precios Compuestos
      - US-COST-003: Actualización Masiva

  sprint_8:
    weeks: "15-16"
    goal: "Presupuestos Maestros (3 niveles)"
    story_points: 13
    tasks:
      - Crear tablas budgets, budget_items, budget_versions
      - Desarrollar BudgetService con generadores
      - Implementar triggers de cálculo automático
      - Desarrollar BudgetWizard (frontend)
      - Implementar árbol jerárquico de partidas
      - Sistema de versionado
      - Tests de integración de presupuestos
    deliverables:
      - US-COST-004: Presupuesto de Obra
      - US-COST-005: Presupuesto de Prototipo

  sprint_9:
    weeks: "17-18"
    goal: "Control de Costos Reales"
    story_points: 10
    tasks:
      - Crear tablas actual_costs, cost_variances, cost_projections
      - Desarrollar CostControlService
      - Implementar integración con Compras/Nómina/Subcontratos
      - Desarrollar CurveSChart (frontend)
      - Implementar análisis de desviaciones
      - Sistema de alertas automáticas
      - Cron job de análisis diario
    deliverables:
      - US-COST-006: Dashboard de Control
      - US-COST-007: Análisis de Desviaciones

  sprint_10:
    weeks: "19-20"
    goal: "Análisis de Rentabilidad"
    story_points: 10
    tasks:
      - Crear tablas profitability_analysis, prototype_profitability
      - Desarrollar ProfitabilityService
      - Implementar cálculos ROI, TIR, punto de equilibrio
      - Desarrollar ScenarioSimulator (frontend)
      - Implementar matriz de sensibilidad
      - Comparación de proyectos
      - Tests E2E completos del módulo
    deliverables:
      - US-COST-008: Análisis de Rentabilidad

# ============================================================================
# DEPENDENCIAS
# ============================================================================

dependencies:
  modules_required:
    - id: MAI-001
      name: Fundamentos
      reason: "Sistema de autenticación, roles, multi-tenancy"
      critical: true

    - id: MAI-002
      name: Proyectos y Obras
      reason: "Estructura de proyectos, etapas, prototipos para presupuestos"
      critical: true

  modules_that_depend_on_this:
    - id: MAI-004
      name: Compras e Inventarios
      reason: "Consume presupuesto para planificar compras, alimenta costos reales"
      impact: high

    - id: MAI-005
      name: Control de Obra
      reason: "Consume presupuesto como baseline, registra avances"
      impact: high

    - id: MAI-007
      name: Recursos Humanos
      reason: "Consume presupuesto de MO, alimenta costos de nómina"
      impact: medium

    - id: MAI-009
      name: Reportes y Analytics
      reason: "Consume datos de costos y rentabilidad para reportes"
      impact: medium

  external_integrations:
    - name: OPUS
      type: import/export
      description: "Importar/exportar catálogo de conceptos"
      priority: medium

    - name: Neodata
      type: import/export
      description: "Importar/exportar presupuestos"
      priority: medium

    - name: Excel/CSV
      type: import/export
      description: "Importar catálogo masivo, exportar reportes"
      priority: high

# ============================================================================
# COBERTURA
# ============================================================================

cobertura:
  rf_total: 4
  rf_implementados: 0
  rf_en_progreso: 0
  rf_pendientes: 4

  et_total: 4
  et_implementados: 0

  us_total: 8
  us_implementados: 0

  tablas_total: 11
  tablas_implementadas: 0

  endpoints_total: 35
  endpoints_implementados: 0

  componentes_ui_total: 10
  componentes_ui_implementados: 0

# ============================================================================
# NOTAS
# ============================================================================

notes:
  - "Módulo completamente nuevo sin reutilización de GAMILIT"
  - "Core crítico del negocio: impacta directamente en rentabilidad"
  - "Integración estrecha con MAI-002 (Proyectos) y MAI-004 (Compras)"
  - "Performance crítica: catálogo puede crecer a 10,000+ conceptos"
  - "Indices full-text y paginación necesarios desde Sprint 7"
  - "Dashboard en tiempo real requiere optimización de queries"
  - "Triggers de cálculo automático deben ser eficientes"
  - "Curva S y gráficas requieren Chart.js en frontend"
  - "Simulador de escenarios debe ser interactivo (cálculos en vivo)"
  - "Plan de 4 sprints (8 semanas) es ajustado pero alcanzable"
  - "Priorizar funcionalidad core sobre features avanzadas si hay retrasos"
  - "Tests de performance necesarios en Sprint 7 (búsqueda) y Sprint 9 (dashboard)"
