ecosystem-wikicómo extender los templates sin romper sus convenciones
‹ todas las recipes

Dar de baja a un tenant entero

template-api
último cambio 2026-09-25

Cerrar una cuenta tiene una pregunta fácil: los datos son de esa persona, y se van con ella. Cerrar un tenant no. Sus filas describen cosas que siguen existiendo cuando él ya no está —personas que siguen siendo clientes de alguien, un historial que alguien tiene que poder enseñar— y por eso no hay un solo destino.

La baja no es un DELETE FROM … WHERE tenantId = …. Es un reparto: cada dato va a quien pueda seguir respondiendo de él, y solo se suprime lo que no reclama nadie.

Los cuatro destinos

Destino Qué va ahí Por qué
Sigue donde está Lo que el tenant escribió sobre algo que hoy atiende otro Nadie tiene que moverlo: si la lectura es por el objeto y no por el tenant, el nuevo ya lo ve
Tenant de sistema Los clientes que seguían con él, con lo suyo Tienen contrato contigo, no con él: la cuenta sigue funcionando
Bloqueado Lo que no reclama nadie pero todavía no puede destruirse Hay un plazo legal o de prescripción que corre aunque el tenant se haya ido
Suprimido Sus datos propios, sus cuentas de personal, lo pendiente No sirven a nadie más

Lo que decide el destino de cada fila es de quién es hoy el objeto, no quién escribió la fila. En petid-api eso es la mascota: un informe de la clínica que se va, sobre un paciente que hoy atiende otra, se queda; el mismo informe sobre un paciente sin dueño, se bloquea.

Lo que no hay que mover

La parte más barata del reparto es la que no se programa. Si el historial se lee por el objeto —findByPetId, sin filtrar por tenant— la cesión ya está hecha: en cuanto el cliente se traslada, el nuevo tenant ve lo que escribió el anterior, con su autoría intacta.

Eso convierte una consulta en una regla de negocio, así que conviene fijarla con un test: “una mascota que cambia de clínica sigue viendo los informes de la clínica inactiva”. El día que alguien añada un filtro por tenant activo, la cesión se rompe sin que falle nada más.

El tenant de sistema

Un tenant con id fijo, creado por migración, donde caen los clientes que se quedaron sin el suyo. No es el tenant del superadmin: ese es de la plataforma y tiene personal; este no tiene ninguno y no se desactiva nunca.

Tiene un precio que conviene decir en voz alta: esos datos pasan a ser tuyos. Mientras había un tenant, tú eras el encargado; después eres el responsable, y eso se sostiene en el contrato que tienes con esa persona, no en el que tenías con quien se fue.

Bloquear no es borrar ni conservar

Un dato bloqueado existe, no lo ve nadie y tiene fecha de caducidad. Las tres cosas a la vez:

La fecha se calcula por objeto, desde su último registro, no desde la baja: dos pacientes del mismo tenant vencen en momentos distintos porque su última visita fue en momentos distintos. Un cron recoge lo vencido y ahí sí destruye: filas y ficheros.

Anonimizar conservando la autoría

El tenant y su personal se anonimizan, pero no del todo: sobrevive lo que firma lo que se queda. El nombre comercial del tenant, y el nombre y número de colegiado de quien firmó un informe que sigue vivo, son parte del acto, no datos de contacto.

Tiene una consecuencia en las pantallas: si el repositorio esconde los tenants borrados, el historial cedido dirá que no lo escribió nadie. Hace falta una consulta que los incluya, y es fácil de olvidar hasta que se ve el hueco.

Las claves ajenas hacen el trabajo difícil

La pregunta incómoda —¿ya puedo borrar esta fila?— la contesta la base de datos. Con Restrict, un borrado falla mientras algo apunte a la fila, así que el cron de limpieza puede ser tonto a propósito:

para cada tenant o usuario anonimizado:
  intenta borrarlo
  si falla, déjalo: algo suyo sigue vivo

Contarlo al revés —calcular quién ya no es referenciado— es reimplementar la integridad referencial en el lenguaje equivocado. Y contar con que el borrado en cascada resuelva el reparto es peor: una cascada se lleva por delante justo las filas que otro tenant necesitaba.

El orden importa

Dentro de la transacción, primero mover y luego bloquear lo que queda: así “lo que queda” se define solo, sin listas de exclusión. Fuera de la transacción van los ficheros y lo que vive en otros servicios, que no pueden participar en ella; si eso falla, la baja no se deshace, se apunta y se reintenta.

Y antes de todo, cortar las sesiones del personal: quien esté dentro mientras se reparte vería un panel a medias. Las de los clientes no, que se van a otro sitio y siguen usando su app.

Qué probar