2026-07-06 12:04:47 +00:00
# Identity And Companies
## Objetivo
Documentar la separación actual entre `modules/identity` y `modules/companies` , evitando mezclar autenticación, memberships y ficha operativa de empresa.
## Responsabilidades por módulo
### `modules/identity`
Gestiona:
- `Account`
- login
- refresh
- logout
- session
- `RefreshToken`
- `CompanyMembership`
2026-07-06 15:47:05 +00:00
- acceso `account-company`
2026-07-06 12:04:47 +00:00
- roles/permisos futuros
Endpoints activos:
```http
POST /identity/auth/login
POST /identity/auth/refresh
POST /identity/auth/logout
GET /identity/auth/session
```
El access token contiene solo:
```ts
{
accountId: string;
email: string;
}
```
No debe contener:
- `companyId`
- `companySlug`
- roles
- permisos
### `modules/companies`
Es la fuente de verdad de la ficha operativa de empresa.
`Company` funcional vive en `modules/companies` .
Campos actuales de `companies` :
```txt
id
legal_name
trade_name
tin
slug
email
phone
website
status
created_at
updated_at
```
Índices actuales:
```txt
UNIQUE(slug)
INDEX(status)
INDEX(tin)
```
`slug` pertenece a `companies` , no a auth ni al token.
## Relación entre ambos módulos
- `CompanyMembership` vive en `identity` .
- `Company` vive en `companies` .
- No mover memberships a `companies` .
- No evolucionar `identity.Company` como ficha operativa ERP.
2026-07-06 15:47:05 +00:00
- No usar `customers` para representar la empresa tenant.
2026-07-06 12:04:47 +00:00
## Servicios públicos
### `identity:general`
Expone autenticación y acceso por membership.
Uso conceptual:
```ts
companyAccess.canAccessCompany(...)
companyAccess.findAccessibleCompanyIds(...)
```
`identity` devuelve IDs accesibles por membership, no fichas completas de empresa.
### `companies:general`
Expone consulta de empresas y validación de empresa activa.
Uso conceptual:
```ts
ICompanyPublicServices {
finder: ICompanyPublicFinder;
}
```
## Por qué no existe `GET /identity/companies`
No se documenta `GET /identity/companies` como endpoint válido porque produciría acoplamiento circular:
```txt
identity -> companies -> identity
```
Si `identity` devolviera fichas completas de company, tendría que depender de `companies` .
Como `companies` ya depende de `identity` para autenticación, el diseño correcto es:
- `identity` resuelve membership y accesibilidad por ID
- `companies` resuelve la ficha completa de empresa
El endpoint vigente para el frontend es:
```http
GET /companies/available
Authorization: Bearer < access_token >
```
2026-07-06 15:47:05 +00:00
Tampoco debe documentarse ni introducirse `GET /account/companies` como variante válida.
2026-07-06 12:04:47 +00:00
## Dependencias permitidas
Para módulos tenant-scoped que usan `requireIdentityTenant(params)` , la dependencia explícita debe ser hacia:
- `identity`
- `companies`
Porque el middleware tenant compone:
```txt
identity:general.companyAccess
companies:general.finder
```
## Dependencias prohibidas
No introducir:
- `identity -> companies`
- recomposición manual de internals de `identity`
- `IdentityInternalDeps`
- `getInternal("identity")` desde módulos consumidores
- helpers locales de auth por módulo como patrón estable
## `GET /companies/available`
Semántica actual:
- requiere `Authorization`
- no requiere `X-Company-Id`
- usa `requireIdentityAuthenticated(params)`
- devuelve companies activas accesibles para la cuenta autenticada
La disponibilidad se calcula con:
```txt
membership active en identity
+
company active en companies
```