Blog Arquitectura Neges

Cambiar de empresa sin perder la página: cómo funciona el selector de tenant

El selector de empresa dejó de mandarte siempre al dashboard. Ahora conserva la pantalla donde estás y sólo retrocede cuando la URL deja de tener sentido en la empresa destino. Esta es la regla que lo decide y por qué crece sola.

9 min de lectura

Antes, elegir otra empresa en el selector del header te devolvía siempre al dashboard, aunque estuvieras a mitad de una pantalla. Ahora el backoffice conserva tu ubicación cuando sigue teniendo sentido, y sólo te reubica cuando la página dejó de existir para la empresa destino.

De "siempre al home" a "quédate donde estás"

El selector de empresa vive en el topbar del backoffice y permite alternar entre las empresas a las que pertenece tu cuenta sin cerrar sesión. Su trabajo real es cambiar el tenant activo: el identificador de empresa que viaja en cada llamada al backend y que decide qué datos ves.

La versión anterior resolvía el cambio de la forma más simple y segura posible: cargaba el contexto de la nueva empresa y navegaba al dashboard. Funcionaba, pero costaba contexto. Si estabas comparando la configuración de dos empresas, o revisando el mismo listado en varias, volvías al inicio en cada salto y tenías que re-navegar.

La clave para mejorarlo estaba en una observación de la propia app: casi todas las pantallas ya se recargan solas cuando cambia el tenant activo. Los listados, los detalles y las pantallas de configuración observan el tenant y vuelven a pedir sus datos por su cuenta. Es decir, la infraestructura para "quedarse en la página" ya existía; el redirect al dashboard la descartaba en el último paso.

Cinco tipos de ruta, tres comportamientos

La ruta activa se clasifica en uno de estos cinco casos, que se reducen a tres acciones: conservar, retroceder al listado o ir al dashboard.
Tipo de rutaEjemploQué pasa al cambiar de empresa
Ajena al tenant/settings/account, /admin/tenants/:idSe conserva tal cual. No depende de la empresa activa (son datos tuyos o del panel de plataforma).
Colección del tenant/products, /sales, /stock/inventorySe conserva. La pantalla recarga sola el listado de la nueva empresa; se resetean página y filtros.
Configuración singleton/settings/tenant/edit, /storefront-studio/heroSe conserva. Cada empresa tiene su propia instancia de esa pantalla; ideal para comparar dos empresas.
Registro concreto/products/:documentId, /sales/:documentIdRetrocede a su listado. Ese registro no existe en la empresa destino, así que te dejamos en la colección.
Módulo no habilitadocualquier ruta cuyo módulo falte en el destinoVa al dashboard con un aviso que nombra el módulo faltante.

La regla: cortar la URL en el primer segmento con parámetro

Lo importante es que esta clasificación no se mantiene a mano. No hay una tabla que enumere las decenas de rutas del backoffice. La decisión se deriva de la configuración de rutas que Angular ya conoce.

Cada ruta de un registro concreto lleva un parámetro en su patrón, por ejemplo products/:documentId/edit. Ese ":documentId" es la frontera exacta entre lo que es común a toda empresa (el prefijo de colección) y lo que pertenece a un registro puntual. La regla reconstruye el patrón de la ruta activa, busca el primer segmento que empieza con ":" y corta la URL justo antes. Lo que queda es siempre una colección válida.

core/tenant/tenant-switch-destination.tsts
// Función pura: recibe la URL, el patrón de la ruta y un predicado de módulos
// del tenant DESTINO. Sin dependencias de Angular Router, se testea sin TestBed.
export function resolveTenantSwitchDestination(
  currentUrl: string,          // "/products/abc123/edit?page=5"
  routeConfigPattern: string,  // "products/:documentId/edit"
  hasModule: (moduleKey: string) => boolean,
): TenantSwitchDestination {
  // 1. Ruta ajena al tenant (/admin, /settings/account…) -> se conserva tal cual.
  // 2. El patrón no tiene parámetros -> se conserva (colección o singleton).
  // 3. El patrón tiene un parámetro -> cortar antes del ":" -> ruta de colección.
  // 4. Esa colección exige un módulo que el destino no tiene -> dashboard + aviso.
}

La cadena de decisión

  1. ¿El prefijo es ajeno al tenant?

    Rutas como /admin o /settings/account no dependen de la empresa activa. Si coincide, no se mueve nada.

  2. ¿El patrón tiene parámetros?

    Si no los tiene, es una colección o una pantalla de configuración: se conserva la URL actual.

  3. Cortar antes del primer parámetro

    Si los tiene, se trunca la URL en ese punto para obtener la ruta de colección candidata.

  4. ¿El destino tiene el módulo que exige el candidato?

    Si no lo tiene, se va al dashboard con un aviso que nombra el módulo faltante.

    Tip: Este último caso lo resuelve el efecto de módulos que ya vivía en el shell, así que la lógica del cambio de empresa no lo duplica.

Los casos borde que el redirect escondía

Al dejar de mandar todo al dashboard, salen a la superficie problemas que el redirect tapaba. Conservar la página obliga a resolverlos bien.

  • Paginación heredada: estar en la página 5 de una empresa con 400 productos y saltar a una con 30 mostraba un listado vacío. Al cambiar de empresa, los listados vuelven a la página 1.
  • Filtros con identificadores ajenos: un filtro por categoría guarda el id de una categoría que no existe en la otra empresa. Al cambiar, los filtros se limpian y la URL queda sin parámetros viejos.
  • Registro inexistente: si estabas en el detalle de un producto, te dejamos en el listado de productos con un aviso, en vez de intentar cargar un registro que no existe.
  • Botón atrás: la reubicación reemplaza la entrada del historial, así que "atrás" no te devuelve a una URL muerta de la empresa anterior.

Por qué esto escala en el tiempo

El mayor riesgo de una regla de navegación es convertirse en una tabla que alguien debe actualizar cada vez que nace una pantalla. Esta regla evita justamente eso: se apoya en la configuración de rutas que Angular ya mantiene, no en un catálogo paralelo.

La consecuencia práctica es que una feature CRUD nueva no necesita tocar el selector de empresa. Si sigue la convención del proyecto (una ruta de listado y rutas de detalle con :documentId), la regla la clasifica correctamente el día que se agrega: el listado se conserva, el detalle retrocede al listado. Cero cambios en el cambio de tenant.

Sólo quedan dos listas pequeñas y explícitas por mantener, y ambas ya existían por otros motivos. La primera es el conjunto de prefijos ajenos al tenant (/admin, /settings/account, /settings/security). La segunda es el mapa de módulos por prefijo de ruta, que el backoffice ya usaba para el sidebar y para el redirect por módulo faltante; se extrajo a un archivo compartido para que el selector y el shell lean la misma fuente.

El reseteo de página y filtros vive una sola vez en la base compartida de los listados paginados, así que las 21 pantallas de listado del backoffice lo heredan sin repetir código. Y como el corazón de la decisión es una función pura, sumar un caso nuevo es sumar un test, no depurar un componente.

Checklist al terminar

  • Ruta de detalle nueva: usa el patrón :documentId y la regla la manda a su listado sola.
  • Feature con módulo propio nuevo: agrega una entrada al mapa de módulos por prefijo (ya es necesaria para el guard y el sidebar).
  • Pantalla que no debe seguir a la empresa activa: súmala a la lista de prefijos ajenos al tenant.
  • Listado nuevo: extiende la base de listados paginados y hereda el reseteo de página y filtros.
  • Cada comportamiento esperado del cambio de empresa se cubre con un caso en el test de la función pura.

Lo que viene después

Esta primera etapa resuelve el pedido concreto: conservar la página. Quedan dos mejoras independientes que se apoyan en la misma base.

  • Unificar el "acceso denegado": hoy la misma condición (un módulo no disponible) puede terminar en la pantalla de acceso denegado o en el dashboard según cómo llegaste. La idea es un solo destino y extender la comprobación a permisos finos, no sólo a módulos.
  • Proteger el trabajo sin guardar: hoy cambiar de empresa desde un formulario a medias descarta lo escrito sin avisar. Un registro de "cambios pendientes" permitiría pedir confirmación sólo cuando de verdad hay algo que perder.

Recursos relacionados

¿Te fue útil este contenido?

Tu feedback nos ayuda a mejorar la documentación de Neges.

Soporte humano

¿No encuentras lo que buscas?

Conversa con nuestro equipo de soporte en español. Respondemos por WhatsApp, correo o ticket en menos de 24 horas hábiles.

contacto@neges.clLun a Vie · 9 a 18 hrs
+56 9 5379 1163WhatsApp Business