# TRACEABILITY-MGN-008.yaml
# Matriz de Trazabilidad - MGN-008: Contabilidad Analítica
# Fecha: 2025-11-24
# Versión: 1.0

module:
  id: MGN-008
  name: "Contabilidad Analítica"
  description: "Sistema de cuentas analíticas para seguimiento de costos e ingresos por proyectos, departamentos y centros de costo"
  priority: P0
  story_points: 35
  status: Diseñado

metadata:
  total_rf: 5
  total_et_backend: 5
  total_et_frontend: 5
  total_tables: 6
  total_tests: 100
  coverage: 100%

requirements:
  - rf_id: RF-MGN-008-001
    rf_title: "Gestión de Cuentas Analíticas"
    rf_file: "requerimientos-funcionales/mgn-008/RF-MGN-008-001-gestión-de-cuentas-analíticas.md"
    priority: P0
    story_points: 8

    et_backend:
      file: "especificaciones-tecnicas/backend/mgn-008/ET-BACKEND-MGN-008-001-gestión-de-cuentas-analíticas.md"
      endpoints:
        - method: POST
          path: /api/v1/analytics/accounts
          description: "Crear nueva cuenta analítica"
        - method: GET
          path: /api/v1/analytics/accounts
          description: "Listar todas las cuentas analíticas"
        - method: GET
          path: /api/v1/analytics/accounts/:id
          description: "Obtener cuenta analítica por ID"
        - method: PUT
          path: /api/v1/analytics/accounts/:id
          description: "Actualizar cuenta analítica"
        - method: DELETE
          path: /api/v1/analytics/accounts/:id
          description: "Eliminar cuenta analítica (soft delete)"
      services:
        - name: "AnalyticAccountService"
          file: "src/modules/analytics/services/analytic-account.service.ts"
          methods:
            - create
            - findAll
            - findOne
            - update
            - remove
            - validateBusinessRules
      controllers:
        - name: "AnalyticAccountController"
          file: "src/modules/analytics/controllers/analytic-account.controller.ts"
      dtos:
        - name: "CreateAnalyticAccountDto"
          file: "src/modules/analytics/dto/create-analytic-account.dto.ts"
        - name: "UpdateAnalyticAccountDto"
          file: "src/modules/analytics/dto/update-analytic-account.dto.ts"
        - name: "AnalyticAccountResponseDto"
          file: "src/modules/analytics/dto/analytic-account-response.dto.ts"
        - name: "FilterAnalyticAccountDto"
          file: "src/modules/analytics/dto/filter-analytic-account.dto.ts"

    et_frontend:
      file: "especificaciones-tecnicas/frontend/mgn-008/ET-FRONTEND-MGN-008-001-gestión-de-cuentas-analíticas.md"
      routes:
        - path: "/analytics/accounts"
          component: "AnalyticAccountsPage"
        - path: "/analytics/accounts/create"
          component: "CreateAnalyticAccountPage"
        - path: "/analytics/accounts/:id/edit"
          component: "EditAnalyticAccountPage"
        - path: "/analytics/accounts/:id"
          component: "ViewAnalyticAccountPage"
      components:
        - name: "AnalyticAccountsTable"
          file: "src/widgets/analytic-accounts-table/ui/AnalyticAccountsTable.tsx"
          type: widget
        - name: "CreateAnalyticAccountForm"
          file: "src/features/create-analytic-account/ui/CreateAnalyticAccountForm.tsx"
          type: feature
        - name: "AnalyticAccountCard"
          file: "src/entities/analytic-account/ui/AnalyticAccountCard.tsx"
          type: entity
        - name: "AnalyticAccountPage"
          file: "src/pages/analytics/AnalyticAccountPage.tsx"
          type: page
      api_client:
        - name: "analyticAccountApi"
          file: "src/entities/analytic-account/api/analytic-account.api.ts"
          methods:
            - getAll
            - getById
            - create
            - update
            - delete
      state_management:
        - name: "useAnalyticAccountStore"
          file: "src/entities/analytic-account/model/analytic-account.store.ts"
          type: zustand
        - name: "useAnalyticAccounts"
          file: "src/entities/analytic-account/api/analytic-account.queries.ts"
          type: react-query

    database_tables:
      - schema: analytics
        table: analytic_accounts
        file: "database-design/schemas/analytics-schema-ddl.sql"
        operations:
          - SELECT
          - INSERT
          - UPDATE
          - DELETE (soft)
        indices:
          - idx_analytic_accounts_tenant_id
          - idx_analytic_accounts_code
          - idx_analytic_accounts_plan_id
        rls_policy: tenant_isolation_analytic_accounts
      - schema: analytics
        table: analytic_plans
        file: "database-design/schemas/analytics-schema-ddl.sql"
        operations:
          - SELECT
        indices:
          - idx_analytic_plans_tenant_id
        rls_policy: tenant_isolation_analytic_plans

    tests:
      backend:
        unit_tests:
          - file: "src/modules/analytics/services/analytic-account.service.spec.ts"
            test_cases:
              - "should create analytic account with valid data"
              - "should throw error when code already exists"
              - "should support hierarchical accounts"
              - "should find all accounts for tenant"
              - "should update account successfully"
        integration_tests:
          - file: "test/analytics/analytic-account.controller.e2e-spec.ts"
            test_cases:
              - "POST /api/v1/analytics/accounts should create account"
              - "GET /api/v1/analytics/accounts should return all accounts"
              - "GET /api/v1/analytics/accounts/:id should return account"
              - "PUT /api/v1/analytics/accounts/:id should update account"
              - "DELETE /api/v1/analytics/accounts/:id should soft delete account"
              - "should enforce tenant isolation"
              - "should require authentication"
              - "should check permissions"
      frontend:
        component_tests:
          - file: "src/widgets/analytic-accounts-table/ui/AnalyticAccountsTable.test.tsx"
            test_cases:
              - "should render table with accounts"
              - "should handle pagination"
              - "should call delete on button click"
          - file: "src/features/create-analytic-account/ui/CreateAnalyticAccountForm.test.tsx"
            test_cases:
              - "should validate required fields"
              - "should submit valid form"
              - "should show error messages"
        e2e_tests:
          - file: "e2e/analytics/analytic-accounts.spec.ts"
            test_cases:
              - "should create analytic account successfully"
              - "should edit analytic account successfully"
              - "should delete analytic account with confirmation"
              - "should enforce permissions"

    acceptance_criteria:
      - id: AC-001
        description: "Usuario puede crear cuentas analíticas con código único"
        status: Pending
        test_reference: "test/analytics/analytic-account.controller.e2e-spec.ts:32"
      - id: AC-002
        description: "Cuentas analíticas soportan estructura jerárquica"
        status: Pending
        test_reference: "src/modules/analytics/services/analytic-account.service.spec.ts:65"
      - id: AC-003
        description: "Cuentas pueden asociarse a diferentes planes analíticos"
        status: Pending
        test_reference: "test/analytics/analytic-account.controller.e2e-spec.ts:98"

    business_rules:
      - id: RN-001
        description: "Código de cuenta analítica debe ser único por tenant"
        implementation: "database-design/schemas/analytics-schema-ddl.sql:CONSTRAINT uq_analytic_accounts_code_tenant"
        test_reference: "src/modules/analytics/services/analytic-account.service.spec.ts:88"
      - id: RN-002
        description: "Cuenta analítica debe estar asociada a un plan analítico"
        implementation: "src/modules/analytics/services/analytic-account.service.ts:validatePlan()"
        test_reference: "src/modules/analytics/services/analytic-account.service.spec.ts:112"
      - id: RN-003
        description: "Cuenta con movimientos no puede ser eliminada"
        implementation: "src/modules/analytics/services/analytic-account.service.ts:remove()"
        test_reference: "src/modules/analytics/services/analytic-account.service.spec.ts:138"

    dependencies:
      rf_dependencies: []
      module_dependencies:
        - MGN-001
      external_dependencies:
        - name: "@nestjs/common"
          version: "^10.0.0"
        - name: "ant-design"
          version: "^5.0.0"

  - rf_id: RF-MGN-008-002
    rf_title: "Registro de Líneas Analíticas"
    rf_file: "requerimientos-funcionales/mgn-008/RF-MGN-008-002-registro-de-líneas-analíticas.md"
    priority: P0
    story_points: 8

    et_backend:
      file: "especificaciones-tecnicas/backend/mgn-008/ET-BACKEND-MGN-008-002-registro-de-líneas-analíticas.md"
      endpoints:
        - method: POST
          path: /api/v1/analytics/lines
          description: "Crear nueva línea analítica"
        - method: GET
          path: /api/v1/analytics/lines
          description: "Listar todas las líneas analíticas"
        - method: GET
          path: /api/v1/analytics/lines/:id
          description: "Obtener línea analítica por ID"
        - method: PUT
          path: /api/v1/analytics/lines/:id
          description: "Actualizar línea analítica"
        - method: DELETE
          path: /api/v1/analytics/lines/:id
          description: "Eliminar línea analítica (soft delete)"
      services:
        - name: "AnalyticLineService"
          file: "src/modules/analytics/services/analytic-line.service.ts"
          methods:
            - create
            - findAll
            - findOne
            - update
            - remove
            - validateBusinessRules
      controllers:
        - name: "AnalyticLineController"
          file: "src/modules/analytics/controllers/analytic-line.controller.ts"
      dtos:
        - name: "CreateAnalyticLineDto"
          file: "src/modules/analytics/dto/create-analytic-line.dto.ts"
        - name: "UpdateAnalyticLineDto"
          file: "src/modules/analytics/dto/update-analytic-line.dto.ts"
        - name: "AnalyticLineResponseDto"
          file: "src/modules/analytics/dto/analytic-line-response.dto.ts"
        - name: "FilterAnalyticLineDto"
          file: "src/modules/analytics/dto/filter-analytic-line.dto.ts"

    et_frontend:
      file: "especificaciones-tecnicas/frontend/mgn-008/ET-FRONTEND-MGN-008-002-registro-de-líneas-analíticas.md"
      routes:
        - path: "/analytics/lines"
          component: "AnalyticLinesPage"
        - path: "/analytics/lines/create"
          component: "CreateAnalyticLinePage"
        - path: "/analytics/lines/:id/edit"
          component: "EditAnalyticLinePage"
        - path: "/analytics/lines/:id"
          component: "ViewAnalyticLinePage"
      components:
        - name: "AnalyticLinesTable"
          file: "src/widgets/analytic-lines-table/ui/AnalyticLinesTable.tsx"
          type: widget
        - name: "CreateAnalyticLineForm"
          file: "src/features/create-analytic-line/ui/CreateAnalyticLineForm.tsx"
          type: feature
        - name: "AnalyticLineCard"
          file: "src/entities/analytic-line/ui/AnalyticLineCard.tsx"
          type: entity
        - name: "AnalyticLinePage"
          file: "src/pages/analytics/AnalyticLinePage.tsx"
          type: page
      api_client:
        - name: "analyticLineApi"
          file: "src/entities/analytic-line/api/analytic-line.api.ts"
          methods:
            - getAll
            - getById
            - create
            - update
            - delete
      state_management:
        - name: "useAnalyticLineStore"
          file: "src/entities/analytic-line/model/analytic-line.store.ts"
          type: zustand
        - name: "useAnalyticLines"
          file: "src/entities/analytic-line/api/analytic-line.queries.ts"
          type: react-query

    database_tables:
      - schema: analytics
        table: analytic_lines
        file: "database-design/schemas/analytics-schema-ddl.sql"
        operations:
          - SELECT
          - INSERT
          - UPDATE
          - DELETE (soft)
        indices:
          - idx_analytic_lines_tenant_id
          - idx_analytic_lines_account_id
          - idx_analytic_lines_date
          - idx_analytic_lines_journal_entry_id
        rls_policy: tenant_isolation_analytic_lines
      - schema: financial
        table: journal_entries
        file: "database-design/schemas/financial-schema-ddl.sql"
        operations:
          - SELECT
        indices:
          - idx_journal_entries_tenant_id
        rls_policy: tenant_isolation_journal_entries

    tests:
      backend:
        unit_tests:
          - file: "src/modules/analytics/services/analytic-line.service.spec.ts"
            test_cases:
              - "should create analytic line with valid data"
              - "should link to journal entry automatically"
              - "should validate account existence"
              - "should find all lines for tenant"
              - "should update line successfully"
        integration_tests:
          - file: "test/analytics/analytic-line.controller.e2e-spec.ts"
            test_cases:
              - "POST /api/v1/analytics/lines should create line"
              - "GET /api/v1/analytics/lines should return all lines"
              - "GET /api/v1/analytics/lines/:id should return line"
              - "PUT /api/v1/analytics/lines/:id should update line"
              - "DELETE /api/v1/analytics/lines/:id should soft delete line"
              - "should enforce tenant isolation"
              - "should require authentication"
              - "should check permissions"
      frontend:
        component_tests:
          - file: "src/widgets/analytic-lines-table/ui/AnalyticLinesTable.test.tsx"
            test_cases:
              - "should render table with lines"
              - "should handle pagination"
              - "should filter by account"
          - file: "src/features/create-analytic-line/ui/CreateAnalyticLineForm.test.tsx"
            test_cases:
              - "should validate required fields"
              - "should submit valid form"
              - "should show error messages"
        e2e_tests:
          - file: "e2e/analytics/analytic-lines.spec.ts"
            test_cases:
              - "should create analytic line successfully"
              - "should edit analytic line successfully"
              - "should delete analytic line with confirmation"
              - "should enforce permissions"

    acceptance_criteria:
      - id: AC-001
        description: "Usuario puede registrar líneas analíticas manualmente"
        status: Pending
        test_reference: "test/analytics/analytic-line.controller.e2e-spec.ts:35"
      - id: AC-002
        description: "Líneas analíticas se crean automáticamente desde asientos contables"
        status: Pending
        test_reference: "src/modules/analytics/services/analytic-line.service.spec.ts:72"
      - id: AC-003
        description: "Líneas soportan montos positivos (ingresos) y negativos (costos)"
        status: Pending
        test_reference: "test/analytics/analytic-line.controller.e2e-spec.ts:108"

    business_rules:
      - id: RN-001
        description: "Línea analítica debe tener cuenta analítica válida"
        implementation: "src/modules/analytics/services/analytic-line.service.ts:validateAccount()"
        test_reference: "src/modules/analytics/services/analytic-line.service.spec.ts:95"
      - id: RN-002
        description: "Monto puede ser positivo (ingreso) o negativo (costo)"
        implementation: "src/modules/analytics/services/analytic-line.service.ts:create()"
        test_reference: "src/modules/analytics/services/analytic-line.service.spec.ts:122"
      - id: RN-003
        description: "Líneas vinculadas a journal_entry no pueden ser editadas"
        implementation: "src/modules/analytics/services/analytic-line.service.ts:update()"
        test_reference: "src/modules/analytics/services/analytic-line.service.spec.ts:148"

    dependencies:
      rf_dependencies:
        - RF-MGN-008-001
        - RF-MGN-004-003
      module_dependencies:
        - MGN-001
        - MGN-004
      external_dependencies:
        - name: "@nestjs/common"
          version: "^10.0.0"

  - rf_id: RF-MGN-008-003
    rf_title: "Distribución Analítica Multi-Cuenta"
    rf_file: "requerimientos-funcionales/mgn-008/RF-MGN-008-003-distribución-analítica-multi-cuenta.md"
    priority: P1
    story_points: 8

    et_backend:
      file: "especificaciones-tecnicas/backend/mgn-008/ET-BACKEND-MGN-008-003-distribución-analítica-multi-cuenta.md"
      endpoints:
        - method: POST
          path: /api/v1/analytics/distributions
          description: "Crear nueva distribución analítica"
        - method: GET
          path: /api/v1/analytics/distributions
          description: "Listar todas las distribuciones"
        - method: GET
          path: /api/v1/analytics/distributions/:id
          description: "Obtener distribución por ID"
        - method: PUT
          path: /api/v1/analytics/distributions/:id
          description: "Actualizar distribución"
        - method: DELETE
          path: /api/v1/analytics/distributions/:id
          description: "Eliminar distribución (soft delete)"
      services:
        - name: "AnalyticDistributionService"
          file: "src/modules/analytics/services/analytic-distribution.service.ts"
          methods:
            - create
            - findAll
            - findOne
            - update
            - remove
            - validateBusinessRules
      controllers:
        - name: "AnalyticDistributionController"
          file: "src/modules/analytics/controllers/analytic-distribution.controller.ts"
      dtos:
        - name: "CreateAnalyticDistributionDto"
          file: "src/modules/analytics/dto/create-analytic-distribution.dto.ts"
        - name: "UpdateAnalyticDistributionDto"
          file: "src/modules/analytics/dto/update-analytic-distribution.dto.ts"
        - name: "AnalyticDistributionResponseDto"
          file: "src/modules/analytics/dto/analytic-distribution-response.dto.ts"
        - name: "FilterAnalyticDistributionDto"
          file: "src/modules/analytics/dto/filter-analytic-distribution.dto.ts"

    et_frontend:
      file: "especificaciones-tecnicas/frontend/mgn-008/ET-FRONTEND-MGN-008-003-distribución-analítica-multi-cuenta.md"
      routes:
        - path: "/analytics/distributions"
          component: "AnalyticDistributionsPage"
        - path: "/analytics/distributions/create"
          component: "CreateAnalyticDistributionPage"
        - path: "/analytics/distributions/:id/edit"
          component: "EditAnalyticDistributionPage"
        - path: "/analytics/distributions/:id"
          component: "ViewAnalyticDistributionPage"
      components:
        - name: "AnalyticDistributionsTable"
          file: "src/widgets/analytic-distributions-table/ui/AnalyticDistributionsTable.tsx"
          type: widget
        - name: "CreateAnalyticDistributionForm"
          file: "src/features/create-analytic-distribution/ui/CreateAnalyticDistributionForm.tsx"
          type: feature
        - name: "AnalyticDistributionCard"
          file: "src/entities/analytic-distribution/ui/AnalyticDistributionCard.tsx"
          type: entity
        - name: "AnalyticDistributionPage"
          file: "src/pages/analytics/AnalyticDistributionPage.tsx"
          type: page
      api_client:
        - name: "analyticDistributionApi"
          file: "src/entities/analytic-distribution/api/analytic-distribution.api.ts"
          methods:
            - getAll
            - getById
            - create
            - update
            - delete
      state_management:
        - name: "useAnalyticDistributionStore"
          file: "src/entities/analytic-distribution/model/analytic-distribution.store.ts"
          type: zustand
        - name: "useAnalyticDistributions"
          file: "src/entities/analytic-distribution/api/analytic-distribution.queries.ts"
          type: react-query

    database_tables:
      - schema: analytics
        table: analytic_distributions
        file: "database-design/schemas/analytics-schema-ddl.sql"
        operations:
          - SELECT
          - INSERT
          - UPDATE
          - DELETE (soft)
        indices:
          - idx_analytic_distributions_tenant_id
          - idx_analytic_distributions_name
        rls_policy: tenant_isolation_analytic_distributions
      - schema: analytics
        table: distribution_lines
        file: "database-design/schemas/analytics-schema-ddl.sql"
        operations:
          - SELECT
          - INSERT
          - UPDATE
          - DELETE
        indices:
          - idx_distribution_lines_distribution_id
          - idx_distribution_lines_account_id
        rls_policy: tenant_isolation_distribution_lines

    tests:
      backend:
        unit_tests:
          - file: "src/modules/analytics/services/analytic-distribution.service.spec.ts"
            test_cases:
              - "should create distribution with multiple accounts"
              - "should validate percentages sum to 100%"
              - "should apply distribution to journal entry"
              - "should find all distributions for tenant"
              - "should update distribution successfully"
        integration_tests:
          - file: "test/analytics/analytic-distribution.controller.e2e-spec.ts"
            test_cases:
              - "POST /api/v1/analytics/distributions should create distribution"
              - "GET /api/v1/analytics/distributions should return all distributions"
              - "GET /api/v1/analytics/distributions/:id should return distribution"
              - "PUT /api/v1/analytics/distributions/:id should update distribution"
              - "DELETE /api/v1/analytics/distributions/:id should soft delete distribution"
              - "should enforce tenant isolation"
              - "should require authentication"
              - "should check permissions"
      frontend:
        component_tests:
          - file: "src/widgets/analytic-distributions-table/ui/AnalyticDistributionsTable.test.tsx"
            test_cases:
              - "should render table with distributions"
              - "should handle pagination"
              - "should call delete on button click"
          - file: "src/features/create-analytic-distribution/ui/CreateAnalyticDistributionForm.test.tsx"
            test_cases:
              - "should validate percentages sum to 100%"
              - "should submit valid form"
              - "should show error messages"
        e2e_tests:
          - file: "e2e/analytics/analytic-distributions.spec.ts"
            test_cases:
              - "should create distribution successfully"
              - "should edit distribution successfully"
              - "should delete distribution with confirmation"
              - "should enforce permissions"

    acceptance_criteria:
      - id: AC-001
        description: "Usuario puede crear distribuciones con múltiples cuentas"
        status: Pending
        test_reference: "test/analytics/analytic-distribution.controller.e2e-spec.ts:38"
      - id: AC-002
        description: "Suma de porcentajes debe ser exactamente 100%"
        status: Pending
        test_reference: "src/modules/analytics/services/analytic-distribution.service.spec.ts:75"
      - id: AC-003
        description: "Distribuciones se aplican automáticamente a asientos contables"
        status: Pending
        test_reference: "test/analytics/analytic-distribution.controller.e2e-spec.ts:112"

    business_rules:
      - id: RN-001
        description: "Suma de porcentajes de distribución debe ser 100%"
        implementation: "src/modules/analytics/services/analytic-distribution.service.ts:validatePercentages()"
        test_reference: "src/modules/analytics/services/analytic-distribution.service.spec.ts:98"
      - id: RN-002
        description: "Distribución debe tener al menos 2 cuentas analíticas"
        implementation: "src/modules/analytics/services/analytic-distribution.service.ts:validateAccounts()"
        test_reference: "src/modules/analytics/services/analytic-distribution.service.spec.ts:125"
      - id: RN-003
        description: "Al aplicar distribución, se crean múltiples líneas analíticas"
        implementation: "src/modules/analytics/services/analytic-distribution.service.ts:apply()"
        test_reference: "src/modules/analytics/services/analytic-distribution.service.spec.ts:152"

    dependencies:
      rf_dependencies:
        - RF-MGN-008-001
        - RF-MGN-008-002
      module_dependencies:
        - MGN-001
        - MGN-004
      external_dependencies:
        - name: "@nestjs/common"
          version: "^10.0.0"

  - rf_id: RF-MGN-008-004
    rf_title: "Tags Analíticos"
    rf_file: "requerimientos-funcionales/mgn-008/RF-MGN-008-004-tags-analíticos.md"
    priority: P1
    story_points: 3

    et_backend:
      file: "especificaciones-tecnicas/backend/mgn-008/ET-BACKEND-MGN-008-004-tags-analíticos.md"
      endpoints:
        - method: POST
          path: /api/v1/analytics/tags
          description: "Crear nuevo tag analítico"
        - method: GET
          path: /api/v1/analytics/tags
          description: "Listar todos los tags"
        - method: GET
          path: /api/v1/analytics/tags/:id
          description: "Obtener tag por ID"
        - method: PUT
          path: /api/v1/analytics/tags/:id
          description: "Actualizar tag"
        - method: DELETE
          path: /api/v1/analytics/tags/:id
          description: "Eliminar tag (soft delete)"
      services:
        - name: "AnalyticTagService"
          file: "src/modules/analytics/services/analytic-tag.service.ts"
          methods:
            - create
            - findAll
            - findOne
            - update
            - remove
            - validateBusinessRules
      controllers:
        - name: "AnalyticTagController"
          file: "src/modules/analytics/controllers/analytic-tag.controller.ts"
      dtos:
        - name: "CreateAnalyticTagDto"
          file: "src/modules/analytics/dto/create-analytic-tag.dto.ts"
        - name: "UpdateAnalyticTagDto"
          file: "src/modules/analytics/dto/update-analytic-tag.dto.ts"
        - name: "AnalyticTagResponseDto"
          file: "src/modules/analytics/dto/analytic-tag-response.dto.ts"
        - name: "FilterAnalyticTagDto"
          file: "src/modules/analytics/dto/filter-analytic-tag.dto.ts"

    et_frontend:
      file: "especificaciones-tecnicas/frontend/mgn-008/ET-FRONTEND-MGN-008-004-tags-analíticos.md"
      routes:
        - path: "/analytics/tags"
          component: "AnalyticTagsPage"
        - path: "/analytics/tags/create"
          component: "CreateAnalyticTagPage"
        - path: "/analytics/tags/:id/edit"
          component: "EditAnalyticTagPage"
        - path: "/analytics/tags/:id"
          component: "ViewAnalyticTagPage"
      components:
        - name: "AnalyticTagsTable"
          file: "src/widgets/analytic-tags-table/ui/AnalyticTagsTable.tsx"
          type: widget
        - name: "CreateAnalyticTagForm"
          file: "src/features/create-analytic-tag/ui/CreateAnalyticTagForm.tsx"
          type: feature
        - name: "AnalyticTagCard"
          file: "src/entities/analytic-tag/ui/AnalyticTagCard.tsx"
          type: entity
        - name: "AnalyticTagPage"
          file: "src/pages/analytics/AnalyticTagPage.tsx"
          type: page
      api_client:
        - name: "analyticTagApi"
          file: "src/entities/analytic-tag/api/analytic-tag.api.ts"
          methods:
            - getAll
            - getById
            - create
            - update
            - delete
      state_management:
        - name: "useAnalyticTagStore"
          file: "src/entities/analytic-tag/model/analytic-tag.store.ts"
          type: zustand
        - name: "useAnalyticTags"
          file: "src/entities/analytic-tag/api/analytic-tag.queries.ts"
          type: react-query

    database_tables:
      - schema: analytics
        table: analytic_tags
        file: "database-design/schemas/analytics-schema-ddl.sql"
        operations:
          - SELECT
          - INSERT
          - UPDATE
          - DELETE (soft)
        indices:
          - idx_analytic_tags_tenant_id
          - idx_analytic_tags_name
        rls_policy: tenant_isolation_analytic_tags
      - schema: analytics
        table: analytic_line_tags
        file: "database-design/schemas/analytics-schema-ddl.sql"
        operations:
          - SELECT
          - INSERT
          - DELETE
        indices:
          - idx_analytic_line_tags_line_id
          - idx_analytic_line_tags_tag_id
        rls_policy: tenant_isolation_analytic_line_tags

    tests:
      backend:
        unit_tests:
          - file: "src/modules/analytics/services/analytic-tag.service.spec.ts"
            test_cases:
              - "should create analytic tag with valid data"
              - "should assign tags to analytic lines"
              - "should find all tags for tenant"
              - "should update tag successfully"
              - "should delete tag if no lines associated"
        integration_tests:
          - file: "test/analytics/analytic-tag.controller.e2e-spec.ts"
            test_cases:
              - "POST /api/v1/analytics/tags should create tag"
              - "GET /api/v1/analytics/tags should return all tags"
              - "GET /api/v1/analytics/tags/:id should return tag"
              - "PUT /api/v1/analytics/tags/:id should update tag"
              - "DELETE /api/v1/analytics/tags/:id should soft delete tag"
              - "should enforce tenant isolation"
              - "should require authentication"
              - "should check permissions"
      frontend:
        component_tests:
          - file: "src/widgets/analytic-tags-table/ui/AnalyticTagsTable.test.tsx"
            test_cases:
              - "should render table with tags"
              - "should handle pagination"
              - "should call delete on button click"
          - file: "src/features/create-analytic-tag/ui/CreateAnalyticTagForm.test.tsx"
            test_cases:
              - "should validate required fields"
              - "should submit valid form"
              - "should show error messages"
        e2e_tests:
          - file: "e2e/analytics/analytic-tags.spec.ts"
            test_cases:
              - "should create analytic tag successfully"
              - "should edit analytic tag successfully"
              - "should delete analytic tag with confirmation"
              - "should enforce permissions"

    acceptance_criteria:
      - id: AC-001
        description: "Usuario puede crear tags para clasificación adicional"
        status: Pending
        test_reference: "test/analytics/analytic-tag.controller.e2e-spec.ts:32"
      - id: AC-002
        description: "Tags se asignan a líneas analíticas (relación many-to-many)"
        status: Pending
        test_reference: "src/modules/analytics/services/analytic-tag.service.spec.ts:68"
      - id: AC-003
        description: "Reportes pueden filtrarse por tags"
        status: Pending
        test_reference: "test/analytics/analytic-tag.controller.e2e-spec.ts:95"

    business_rules:
      - id: RN-001
        description: "Nombre de tag debe ser único por tenant"
        implementation: "database-design/schemas/analytics-schema-ddl.sql:CONSTRAINT uq_analytic_tags_name_tenant"
        test_reference: "src/modules/analytics/services/analytic-tag.service.spec.ts:88"
      - id: RN-002
        description: "Una línea analítica puede tener múltiples tags"
        implementation: "database-design/schemas/analytics-schema-ddl.sql:analytic_line_tags table"
        test_reference: "src/modules/analytics/services/analytic-tag.service.spec.ts:112"
      - id: RN-003
        description: "Tag con líneas asociadas no puede ser eliminado permanentemente"
        implementation: "src/modules/analytics/services/analytic-tag.service.ts:remove()"
        test_reference: "src/modules/analytics/services/analytic-tag.service.spec.ts:138"

    dependencies:
      rf_dependencies:
        - RF-MGN-008-002
      module_dependencies:
        - MGN-001
      external_dependencies:
        - name: "@nestjs/common"
          version: "^10.0.0"

  - rf_id: RF-MGN-008-005
    rf_title: "Reportes Analíticos (P&L por Proyecto)"
    rf_file: "requerimientos-funcionales/mgn-008/RF-MGN-008-005-reportes-analíticos-p&l-por-proyecto.md"
    priority: P0
    story_points: 8

    et_backend:
      file: "especificaciones-tecnicas/backend/mgn-008/ET-BACKEND-MGN-008-005-reportes-analíticos-p&l-por-proyecto.md"
      endpoints:
        - method: GET
          path: /api/v1/analytics/reports/pl
          description: "Obtener reporte P&L por cuenta analítica"
        - method: GET
          path: /api/v1/analytics/reports/balance
          description: "Obtener balance analítico"
        - method: GET
          path: /api/v1/analytics/reports/summary
          description: "Resumen analítico por período"
        - method: GET
          path: /api/v1/analytics/reports/comparison
          description: "Comparación de cuentas analíticas"
        - method: GET
          path: /api/v1/analytics/reports/trends
          description: "Tendencias analíticas"
      services:
        - name: "AnalyticReportService"
          file: "src/modules/analytics/services/analytic-report.service.ts"
          methods:
            - getProfitAndLoss
            - getBalance
            - getSummary
            - getComparison
            - getTrends
      controllers:
        - name: "AnalyticReportController"
          file: "src/modules/analytics/controllers/analytic-report.controller.ts"
      dtos:
        - name: "AnalyticReportFilterDto"
          file: "src/modules/analytics/dto/analytic-report-filter.dto.ts"
        - name: "AnalyticReportResponseDto"
          file: "src/modules/analytics/dto/analytic-report-response.dto.ts"

    et_frontend:
      file: "especificaciones-tecnicas/frontend/mgn-008/ET-FRONTEND-MGN-008-005-reportes-analíticos-p&l-por-proyecto.md"
      routes:
        - path: "/analytics/reports"
          component: "AnalyticReportsPage"
        - path: "/analytics/reports/pl"
          component: "AnalyticPLPage"
        - path: "/analytics/reports/balance"
          component: "AnalyticBalancePage"
      components:
        - name: "AnalyticReportDashboard"
          file: "src/widgets/analytic-report-dashboard/ui/AnalyticReportDashboard.tsx"
          type: widget
        - name: "AnalyticChart"
          file: "src/features/analytic-chart/ui/AnalyticChart.tsx"
          type: feature
        - name: "AnalyticReportFilters"
          file: "src/entities/analytic-report/ui/AnalyticReportFilters.tsx"
          type: entity
        - name: "AnalyticReportsPage"
          file: "src/pages/analytics/AnalyticReportsPage.tsx"
          type: page
      api_client:
        - name: "analyticReportApi"
          file: "src/entities/analytic-report/api/analytic-report.api.ts"
          methods:
            - getPL
            - getBalance
            - getSummary
            - getComparison
            - getTrends
      state_management:
        - name: "useAnalyticReportStore"
          file: "src/entities/analytic-report/model/analytic-report.store.ts"
          type: zustand
        - name: "useAnalyticReports"
          file: "src/entities/analytic-report/api/analytic-report.queries.ts"
          type: react-query

    database_tables:
      - schema: analytics
        table: analytic_lines
        file: "database-design/schemas/analytics-schema-ddl.sql"
        operations:
          - SELECT
        indices:
          - idx_analytic_lines_date
          - idx_analytic_lines_account_id
        rls_policy: tenant_isolation_analytic_lines
      - schema: analytics
        table: analytic_accounts
        file: "database-design/schemas/analytics-schema-ddl.sql"
        operations:
          - SELECT
        indices:
          - idx_analytic_accounts_tenant_id
        rls_policy: tenant_isolation_analytic_accounts

    tests:
      backend:
        unit_tests:
          - file: "src/modules/analytics/services/analytic-report.service.spec.ts"
            test_cases:
              - "should generate P&L report by account"
              - "should calculate income, expenses, and profit"
              - "should generate balance report"
              - "should compare multiple accounts"
              - "should calculate trends over time"
        integration_tests:
          - file: "test/analytics/analytic-report.controller.e2e-spec.ts"
            test_cases:
              - "GET /api/v1/analytics/reports/pl should return P&L report"
              - "GET /api/v1/analytics/reports/balance should return balance"
              - "GET /api/v1/analytics/reports/summary should return summary"
              - "GET /api/v1/analytics/reports/comparison should compare accounts"
              - "GET /api/v1/analytics/reports/trends should return trends"
              - "should enforce tenant isolation"
              - "should require authentication"
              - "should check permissions"
      frontend:
        component_tests:
          - file: "src/widgets/analytic-report-dashboard/ui/AnalyticReportDashboard.test.tsx"
            test_cases:
              - "should render dashboard with charts"
              - "should apply filters"
              - "should export report"
          - file: "src/features/analytic-chart/ui/AnalyticChart.test.tsx"
            test_cases:
              - "should render chart with data"
              - "should change chart type"
              - "should handle empty data"
        e2e_tests:
          - file: "e2e/analytics/analytic-reports.spec.ts"
            test_cases:
              - "should display P&L report"
              - "should filter by date range"
              - "should export to PDF/Excel"
              - "should enforce permissions"

    acceptance_criteria:
      - id: AC-001
        description: "Usuario puede generar P&L por cuenta analítica"
        status: Pending
        test_reference: "test/analytics/analytic-report.controller.e2e-spec.ts:42"
      - id: AC-002
        description: "Reporte muestra ingresos, costos y margen neto"
        status: Pending
        test_reference: "src/modules/analytics/services/analytic-report.service.spec.ts:78"
      - id: AC-003
        description: "Reportes soportan filtros por fecha, tags y cuentas"
        status: Pending
        test_reference: "test/analytics/analytic-report.controller.e2e-spec.ts:115"

    business_rules:
      - id: RN-001
        description: "P&L suma líneas positivas como ingresos, negativas como costos"
        implementation: "src/modules/analytics/services/analytic-report.service.ts:calculatePL()"
        test_reference: "src/modules/analytics/services/analytic-report.service.spec.ts:98"
      - id: RN-002
        description: "Margen = Ingresos - Costos, expresado también en porcentaje"
        implementation: "src/modules/analytics/services/analytic-report.service.ts:calculateMargin()"
        test_reference: "src/modules/analytics/services/analytic-report.service.spec.ts:125"
      - id: RN-003
        description: "Reportes solo incluyen líneas de cuentas activas"
        implementation: "src/modules/analytics/services/analytic-report.service.ts:filterActiveAccounts()"
        test_reference: "src/modules/analytics/services/analytic-report.service.spec.ts:152"

    dependencies:
      rf_dependencies:
        - RF-MGN-008-001
        - RF-MGN-008-002
      module_dependencies:
        - MGN-001
        - MGN-012
      external_dependencies:
        - name: "chart.js"
          version: "^4.0.0"
        - name: "exceljs"
          version: "^4.3.0"

coverage:
  rf_to_et_backend: 100%
  rf_to_et_frontend: 100%
  rf_to_database: 100%
  rf_to_tests: 100%
  backend_tests: 100%
  frontend_tests: 100%

statistics:
  total_endpoints: 25
  total_components: 20
  total_tables: 6
  total_test_cases: 100
  estimated_duration_sprints: 2
