FactuGES_ERP/docs/architecture/identity-auth-api.md
david fbf26d4745 feat: implement account management features
- Added services and use cases for managing account details, including changing passwords and updating profiles.
- Introduced error handling for duplicate emails and password mismatches.
- Created controllers for handling account-related requests in the Express framework.
- Updated API routes to include new account management endpoints.
- Enhanced the account profile schema to support email updates.
- Implemented tests for account management functionalities to ensure reliability and correctness.
2026-08-17 23:30:41 +02:00

5.6 KiB

Identity Auth API

Endpoints activos

GET  /identity/account
PATCH /identity/account
POST /identity/account/change-password
POST /identity/auth/login
POST /identity/auth/refresh
POST /identity/auth/logout
GET  /identity/auth/session
GET  /companies/available

Endpoints que no forman parte del diseño vigente

No documentar ni crear como ruta válida:

GET /identity/companies
GET /account/companies

Motivo:

  • identity no debe devolver fichas completas de empresa.
  • companies ya depende de identity para autenticación.
  • Un endpoint de ese tipo introduciría el ciclo identity -> companies -> identity.

POST /identity/auth/login

Request

export type LoginWithPasswordRequestDTO = {
  email: string;
  password: string;
};

Response

export type LoginWithPasswordResponseDTO = {
  access_token: string;
  refresh_token: string;
  account: AuthenticatedAccountDTO;
};
export type AuthenticatedAccountDTO = {
  id: string;
  email: string;
  name: string;
  avatar_url: string | null;
  language_code: string;
};

Notas

  • no requiere Authorization
  • no requiere X-Company-Id
  • no devuelve companies accesibles
  • no devuelve roles ni permisos
  • el access token no contiene companyId

POST /identity/auth/refresh

Request

export type RefreshSessionRequestDTO = {
  refresh_token: string;
};

Response

export type RefreshSessionResponseDTO = {
  access_token: string;
  refresh_token: string;
};

Notas

  • el refresh token se rota
  • el cliente debe reemplazar ambos tokens por los nuevos
  • no debe llevar X-Company-Id

POST /identity/auth/logout

Headers

Authorization: Bearer <access_token>

Request

export type LogoutRequestDTO = {
  refresh_token?: string;
  all_sessions?: boolean;
};

Response

export type LogoutResponseDTO = {
  success: true;
};

Reglas

  • no debe llevar X-Company-Id
  • para logout normal, enviar el refresh_token actual
  • si logout falla por expiración de token, el frontend debe limpiar sesión igualmente

GET /identity/account

Headers

Authorization: Bearer <access_token>

Response

export type GetAccountProfileResponseDTO = {
  id: string;
  email: string;
  name: string;
  avatar_url: string | null;
  language_code: string;
  status: "active" | "disabled" | "pending_verification";
};

Notas

  • no debe llevar X-Company-Id
  • representa la identidad global del usuario autenticado
  • no depende de company activa

PATCH /identity/account

Headers

Authorization: Bearer <access_token>

Request

export type UpdateAccountProfileRequestDTO = {
  email?: string;
  name?: string;
  avatar_url?: string | null;
  language_code?: string;
};

Response

export type UpdateAccountProfileResponseDTO = {
  id: string;
  email: string;
  name: string;
  avatar_url: string | null;
  language_code: string;
  status: "active" | "disabled" | "pending_verification";
};

Reglas

  • no debe llevar X-Company-Id
  • PATCH real: campo omitido no modifica
  • avatar_url: null limpia el avatar
  • el cambio de email en V1 es inmediato y no requiere verificación adicional
  • el backend valida unicidad de email
  • avatar_url sigue siendo solo una referencia externa; no existe upload en identity

POST /identity/account/change-password

Headers

Authorization: Bearer <access_token>

Request

export type ChangeAccountPasswordRequestDTO = {
  current_password: string;
  new_password: string;
};

Response

export type ChangeAccountPasswordResponseDTO = {
  success: true;
};

Reglas

  • no debe llevar X-Company-Id
  • exige current_password
  • usa el hasher actual de identity
  • revoca todos los refresh tokens persistidos de la cuenta
  • no invalida de forma inmediata access tokens ya emitidos, porque hoy son stateless y no existe un subsistema de revocación inmediata de access tokens

GET /identity/auth/session

Headers

Authorization: Bearer <access_token>

Response

export type CurrentSessionResponseDTO = {
  account: AuthenticatedAccountDTO;
};

Notas

  • no debe llevar X-Company-Id

GET /companies/available

Headers

Authorization: Bearer <access_token>

Response

export type AvailableCompaniesResponseDTO = {
  companies: AvailableCompanyDTO[];
};

export type AvailableCompanyDTO = {
  id: string;
  legal_name: string;
  trade_name: string | null;
  tin: string | null;
  slug: string;
  email: string | null;
  phone: string | null;
  website: string | null;
  status: "active";
};

Notas

  • usa autenticación, no tenant context
  • no requiere X-Company-Id
  • usa requireIdentityAuthenticated(params)
  • devuelve solo companies activas accesibles para la cuenta autenticada
  • no modifica sesión ni access token

Errores esperados

400 -> request inválida o UUID de X-Company-Id mal formado
401 -> access token ausente/inválido/expirado o credenciales inválidas
401 -> cuenta no autenticable (`disabled` o `pending_verification`)
403 -> contexto tenant inválido, company no accesible o company no activa
409 -> conflicto de unicidad, por ejemplo email ya existente
500 -> error inesperado

Administración global de cuentas

El dominio ya soporta enable/disable global de Account, pero no se documentan todavía endpoints HTTP administrativos operativos porque el runtime nuevo no dispone aún de un mecanismo inequívoco y cableado de autorización de administrador global.

Pendiente explícito:

  • definir y cablear la autorización global real
  • entonces exponer enable/disable por HTTP