Uecko_ERP/docs/architecture/identity-backend-architecture.md

222 lines
3.5 KiB
Markdown

# 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
<module>-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`.