- Add UpdateCurrentCompanyUseCase to handle company updates. - Create update-current-company.controller.ts to manage update requests. - Implement validation and mapping for update requests using Zod. - Add tests for the update use case and controller to ensure functionality. - Introduce error handling and feedback state management for company details settings. - Create utility functions for error normalization and feedback state resolution. - Implement tests for error handling and feedback state utilities. - Ensure nullable fields are handled correctly in DTOs and forms.
215 lines
4.0 KiB
Markdown
215 lines
4.0 KiB
Markdown
# 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`
|
|
- acceso `account-company`
|
|
- 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
|
|
default_payment_term_id
|
|
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.
|
|
- No usar `customers` para representar la empresa tenant.
|
|
|
|
## 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>
|
|
```
|
|
|
|
Para settings de empresa activa, los endpoints vigentes son:
|
|
|
|
```http
|
|
GET /companies/current
|
|
PATCH /companies/current
|
|
```
|
|
|
|
Esos endpoints resuelven la empresa exclusivamente desde:
|
|
|
|
```txt
|
|
X-Company-Id
|
|
+ requireIdentityTenant(params)
|
|
```
|
|
|
|
No desde `companyId` enviado por body, query o params arbitrarios.
|
|
|
|
Tampoco debe documentarse ni introducirse `GET /account/companies` como variante válida.
|
|
|
|
## 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
|
|
```
|
|
|
|
## Autorización V1 de edición de company
|
|
|
|
En la V1 actual:
|
|
|
|
```txt
|
|
cualquier miembro activo de la company
|
|
puede editar sus datos generales
|
|
```
|
|
|
|
Esto aplica a:
|
|
|
|
```http
|
|
PATCH /companies/current
|
|
```
|
|
|
|
No debe documentarse como permiso granular real.
|
|
|
|
`identity:companies:update` puede existir como código futuro del catálogo de permisos, pero no representa enforcement runtime hoy.
|