Uecko_ERP/docs/architecture/identity-backend-architecture.md
2026-07-06 14:04:47 +02:00

136 lines
2.5 KiB
Markdown

# Identity Backend Architecture
## Objetivo del módulo `identity`
`identity` sustituye progresivamente al módulo legacy `auth`.
Responsabilidades actuales:
- cuentas autenticables
- login/password
- access token
- refresh token rotado
- logout
- sesión actual
- memberships
- validación de acceso account-company
- base para roles/permisos futuros
## Dominio actual
Agregados y conceptos relevantes:
```txt
Account
RefreshToken
CompanyMembership
Role
```
`Company` funcional no pertenece a `identity`; vive en `modules/companies`.
## Seguridad
Servicios definidos:
```txt
IPasswordHasher
IAccessTokenIssuer
IAccessTokenVerifier
IRefreshTokenGenerator
IRefreshTokenHasher
```
Decisiones vigentes:
- password hashing con `bcrypt`
- access token JWT con `accountId` y `email`
- refresh token aleatorio
- refresh token persistido como hash
- no incluir `companyId`, `companySlug`, roles ni permisos en access token
## Builders públicos
`identity` expone desde `@erp/identity/api`:
```ts
requireIdentityAuthenticated(params: StartParams): RequestHandler[];
requireIdentityTenant(params: StartParams): RequestHandler[];
```
Uso correcto:
```ts
import { requireIdentityTenant } from "@erp/identity/api";
router.use(...requireIdentityTenant(params));
```
```ts
import { requireIdentityAuthenticated } from "@erp/identity/api";
router.use(...requireIdentityAuthenticated(params));
```
## `req.user`
Shape mínimo esperado:
```ts
{
userId: UniqueID;
email?: EmailAddress;
companyId?: UniqueID;
roles?: string[];
}
```
`req.user.companyId` solo se debe poblar cuando el middleware tenant valida correctamente la request.
No añadir:
- `companySlug`
- `company`
- `permissions` enriquecidos
- `companyStatus`
## Tenant validation
`requireIdentityTenant(params)` ya no es solo validación sintáctica.
Valida:
1. token válido
2. account autenticable
3. `X-Company-Id` presente
4. UUID válido
5. membership `active`
6. company `active`
## Relación con `companies`
- `identity` resuelve membership y accesibilidad
- `companies` resuelve la ficha operativa de empresa
- no introducir dependencia `identity -> companies`
Si un consumidor necesita `slug`, debe resolverlo desde `companies`, no desde auth.
## Prohibiciones de diseño
No usar en módulos consumidores:
```ts
IdentityInternalDeps;
authenticateUserDependencies;
getInternal("identity");
```
No crear helpers locales de auth por módulo como patrón estable.
No añadir al access token:
- `companyId`
- `companySlug`
- roles
- permisos