# TRACEABILITY-MGN-003.yaml
# Matriz de Trazabilidad - MGN-003: Catálogos Maestros
# Fecha: 2025-11-24
# Versión: 1.0

module:
  id: MGN-003
  name: "Catálogos Maestros"
  description: "Partners universales, países, monedas, unidades de medida, categorías y términos de pago"
  priority: P0
  story_points: 29
  status: Diseñado

metadata:
  total_rf: 6
  total_et_backend: 6
  total_et_frontend: 6
  total_tables: 9
  total_tests: 120
  coverage: 100%

requirements:
  - rf_id: RF-MGN-003-001
    rf_title: "Gestión de Partners Universales"
    rf_file: "requerimientos-funcionales/mgn-003/RF-MGN-003-001-gestion-partners.md"
    priority: P0
    story_points: 8

    et_backend:
      file: "especificaciones-tecnicas/backend/mgn-003/ET-BACKEND-MGN-003-001-gestión-de-partners-universales.md"
      endpoints:
        - method: POST
          path: /api/v1/partners
          description: "Crear partner (cliente, proveedor o ambos)"
        - method: GET
          path: /api/v1/partners
          description: "Listar partners con filtros"
        - method: GET
          path: /api/v1/partners/:id
          description: "Obtener partner por ID"
        - method: PUT
          path: /api/v1/partners/:id
          description: "Actualizar partner"
        - method: DELETE
          path: /api/v1/partners/:id
          description: "Desactivar partner (soft delete)"
      services:
        - name: "PartnerService"
          file: "src/modules/partners/services/partner.service.ts"
          methods:
            - create
            - findAll
            - findOne
            - update
            - remove
      controllers:
        - name: "PartnerController"
          file: "src/modules/partners/controllers/partner.controller.ts"
      dtos:
        - name: "CreatePartnerDto"
          file: "src/modules/partners/dto/create-partner.dto.ts"
        - name: "UpdatePartnerDto"
          file: "src/modules/partners/dto/update-partner.dto.ts"

    et_frontend:
      file: "especificaciones-tecnicas/frontend/mgn-003/ET-FRONTEND-MGN-003-001-gestión-de-partners-universales.md"
      routes:
        - path: "/partners"
          component: "PartnersPage"
        - path: "/partners/create"
          component: "CreatePartnerPage"
        - path: "/partners/:id/edit"
          component: "EditPartnerPage"
        - path: "/partners/:id"
          component: "ViewPartnerPage"
      components:
        - name: "PartnersTable"
          file: "src/widgets/partners-table/ui/PartnersTable.tsx"
          type: widget
        - name: "CreatePartnerForm"
          file: "src/features/create-partner/ui/CreatePartnerForm.tsx"
          type: feature
        - name: "PartnerCard"
          file: "src/entities/partner/ui/PartnerCard.tsx"
          type: entity
      api_client:
        - name: "partnerApi"
          file: "src/entities/partner/api/partner.api.ts"
          methods:
            - getAll
            - getById
            - create
            - update
            - delete
      state_management:
        - name: "usePartnerStore"
          file: "src/entities/partner/model/partner.store.ts"
          type: zustand

    database_tables:
      - schema: core
        table: partners
        file: "database-design/schemas/core-schema-ddl.sql"
        operations:
          - SELECT
          - INSERT
          - UPDATE
          - DELETE (soft)
        indices:
          - idx_partners_tenant_id
          - idx_partners_company_id
          - idx_partners_tax_id
          - idx_partners_type
        rls_policy: tenant_isolation_partners

    tests:
      backend:
        unit_tests:
          - file: "src/modules/partners/services/partner.service.spec.ts"
            test_cases:
              - "should create partner with valid data"
              - "should create customer partner"
              - "should create supplier partner"
              - "should create partner as both customer and supplier"
              - "should throw error when tax_id already exists"
              - "should find all partners for tenant"
              - "should update partner successfully"
              - "should soft delete partner"
        integration_tests:
          - file: "test/partners/partner.controller.e2e-spec.ts"
            test_cases:
              - "POST /api/v1/partners should create partner"
              - "GET /api/v1/partners should return all partners"
              - "GET /api/v1/partners/:id should return partner"
              - "PUT /api/v1/partners/:id should update partner"
              - "DELETE /api/v1/partners/:id should soft delete partner"
              - "should filter partners by type (customer/supplier)"
              - "should enforce tenant isolation"
              - "should require authentication"
      frontend:
        component_tests:
          - file: "src/widgets/partners-table/ui/PartnersTable.test.tsx"
            test_cases:
              - "should render table with partners"
              - "should handle pagination"
              - "should filter by type"
          - file: "src/features/create-partner/ui/CreatePartnerForm.test.tsx"
            test_cases:
              - "should validate required fields"
              - "should validate tax_id format"
              - "should submit valid form"
        e2e_tests:
          - file: "e2e/partners/partners.spec.ts"
            test_cases:
              - "should create partner successfully"
              - "should edit partner successfully"
              - "should delete partner with confirmation"
              - "should filter partners by type"

    acceptance_criteria:
      - id: AC-001
        description: "Usuario puede crear partners como cliente, proveedor o ambos"
        status: Pending
        test_reference: "test/partners/partner.controller.e2e-spec.ts:28"
      - id: AC-002
        description: "Sistema valida que tax_id sea único por tenant"
        status: Pending
        test_reference: "src/modules/partners/services/partner.service.spec.ts:65"
      - id: AC-003
        description: "Partner puede tener múltiples direcciones y contactos"
        status: Pending
        test_reference: "test/partners/partner.controller.e2e-spec.ts:95"

    business_rules:
      - id: RN-001
        description: "Partner puede ser cliente, proveedor o ambos (is_customer, is_supplier)"
        implementation: "database-design/schemas/core-schema-ddl.sql:partners table"
        test_reference: "src/modules/partners/services/partner.service.spec.ts:48"
      - id: RN-002
        description: "Tax ID debe ser único por tenant (no globalmente)"
        implementation: "database-design/schemas/core-schema-ddl.sql:CONSTRAINT uq_partners_tax_id_tenant"
        test_reference: "src/modules/partners/services/partner.service.spec.ts:78"
      - id: RN-003
        description: "Empresa también es partner (is_company=true)"
        implementation: "src/modules/companies/services/company.service.ts:create()"
        test_reference: "src/modules/partners/services/partner.service.spec.ts:105"

    dependencies:
      rf_dependencies:
        - RF-MGN-001-001
        - RF-MGN-003-002
      module_dependencies:
        - MGN-001
      external_dependencies: []

  - rf_id: RF-MGN-003-002
    rf_title: "Gestión de Países y Regiones"
    rf_file: "requerimientos-funcionales/mgn-003/RF-MGN-003-002-gestión-de-países-y-regiones.md"
    priority: P0
    story_points: 3

    et_backend:
      file: "especificaciones-tecnicas/backend/mgn-003/ET-BACKEND-MGN-003-002-gestión-de-países-y-regiones.md"
      endpoints:
        - method: GET
          path: /api/v1/countries
          description: "Listar países"
        - method: GET
          path: /api/v1/countries/:id
          description: "Obtener país por ID"
        - method: GET
          path: /api/v1/countries/:id/states
          description: "Obtener estados/provincias de país"
      services:
        - name: "CountryService"
          file: "src/modules/catalogs/services/country.service.ts"
          methods:
            - findAll
            - findOne
            - findStates
      controllers:
        - name: "CountryController"
          file: "src/modules/catalogs/controllers/country.controller.ts"
      dtos: []

    et_frontend:
      file: "especificaciones-tecnicas/frontend/mgn-003/ET-FRONTEND-MGN-003-002-gestión-de-países-y-regiones.md"
      routes:
        - path: "/catalogs/countries"
          component: "CountriesPage"
      components:
        - name: "CountriesTable"
          file: "src/widgets/countries-table/ui/CountriesTable.tsx"
          type: widget
        - name: "CountrySelector"
          file: "src/shared/ui/CountrySelector.tsx"
          type: shared
      api_client:
        - name: "countryApi"
          file: "src/entities/country/api/country.api.ts"
          methods:
            - getAll
            - getById
            - getStates
      state_management:
        - name: "useCountryStore"
          file: "src/entities/country/model/country.store.ts"
          type: zustand

    database_tables:
      - schema: core
        table: countries
        file: "database-design/schemas/core-schema-ddl.sql"
        operations:
          - SELECT
        indices:
          - idx_countries_code
        rls_policy: null
      - schema: core
        table: states
        file: "database-design/schemas/core-schema-ddl.sql"
        operations:
          - SELECT
        indices:
          - idx_states_country_id
        rls_policy: null

    tests:
      backend:
        unit_tests:
          - file: "src/modules/catalogs/services/country.service.spec.ts"
            test_cases:
              - "should find all countries"
              - "should find country by id"
              - "should find states by country"
        integration_tests:
          - file: "test/catalogs/country.controller.e2e-spec.ts"
            test_cases:
              - "GET /api/v1/countries should return all countries"
              - "GET /api/v1/countries/:id should return country"
              - "GET /api/v1/countries/:id/states should return states"
              - "should not require authentication for read"
      frontend:
        component_tests:
          - file: "src/widgets/countries-table/ui/CountriesTable.test.tsx"
            test_cases:
              - "should render table with countries"
              - "should show country details"
        e2e_tests:
          - file: "e2e/catalogs/countries.spec.ts"
            test_cases:
              - "should list countries successfully"
              - "should select country in selector"

    acceptance_criteria:
      - id: AC-001
        description: "Sistema provee catálogo de países ISO 3166"
        status: Pending
        test_reference: "test/catalogs/country.controller.e2e-spec.ts:22"
      - id: AC-002
        description: "Sistema provee estados/provincias por país"
        status: Pending
        test_reference: "test/catalogs/country.controller.e2e-spec.ts:48"
      - id: AC-003
        description: "Catálogo es precargado en base de datos"
        status: Pending
        test_reference: "database-design/schemas/core-schema-ddl.sql:countries seed"

    business_rules:
      - id: RN-001
        description: "Catálogo de países es global (no por tenant)"
        implementation: "database-design/schemas/core-schema-ddl.sql:countries table"
        test_reference: "src/modules/catalogs/services/country.service.spec.ts:38"
      - id: RN-002
        description: "Código de país sigue ISO 3166-1 alpha-2"
        implementation: "database-design/schemas/core-schema-ddl.sql:countries.code"
        test_reference: "src/modules/catalogs/services/country.service.spec.ts:52"
      - id: RN-003
        description: "Estados son opcionales (no todos los países tienen estados)"
        implementation: "database-design/schemas/core-schema-ddl.sql:states table"
        test_reference: "src/modules/catalogs/services/country.service.spec.ts:68"

    dependencies:
      rf_dependencies: []
      module_dependencies: []
      external_dependencies: []

  - rf_id: RF-MGN-003-003
    rf_title: "Gestión de Monedas y Tasas de Cambio"
    rf_file: "requerimientos-funcionales/mgn-003/RF-MGN-003-003-gestión-de-monedas-y-tasas-de-cambio.md"
    priority: P0
    story_points: 5

    et_backend:
      file: "especificaciones-tecnicas/backend/mgn-003/ET-BACKEND-MGN-003-003-gestión-de-monedas-y-tasas-de-cambio.md"
      endpoints:
        - method: GET
          path: /api/v1/currencies
          description: "Listar monedas"
        - method: GET
          path: /api/v1/currencies/:id
          description: "Obtener moneda por ID"
        - method: POST
          path: /api/v1/exchange-rates
          description: "Crear tasa de cambio"
        - method: GET
          path: /api/v1/exchange-rates
          description: "Listar tasas de cambio"
        - method: PUT
          path: /api/v1/exchange-rates/:id
          description: "Actualizar tasa de cambio"
      services:
        - name: "CurrencyService"
          file: "src/modules/catalogs/services/currency.service.ts"
          methods:
            - findAll
            - findOne
        - name: "ExchangeRateService"
          file: "src/modules/catalogs/services/exchange-rate.service.ts"
          methods:
            - create
            - findAll
            - update
            - getRate
      controllers:
        - name: "CurrencyController"
          file: "src/modules/catalogs/controllers/currency.controller.ts"
        - name: "ExchangeRateController"
          file: "src/modules/catalogs/controllers/exchange-rate.controller.ts"
      dtos:
        - name: "CreateExchangeRateDto"
          file: "src/modules/catalogs/dto/create-exchange-rate.dto.ts"
        - name: "UpdateExchangeRateDto"
          file: "src/modules/catalogs/dto/update-exchange-rate.dto.ts"

    et_frontend:
      file: "especificaciones-tecnicas/frontend/mgn-003/ET-FRONTEND-MGN-003-003-gestión-de-monedas-y-tasas-de-cambio.md"
      routes:
        - path: "/catalogs/currencies"
          component: "CurrenciesPage"
        - path: "/catalogs/exchange-rates"
          component: "ExchangeRatesPage"
      components:
        - name: "CurrenciesTable"
          file: "src/widgets/currencies-table/ui/CurrenciesTable.tsx"
          type: widget
        - name: "ExchangeRatesTable"
          file: "src/widgets/exchange-rates-table/ui/ExchangeRatesTable.tsx"
          type: widget
        - name: "CreateExchangeRateForm"
          file: "src/features/create-exchange-rate/ui/CreateExchangeRateForm.tsx"
          type: feature
      api_client:
        - name: "currencyApi"
          file: "src/entities/currency/api/currency.api.ts"
          methods:
            - getAll
            - getById
        - name: "exchangeRateApi"
          file: "src/entities/exchange-rate/api/exchange-rate.api.ts"
          methods:
            - getAll
            - create
            - update
      state_management:
        - name: "useCurrencyStore"
          file: "src/entities/currency/model/currency.store.ts"
          type: zustand

    database_tables:
      - schema: core
        table: currencies
        file: "database-design/schemas/core-schema-ddl.sql"
        operations:
          - SELECT
        indices:
          - idx_currencies_code
        rls_policy: null
      - schema: core
        table: exchange_rates
        file: "database-design/schemas/core-schema-ddl.sql"
        operations:
          - SELECT
          - INSERT
          - UPDATE
        indices:
          - idx_exchange_rates_from_to_date
          - idx_exchange_rates_company_id
        rls_policy: tenant_isolation_exchange_rates

    tests:
      backend:
        unit_tests:
          - file: "src/modules/catalogs/services/exchange-rate.service.spec.ts"
            test_cases:
              - "should create exchange rate"
              - "should get rate for date"
              - "should use latest rate if no date specified"
              - "should calculate conversion"
              - "should update exchange rate"
        integration_tests:
          - file: "test/catalogs/exchange-rate.controller.e2e-spec.ts"
            test_cases:
              - "POST /api/v1/exchange-rates should create rate"
              - "GET /api/v1/exchange-rates should return all rates"
              - "PUT /api/v1/exchange-rates/:id should update rate"
              - "should enforce tenant isolation"
              - "should require authentication"
      frontend:
        component_tests:
          - file: "src/widgets/exchange-rates-table/ui/ExchangeRatesTable.test.tsx"
            test_cases:
              - "should render table with rates"
              - "should show conversion preview"
          - file: "src/features/create-exchange-rate/ui/CreateExchangeRateForm.test.tsx"
            test_cases:
              - "should validate required fields"
              - "should validate rate > 0"
              - "should submit valid form"
        e2e_tests:
          - file: "e2e/catalogs/exchange-rates.spec.ts"
            test_cases:
              - "should create exchange rate successfully"
              - "should update rate successfully"
              - "should show rate history"

    acceptance_criteria:
      - id: AC-001
        description: "Usuario puede crear tasas de cambio por fecha"
        status: Pending
        test_reference: "test/catalogs/exchange-rate.controller.e2e-spec.ts:28"
      - id: AC-002
        description: "Sistema usa tasa más reciente si no hay tasa para fecha específica"
        status: Pending
        test_reference: "src/modules/catalogs/services/exchange-rate.service.spec.ts:68"
      - id: AC-003
        description: "Sistema convierte montos entre monedas automáticamente"
        status: Pending
        test_reference: "src/modules/catalogs/services/exchange-rate.service.spec.ts:95"

    business_rules:
      - id: RN-001
        description: "Tasa de cambio es específica por empresa y fecha"
        implementation: "database-design/schemas/core-schema-ddl.sql:exchange_rates table"
        test_reference: "src/modules/catalogs/services/exchange-rate.service.spec.ts:48"
      - id: RN-002
        description: "Rate debe ser mayor a 0"
        implementation: "src/modules/catalogs/dto/create-exchange-rate.dto.ts:@Min(0.000001)"
        test_reference: "src/modules/catalogs/services/exchange-rate.service.spec.ts:78"
      - id: RN-003
        description: "Si no hay tasa para fecha, usar tasa más reciente"
        implementation: "src/modules/catalogs/services/exchange-rate.service.ts:getRate()"
        test_reference: "src/modules/catalogs/services/exchange-rate.service.spec.ts:108"

    dependencies:
      rf_dependencies:
        - RF-MGN-002-001
      module_dependencies:
        - MGN-002
      external_dependencies: []

  - rf_id: RF-MGN-003-004
    rf_title: "Gestión de Unidades de Medida (UoM)"
    rf_file: "requerimientos-funcionales/mgn-003/RF-MGN-003-004-gestión-de-unidades-de-medida-uom.md"
    priority: P0
    story_points: 5

    et_backend:
      file: "especificaciones-tecnicas/backend/mgn-003/ET-BACKEND-MGN-003-004-gestión-de-unidades-de-medida-uom.md"
      endpoints:
        - method: POST
          path: /api/v1/uom
          description: "Crear unidad de medida"
        - method: GET
          path: /api/v1/uom
          description: "Listar unidades de medida"
        - method: GET
          path: /api/v1/uom/:id
          description: "Obtener UoM por ID"
        - method: PUT
          path: /api/v1/uom/:id
          description: "Actualizar UoM"
        - method: DELETE
          path: /api/v1/uom/:id
          description: "Eliminar UoM"
      services:
        - name: "UomService"
          file: "src/modules/catalogs/services/uom.service.ts"
          methods:
            - create
            - findAll
            - findOne
            - update
            - remove
            - convert
      controllers:
        - name: "UomController"
          file: "src/modules/catalogs/controllers/uom.controller.ts"
      dtos:
        - name: "CreateUomDto"
          file: "src/modules/catalogs/dto/create-uom.dto.ts"
        - name: "UpdateUomDto"
          file: "src/modules/catalogs/dto/update-uom.dto.ts"

    et_frontend:
      file: "especificaciones-tecnicas/frontend/mgn-003/ET-FRONTEND-MGN-003-004-gestión-de-unidades-de-medida-uom.md"
      routes:
        - path: "/catalogs/uom"
          component: "UomPage"
        - path: "/catalogs/uom/create"
          component: "CreateUomPage"
      components:
        - name: "UomTable"
          file: "src/widgets/uom-table/ui/UomTable.tsx"
          type: widget
        - name: "CreateUomForm"
          file: "src/features/create-uom/ui/CreateUomForm.tsx"
          type: feature
        - name: "UomSelector"
          file: "src/shared/ui/UomSelector.tsx"
          type: shared
      api_client:
        - name: "uomApi"
          file: "src/entities/uom/api/uom.api.ts"
          methods:
            - getAll
            - getById
            - create
            - update
            - delete
      state_management:
        - name: "useUomStore"
          file: "src/entities/uom/model/uom.store.ts"
          type: zustand

    database_tables:
      - schema: core
        table: uom_categories
        file: "database-design/schemas/core-schema-ddl.sql"
        operations:
          - SELECT
          - INSERT
          - UPDATE
        indices:
          - idx_uom_categories_tenant_id
        rls_policy: tenant_isolation_uom_categories
      - schema: core
        table: uom
        file: "database-design/schemas/core-schema-ddl.sql"
        operations:
          - SELECT
          - INSERT
          - UPDATE
          - DELETE
        indices:
          - idx_uom_category_id
          - idx_uom_tenant_id
        rls_policy: tenant_isolation_uom

    tests:
      backend:
        unit_tests:
          - file: "src/modules/catalogs/services/uom.service.spec.ts"
            test_cases:
              - "should create UoM with valid data"
              - "should create UoM category"
              - "should convert between UoMs of same category"
              - "should throw error for different categories"
              - "should update UoM successfully"
        integration_tests:
          - file: "test/catalogs/uom.controller.e2e-spec.ts"
            test_cases:
              - "POST /api/v1/uom should create UoM"
              - "GET /api/v1/uom should return all UoMs"
              - "GET /api/v1/uom/:id should return UoM"
              - "PUT /api/v1/uom/:id should update UoM"
              - "DELETE /api/v1/uom/:id should delete UoM"
              - "should enforce tenant isolation"
              - "should require authentication"
      frontend:
        component_tests:
          - file: "src/widgets/uom-table/ui/UomTable.test.tsx"
            test_cases:
              - "should render table with UoMs"
              - "should group by category"
          - file: "src/features/create-uom/ui/CreateUomForm.test.tsx"
            test_cases:
              - "should validate required fields"
              - "should validate ratio > 0"
              - "should submit valid form"
        e2e_tests:
          - file: "e2e/catalogs/uom.spec.ts"
            test_cases:
              - "should create UoM successfully"
              - "should edit UoM successfully"
              - "should delete UoM with confirmation"

    acceptance_criteria:
      - id: AC-001
        description: "Usuario puede crear unidades de medida agrupadas por categoría"
        status: Pending
        test_reference: "test/catalogs/uom.controller.e2e-spec.ts:28"
      - id: AC-002
        description: "Sistema convierte cantidades entre UoMs de misma categoría"
        status: Pending
        test_reference: "src/modules/catalogs/services/uom.service.spec.ts:68"
      - id: AC-003
        description: "Sistema previene conversión entre categorías diferentes"
        status: Pending
        test_reference: "src/modules/catalogs/services/uom.service.spec.ts:95"

    business_rules:
      - id: RN-001
        description: "UoMs se agrupan en categorías (Peso, Longitud, Volumen, Tiempo)"
        implementation: "database-design/schemas/core-schema-ddl.sql:uom_categories table"
        test_reference: "src/modules/catalogs/services/uom.service.spec.ts:48"
      - id: RN-002
        description: "Conversión solo entre UoMs de misma categoría"
        implementation: "src/modules/catalogs/services/uom.service.ts:convert()"
        test_reference: "src/modules/catalogs/services/uom.service.spec.ts:78"
      - id: RN-003
        description: "Ratio define conversión respecto a UoM base (ej: 1 kg = 1000 g)"
        implementation: "database-design/schemas/core-schema-ddl.sql:uom.ratio"
        test_reference: "src/modules/catalogs/services/uom.service.spec.ts:108"

    dependencies:
      rf_dependencies: []
      module_dependencies: []
      external_dependencies: []

  - rf_id: RF-MGN-003-005
    rf_title: "Gestión de Categorías de Productos"
    rf_file: "requerimientos-funcionales/mgn-003/RF-MGN-003-005-gestión-de-categorías-de-productos.md"
    priority: P0
    story_points: 3

    et_backend:
      file: "especificaciones-tecnicas/backend/mgn-003/ET-BACKEND-MGN-003-005-gestión-de-categorías-de-productos.md"
      endpoints:
        - method: POST
          path: /api/v1/product-categories
          description: "Crear categoría de producto"
        - method: GET
          path: /api/v1/product-categories
          description: "Listar categorías"
        - method: GET
          path: /api/v1/product-categories/:id
          description: "Obtener categoría por ID"
        - method: PUT
          path: /api/v1/product-categories/:id
          description: "Actualizar categoría"
        - method: DELETE
          path: /api/v1/product-categories/:id
          description: "Eliminar categoría"
      services:
        - name: "ProductCategoryService"
          file: "src/modules/catalogs/services/product-category.service.ts"
          methods:
            - create
            - findAll
            - findOne
            - update
            - remove
      controllers:
        - name: "ProductCategoryController"
          file: "src/modules/catalogs/controllers/product-category.controller.ts"
      dtos:
        - name: "CreateProductCategoryDto"
          file: "src/modules/catalogs/dto/create-product-category.dto.ts"
        - name: "UpdateProductCategoryDto"
          file: "src/modules/catalogs/dto/update-product-category.dto.ts"

    et_frontend:
      file: "especificaciones-tecnicas/frontend/mgn-003/ET-FRONTEND-MGN-003-005-gestión-de-categorías-de-productos.md"
      routes:
        - path: "/catalogs/product-categories"
          component: "ProductCategoriesPage"
      components:
        - name: "ProductCategoriesTable"
          file: "src/widgets/product-categories-table/ui/ProductCategoriesTable.tsx"
          type: widget
        - name: "CreateProductCategoryForm"
          file: "src/features/create-product-category/ui/CreateProductCategoryForm.tsx"
          type: feature
        - name: "CategoryTree"
          file: "src/widgets/category-tree/ui/CategoryTree.tsx"
          type: widget
      api_client:
        - name: "productCategoryApi"
          file: "src/entities/product-category/api/product-category.api.ts"
          methods:
            - getAll
            - getById
            - create
            - update
            - delete
      state_management:
        - name: "useProductCategoryStore"
          file: "src/entities/product-category/model/product-category.store.ts"
          type: zustand

    database_tables:
      - schema: inventory
        table: product_categories
        file: "database-design/schemas/inventory-schema-ddl.sql"
        operations:
          - SELECT
          - INSERT
          - UPDATE
          - DELETE
        indices:
          - idx_product_categories_parent_id
          - idx_product_categories_tenant_id
        rls_policy: tenant_isolation_product_categories

    tests:
      backend:
        unit_tests:
          - file: "src/modules/catalogs/services/product-category.service.spec.ts"
            test_cases:
              - "should create product category"
              - "should create nested categories"
              - "should validate parent exists"
              - "should update category successfully"
              - "should delete category"
        integration_tests:
          - file: "test/catalogs/product-category.controller.e2e-spec.ts"
            test_cases:
              - "POST /api/v1/product-categories should create category"
              - "GET /api/v1/product-categories should return all categories"
              - "GET /api/v1/product-categories/:id should return category"
              - "PUT /api/v1/product-categories/:id should update category"
              - "DELETE /api/v1/product-categories/:id should delete category"
              - "should enforce tenant isolation"
              - "should require authentication"
      frontend:
        component_tests:
          - file: "src/widgets/product-categories-table/ui/ProductCategoriesTable.test.tsx"
            test_cases:
              - "should render table with categories"
              - "should show hierarchy"
          - file: "src/features/create-product-category/ui/CreateProductCategoryForm.test.tsx"
            test_cases:
              - "should validate required fields"
              - "should submit valid form"
        e2e_tests:
          - file: "e2e/catalogs/product-categories.spec.ts"
            test_cases:
              - "should create category successfully"
              - "should create nested category"
              - "should delete category with confirmation"

    acceptance_criteria:
      - id: AC-001
        description: "Usuario puede crear categorías de productos jerárquicas"
        status: Pending
        test_reference: "test/catalogs/product-category.controller.e2e-spec.ts:28"
      - id: AC-002
        description: "Sistema muestra árbol de categorías"
        status: Pending
        test_reference: "e2e/catalogs/product-categories.spec.ts:48"
      - id: AC-003
        description: "Categorías pueden tener subcategorías ilimitadas"
        status: Pending
        test_reference: "src/modules/catalogs/services/product-category.service.spec.ts:68"

    business_rules:
      - id: RN-001
        description: "Categorías soportan jerarquía con parent_id"
        implementation: "database-design/schemas/inventory-schema-ddl.sql:product_categories.parent_id"
        test_reference: "src/modules/catalogs/services/product-category.service.spec.ts:48"
      - id: RN-002
        description: "Productos heredan propiedades de categoría (cuentas contables)"
        implementation: "src/modules/inventory/services/product.service.ts:create()"
        test_reference: "src/modules/catalogs/services/product-category.service.spec.ts:78"
      - id: RN-003
        description: "No se puede eliminar categoría con productos asignados"
        implementation: "src/modules/catalogs/services/product-category.service.ts:remove()"
        test_reference: "src/modules/catalogs/services/product-category.service.spec.ts:95"

    dependencies:
      rf_dependencies: []
      module_dependencies: []
      external_dependencies: []

  - rf_id: RF-MGN-003-006
    rf_title: "Condiciones de Pago (Payment Terms)"
    rf_file: "requerimientos-funcionales/mgn-003/RF-MGN-003-006-condiciones-de-pago-payment-terms.md"
    priority: P0
    story_points: 5

    et_backend:
      file: "especificaciones-tecnicas/backend/mgn-003/ET-BACKEND-MGN-003-006-condiciones-de-pago-payment-terms.md"
      endpoints:
        - method: POST
          path: /api/v1/payment-terms
          description: "Crear término de pago"
        - method: GET
          path: /api/v1/payment-terms
          description: "Listar términos de pago"
        - method: GET
          path: /api/v1/payment-terms/:id
          description: "Obtener término por ID"
        - method: PUT
          path: /api/v1/payment-terms/:id
          description: "Actualizar término"
        - method: DELETE
          path: /api/v1/payment-terms/:id
          description: "Eliminar término"
      services:
        - name: "PaymentTermService"
          file: "src/modules/catalogs/services/payment-term.service.ts"
          methods:
            - create
            - findAll
            - findOne
            - update
            - remove
            - calculateDueDate
      controllers:
        - name: "PaymentTermController"
          file: "src/modules/catalogs/controllers/payment-term.controller.ts"
      dtos:
        - name: "CreatePaymentTermDto"
          file: "src/modules/catalogs/dto/create-payment-term.dto.ts"
        - name: "UpdatePaymentTermDto"
          file: "src/modules/catalogs/dto/update-payment-term.dto.ts"

    et_frontend:
      file: "especificaciones-tecnicas/frontend/mgn-003/ET-FRONTEND-MGN-003-006-condiciones-de-pago-payment-terms.md"
      routes:
        - path: "/catalogs/payment-terms"
          component: "PaymentTermsPage"
      components:
        - name: "PaymentTermsTable"
          file: "src/widgets/payment-terms-table/ui/PaymentTermsTable.tsx"
          type: widget
        - name: "CreatePaymentTermForm"
          file: "src/features/create-payment-term/ui/CreatePaymentTermForm.tsx"
          type: feature
        - name: "PaymentTermSelector"
          file: "src/shared/ui/PaymentTermSelector.tsx"
          type: shared
      api_client:
        - name: "paymentTermApi"
          file: "src/entities/payment-term/api/payment-term.api.ts"
          methods:
            - getAll
            - getById
            - create
            - update
            - delete
      state_management:
        - name: "usePaymentTermStore"
          file: "src/entities/payment-term/model/payment-term.store.ts"
          type: zustand

    database_tables:
      - schema: core
        table: payment_terms
        file: "database-design/schemas/core-schema-ddl.sql"
        operations:
          - SELECT
          - INSERT
          - UPDATE
          - DELETE
        indices:
          - idx_payment_terms_tenant_id
          - idx_payment_terms_company_id
        rls_policy: tenant_isolation_payment_terms

    tests:
      backend:
        unit_tests:
          - file: "src/modules/catalogs/services/payment-term.service.spec.ts"
            test_cases:
              - "should create payment term"
              - "should calculate due date from invoice date"
              - "should handle immediate payment"
              - "should handle 30/60/90 days terms"
              - "should update payment term"
        integration_tests:
          - file: "test/catalogs/payment-term.controller.e2e-spec.ts"
            test_cases:
              - "POST /api/v1/payment-terms should create term"
              - "GET /api/v1/payment-terms should return all terms"
              - "GET /api/v1/payment-terms/:id should return term"
              - "PUT /api/v1/payment-terms/:id should update term"
              - "DELETE /api/v1/payment-terms/:id should delete term"
              - "should enforce tenant isolation"
              - "should require authentication"
      frontend:
        component_tests:
          - file: "src/widgets/payment-terms-table/ui/PaymentTermsTable.test.tsx"
            test_cases:
              - "should render table with terms"
              - "should show days calculation"
          - file: "src/features/create-payment-term/ui/CreatePaymentTermForm.test.tsx"
            test_cases:
              - "should validate required fields"
              - "should validate days >= 0"
              - "should submit valid form"
        e2e_tests:
          - file: "e2e/catalogs/payment-terms.spec.ts"
            test_cases:
              - "should create payment term successfully"
              - "should edit payment term"
              - "should delete payment term with confirmation"

    acceptance_criteria:
      - id: AC-001
        description: "Usuario puede crear términos de pago con días personalizados"
        status: Pending
        test_reference: "test/catalogs/payment-term.controller.e2e-spec.ts:28"
      - id: AC-002
        description: "Sistema calcula fecha de vencimiento automáticamente"
        status: Pending
        test_reference: "src/modules/catalogs/services/payment-term.service.spec.ts:68"
      - id: AC-003
        description: "Términos comunes: Contado (0 días), 30, 60, 90 días"
        status: Pending
        test_reference: "test/catalogs/payment-term.controller.e2e-spec.ts:95"

    business_rules:
      - id: RN-001
        description: "Payment term define días hasta vencimiento"
        implementation: "database-design/schemas/core-schema-ddl.sql:payment_terms.days"
        test_reference: "src/modules/catalogs/services/payment-term.service.spec.ts:48"
      - id: RN-002
        description: "Fecha vencimiento = fecha factura + días del término"
        implementation: "src/modules/catalogs/services/payment-term.service.ts:calculateDueDate()"
        test_reference: "src/modules/catalogs/services/payment-term.service.spec.ts:78"
      - id: RN-003
        description: "Partners y empresas tienen payment term por defecto"
        implementation: "database-design/schemas/core-schema-ddl.sql:partners.payment_term_id"
        test_reference: "src/modules/catalogs/services/payment-term.service.spec.ts:108"

    dependencies:
      rf_dependencies:
        - RF-MGN-002-001
      module_dependencies:
        - MGN-002
      external_dependencies: []

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: 30
  total_components: 24
  total_tables: 9
  total_test_cases: 120
  estimated_duration_sprints: 2
