Skip to main content

Centro médico activo

Además de la empresa, la sesión tiene un centro médico activo que acota lo que se ve y lo que se crea. Es un scoping ortogonal al de multi-tenant: ambos son fail-closed y ambos pueden producir el mismo síntoma.

El flujo completo

  1. GET /v1/health-center/mine devuelve los centros del usuario. No requiere permiso: cualquier usuario autenticado necesita conocer sus centros para poder elegir uno.
  2. ActiveHealthCenterService (frontend) guarda centers, activeCenterId y activeCenter como signals, y persiste la selección en localStorage.
  3. healthCenterInterceptor lee ese localStorage y agrega el header X-Health-Center-Id a cada request.
  4. El backend lo pone en req.userData.healthCenterId, lo valida contra la membresía del usuario y lo expone al service vía SecuredController.getHealthCenterId(req).
  5. Los episodios y los insumos llevan HEALTHCENTERID, y las bandejas filtran por él.

Autoselección

Solo se autoselecciona si el usuario tiene un único centro. Con varios queda sin elegir a propósito: el usuario multi-centro debe decidir explícitamente, y un ADMIN ve todos.

Fail-closed

NO_HEALTH_CENTER_SCOPE = -1, igual que el de empresa:

ValorSignificado
nullVe todos los centros (para SUPERUSER / ADMIN sin uno puntual seleccionado)
-1No ve nada

El módulo

src/modules/health-center/ — entidades HealthCenter y HealthCenterServiceLine (las líneas de atención del centro), un controller y dos services. Es el molde limpio del patrón de módulo de feature: si vas a escribir un módulo nuevo, copiá este.

  • Pantallas: health-centers y health-centers/:id.
  • Permisos: HEALTHCENTER_ABM_VIEW, HEALTHCENTER_DETAIL_VIEW, etc.
  • El código del centro tiene unicidad case-insensitive y a prueba de espacios: el índice normaliza con UPPER(TRIM(...)).

Gotchas

OPS: el header tiene que estar permitido dos veces

X-Health-Center-Id debe estar en la allowlist de CORS del backend y en nginx. Si falta en cualquiera de los dos, todos los requests fallan por preflight.

Sin backfill, los episodios viejos desaparecen

El DDL va en orden: centros → usuarios → columnas en episodios/insumos → backfill del centro por defecto. Sin el backfill, los episodios y los insumos previos quedan sin centro y desaparecen de la bandeja.

  • Al cerrar sesión hay que llamar reset(). Si no, el centro del usuario anterior queda en localStorage y se manda con la sesión nueva. El backend lo rechaza por membresía, pero el usuario ve cero filas sin entender por qué.
  • Es un scoping distinto del de empresa. Un usuario puede tener la empresa correcta y el centro incorrecto: el síntoma es idéntico ("no veo nada"). Chequeá los dos.
  • La validación de aplicación tiene que espejar la expresión del índice único exactamente. Si el índice normaliza con UPPER(TRIM(...)) y el service compara el valor crudo, el usuario ve un error 23505 de Postgres en vez del mensaje de negocio — y hay que validar también en el update, no solo en el create.