Antes, createTenant() solo seteaba nombre, rfc, plan y databaseName. Ahora registra tenants completos como despachos: - dbMode: 'MANAGED' - verticalProfile: CONTABLE | JURIDICO | ARQUITECTURA - trialEndsAt: +30 días para plan trial - codigoPostal: opcional (se llena automáticamente de la CSF al subir FIEL) Frontend: - Selector de Tipo de Despacho en /clientes - C.P. omitido del formulario (viene de CSF -> sincronizarDatosFiscales) - Tipos Tenant y CreateTenantData actualizados Backend: - getAllTenants y getTenantById retornan verticalProfile y codigoPostal Refs: docs/sessions/2026-05-04-fix-clientes-crea-despacho.md
4.3 KiB
Sesión: Fix — Crear cliente desde /clientes registra como despacho
Fecha: 2026-05-04
Bug: El admin global creaba tenants "legacy" (sin dbMode, verticalProfile, trialEndsAt) desde /clientes. Ahora se registran como despachos completos.
1. Problema
Síntoma
Cuando el administrador global creaba un nuevo cliente desde /clientes, el tenant se creaba sin los campos de despacho:
dbMode=null(debería serMANAGED)verticalProfile=null(debería serCONTABLE/JURIDICO/ARQUITECTURA)trialEndsAt=null(debería ser +30 días para plan trial)codigoPostalno se seteaba
Esto causaba que el nuevo cliente no funcionara correctamente como despacho (no aparecía en el selector de despachos, no tenía trial, etc.).
Causa raíz
El flujo de registro público (/register-despacho → signupDespacho()) sí seteaba estos campos correctamente.
Pero el flujo de creación por admin (/clientes → createTenant()) no lo hacía — solo creaba el tenant con nombre, rfc, plan, databaseName.
2. Cambios realizados
2.1 Backend — tenants.service.ts
Firma ampliada:
export async function createTenant(data: {
// ... campos existentes ...
verticalProfile?: 'CONTABLE' | 'JURIDICO' | 'ARQUITECTURA';
codigoPostal?: string;
})
Creación del tenant ahora setea despacho fields:
const tenant = await prisma.tenant.create({
data: {
nombre: data.nombre,
rfc: data.rfc.toUpperCase(),
plan,
databaseName,
dbMode: 'MANAGED',
verticalProfile: data.verticalProfile || 'CONTABLE',
codigoPostal: data.codigoPostal || undefined,
trialEndsAt: isTrial ? new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) : undefined,
}
});
Queries getAllTenants y getTenantById ahora retornan:
verticalProfilecodigoPostal
2.2 Backend — tenants.controller.ts
El endpoint POST /tenants ahora acepta y pasa:
verticalProfile(default:'CONTABLE')codigoPostal(opcional)
2.3 Frontend — clientes/page.tsx
Nuevo campo en el formulario: Tipo de Despacho
- Select con opciones: Contable, Jurídico, Arquitectura
- Default: Contable
- Se persiste al crear y se carga al editar
C.P. deliberadamente omitido:
El campo codigoPostal no se incluyó en el formulario. Se obtiene automáticamente de la CSF cuando el dueño del despacho sube su FIEL por primera vez (fiel.service.ts → consultarConstancia() → sincronizarDatosFiscales()).
2.4 Frontend — lib/api/tenants.ts
Tipos actualizados:
export interface Tenant {
// ... campos existentes ...
verticalProfile?: 'CONTABLE' | 'JURIDICO' | 'ARQUITECTURA' | null;
codigoPostal?: string | null;
}
export interface CreateTenantData {
// ... campos existentes ...
verticalProfile?: 'CONTABLE' | 'JURIDICO' | 'ARQUITECTURA';
codigoPostal?: string;
}
3. Flujo resultante
Admin global crea cliente en /clientes
↓
Tenant creado con:
dbMode = 'MANAGED'
verticalProfile = (seleccionado por admin, default CONTABLE)
trialEndsAt = +30 días (si plan = trial)
codigoPostal = undefined (se llenará después)
↓
Dueño del despacho entra a la plataforma
↓
Sube FIEL del despacho (primer contribuyente)
↓
Sistema extrae CSF automáticamente
↓
Tenant actualizado con codigoPostal, calle, estado, regímenes...
4. Archivos modificados
| Archivo | Cambio |
|---|---|
apps/api/src/services/tenants.service.ts |
createTenant setea dbMode, verticalProfile, trialEndsAt, codigoPostal; queries retornan nuevos campos |
apps/api/src/controllers/tenants.controller.ts |
Acepta verticalProfile y codigoPostal del body |
apps/web/app/(dashboard)/clientes/page.tsx |
Formulario con selector de verticalProfile; C.P. omitido (viene de CSF) |
apps/web/lib/api/tenants.ts |
Tipos Tenant y CreateTenantData ampliados |
5. Notas
- El campo
codigoPostaldel backend es opcional y se dejó en la firma por si en el futuro se quiere pasar manualmente (ej. onboarding asistido). - No se requirió migración de base de datos —
codigoPostalya existía como columnaString?enTenant. trialEndsAtse calcula comoDate.now() + 30 díaspara plantrial, igual que ensignupDespacho().