Provisioning de tenant desde superadmin
Objetivo
Dar de alta una clínica nueva (tenant + su admin) en un solo paso desde el panel de superadmin.
Cómo empieza
Superadmin en petid-admin, alta de tenant, con datos de la clínica + email/nombre del admin.
Pasos principales
ProvisionTenantUseCase.execute(): valida que el nombre de tenant y el email del admin no existan, genera slug, genera temp password (igual que enaccount-activation.md— nunca se expone).tenants.createWithAdmin(tenant, user, profile)— transacción atómica en Postgres: tenant + user admin + profile, todo o nada.- Después de que la transacción confirma:
notificationTenants.create(tenant.id, tenant.name)— llamada HTTP anotification-apipara espejar el tenant allá. Esto ya no está dentro de la transacción. - Emite
UserRegisteredEvent→ dispara el flujo deaccount-activation.md(email de activación al admin).
Reglas de negocio
- El id del tenant en
notification-apies el mismo UUID que enpetid-api(created.tenant.id) — asumido en todo el resto del sistema como “mismo id en ambos lados”.
Interacciones
petid-admin → petid-api → Postgres (transacción) → notification-api (mirror, HTTP, con reintentos best-effort) → email vía account-activation.md.
Dónde seguir mirando
petid-api/src/application/superadmin/provision-tenant.use-case.tspetid-api/src/infrastructure/notifications/notification-service-tenant-creator.ts(el cliente que llama anotification-api, reintenta y loguea si falla)
Casos especiales
- Si el mirror a
notification-apifalla (después de sus reintentos), el tenant queda creado enpetid-apipero inexistente ennotification-api— cualquier notificación futura para ese tenant fallará silenciosamente hasta crearlo ahí a mano. No hay compensación automática ni rollback del tenant en Postgres. - Este gap ya se dio en la práctica: el tenant
petid-system(creado por un seed script que llamaprisma.tenant.upsertdirecto, no este use case) nunca pasó por este mirror y tuvo que crearse manualmente ennotification-api— vernotification-template-routing.md.