# Plan Custom — gratis, sin fecha fin, solo asignable por Admin Global ## Contexto El owner pidió un plan "Custom" para casos donde quiere otorgar acceso al sistema sin cobro y sin fecha de finalización (cortesía, beta tester, caso especial). Solo el Admin Global puede asignarlo; los usuarios finales no deben verlo en su catálogo de planes. ## Decisión clave — Reusar enum `custom` El Plan enum de Prisma ya incluye `custom` (legacy: "precio variable por tenant"). En dev hay **0 tenants** en ese plan, y la lógica antigua en `subscription.service.ts` rechaza `custom` del flujo self-serve — patrón que coincide con la nueva semántica. Reusar el enum evita migration y mantiene compatibilidad. ## Reglas - **Comportamiento**: idéntico a Mi Empresa (1 RFC, MANAGED, 50 timbres/mes, features básicas, sin API ni Lolita). - **Costo**: $0. No genera Subscription, no usa MercadoPago. - **Vigencia**: indefinida. `tenant.trialEndsAt = null`. Sin `currentPeriodEnd`. Ningún cron lo expira. - **Visibilidad**: oculto del catálogo user-facing. Solo aparece como opción en `/clientes` (admin global). ## Cambios — Catálogo `packages/shared/src/constants/despacho-plans.ts`: ```ts custom: { name: 'Custom', maxRfcs: 1, maxUsers: 3, maxCfdisPorContribuyente: 1_000_000, timbresIncluidosMes: 50, dbMode: 'MANAGED' as const, permiteServidorBackup: false, features: [ 'dashboard', 'cfdi_basic', 'iva_isr', 'reportes', 'alertas', 'calendario', 'conciliacion', 'documentos', 'facturacion', 'forecasting', 'xml_sat', ], }, ``` NO se agrega a `DESPACHO_PLAN_PRICES` (gratis). Helpers existentes: - `permiteOverage('custom')` → `false` ✓ (ya retorna false porque solo cubre business_control y business_cloud) - `isDespachoPaidPlan('custom')` → `false` ✓ (idem) - `permiteFrecuenciaMensual('custom')` → `false` ✓ (no está en DESPACHO_PLAN_PRICES) ## Cambios — Frontend types `apps/web/lib/api/tenants.ts`: Extender el tipo del campo `plan` en `CreateTenantData` y `UpdateTenantData`: ```ts type AdminAssignablePlan = | 'starter' | 'business' | 'business_ia' | 'enterprise' // legacy Horux 360 | 'custom'; // nuevo ``` (Despacho paid plans NO se incluyen — esos van por self-serve del owner, fuera de scope per acuerdo con owner.) ## Cambios — Página `/clientes` (admin) `apps/web/app/(dashboard)/clientes/page.tsx`: 1. Reemplazar `PlanType` local por `AdminAssignablePlan` importado. 2. Eliminar el `planLabels` local (líneas 174-178) y `planColors` local (líneas 180-184). Usar el `PLAN_LABELS` global que ya existe arriba del archivo (cubre todo). Para colores, expandir el map global o inline en el render. 3. Extender el `