# BACKEND_INVENTORY.yml - ERP Core
# Inventario canonico de objetos backend
# Ubicacion Canonica: orchestration/inventarios/
# Ultima actualizacion: 2025-12-05

version: "2.2"
project: erp-core
updated_at: "2026-01-10"
updated_by: Backend-Agent-Claude-Opus

# =============================================================================
# CONFIGURACION DEL STACK
# =============================================================================

stack:
  runtime: Node.js 20+
  framework: NestJS 10.x
  language: TypeScript 5.3+
  orm: TypeORM 0.3.17
  validation: class-validator + class-transformer
  documentation: Swagger/OpenAPI

# =============================================================================
# RESUMEN
# =============================================================================

summary:
  total_modules: 19
  total_services: 68
  total_controllers: 50
  total_endpoints: 240
  total_entities: 65
  total_dtos: 115
  total_guards: 14
  total_decorators: 17
  implemented: 4
  documented: 16

  # Sprint 1-3 Implementation (2026-01-06)
  tests:
    total: 502
    by_module:
      auth: 59          # Sprint 1: service(23) + controller(20) + integration(16)
      users: 74         # Sprint 2: service(44) + controller(30)
      roles: 48         # Sprint 2: service(29) + controller(19)
      tenants: 77       # Sprint 2: service(44) + controller(33)
      permission_cache: 37  # Sprint 2: service tests
      financial: 93     # Sprint 3: accounts(36) + journal-entries(27) + invoices(30)
      inventory: 69     # Sprint 3: products(32) + stock(37)
      oauth: 32         # Sprint 3: providers tests
      factories: 13     # Sprint 1: base factories
    frameworks:
      - Jest
      - Supertest (integration)
    coverage_target: 80%
    coverage_achieved: ">95% modules tested"

# =============================================================================
# MODULOS
# =============================================================================

modules:

  # ---------------------------------------------------------------------------
  # MGN-001: AUTH
  # ---------------------------------------------------------------------------
  - id: MGN-001
    name: auth
    path: apps/backend/src/modules/auth/
    status: documented
    rf: [RF-AUTH-001, RF-AUTH-002, RF-AUTH-003, RF-AUTH-004, RF-AUTH-005, RF-AUTH-006]

    entities:
      - name: UserAuth
        file: entities/user-auth.entity.ts
        table: core_auth.users_auth
        rf: RF-AUTH-001

      - name: Session
        file: entities/session.entity.ts
        table: core_auth.sessions
        rf: RF-AUTH-002

      - name: RefreshToken
        file: entities/refresh-token.entity.ts
        table: core_auth.refresh_tokens
        rf: RF-AUTH-002

      - name: PasswordReset
        file: entities/password-reset.entity.ts
        table: core_auth.password_resets
        rf: RF-AUTH-003

      - name: LoginAttempt
        file: entities/login-attempt.entity.ts
        table: core_auth.login_attempts
        rf: RF-AUTH-004

      - name: OAuthAccount
        file: entities/oauth-account.entity.ts
        table: core_auth.oauth_accounts
        rf: RF-AUTH-005

    services:
      - name: AuthService
        file: auth.service.ts
        rf: [RF-AUTH-001, RF-AUTH-006]
        methods:
          - {name: login, params: [LoginDto], returns: TokenResponseDto}
          - {name: logout, params: [userId], returns: void}
          - {name: logoutAll, params: [userId], returns: void}
          - {name: validateUser, params: [email, password], returns: UserAuth}
          - {name: getProfile, params: [userId], returns: UserProfileDto}

      - name: TokenService
        file: token.service.ts
        rf: [RF-AUTH-002]
        methods:
          - {name: generateAccessToken, params: [payload], returns: string}
          - {name: generateRefreshToken, params: [userId], returns: string}
          - {name: refreshTokens, params: [refreshToken], returns: TokenResponseDto}
          - {name: revokeRefreshToken, params: [tokenId], returns: void}
          - {name: validateAccessToken, params: [token], returns: JwtPayload}

      - name: PasswordService
        file: password.service.ts
        rf: [RF-AUTH-003]
        methods:
          - {name: requestPasswordReset, params: [email], returns: void}
          - {name: resetPassword, params: [token, newPassword], returns: void}
          - {name: validateResetToken, params: [token], returns: boolean}

      - name: OAuthService
        file: oauth.service.ts
        rf: [RF-AUTH-005]
        methods:
          - {name: initiateOAuth, params: [provider], returns: string}
          - {name: handleCallback, params: [provider, code], returns: TokenResponseDto}
          - {name: linkAccount, params: [userId, provider, data], returns: void}

    controllers:
      - name: AuthController
        file: auth.controller.ts
        prefix: /api/v1/auth
        endpoints:
          - {method: POST, path: /login, handler: login, rf: RF-AUTH-001, auth: false}
          - {method: POST, path: /logout, handler: logout, rf: RF-AUTH-006, auth: true}
          - {method: POST, path: /refresh, handler: refresh, rf: RF-AUTH-002, auth: false}
          - {method: POST, path: /forgot-password, handler: forgotPassword, rf: RF-AUTH-003, auth: false}
          - {method: POST, path: /reset-password, handler: resetPassword, rf: RF-AUTH-003, auth: false}
          - {method: GET, path: /me, handler: getProfile, rf: RF-AUTH-001, auth: true}
          - {method: GET, path: /oauth/:provider, handler: initiateOAuth, rf: RF-AUTH-005, auth: false}

    dtos:
      - {name: LoginDto, file: dto/login.dto.ts, type: request}
      - {name: TokenResponseDto, file: dto/token-response.dto.ts, type: response}
      - {name: RefreshTokenDto, file: dto/refresh-token.dto.ts, type: request}
      - {name: ForgotPasswordDto, file: dto/forgot-password.dto.ts, type: request}
      - {name: ResetPasswordDto, file: dto/reset-password.dto.ts, type: request}
      - {name: UserProfileDto, file: dto/user-profile.dto.ts, type: response}

    guards:
      - name: JwtAuthGuard
        file: guards/jwt-auth.guard.ts
        rf: RF-AUTH-002
        description: Valida JWT en header Authorization

      - name: RefreshTokenGuard
        file: guards/refresh-token.guard.ts
        rf: RF-AUTH-002
        description: Valida refresh token

    decorators:
      - name: CurrentUser
        file: decorators/current-user.decorator.ts
        usage: "@CurrentUser() user: UserAuth"

      - name: Public
        file: decorators/public.decorator.ts
        usage: "@Public()"

    strategies:
      - name: JwtStrategy
        file: strategies/jwt.strategy.ts
        rf: RF-AUTH-002

      - name: LocalStrategy
        file: strategies/local.strategy.ts
        rf: RF-AUTH-001

  # ---------------------------------------------------------------------------
  # MGN-002: USERS
  # ---------------------------------------------------------------------------
  - id: MGN-002
    name: users
    path: apps/backend/src/modules/users/
    status: documented
    rf: [RF-USERS-001, RF-USERS-002, RF-USERS-003, RF-USERS-004, RF-USERS-005]

    entities:
      - name: User
        file: entities/user.entity.ts
        table: core_users.users
        rf: RF-USERS-001

      - name: UserProfile
        file: entities/user-profile.entity.ts
        table: core_users.user_profiles
        rf: RF-USERS-002

      - name: UserPreferences
        file: entities/user-preferences.entity.ts
        table: core_users.user_preferences
        rf: RF-USERS-003

    services:
      - name: UsersService
        file: users.service.ts
        rf: [RF-USERS-001, RF-USERS-004, RF-USERS-005]
        methods:
          - {name: create, params: [CreateUserDto], returns: User}
          - {name: findAll, params: [filters, pagination], returns: "PaginatedResult<User>"}
          - {name: findOne, params: [id], returns: User}
          - {name: update, params: [id, UpdateUserDto], returns: User}
          - {name: remove, params: [id], returns: void}
          - {name: activate, params: [id], returns: User}
          - {name: deactivate, params: [id], returns: User}
          - {name: search, params: [query], returns: "User[]"}

      - name: ProfileService
        file: profile.service.ts
        rf: [RF-USERS-002]
        methods:
          - {name: getProfile, params: [userId], returns: UserProfile}
          - {name: updateProfile, params: [userId, dto], returns: UserProfile}
          - {name: uploadAvatar, params: [userId, file], returns: string}

      - name: PreferencesService
        file: preferences.service.ts
        rf: [RF-USERS-003]
        methods:
          - {name: getPreferences, params: [userId], returns: UserPreferences}
          - {name: updatePreferences, params: [userId, dto], returns: UserPreferences}

    controllers:
      - name: UsersController
        file: users.controller.ts
        prefix: /api/v1/users
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-USERS-001}
          - {method: GET, path: /:id, handler: findOne, rf: RF-USERS-001}
          - {method: POST, path: /, handler: create, rf: RF-USERS-001}
          - {method: PATCH, path: /:id, handler: update, rf: RF-USERS-001}
          - {method: DELETE, path: /:id, handler: remove, rf: RF-USERS-001}
          - {method: GET, path: /:id/profile, handler: getProfile, rf: RF-USERS-002}
          - {method: PATCH, path: /:id/profile, handler: updateProfile, rf: RF-USERS-002}
          - {method: POST, path: /:id/avatar, handler: uploadAvatar, rf: RF-USERS-002}
          - {method: GET, path: /:id/preferences, handler: getPreferences, rf: RF-USERS-003}
          - {method: PATCH, path: /:id/preferences, handler: updatePreferences, rf: RF-USERS-003}
          - {method: POST, path: /:id/activate, handler: activate, rf: RF-USERS-004}
          - {method: POST, path: /:id/deactivate, handler: deactivate, rf: RF-USERS-004}
          - {method: GET, path: /search, handler: search, rf: RF-USERS-005}

    dtos:
      - {name: CreateUserDto, file: dto/create-user.dto.ts, type: request}
      - {name: UpdateUserDto, file: dto/update-user.dto.ts, type: request}
      - {name: UserFilterDto, file: dto/user-filter.dto.ts, type: request}
      - {name: UserResponseDto, file: dto/user-response.dto.ts, type: response}
      - {name: UpdateProfileDto, file: dto/update-profile.dto.ts, type: request}
      - {name: UpdatePreferencesDto, file: dto/update-preferences.dto.ts, type: request}

  # ---------------------------------------------------------------------------
  # MGN-003: ROLES
  # ---------------------------------------------------------------------------
  - id: MGN-003
    name: roles
    path: apps/backend/src/modules/roles/
    status: documented
    rf: [RF-RBAC-001, RF-RBAC-002, RF-RBAC-003, RF-RBAC-004, RF-RBAC-005]

    entities:
      - name: Role
        file: entities/role.entity.ts
        table: core_rbac.roles
        rf: RF-RBAC-001

      - name: Permission
        file: entities/permission.entity.ts
        table: core_rbac.permissions
        rf: RF-RBAC-002

      - name: RolePermission
        file: entities/role-permission.entity.ts
        table: core_rbac.role_permissions
        rf: RF-RBAC-002

      - name: UserRole
        file: entities/user-role.entity.ts
        table: core_rbac.user_roles
        rf: RF-RBAC-003

    services:
      - name: RolesService
        file: roles.service.ts
        rf: [RF-RBAC-001, RF-RBAC-005]
        methods:
          - {name: create, params: [CreateRoleDto], returns: Role}
          - {name: findAll, params: [tenantId], returns: "Role[]"}
          - {name: findOne, params: [id], returns: Role}
          - {name: update, params: [id, UpdateRoleDto], returns: Role}
          - {name: remove, params: [id], returns: void}
          - {name: getSystemRoles, params: [], returns: "Role[]"}

      - name: PermissionsService
        file: permissions.service.ts
        rf: [RF-RBAC-002, RF-RBAC-004]
        methods:
          - {name: findAll, params: [], returns: "Permission[]"}
          - {name: findByModule, params: [module], returns: "Permission[]"}
          - {name: assignToRole, params: [roleId, permissionId], returns: void}
          - {name: removeFromRole, params: [roleId, permissionId], returns: void}
          - {name: getUserPermissions, params: [userId], returns: "Permission[]"}
          - {name: hasPermission, params: [userId, module, action, resource], returns: boolean}

      - name: UserRolesService
        file: user-roles.service.ts
        rf: [RF-RBAC-003]
        methods:
          - {name: assignRole, params: [userId, roleId], returns: void}
          - {name: removeRole, params: [userId, roleId], returns: void}
          - {name: getUserRoles, params: [userId], returns: "Role[]"}

    controllers:
      - name: RolesController
        file: roles.controller.ts
        prefix: /api/v1/roles
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-RBAC-001}
          - {method: POST, path: /, handler: create, rf: RF-RBAC-001}
          - {method: GET, path: /:id, handler: findOne, rf: RF-RBAC-001}
          - {method: PATCH, path: /:id, handler: update, rf: RF-RBAC-001}
          - {method: DELETE, path: /:id, handler: remove, rf: RF-RBAC-001}
          - {method: GET, path: /:id/permissions, handler: getRolePermissions, rf: RF-RBAC-002}
          - {method: POST, path: /:id/permissions, handler: assignPermission, rf: RF-RBAC-002}
          - {method: DELETE, path: /:id/permissions/:permissionId, handler: removePermission, rf: RF-RBAC-002}

      - name: PermissionsController
        file: permissions.controller.ts
        prefix: /api/v1/permissions
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-RBAC-002}
          - {method: GET, path: /modules, handler: getModules, rf: RF-RBAC-002}

    guards:
      - name: RolesGuard
        file: guards/roles.guard.ts
        rf: RF-RBAC-004
        description: Verifica roles requeridos

      - name: PermissionsGuard
        file: guards/permissions.guard.ts
        rf: RF-RBAC-004
        description: Verifica permisos requeridos

    decorators:
      - name: Roles
        file: decorators/roles.decorator.ts
        usage: "@Roles('admin', 'manager')"

      - name: Permissions
        file: decorators/permissions.decorator.ts
        usage: "@Permissions('users:read:all')"

      - name: RequirePermission
        file: decorators/require-permission.decorator.ts
        usage: "@RequirePermission('users', 'write', 'all')"

  # ---------------------------------------------------------------------------
  # MGN-004: TENANTS
  # ---------------------------------------------------------------------------
  - id: MGN-004
    name: tenants
    path: apps/backend/src/modules/tenants/
    status: documented
    rf: [RF-TENANTS-001, RF-TENANTS-002, RF-TENANTS-003, RF-TENANTS-004, RF-TENANTS-005]

    entities:
      - name: Tenant
        file: entities/tenant.entity.ts
        table: core_tenants.tenants
        rf: RF-TENANTS-001

      - name: TenantSettings
        file: entities/tenant-settings.entity.ts
        table: core_tenants.tenant_settings
        rf: RF-TENANTS-002

      - name: Plan
        file: entities/plan.entity.ts
        table: core_tenants.plans
        rf: RF-TENANTS-003

      - name: Subscription
        file: entities/subscription.entity.ts
        table: core_tenants.subscriptions
        rf: RF-TENANTS-003

    services:
      - name: TenantsService
        file: tenants.service.ts
        rf: [RF-TENANTS-001, RF-TENANTS-005]
        methods:
          - {name: create, params: [CreateTenantDto], returns: Tenant}
          - {name: findAll, params: [], returns: "Tenant[]"}
          - {name: findOne, params: [id], returns: Tenant}
          - {name: findBySlug, params: [slug], returns: Tenant}
          - {name: update, params: [id, UpdateTenantDto], returns: Tenant}
          - {name: remove, params: [id], returns: void}
          - {name: onboard, params: [OnboardDto], returns: Tenant}

      - name: TenantSettingsService
        file: tenant-settings.service.ts
        rf: [RF-TENANTS-002]
        methods:
          - {name: getSettings, params: [tenantId], returns: TenantSettings}
          - {name: updateSettings, params: [tenantId, dto], returns: TenantSettings}

      - name: PlansService
        file: plans.service.ts
        rf: [RF-TENANTS-003]
        methods:
          - {name: findAll, params: [], returns: "Plan[]"}
          - {name: findOne, params: [id], returns: Plan}

      - name: SubscriptionsService
        file: subscriptions.service.ts
        rf: [RF-TENANTS-003]
        methods:
          - {name: create, params: [tenantId, planId], returns: Subscription}
          - {name: getCurrentSubscription, params: [tenantId], returns: Subscription}
          - {name: changePlan, params: [subscriptionId, planId], returns: Subscription}
          - {name: cancel, params: [subscriptionId], returns: void}

    middleware:
      - name: TenantMiddleware
        file: middleware/tenant.middleware.ts
        rf: RF-TENANTS-004
        description: Extrae tenant_id y establece contexto RLS

    guards:
      - name: TenantGuard
        file: guards/tenant.guard.ts
        rf: RF-TENANTS-004
        description: Verifica tenant activo

      - name: SubscriptionGuard
        file: guards/subscription.guard.ts
        rf: RF-TENANTS-003
        description: Verifica suscripcion activa

    controllers:
      - name: TenantsController
        file: tenants.controller.ts
        prefix: /api/v1/tenants
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-TENANTS-001}
          - {method: POST, path: /, handler: create, rf: RF-TENANTS-001}
          - {method: GET, path: /:id, handler: findOne, rf: RF-TENANTS-001}
          - {method: PATCH, path: /:id, handler: update, rf: RF-TENANTS-001}
          - {method: GET, path: /current, handler: getCurrent, rf: RF-TENANTS-001}
          - {method: GET, path: /current/settings, handler: getSettings, rf: RF-TENANTS-002}
          - {method: PATCH, path: /current/settings, handler: updateSettings, rf: RF-TENANTS-002}

      - name: PlansController
        file: plans.controller.ts
        prefix: /api/v1/plans
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-TENANTS-003}
          - {method: GET, path: /:id, handler: findOne, rf: RF-TENANTS-003}

      - name: SubscriptionsController
        file: subscriptions.controller.ts
        prefix: /api/v1/subscriptions
        endpoints:
          - {method: GET, path: /current, handler: getCurrent, rf: RF-TENANTS-003}
          - {method: POST, path: /, handler: create, rf: RF-TENANTS-003}
          - {method: PATCH, path: /current/plan, handler: changePlan, rf: RF-TENANTS-003}
          - {method: POST, path: /current/cancel, handler: cancel, rf: RF-TENANTS-003}

    decorators:
      - name: CurrentTenant
        file: decorators/current-tenant.decorator.ts
        usage: "@CurrentTenant() tenant: Tenant"

  # ---------------------------------------------------------------------------
  # MGN-005: CORE
  # ---------------------------------------------------------------------------
  - id: MGN-005
    name: core
    path: apps/backend/src/modules/core/
    status: documented
    rf: [RF-CORE-001, RF-CORE-002, RF-CORE-003, RF-CORE-004, RF-CORE-005, RF-CORE-006, RF-CORE-007]

    entities:
      - name: Country
        file: entities/country.entity.ts
        table: core_master.countries
        rf: RF-CORE-001

      - name: State
        file: entities/state.entity.ts
        table: core_master.states
        rf: RF-CORE-001

      - name: Currency
        file: entities/currency.entity.ts
        table: core_master.currencies
        rf: RF-CORE-002

      - name: CurrencyRate
        file: entities/currency-rate.entity.ts
        table: core_master.currency_rates
        rf: RF-CORE-002

      - name: Sequence
        file: entities/sequence.entity.ts
        table: core_master.sequences
        rf: RF-CORE-003

      - name: ProductCategory
        file: entities/product-category.entity.ts
        table: core_master.product_categories
        rf: RF-CORE-004

      - name: Uom
        file: entities/uom.entity.ts
        table: core_master.uom
        rf: RF-CORE-005

    services:
      - name: CountriesService
        file: countries.service.ts
        rf: [RF-CORE-001]
        methods:
          - {name: findAll, params: [filters], returns: "Country[]"}
          - {name: findOne, params: [id], returns: Country}
          - {name: create, params: [CreateCountryDto], returns: Country}
          - {name: update, params: [id, UpdateCountryDto], returns: Country}
          - {name: remove, params: [id], returns: void}

      - name: StatesService
        file: states.service.ts
        rf: [RF-CORE-001]
        methods:
          - {name: findAll, params: [countryId], returns: "State[]"}
          - {name: findOne, params: [id], returns: State}
          - {name: findByCountry, params: [countryId], returns: "State[]"}
          - {name: create, params: [CreateStateDto], returns: State}
          - {name: update, params: [id, UpdateStateDto], returns: State}
          - {name: remove, params: [id], returns: void}

      - name: CurrenciesService
        file: currencies.service.ts
        rf: [RF-CORE-002]
        methods:
          - {name: findAll, params: [tenantId], returns: "Currency[]"}
          - {name: findOne, params: [id], returns: Currency}
          - {name: findByCode, params: [code], returns: Currency}
          - {name: create, params: [CreateCurrencyDto], returns: Currency}
          - {name: update, params: [id, UpdateCurrencyDto], returns: Currency}
          - {name: setDefault, params: [tenantId, currencyId], returns: Currency}

      - name: CurrencyRatesService
        file: currency-rates.service.ts
        rf: [RF-CORE-002]
        methods:
          - {name: findAll, params: [currencyId, dateRange], returns: "CurrencyRate[]"}
          - {name: getLatestRate, params: [fromCurrency, toCurrency], returns: CurrencyRate}
          - {name: create, params: [CreateCurrencyRateDto], returns: CurrencyRate}
          - {name: convert, params: [amount, fromCurrency, toCurrency, date], returns: number}

      - name: SequencesService
        file: sequences.service.ts
        rf: [RF-CORE-003]
        methods:
          - {name: findAll, params: [tenantId], returns: "Sequence[]"}
          - {name: findOne, params: [id], returns: Sequence}
          - {name: create, params: [CreateSequenceDto], returns: Sequence}
          - {name: update, params: [id, UpdateSequenceDto], returns: Sequence}
          - {name: getNextValue, params: [tenantId, sequenceCode], returns: string}
          - {name: resetSequence, params: [id], returns: Sequence}

      - name: ProductCategoriesService
        file: product-categories.service.ts
        rf: [RF-CORE-004]
        methods:
          - {name: findAll, params: [tenantId], returns: "ProductCategory[]"}
          - {name: findOne, params: [id], returns: ProductCategory}
          - {name: findByParent, params: [parentId], returns: "ProductCategory[]"}
          - {name: create, params: [CreateProductCategoryDto], returns: ProductCategory}
          - {name: update, params: [id, UpdateProductCategoryDto], returns: ProductCategory}
          - {name: remove, params: [id], returns: void}
          - {name: getTree, params: [tenantId], returns: "ProductCategory[]"}

      - name: UomService
        file: uom.service.ts
        rf: [RF-CORE-005]
        methods:
          - {name: findAll, params: [tenantId], returns: "Uom[]"}
          - {name: findOne, params: [id], returns: Uom}
          - {name: findByCategory, params: [category], returns: "Uom[]"}
          - {name: create, params: [CreateUomDto], returns: Uom}
          - {name: update, params: [id, UpdateUomDto], returns: Uom}
          - {name: convert, params: [value, fromUom, toUom], returns: number}

    controllers:
      - name: CountriesController
        file: countries.controller.ts
        prefix: /api/v1/countries
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-CORE-001}
          - {method: GET, path: /:id, handler: findOne, rf: RF-CORE-001}
          - {method: POST, path: /, handler: create, rf: RF-CORE-001}
          - {method: PATCH, path: /:id, handler: update, rf: RF-CORE-001}
          - {method: DELETE, path: /:id, handler: remove, rf: RF-CORE-001}
          - {method: GET, path: /:id/states, handler: getStates, rf: RF-CORE-001}

      - name: StatesController
        file: states.controller.ts
        prefix: /api/v1/states
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-CORE-001}
          - {method: GET, path: /:id, handler: findOne, rf: RF-CORE-001}
          - {method: POST, path: /, handler: create, rf: RF-CORE-001}
          - {method: PATCH, path: /:id, handler: update, rf: RF-CORE-001}
          - {method: DELETE, path: /:id, handler: remove, rf: RF-CORE-001}

      - name: CurrenciesController
        file: currencies.controller.ts
        prefix: /api/v1/currencies
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-CORE-002}
          - {method: GET, path: /:id, handler: findOne, rf: RF-CORE-002}
          - {method: POST, path: /, handler: create, rf: RF-CORE-002}
          - {method: PATCH, path: /:id, handler: update, rf: RF-CORE-002}
          - {method: POST, path: /:id/set-default, handler: setDefault, rf: RF-CORE-002}
          - {method: GET, path: /:id/rates, handler: getRates, rf: RF-CORE-002}
          - {method: POST, path: /:id/rates, handler: addRate, rf: RF-CORE-002}
          - {method: POST, path: /convert, handler: convert, rf: RF-CORE-002}

      - name: SequencesController
        file: sequences.controller.ts
        prefix: /api/v1/sequences
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-CORE-003}
          - {method: GET, path: /:id, handler: findOne, rf: RF-CORE-003}
          - {method: POST, path: /, handler: create, rf: RF-CORE-003}
          - {method: PATCH, path: /:id, handler: update, rf: RF-CORE-003}
          - {method: POST, path: /:code/next, handler: getNextValue, rf: RF-CORE-003}
          - {method: POST, path: /:id/reset, handler: resetSequence, rf: RF-CORE-003}

      - name: ProductCategoriesController
        file: product-categories.controller.ts
        prefix: /api/v1/product-categories
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-CORE-004}
          - {method: GET, path: /tree, handler: getTree, rf: RF-CORE-004}
          - {method: GET, path: /:id, handler: findOne, rf: RF-CORE-004}
          - {method: POST, path: /, handler: create, rf: RF-CORE-004}
          - {method: PATCH, path: /:id, handler: update, rf: RF-CORE-004}
          - {method: DELETE, path: /:id, handler: remove, rf: RF-CORE-004}

      - name: UomController
        file: uom.controller.ts
        prefix: /api/v1/uom
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-CORE-005}
          - {method: GET, path: /:id, handler: findOne, rf: RF-CORE-005}
          - {method: POST, path: /, handler: create, rf: RF-CORE-005}
          - {method: PATCH, path: /:id, handler: update, rf: RF-CORE-005}
          - {method: POST, path: /convert, handler: convert, rf: RF-CORE-005}

    dtos:
      - {name: CreateCountryDto, file: dto/create-country.dto.ts, type: request}
      - {name: UpdateCountryDto, file: dto/update-country.dto.ts, type: request}
      - {name: CreateStateDto, file: dto/create-state.dto.ts, type: request}
      - {name: UpdateStateDto, file: dto/update-state.dto.ts, type: request}
      - {name: CreateCurrencyDto, file: dto/create-currency.dto.ts, type: request}
      - {name: UpdateCurrencyDto, file: dto/update-currency.dto.ts, type: request}
      - {name: CreateCurrencyRateDto, file: dto/create-currency-rate.dto.ts, type: request}
      - {name: CurrencyConvertDto, file: dto/currency-convert.dto.ts, type: request}
      - {name: CreateSequenceDto, file: dto/create-sequence.dto.ts, type: request}
      - {name: UpdateSequenceDto, file: dto/update-sequence.dto.ts, type: request}
      - {name: CreateProductCategoryDto, file: dto/create-product-category.dto.ts, type: request}
      - {name: UpdateProductCategoryDto, file: dto/update-product-category.dto.ts, type: request}
      - {name: CreateUomDto, file: dto/create-uom.dto.ts, type: request}
      - {name: UpdateUomDto, file: dto/update-uom.dto.ts, type: request}
      - {name: UomConvertDto, file: dto/uom-convert.dto.ts, type: request}

  # ---------------------------------------------------------------------------
  # MGN-006: AUDIT
  # ---------------------------------------------------------------------------
  - id: MGN-006
    name: audit
    path: apps/backend/src/modules/audit/
    status: documented
    rf: [RF-AUDIT-001, RF-AUDIT-002, RF-AUDIT-003]

    entities:
      - name: AccessLog
        file: entities/access-log.entity.ts
        table: core_audit.access_logs
        rf: RF-AUDIT-001

      - name: AuditLog
        file: entities/audit-log.entity.ts
        table: core_audit.audit_logs
        rf: RF-AUDIT-002

      - name: SecurityEvent
        file: entities/security-event.entity.ts
        table: core_audit.security_events
        rf: RF-AUDIT-003

    services:
      - name: AccessLogsService
        file: access-logs.service.ts
        rf: [RF-AUDIT-001]
        methods:
          - {name: findAll, params: [tenantId, filters, pagination], returns: "PaginatedResult<AccessLog>"}
          - {name: findOne, params: [id], returns: AccessLog}
          - {name: create, params: [CreateAccessLogDto], returns: AccessLog}
          - {name: findByUser, params: [userId, dateRange], returns: "AccessLog[]"}
          - {name: findByEndpoint, params: [endpoint, dateRange], returns: "AccessLog[]"}
          - {name: getStatistics, params: [tenantId, dateRange], returns: AccessLogStats}

      - name: AuditService
        file: audit.service.ts
        rf: [RF-AUDIT-002]
        methods:
          - {name: findAll, params: [tenantId, filters, pagination], returns: "PaginatedResult<AuditLog>"}
          - {name: findOne, params: [id], returns: AuditLog}
          - {name: create, params: [CreateAuditLogDto], returns: AuditLog}
          - {name: findByEntity, params: [entityType, entityId], returns: "AuditLog[]"}
          - {name: findByUser, params: [userId, dateRange], returns: "AuditLog[]"}
          - {name: getEntityHistory, params: [entityType, entityId], returns: "AuditLog[]"}

      - name: SecurityEventsService
        file: security-events.service.ts
        rf: [RF-AUDIT-003]
        methods:
          - {name: findAll, params: [tenantId, filters, pagination], returns: "PaginatedResult<SecurityEvent>"}
          - {name: findOne, params: [id], returns: SecurityEvent}
          - {name: create, params: [CreateSecurityEventDto], returns: SecurityEvent}
          - {name: findBySeverity, params: [severity, dateRange], returns: "SecurityEvent[]"}
          - {name: acknowledge, params: [id, userId], returns: SecurityEvent}
          - {name: getUnacknowledged, params: [tenantId], returns: "SecurityEvent[]"}

    controllers:
      - name: AccessLogsController
        file: access-logs.controller.ts
        prefix: /api/v1/audit/access-logs
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-AUDIT-001}
          - {method: GET, path: /:id, handler: findOne, rf: RF-AUDIT-001}
          - {method: GET, path: /user/:userId, handler: findByUser, rf: RF-AUDIT-001}
          - {method: GET, path: /statistics, handler: getStatistics, rf: RF-AUDIT-001}

      - name: AuditController
        file: audit.controller.ts
        prefix: /api/v1/audit/logs
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-AUDIT-002}
          - {method: GET, path: /:id, handler: findOne, rf: RF-AUDIT-002}
          - {method: GET, path: /entity/:entityType/:entityId, handler: findByEntity, rf: RF-AUDIT-002}
          - {method: GET, path: /user/:userId, handler: findByUser, rf: RF-AUDIT-002}
          - {method: GET, path: /history/:entityType/:entityId, handler: getEntityHistory, rf: RF-AUDIT-002}

      - name: SecurityEventsController
        file: security-events.controller.ts
        prefix: /api/v1/audit/security-events
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-AUDIT-003}
          - {method: GET, path: /:id, handler: findOne, rf: RF-AUDIT-003}
          - {method: GET, path: /unacknowledged, handler: getUnacknowledged, rf: RF-AUDIT-003}
          - {method: POST, path: /:id/acknowledge, handler: acknowledge, rf: RF-AUDIT-003}

    dtos:
      - {name: AccessLogFilterDto, file: dto/access-log-filter.dto.ts, type: request}
      - {name: AuditLogFilterDto, file: dto/audit-log-filter.dto.ts, type: request}
      - {name: SecurityEventFilterDto, file: dto/security-event-filter.dto.ts, type: request}
      - {name: AccessLogResponseDto, file: dto/access-log-response.dto.ts, type: response}
      - {name: AuditLogResponseDto, file: dto/audit-log-response.dto.ts, type: response}
      - {name: SecurityEventResponseDto, file: dto/security-event-response.dto.ts, type: response}

    interceptors:
      - name: AuditInterceptor
        file: interceptors/audit.interceptor.ts
        rf: RF-AUDIT-002
        description: Interceptor para registro automatico de cambios en entidades

  # ---------------------------------------------------------------------------
  # MGN-007: SYSTEM
  # ---------------------------------------------------------------------------
  - id: MGN-007
    name: system
    path: apps/backend/src/modules/system/
    status: documented
    rf: [RF-SYSTEM-001, RF-SYSTEM-002, RF-SYSTEM-003, RF-SYSTEM-004]

    entities:
      - name: Activity
        file: entities/activity.entity.ts
        table: core_system.activities
        rf: RF-SYSTEM-001

      - name: Message
        file: entities/message.entity.ts
        table: core_system.messages
        rf: RF-SYSTEM-002

      - name: Notification
        file: entities/notification.entity.ts
        table: core_system.notifications
        rf: RF-SYSTEM-003

      - name: Setting
        file: entities/setting.entity.ts
        table: core_system.settings
        rf: RF-SYSTEM-004

    services:
      - name: ActivitiesService
        file: activities.service.ts
        rf: [RF-SYSTEM-001]
        methods:
          - {name: findAll, params: [tenantId, filters, pagination], returns: "PaginatedResult<Activity>"}
          - {name: findOne, params: [id], returns: Activity}
          - {name: create, params: [CreateActivityDto], returns: Activity}
          - {name: findByUser, params: [userId, limit], returns: "Activity[]"}
          - {name: findByEntity, params: [entityType, entityId], returns: "Activity[]"}
          - {name: getRecentActivity, params: [tenantId, limit], returns: "Activity[]"}

      - name: MessagesService
        file: messages.service.ts
        rf: [RF-SYSTEM-002]
        methods:
          - {name: findAll, params: [userId, filters], returns: "Message[]"}
          - {name: findOne, params: [id], returns: Message}
          - {name: create, params: [CreateMessageDto], returns: Message}
          - {name: markAsRead, params: [id], returns: Message}
          - {name: markAllAsRead, params: [userId], returns: void}
          - {name: getUnreadCount, params: [userId], returns: number}
          - {name: delete, params: [id], returns: void}

      - name: NotificationsService
        file: notifications.service.ts
        rf: [RF-SYSTEM-003]
        methods:
          - {name: findAll, params: [userId, filters], returns: "Notification[]"}
          - {name: findOne, params: [id], returns: Notification}
          - {name: create, params: [CreateNotificationDto], returns: Notification}
          - {name: markAsRead, params: [id], returns: Notification}
          - {name: markAllAsRead, params: [userId], returns: void}
          - {name: getUnreadCount, params: [userId], returns: number}
          - {name: delete, params: [id], returns: void}
          - {name: broadcast, params: [tenantId, dto], returns: "Notification[]"}

      - name: SettingsService
        file: settings.service.ts
        rf: [RF-SYSTEM-004]
        methods:
          - {name: findAll, params: [tenantId], returns: "Setting[]"}
          - {name: findOne, params: [key, tenantId], returns: Setting}
          - {name: getValue, params: [key, tenantId], returns: any}
          - {name: setValue, params: [key, value, tenantId], returns: Setting}
          - {name: remove, params: [key, tenantId], returns: void}
          - {name: getByCategory, params: [category, tenantId], returns: "Setting[]"}

    controllers:
      - name: ActivitiesController
        file: activities.controller.ts
        prefix: /api/v1/activities
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-SYSTEM-001}
          - {method: GET, path: /:id, handler: findOne, rf: RF-SYSTEM-001}
          - {method: GET, path: /user/:userId, handler: findByUser, rf: RF-SYSTEM-001}
          - {method: GET, path: /recent, handler: getRecentActivity, rf: RF-SYSTEM-001}

      - name: MessagesController
        file: messages.controller.ts
        prefix: /api/v1/messages
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-SYSTEM-002}
          - {method: GET, path: /:id, handler: findOne, rf: RF-SYSTEM-002}
          - {method: POST, path: /, handler: create, rf: RF-SYSTEM-002}
          - {method: POST, path: /:id/read, handler: markAsRead, rf: RF-SYSTEM-002}
          - {method: POST, path: /read-all, handler: markAllAsRead, rf: RF-SYSTEM-002}
          - {method: GET, path: /unread/count, handler: getUnreadCount, rf: RF-SYSTEM-002}
          - {method: DELETE, path: /:id, handler: delete, rf: RF-SYSTEM-002}

      - name: NotificationsController
        file: notifications.controller.ts
        prefix: /api/v1/notifications
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-SYSTEM-003}
          - {method: GET, path: /:id, handler: findOne, rf: RF-SYSTEM-003}
          - {method: POST, path: /:id/read, handler: markAsRead, rf: RF-SYSTEM-003}
          - {method: POST, path: /read-all, handler: markAllAsRead, rf: RF-SYSTEM-003}
          - {method: GET, path: /unread/count, handler: getUnreadCount, rf: RF-SYSTEM-003}
          - {method: DELETE, path: /:id, handler: delete, rf: RF-SYSTEM-003}
          - {method: POST, path: /broadcast, handler: broadcast, rf: RF-SYSTEM-003}

      - name: SettingsController
        file: settings.controller.ts
        prefix: /api/v1/settings
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-SYSTEM-004}
          - {method: GET, path: /:key, handler: findOne, rf: RF-SYSTEM-004}
          - {method: PUT, path: /:key, handler: setValue, rf: RF-SYSTEM-004}
          - {method: DELETE, path: /:key, handler: remove, rf: RF-SYSTEM-004}
          - {method: GET, path: /category/:category, handler: getByCategory, rf: RF-SYSTEM-004}

    dtos:
      - {name: CreateActivityDto, file: dto/create-activity.dto.ts, type: request}
      - {name: ActivityFilterDto, file: dto/activity-filter.dto.ts, type: request}
      - {name: CreateMessageDto, file: dto/create-message.dto.ts, type: request}
      - {name: MessageFilterDto, file: dto/message-filter.dto.ts, type: request}
      - {name: CreateNotificationDto, file: dto/create-notification.dto.ts, type: request}
      - {name: NotificationFilterDto, file: dto/notification-filter.dto.ts, type: request}
      - {name: BroadcastNotificationDto, file: dto/broadcast-notification.dto.ts, type: request}
      - {name: SetSettingDto, file: dto/set-setting.dto.ts, type: request}

  # ---------------------------------------------------------------------------
  # MGN-008: REPORTING
  # ---------------------------------------------------------------------------
  - id: MGN-008
    name: reporting
    path: apps/backend/src/modules/reporting/
    status: documented
    rf: [RF-REPORTING-001, RF-REPORTING-002, RF-REPORTING-003, RF-REPORTING-004, RF-REPORTING-005, RF-REPORTING-006]

    entities:
      - name: Report
        file: entities/report.entity.ts
        table: core_reporting.reports
        rf: RF-REPORTING-001

      - name: Dashboard
        file: entities/dashboard.entity.ts
        table: core_reporting.dashboards
        rf: RF-REPORTING-002

      - name: ExportJob
        file: entities/export-job.entity.ts
        table: core_reporting.export_jobs
        rf: RF-REPORTING-003

      - name: ScheduledReport
        file: entities/scheduled-report.entity.ts
        table: core_reporting.scheduled_reports
        rf: RF-REPORTING-006

    services:
      - name: ReportsService
        file: reports.service.ts
        rf: [RF-REPORTING-001]
        methods:
          - {name: findAll, params: [tenantId, filters], returns: "Report[]"}
          - {name: findOne, params: [id], returns: Report}
          - {name: create, params: [CreateReportDto], returns: Report}
          - {name: update, params: [id, UpdateReportDto], returns: Report}
          - {name: remove, params: [id], returns: void}
          - {name: execute, params: [id, params], returns: ReportResult}

      - name: DashboardsService
        file: dashboards.service.ts
        rf: [RF-REPORTING-002]
        methods:
          - {name: findAll, params: [tenantId, userId], returns: "Dashboard[]"}
          - {name: findOne, params: [id], returns: Dashboard}
          - {name: create, params: [CreateDashboardDto], returns: Dashboard}
          - {name: update, params: [id, UpdateDashboardDto], returns: Dashboard}
          - {name: remove, params: [id], returns: void}
          - {name: clone, params: [id, userId], returns: Dashboard}

      - name: ExportService
        file: export.service.ts
        rf: [RF-REPORTING-003]
        methods:
          - {name: export, params: [data, format, options], returns: ExportResult}
          - {name: exportToPdf, params: [data, options], returns: Buffer}
          - {name: exportToExcel, params: [data, options], returns: Buffer}
          - {name: exportToCsv, params: [data, options], returns: Buffer}
          - {name: getJobStatus, params: [jobId], returns: ExportJob}

      - name: PdfService
        file: pdf.service.ts
        rf: [RF-REPORTING-003]
        methods:
          - {name: generateFromHtml, params: [html, options], returns: Buffer}
          - {name: generateFromTemplate, params: [template, data, options], returns: Buffer}
          - {name: merge, params: [pdfs], returns: Buffer}
          - {name: addWatermark, params: [pdf, watermarkText], returns: Buffer}

      - name: ReportBuilderService
        file: report-builder.service.ts
        rf: [RF-REPORTING-004]
        methods:
          - {name: getDataSources, params: [tenantId], returns: "DataSource[]"}
          - {name: getFields, params: [dataSourceId], returns: "Field[]"}
          - {name: preview, params: [dto], returns: PreviewResult}
          - {name: build, params: [dto], returns: Report}

      - name: SchedulerService
        file: scheduler.service.ts
        rf: [RF-REPORTING-006]
        methods:
          - {name: findAll, params: [tenantId], returns: "ScheduledReport[]"}
          - {name: findOne, params: [id], returns: ScheduledReport}
          - {name: create, params: [CreateScheduledReportDto], returns: ScheduledReport}
          - {name: update, params: [id, UpdateScheduledReportDto], returns: ScheduledReport}
          - {name: remove, params: [id], returns: void}
          - {name: toggle, params: [id, isActive], returns: ScheduledReport}
          - {name: executeScheduled, params: [id], returns: void}

    controllers:
      - name: ReportsController
        file: reports.controller.ts
        prefix: /api/v1/reporting/reports
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-REPORTING-001}
          - {method: GET, path: /:id, handler: findOne, rf: RF-REPORTING-001}
          - {method: POST, path: /, handler: create, rf: RF-REPORTING-001}
          - {method: PATCH, path: /:id, handler: update, rf: RF-REPORTING-001}
          - {method: DELETE, path: /:id, handler: remove, rf: RF-REPORTING-001}
          - {method: POST, path: /:id/execute, handler: execute, rf: RF-REPORTING-001}

      - name: DashboardsController
        file: dashboards.controller.ts
        prefix: /api/v1/reporting/dashboards
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-REPORTING-002}
          - {method: GET, path: /:id, handler: findOne, rf: RF-REPORTING-002}
          - {method: POST, path: /, handler: create, rf: RF-REPORTING-002}
          - {method: PATCH, path: /:id, handler: update, rf: RF-REPORTING-002}
          - {method: DELETE, path: /:id, handler: remove, rf: RF-REPORTING-002}
          - {method: POST, path: /:id/clone, handler: clone, rf: RF-REPORTING-002}

      - name: ExportController
        file: export.controller.ts
        prefix: /api/v1/reporting/export
        endpoints:
          - {method: POST, path: /pdf, handler: exportToPdf, rf: RF-REPORTING-003}
          - {method: POST, path: /excel, handler: exportToExcel, rf: RF-REPORTING-003}
          - {method: POST, path: /csv, handler: exportToCsv, rf: RF-REPORTING-003}
          - {method: GET, path: /jobs/:jobId, handler: getJobStatus, rf: RF-REPORTING-003}

      - name: ReportBuilderController
        file: report-builder.controller.ts
        prefix: /api/v1/reporting/builder
        endpoints:
          - {method: GET, path: /data-sources, handler: getDataSources, rf: RF-REPORTING-004}
          - {method: GET, path: /data-sources/:id/fields, handler: getFields, rf: RF-REPORTING-004}
          - {method: POST, path: /preview, handler: preview, rf: RF-REPORTING-004}
          - {method: POST, path: /build, handler: build, rf: RF-REPORTING-004}

      - name: SchedulerController
        file: scheduler.controller.ts
        prefix: /api/v1/reporting/schedules
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-REPORTING-006}
          - {method: GET, path: /:id, handler: findOne, rf: RF-REPORTING-006}
          - {method: POST, path: /, handler: create, rf: RF-REPORTING-006}
          - {method: PATCH, path: /:id, handler: update, rf: RF-REPORTING-006}
          - {method: DELETE, path: /:id, handler: remove, rf: RF-REPORTING-006}
          - {method: POST, path: /:id/toggle, handler: toggle, rf: RF-REPORTING-006}

    dtos:
      - {name: CreateReportDto, file: dto/create-report.dto.ts, type: request}
      - {name: UpdateReportDto, file: dto/update-report.dto.ts, type: request}
      - {name: ExecuteReportDto, file: dto/execute-report.dto.ts, type: request}
      - {name: CreateDashboardDto, file: dto/create-dashboard.dto.ts, type: request}
      - {name: UpdateDashboardDto, file: dto/update-dashboard.dto.ts, type: request}
      - {name: ExportOptionsDto, file: dto/export-options.dto.ts, type: request}
      - {name: BuildReportDto, file: dto/build-report.dto.ts, type: request}
      - {name: CreateScheduledReportDto, file: dto/create-scheduled-report.dto.ts, type: request}
      - {name: UpdateScheduledReportDto, file: dto/update-scheduled-report.dto.ts, type: request}

  # ---------------------------------------------------------------------------
  # MGN-009: REPORTS
  # ---------------------------------------------------------------------------
  - id: MGN-009
    name: reports
    path: apps/backend/src/modules/reports/
    status: implemented
    rf: [RF-REPORT-001, RF-REPORT-002, RF-REPORT-003, RF-REPORT-004]
    updated: "2026-01-07"
    sprint: "8-13 + BE-026"

    services:
      - name: ReportsService
        file: reports.service.ts
        rf: [RF-REPORT-001]
        status: implemented
        methods:
          - {name: findAllDefinitions, params: [tenantId, filters], returns: "PaginatedResult"}
          - {name: findDefinitionById, params: [id, tenantId], returns: "ReportDefinition"}
          - {name: createDefinition, params: [dto, tenantId, userId], returns: "ReportDefinition"}
          - {name: executeReport, params: [dto, tenantId, userId], returns: "ReportExecution"}
          - {name: findExecutionById, params: [id, tenantId], returns: "ReportExecution"}
          - {name: generateTrialBalance, params: [tenantId, companyId, dateFrom, dateTo], returns: "any[]"}
          - {name: generateGeneralLedger, params: [tenantId, companyId, accountId, dateFrom, dateTo], returns: "any[]"}

      - name: DashboardsService
        file: dashboards.service.ts
        rf: [RF-REPORT-002]
        status: implemented
        methods:
          - {name: findAll, params: [tenantId, userId], returns: "Dashboard[]"}
          - {name: findById, params: [id, tenantId], returns: "Dashboard"}
          - {name: create, params: [dto, tenantId, userId], returns: "Dashboard"}
          - {name: update, params: [id, dto, tenantId], returns: "Dashboard"}
          - {name: delete, params: [id, tenantId], returns: void}
          - {name: clone, params: [id, tenantId, userId], returns: "Dashboard"}

      - name: ExportService
        file: export.service.ts
        rf: [RF-REPORT-001]
        status: implemented
        methods:
          - {name: export, params: [data, options], returns: "ExportResult"}
          - {name: exportToPdf, params: [data, options, filename], returns: "ExportResult"}
          - {name: exportToCsv, params: [data, options, filename], returns: "ExportResult"}
          - {name: exportToXlsx, params: [data, options, filename], returns: "ExportResult"}
          - {name: exportToJson, params: [data, options, filename], returns: "ExportResult"}
          - {name: exportToHtml, params: [data, options, filename], returns: "ExportResult"}

      - name: PdfService
        file: pdf.service.ts
        rf: [RF-REPORT-001]
        status: implemented
        created: "2026-01-07"
        task: "BE-026"
        methods:
          - {name: generateFromHtml, params: [html, options], returns: "PdfResult"}
          - {name: generateFromUrl, params: [url, options], returns: "PdfResult"}
          - {name: healthCheck, params: [], returns: "{available, error}"}
          - {name: close, params: [], returns: void}
        dependencies:
          - {package: puppeteer, version: "^22.15.0"}

      - name: ReportTemplates
        file: templates/report-templates.ts
        rf: [RF-REPORT-001]
        status: implemented
        created: "2026-01-07"
        task: "BE-026"
        functions:
          - {name: generateTabularReport, description: "Template tabular genérico"}
          - {name: generateFinancialReport, description: "Template estados financieros"}
          - {name: generateTrialBalance, description: "Template balanza de comprobación"}
          - {name: generateDashboardExport, description: "Template exportación dashboard"}

      - name: ReportBuilderService
        file: report-builder.service.ts
        rf: [RF-REPORT-003]
        status: implemented
        methods:
          - {name: getEntities, params: [tenantId], returns: "DataModelEntity[]"}
          - {name: getFields, params: [entityId], returns: "DataModelField[]"}
          - {name: previewReport, params: [dto, tenantId], returns: "any[]"}
          - {name: saveCustomReport, params: [dto, tenantId, userId], returns: "CustomReport"}

      - name: SchedulerService
        file: scheduler.service.ts
        rf: [RF-REPORT-004]
        status: implemented
        methods:
          - {name: findAllSchedules, params: [tenantId], returns: "ReportSchedule[]"}
          - {name: createSchedule, params: [dto, tenantId, userId], returns: "ReportSchedule"}
          - {name: toggleSchedule, params: [id, tenantId, isActive], returns: "ReportSchedule"}
          - {name: deleteSchedule, params: [id, tenantId], returns: void}

    controllers:
      - name: ReportsController
        file: reports.controller.ts
        prefix: /api/v1/reports
        status: implemented
        endpoints:
          - {method: GET, path: /definitions, handler: findAllDefinitions, rf: RF-REPORT-001}
          - {method: GET, path: /definitions/:id, handler: findDefinitionById, rf: RF-REPORT-001}
          - {method: POST, path: /definitions, handler: createDefinition, rf: RF-REPORT-001}
          - {method: POST, path: /execute, handler: executeReport, rf: RF-REPORT-001}
          - {method: GET, path: /executions, handler: findRecentExecutions, rf: RF-REPORT-001}
          - {method: GET, path: /executions/:id, handler: findExecutionById, rf: RF-REPORT-001}
          - {method: POST, path: /executions/:id/export, handler: exportExecution, rf: RF-REPORT-001, task: BE-026}
          - {method: GET, path: /quick/trial-balance, handler: getTrialBalance, rf: RF-REPORT-001}
          - {method: GET, path: /quick/trial-balance/export, handler: exportTrialBalance, rf: RF-REPORT-001, task: BE-026}
          - {method: GET, path: /quick/general-ledger, handler: getGeneralLedger, rf: RF-REPORT-001}
          - {method: GET, path: /pdf/health, handler: checkPdfHealth, rf: RF-REPORT-001, task: BE-026}
          - {method: GET, path: /schedules, handler: findAllSchedules, rf: RF-REPORT-004}
          - {method: POST, path: /schedules, handler: createSchedule, rf: RF-REPORT-004}
          - {method: PATCH, path: /schedules/:id/toggle, handler: toggleSchedule, rf: RF-REPORT-004}
          - {method: DELETE, path: /schedules/:id, handler: deleteSchedule, rf: RF-REPORT-004}

      - name: DashboardsController
        file: dashboards.controller.ts
        prefix: /api/v1/dashboards
        status: implemented
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-REPORT-002}
          - {method: GET, path: /default, handler: findDefault, rf: RF-REPORT-002}
          - {method: GET, path: /:id, handler: findById, rf: RF-REPORT-002}
          - {method: POST, path: /, handler: create, rf: RF-REPORT-002}
          - {method: PATCH, path: /:id, handler: update, rf: RF-REPORT-002}
          - {method: DELETE, path: /:id, handler: delete, rf: RF-REPORT-002}
          - {method: POST, path: /:id/clone, handler: clone, rf: RF-REPORT-002}
          - {method: PUT, path: /:id/layout, handler: updateLayout, rf: RF-REPORT-002}
          - {method: GET, path: /:id/data, handler: getDashboardData, rf: RF-REPORT-002}
          - {method: POST, path: /:id/widgets, handler: addWidget, rf: RF-REPORT-002}
          - {method: PATCH, path: /:id/widgets/:widgetId, handler: updateWidget, rf: RF-REPORT-002}
          - {method: DELETE, path: /:id/widgets/:widgetId, handler: removeWidget, rf: RF-REPORT-002}
          - {method: GET, path: /:id/widgets/:widgetId/data, handler: getWidgetData, rf: RF-REPORT-002}

  # ---------------------------------------------------------------------------
  # MGN-010: FINANCIAL
  # ---------------------------------------------------------------------------
  - id: MGN-010
    name: financial
    path: apps/backend/src/modules/financial/
    status: documented
    rf: [RF-FIN-001, RF-FIN-002, RF-FIN-003, RF-FIN-004, RF-FIN-005, RF-FIN-006]

    entities:
      - name: Incoterm
        file: entities/incoterm.entity.ts
        table: core_financial.incoterms
        rf: RF-FIN-001

      - name: PaymentMethod
        file: entities/payment-method.entity.ts
        table: core_financial.payment_methods
        rf: RF-FIN-002

      - name: PaymentTerm
        file: entities/payment-term.entity.ts
        table: core_financial.payment_terms
        rf: RF-FIN-003

      - name: ReconcileModel
        file: entities/reconcile-model.entity.ts
        table: core_financial.reconcile_models
        rf: RF-FIN-004

    services:
      - name: IncotermsService
        file: incoterms.service.ts
        rf: [RF-FIN-001]
        methods:
          - {name: findAll, params: [tenantId], returns: "Incoterm[]"}
          - {name: findOne, params: [id], returns: Incoterm}
          - {name: findByCode, params: [code], returns: Incoterm}
          - {name: create, params: [CreateIncotermDto], returns: Incoterm}
          - {name: update, params: [id, UpdateIncotermDto], returns: Incoterm}
          - {name: remove, params: [id], returns: void}

      - name: PaymentMethodsService
        file: payment-methods.service.ts
        rf: [RF-FIN-002]
        methods:
          - {name: findAll, params: [tenantId], returns: "PaymentMethod[]"}
          - {name: findOne, params: [id], returns: PaymentMethod}
          - {name: findByType, params: [type, tenantId], returns: "PaymentMethod[]"}
          - {name: create, params: [CreatePaymentMethodDto], returns: PaymentMethod}
          - {name: update, params: [id, UpdatePaymentMethodDto], returns: PaymentMethod}
          - {name: remove, params: [id], returns: void}
          - {name: setDefault, params: [tenantId, paymentMethodId], returns: PaymentMethod}

      - name: PaymentTermsService
        file: payment-terms.service.ts
        rf: [RF-FIN-003]
        methods:
          - {name: findAll, params: [tenantId], returns: "PaymentTerm[]"}
          - {name: findOne, params: [id], returns: PaymentTerm}
          - {name: create, params: [CreatePaymentTermDto], returns: PaymentTerm}
          - {name: update, params: [id, UpdatePaymentTermDto], returns: PaymentTerm}
          - {name: remove, params: [id], returns: void}
          - {name: calculateDueDate, params: [invoiceDate, paymentTermId], returns: Date}
          - {name: setDefault, params: [tenantId, paymentTermId], returns: PaymentTerm}

      - name: ReconcileModelsService
        file: reconcile-models.service.ts
        rf: [RF-FIN-004]
        methods:
          - {name: findAll, params: [tenantId], returns: "ReconcileModel[]"}
          - {name: findOne, params: [id], returns: ReconcileModel}
          - {name: create, params: [CreateReconcileModelDto], returns: ReconcileModel}
          - {name: update, params: [id, UpdateReconcileModelDto], returns: ReconcileModel}
          - {name: remove, params: [id], returns: void}
          - {name: execute, params: [modelId, params], returns: ReconcileResult}
          - {name: preview, params: [modelId, params], returns: ReconcilePreview}

    controllers:
      - name: IncotermsController
        file: incoterms.controller.ts
        prefix: /api/v1/financial/incoterms
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-FIN-001}
          - {method: GET, path: /:id, handler: findOne, rf: RF-FIN-001}
          - {method: POST, path: /, handler: create, rf: RF-FIN-001}
          - {method: PATCH, path: /:id, handler: update, rf: RF-FIN-001}
          - {method: DELETE, path: /:id, handler: remove, rf: RF-FIN-001}

      - name: PaymentMethodsController
        file: payment-methods.controller.ts
        prefix: /api/v1/financial/payment-methods
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-FIN-002}
          - {method: GET, path: /:id, handler: findOne, rf: RF-FIN-002}
          - {method: POST, path: /, handler: create, rf: RF-FIN-002}
          - {method: PATCH, path: /:id, handler: update, rf: RF-FIN-002}
          - {method: DELETE, path: /:id, handler: remove, rf: RF-FIN-002}
          - {method: POST, path: /:id/set-default, handler: setDefault, rf: RF-FIN-002}

      - name: PaymentTermsController
        file: payment-terms.controller.ts
        prefix: /api/v1/financial/payment-terms
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-FIN-003}
          - {method: GET, path: /:id, handler: findOne, rf: RF-FIN-003}
          - {method: POST, path: /, handler: create, rf: RF-FIN-003}
          - {method: PATCH, path: /:id, handler: update, rf: RF-FIN-003}
          - {method: DELETE, path: /:id, handler: remove, rf: RF-FIN-003}
          - {method: POST, path: /:id/set-default, handler: setDefault, rf: RF-FIN-003}
          - {method: POST, path: /calculate-due-date, handler: calculateDueDate, rf: RF-FIN-003}

      - name: ReconcileModelsController
        file: reconcile-models.controller.ts
        prefix: /api/v1/financial/reconcile-models
        endpoints:
          - {method: GET, path: /, handler: findAll, rf: RF-FIN-004}
          - {method: GET, path: /:id, handler: findOne, rf: RF-FIN-004}
          - {method: POST, path: /, handler: create, rf: RF-FIN-004}
          - {method: PATCH, path: /:id, handler: update, rf: RF-FIN-004}
          - {method: DELETE, path: /:id, handler: remove, rf: RF-FIN-004}
          - {method: POST, path: /:id/execute, handler: execute, rf: RF-FIN-004}
          - {method: POST, path: /:id/preview, handler: preview, rf: RF-FIN-004}

    dtos:
      - {name: CreateIncotermDto, file: dto/create-incoterm.dto.ts, type: request}
      - {name: UpdateIncotermDto, file: dto/update-incoterm.dto.ts, type: request}
      - {name: CreatePaymentMethodDto, file: dto/create-payment-method.dto.ts, type: request}
      - {name: UpdatePaymentMethodDto, file: dto/update-payment-method.dto.ts, type: request}
      - {name: CreatePaymentTermDto, file: dto/create-payment-term.dto.ts, type: request}
      - {name: UpdatePaymentTermDto, file: dto/update-payment-term.dto.ts, type: request}
      - {name: CalculateDueDateDto, file: dto/calculate-due-date.dto.ts, type: request}
      - {name: CreateReconcileModelDto, file: dto/create-reconcile-model.dto.ts, type: request}
      - {name: UpdateReconcileModelDto, file: dto/update-reconcile-model.dto.ts, type: request}
      - {name: ExecuteReconcileDto, file: dto/execute-reconcile.dto.ts, type: request}

# =============================================================================
# SHARED / COMMON
# =============================================================================

shared:
  path: apps/backend/src/shared/

  utils:
    - {name: pagination.util.ts, description: Helpers de paginacion}
    - {name: hash.util.ts, description: Funciones de hash}
    - {name: date.util.ts, description: Manipulacion de fechas}

  types:
    - {name: pagination.types.ts, description: Tipos de paginacion}
    - {name: api-response.types.ts, description: Tipos de respuesta API}

  constants:
    - {name: roles.constants.ts, description: Constantes de roles}
    - {name: permissions.constants.ts, description: Lista de permisos}

  interceptors:
    - {name: logging.interceptor.ts, description: Log de requests}
    - {name: transform.interceptor.ts, description: Transformacion de respuestas}

  filters:
    - {name: http-exception.filter.ts, description: Manejo de excepciones HTTP}
    - {name: validation.filter.ts, description: Errores de validacion}

  pipes:
    - {name: validation.pipe.ts, description: Validacion global}
    - {name: parse-uuid.pipe.ts, description: Parsing de UUIDs}

# =============================================================================
# CONFIGURACION
# =============================================================================

config:
  path: apps/backend/src/config/
  files:
    - {name: database.config.ts, description: Conexion PostgreSQL}
    - {name: jwt.config.ts, description: Configuracion JWT}
    - {name: cors.config.ts, description: Configuracion CORS}
    - {name: app.config.ts, description: Configuracion general}
    - {name: redis.config.ts, description: Conexion Redis}
    - {name: mail.config.ts, description: Configuracion email}

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

dependencies:
  production:
    - "@nestjs/common": "^10.0.0"
    - "@nestjs/core": "^10.0.0"
    - "@nestjs/platform-express": "^10.0.0"
    - "@nestjs/typeorm": "^10.0.0"
    - "@nestjs/jwt": "^10.0.0"
    - "@nestjs/passport": "^10.0.0"
    - "@nestjs/swagger": "^7.0.0"
    - "typeorm": "^0.3.17"
    - "pg": "^8.11.0"
    - "bcryptjs": "^2.4.3"
    - "passport": "^0.7.0"
    - "passport-jwt": "^4.0.1"
    - "passport-local": "^1.0.0"
    - "class-validator": "^0.14.0"
    - "class-transformer": "^0.5.1"
    - "uuid": "^9.0.0"

  development:
    - "typescript": "^5.3.0"
    - "@nestjs/cli": "^10.0.0"
    - "@nestjs/testing": "^10.0.0"
    - "jest": "^29.0.0"
    - "supertest": "^6.3.0"
    - "@types/node": "^20.0.0"

# =============================================================================
# TESTS
# =============================================================================

tests:
  framework: Jest
  target_coverage: 80%
  structure:
    unit: "src/**/__tests__/*.spec.ts"
    integration: "test/**/*.e2e-spec.ts"

# =============================================================================
# HISTORIAL
# =============================================================================

history:
  - date: "2026-01-10"
    action: "Documentacion modulos MGN-005 a MGN-010"
    author: Backend-Agent-Claude-Opus
    changes:
      - "MGN-005 (core): countries, states, currencies, currency-rates, sequences, product-categories, uom"
      - "MGN-006 (audit): access-logs, audit, security-events"
      - "MGN-007 (system): activities, messages, notifications, settings"
      - "MGN-008 (reporting): reports, dashboards, export, pdf, report-builder, scheduler"
      - "MGN-010 (financial): incoterms, payment-methods, payment-terms, reconcile-models"
      - "Actualizados conteos en summary: services 68, controllers 50, endpoints 240, entities 65, dtos 115"

  - date: "2026-01-07"
    action: "BE-026: PDF Export Implementation"
    author: Backend-Agent-Claude-Opus
    task: "BE-026"
    changes:
      - "PdfService con Puppeteer para generación PDF real"
      - "ReportTemplates para reportes financieros"
      - "Endpoints export: /executions/:id/export, /trial-balance/export"
      - "Health check endpoint: /pdf/health"
      - "ExportService actualizado para usar PdfService"
    files_created:
      - backend/src/modules/reports/pdf.service.ts
      - backend/src/modules/reports/templates/report-templates.ts
    files_modified:
      - backend/src/modules/reports/export.service.ts
      - backend/src/modules/reports/reports.controller.ts
      - backend/src/modules/reports/reports.routes.ts

  - date: "2026-01-06"
    action: "Implementacion Sprints 1-3 (109 SP)"
    author: ORQUESTADOR-Claude-Opus
    sprint: "1-3"
    changes:
      - "502 tests implementados y pasando"
      - "OAuth2 Google/Microsoft con PKCE implementado"
      - "Permission Cache Service con Redis"
      - "Factories completas para todos los modulos"
    files_created:
      tests:
        - tests/factories/user.factory.ts
        - tests/factories/tenant.factory.ts
        - tests/factories/role.factory.ts
        - tests/factories/financial.factory.ts
        - tests/factories/inventory.factory.ts
        - src/modules/auth/__tests__/auth.service.spec.ts
        - src/modules/auth/__tests__/auth.controller.spec.ts
        - src/modules/auth/__tests__/auth.integration.spec.ts
        - src/modules/users/__tests__/users.service.spec.ts
        - src/modules/users/__tests__/users.controller.spec.ts
        - src/modules/roles/__tests__/roles.service.spec.ts
        - src/modules/roles/__tests__/roles.controller.spec.ts
        - src/modules/tenants/__tests__/tenants.service.spec.ts
        - src/modules/tenants/__tests__/tenants.controller.spec.ts
        - src/modules/auth/services/__tests__/permission-cache.service.spec.ts
        - src/modules/financial/__tests__/accounts.service.spec.ts
        - src/modules/financial/__tests__/journal-entries.service.spec.ts
        - src/modules/financial/__tests__/invoices.service.spec.ts
        - src/modules/inventory/__tests__/products.service.spec.ts
        - src/modules/inventory/__tests__/stock.service.spec.ts
        - src/modules/auth/providers/__tests__/oauth.spec.ts
      services:
        - src/modules/auth/services/permission-cache.service.ts
        - src/modules/auth/providers/oauth.service.ts
        - src/modules/auth/providers/google.provider.ts
        - src/modules/auth/providers/microsoft.provider.ts
      controllers:
        - src/modules/auth/oauth.controller.ts
      types:
        - src/modules/auth/providers/oauth.types.ts
      routes:
        - src/modules/auth/oauth.routes.ts

  - date: "2025-12-05"
    action: "Reestructuracion completa siguiendo filosofia GAMILIT"
    author: Requirements-Analyst
    changes:
      - "Documentados 4 modulos foundation completos"
      - "Agregada trazabilidad RF por servicio y endpoint"
      - "Documentados DTOs, guards, decorators"
