# 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 X-Company-Id: ``` `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 ```