# Identity Backend Architecture ## Objetivo del módulo `identity` `identity` sustituye progresivamente al módulo legacy `auth`. Responsabilidades previstas: - cuentas autenticables - login/password - access token - refresh token rotado - logout - sesión actual - empresas accesibles - memberships - roles - permisos - autorización futura ## Dominio mínimo creado Agregados principales: ```txt Account Company CompanyMembership Role RefreshToken ``` ## Value Objects reutilizados Desde `@repo/rdx-ddd`: ```txt UniqueID LanguageCode Name TextValue UtcDate EmailAddress URLAddress ``` VOs específicos de `identity`: ```txt PasswordHash RefreshTokenHash RoleCode AccountStatus CompanyStatus CompanyMembershipStatus ``` ## Seguridad Servicios definidos: ```txt IPasswordHasher IAccessTokenIssuer IAccessTokenVerifier IRefreshTokenGenerator IRefreshTokenHasher ``` Implementaciones actuales: ```txt BcryptPasswordHasher JsonWebTokenAccessTokenIssuer JsonWebTokenAccessTokenVerifier CryptoRefreshTokenGenerator Sha256RefreshTokenHasher ``` Decisiones: - password hashing con `bcrypt` en V1. - access token JWT con `accountId` y `email`. - refresh token aleatorio con `crypto.randomBytes`. - refresh token persistido solo como hash SHA-256. - no incluir `companyId`, roles ni permisos en access token. ## Persistencia mínima Tablas/modelos creados: ```txt identity_accounts identity_refresh_tokens ``` Repositorios: ```txt IAccountRepository IRefreshTokenRepository SequelizeAccountRepository SequelizeRefreshTokenRepository ``` ## Servicios públicos del módulo `identity` registra un servicio público: ```txt identity:general ``` Incluye: ```ts auth.authenticatedOnly(): RequestHandler[]; auth.tenantRequired(): RequestHandler[]; ``` Pero los consumidores no deberían usar directamente `identity:general` en routers. Deben usar los builders públicos: ```ts requireIdentityAuthenticated(params: StartParams): RequestHandler[]; requireIdentityTenant(params: StartParams): RequestHandler[]; ``` ## Uso correcto en routers ```ts import { requireIdentityTenant } from "@erp/identity/api"; export function buildSomeRoutes(params: StartParams) { const router = Router(); router.use(...requireIdentityTenant(params)); return router; } ``` ## Shape actual de `req.user` ```ts { userId: UniqueID; email?: EmailAddress; companyId?: UniqueID; roles?: string[]; } ``` Compatibilidad provisional: - `roles` puede ser `[]`. - `companyId` viene de `X-Company-Id`. - `companySlug` no debe depender de auth. ## Prohibiciones de diseño No usar en módulos consumidores: ```ts IdentityInternalDeps; authenticateUserDependencies; getInternal("identity"); ``` No crear: ```txt -auth-middlewares.ts ``` como patrón estable. No añadir a access token: ```txt companyId roles permissions companySlug ``` ## Permisos Cada módulo define sus propios permisos. `core` contiene contratos transversales mínimos: ```ts export type PermissionCode = string; export type PermissionDefinition = { code: PermissionCode; module: string; description: string; }; ``` `identity` define solo sus permisos propios: ```txt identity:companies:update identity:roles:read identity:roles:create identity:roles:update identity:roles:delete identity:company-users:read identity:company-users:update-roles identity:company-users:disable identity:company-users:enable identity:permissions:read ``` `Role.permissionCodes` usa `PermissionCode[]`, no `IdentityPermissionCode[]`. La existencia real de permisos se valida en Application con `IPermissionCatalog`.