Uecko_ERP/docs/architecture/identity-and-companies.md
2026-07-06 17:47:05 +02:00

3.3 KiB

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:

POST /identity/auth/login
POST /identity/auth/refresh
POST /identity/auth/logout
GET  /identity/auth/session

El access token contiene solo:

{
  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:

id
legal_name
trade_name
tin
slug
email
phone
website
status
created_at
updated_at

Índices actuales:

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:

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:

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:

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:

GET /companies/available
Authorization: Bearer <access_token>

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:

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:

membership active en identity
+
company active en companies