116 lines
2.3 KiB
Markdown
116 lines
2.3 KiB
Markdown
# Tenant Context
|
|
|
|
## Objetivo
|
|
|
|
Documentar cómo se resuelve el contexto tenant actual del ERP mediante `X-Company-Id` y `requireIdentityTenant(params)`.
|
|
|
|
## Header tenant
|
|
|
|
Las rutas tenant-scoped deben recibir:
|
|
|
|
```http
|
|
Authorization: Bearer <access_token>
|
|
X-Company-Id: <uuid-company>
|
|
```
|
|
|
|
`X-Company-Id` es el identificador de la company activa en la request.
|
|
|
|
No usar:
|
|
|
|
- `X-Company-Slug`
|
|
- `companySlug` en token
|
|
- `req.user.companySlug`
|
|
|
|
## Middleware público
|
|
|
|
Para rutas tenant-scoped:
|
|
|
|
```ts
|
|
import { requireIdentityTenant } from "@erp/identity/api";
|
|
|
|
router.use(...requireIdentityTenant(params));
|
|
```
|
|
|
|
Para rutas solo autenticadas:
|
|
|
|
```ts
|
|
import { requireIdentityAuthenticated } from "@erp/identity/api";
|
|
|
|
router.use(...requireIdentityAuthenticated(params));
|
|
```
|
|
|
|
## Validación real de `requireIdentityTenant(params)`
|
|
|
|
Actualmente ya valida:
|
|
|
|
1. access token válido
|
|
2. account autenticable
|
|
3. `X-Company-Id` presente
|
|
4. `X-Company-Id` con formato UUID válido
|
|
5. membership `active` en `identity_company_memberships`
|
|
6. company `active` en `companies`
|
|
7. solo entonces rellena `req.user.companyId`
|
|
|
|
## Semántica esperada de errores
|
|
|
|
```txt
|
|
sin Authorization -> 401
|
|
token inválido -> 401
|
|
cuenta inexistente/no autenticable -> 401
|
|
sin X-Company-Id -> 403
|
|
X-Company-Id inválido -> 400
|
|
company inexistente -> 403
|
|
company disabled -> 403
|
|
membership inexistente -> 403
|
|
membership disabled/invited -> 403
|
|
membership active + company active -> entra al controller
|
|
```
|
|
|
|
## Shape mínimo de `req.user`
|
|
|
|
```ts
|
|
{
|
|
userId: UniqueID;
|
|
email?: EmailAddress;
|
|
companyId?: UniqueID;
|
|
roles?: string[];
|
|
}
|
|
```
|
|
|
|
No añadir:
|
|
|
|
- `companySlug`
|
|
- `company`
|
|
- `permissions` enriquecidos
|
|
- `companyStatus`
|
|
|
|
## Módulos tenant-scoped migrados
|
|
|
|
Actualmente usan `requireIdentityTenant(params)`:
|
|
|
|
- `modules/catalogs`
|
|
- `modules/customers`
|
|
- `modules/customer-invoices`
|
|
- `modules/factuges`
|
|
|
|
`modules/supplier` queda fuera de esta migración por ahora.
|
|
|
|
## Qué no debe ir en el token
|
|
|
|
El access token no debe incluir:
|
|
|
|
- `companyId`
|
|
- `companySlug`
|
|
- roles
|
|
- permisos
|
|
|
|
El contexto tenant se resuelve por request con `X-Company-Id`.
|
|
|
|
## Document context
|
|
|
|
Si un flujo documental necesita `companySlug`, debe resolverlo desde `companies`, por ejemplo:
|
|
|
|
```txt
|
|
companyId -> companies:general.finder.findById(...) -> slug
|
|
```
|