# 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