Appearance
Registro de Decisiones de Arquitectura (ADRs) — ITECEL ADM
Última actualización: 2026-09-27
Estado: Documento Vivo / Canon Técnico
Propósito: Registrar de forma inmutable las decisiones arquitectónicas, de seguridad, datos y procesos operativos de ITECEL ADM, con su contexto, justificación y consecuencias.
Índice de Decisiones
| ID | Título | Fecha | Estado |
|---|---|---|---|
| ADR-001 | Límites por licencia aplicados en BASE DE DATOS (trigger), no en UI | 2026-09-15 | Vigente |
| ADR-002 | Separación identidad vs descriptivo: acceso personal ≠ ficha institucional | 2026-09-16 | Vigente |
| ADR-003 | Matriz de precios bidimensional tier × ciclo y deuda de columna tier | 2026-09-18 | Vigente (con deuda declarada) |
| ADR-004 | Licencia PERPETUA: monto 0, sin selector ciclo/tier, notas de texto libre | 2026-09-18 | Vigente |
| ADR-005 | Superadmins intocables: sin licencias, sin contextos, alcance global de por vida | 2026-09-18 | Vigente |
| ADR-006 | Auditoría de nube con JWT VERIFICADO vía trigger de BD | 2026-09-20 | Vigente (verificación en borrado PENDIENTE) |
| ADR-007 | Anti-spam en formulario demo: OTP + filtro de dominios corporativos | 2026-09-21 | Vigente |
| ADR-008 | Protocolo anti-deadlock para DDL en producción | 2026-09-22 | Vigente |
| ADR-009 | Política de supresión de Resend: prohibición de casillas inexistentes | 2026-09-22 | Vigente |
| ADR-010 | Wiki: fuente de verdad en repo (Markdown), visor y chatbot desacoplados | 2026-09-27 | Vigente |
| ADR-011 | Doble despliegue: separación estricta entre Vercel y Supabase | 2026-09-14 | Vigente |
| ADR-012 | Vínculos por email en cadena de identidad y riesgo de orfandad | 2026-09-27 | Vigente (deuda declarada) |
| ADR-013 | Auditoría Vía B: trigger de BD para DELETE en license_requests | 2026-09-27 | Vigente |
| ADR-014 | Sistema unificado de límites basado en plan_limits | 2026-09-27 | Vigente |
| ADR-015 | Tres estados de licencia y regla de purga post-caducidad a 30 días | 2026-09-27 | Vigente (deuda declarada) |
ADR-001: Límites por licencia aplicados en BASE DE DATOS (trigger), no en UI — El servidor manda
- Número: ADR-001
- Fecha: 2026-09-15
- Estado: Vigente
Contexto
Las cuentas en ITECEL ADM poseen diferentes tipos de licencia (demo, planes estándar, ilimitadas). Inicialmente existía el riesgo de validar cuotas de unidades (inmuebles), límites de residentes o envíos únicamente en la interfaz de React (src/). Un usuario con conocimientos técnicos, inspeccionando la consola de desarrollo o invocando directamente la API de Supabase, podría saltarse las restricciones de su plan.
Decisión
Todos los límites operativos vinculados al plan de licencia se aplican y auditan en PostgreSQL (Base de Datos) mediante triggers BEFORE INSERT / UPDATE y funciones RPC de backend:
- El cliente web puede realizar validaciones UX preventivas (mostrar advertencias o inhabilitar botones), pero la BD es la autoridad final e inapelable.
- Si una transacción excede las unidades autorizadas por la licencia vigente del condominio, el trigger emite una excepción SQL (
RAISE EXCEPTION) bloqueando la inserción. - Se rige por la regla metodológica: El servidor manda; lo local es contingencia.
Consecuencias
- Qué habilita:
- Seguridad a nivel de datos blindada contra manipulaciones de cliente, llamadas manuales de API o herramientas externas.
- Consistencia total independiente del cliente que consuma la base de datos (web, móvil futuro, o scripts de soporte).
- Qué cuesta:
- Las modificaciones de topes o reglas de planes no son simples ajustes de interfaz; requieren migraciones de funciones/triggers en PostgreSQL.
- La interfaz debe manejar adecuadamente las excepciones de base de datos capturadas para mostrar retroalimentación amigable al usuario.
ADR-002: Separación identidad vs descriptivo: acceso personal ≠ ficha institucional
- Número: ADR-002
- Fecha: 2026-09-16
- Estado: Vigente
Contexto
Existía ambigüedad y riesgo de acoplamiento entre los correos y nombres usados para autenticar a personas físicas en la plataforma y los correos/contactos institucionales del condominio o vivienda. Si un administrador modificaba los datos de contacto del condominio, corría el riesgo de alterar sus credenciales de acceso a Supabase Auth o corromper su asignación de licencias.
Decisión
Separación estricta y absoluta entre Entidades de Identidad y Entidades Descriptivas:
- Identidad / Acceso Personal:
auth.users(UUID, correo personal autenticado, credenciales seguras).public.app_users(UUID sincronizado conauth.users, correo personal, rol global/sistema).public.condo_licenses/ asignación de licencias (vinculadas a la persona o correo de acceso personal).
- Ficha Descriptiva / Institucional:
public.condos(email,contact_name,phone,address): son datos meramente informativos para recibos, estados de cuenta y cartelera del inmueble.- Contactos de
housing_units(propietario/inquilino nominal): fichas informativas que no otorgan acceso por sí solas hasta que se cree una invitación formal.
- Regla canónica: La ficha del condominio es institucional; el acceso es personal.
Consecuencias
- Qué habilita:
- Un administrador puede actualizar el email institucional del condominio (ej.
administracion@condominiolaspalmas.com) sin perder su cuenta personal de acceso ni invalidar su licencia. - Facilita la transición futura de administradores en un mismo condominio sin migrar licencias destructivamente.
- Un administrador puede actualizar el email institucional del condominio (ej.
- Qué cuesta:
- El frontend debe mantener formularios completamente separados para "Perfil de Usuario" vs "Datos del Condominio".
- En el código existen puntos históricos que vincularon entidades por email en lugar de UUID; se mantiene la deuda técnica documentada para cambio de correo (D-NUEVA-2 / Sección 10.2).
ADR-003: Matriz de precios bidimensional tier × ciclo y deuda de columna tier
- Número: ADR-003
- Fecha: 2026-09-18
- Estado: Vigente (con deuda declarada)
Contexto
El modelo comercial de ITECEL ADM requiere planes estructurados por escala/capacidad de unidades (tier: Lite, Standard, Pro, Enterprise) y por periodicidad de pago (ciclo: mensual, trimestral, semestral, anual). Sin embargo, el esquema histórico en PostgreSQL definió un enum o campo de plan centrado principalmente en la duración (plan_type: mensual, semestral, anual, demo, etc.) sin una dimensión formal para el tier.
Decisión
- Se establece conceptualmente la Matriz de Precios Bidimensional formal:
- Eje X: Ciclo de facturación (mensual, trimestral, semestral, anual).
- Eje Y: Nivel o Capacidad (Lite, Standard, Pro, Enterprise).
- En base de datos, mientras se planifica la migración de esquema, el campo existente almacena el plan/duración y se declara formalmente como Deuda Técnica la creación de la columna explícita
tiery la migración controlada de tipos.
Consecuencias
- Qué habilita:
- Claridad comercial absoluta para cotizaciones, tablas comparativas y modalidades de cobro al cliente.
- Base para la futura pasarela de pagos automatizada.
- Qué cuesta:
- Requiere convivir temporalmente con el enum histórico en BD hasta que se ejecute la migración formal de DDL anti-deadlock.
- Debe mantenerse la documentación sincronizada entre el modelo comercial y el esquema de base de datos.
IMPORTANT
Enmienda ADR-003 (2026-09-27 — Corregida con Evidencia de Producción):
La columna tier en public.licenses almacena efectivamente valores comerciales ('demo', 'lite', 'standard', 'pro', 'enterprise', 'perpetua'). El requisito vigente del sistema es que todos los flujos de creación/edición de licencias (createLicense, convertDemoToFullLicense, etc.) garanticen la escritura del tier comercial explícito. El catálogo canónico de capacidades y cuotas operativas radica en public.plan_limits.plan_tier.
ADR-004: Licencia PERPETUA para socios, equipo y colaboradores
- Número: ADR-004
- Fecha: 2026-09-18
- Estado: Vigente
Contexto
El proyecto cuenta con condominios piloto operados por socios fundadores y colaboradores clave (ej. Condominio Piloto #1 y Piloto #2). Se requería una figura de licencia que no estuviera sujeta a vencimientos mensuales/anuales ni exigiera registros ficticios de transacciones comerciales en los reportes financieros del SaaS.
Decisión
Crear y soportar el tipo de licencia PERPETUA:
- Monto asignado: $0.00 invariable.
- Sin selectores de ciclo de facturación ni cálculo de fecha de caducidad (indefinida / permanente).
- Campo de notas de texto libre obligatorio en la asignación para registrar la justificación institucional (ej. "Socio fundador", "Colaborador de pruebas de campo", "Equipo de desarrollo").
Consecuencias
- Qué habilita:
- Soporte continuo para pilotos activos de largo plazo sin bloqueos automáticos por caducidad de fecha.
- Separación limpia en métricas financieras entre clientes de pago y cuentas operativas de desarrollo/socios.
- Qué cuesta:
- Reglas especiales en el cálculo de métricas de ingresos (MRR / ARR) para excluir licencias con monto 0 y tipo perpetuo.
ADR-005: Superadmins intocables: sin licencias, sin contextos, alcance global
- Número: ADR-005
- Fecha: 2026-09-18
- Estado: Vigente
Contexto
Los superadministradores son los socios fundadores y operadores maestros de la plataforma. Si se les tratara como administradores convencionales, requerirían licencias asociadas a sus correos, estarían atados a un condominio específico y su acceso podría quedar bloqueado si una licencia expiraba.
Decisión
Regla R7 de Gobernanza codificada en arquitectura:
- Sin licencias: El sistema de licencias rechaza categóricamente cualquier intento de crear o asignar licencias a un superadmin (rechazo con mensaje claro de validación).
- Sin contextos de condominio: El superadmin opera con alcance global en todo el SaaS, sin estar anclado a un
condo_iden particular para su funcionamiento. - Contactos descriptivos: Si el correo o nombre de un superadmin aparece en el Directorio o en una unidad habitacional (por ser propietario o residente personal), dicha aparición es meramente una ficha descriptiva, jamás un contexto de administración ni generador de licencia.
- De por vida: Los superadmins designados son permanentes e intocables.
Consecuencias
- Qué habilita:
- Capacidad de auditoría, soporte y diagnóstico forense global en cualquier condominio del sistema en todo momento.
- Inmunidad ante bloqueos de facturación, expiración de demos o bugs en el módulo de licencias.
- Qué cuesta:
- El código de RLS y frontend debe contemplar siempre el bypass seguro del superadmin (
is_superadmin) para no exigir llaves foráneas de condominio en su navegación.
- El código de RLS y frontend debe contemplar siempre el bypass seguro del superadmin (
ADR-006: Auditoría de nube con JWT VERIFICADO vía trigger de BD
- Número: ADR-006
- Fecha: 2026-09-20
- Estado: Vigente (con verificación en borrado de solicitudes PENDIENTE)
Contexto
En un sistema multi-condominio con impacto contable, el registro de auditoría (audit_log) no puede confiar en los datos que el cliente envíe en el payload HTTP (ej. un usuario enviando un user_id arbitrario en el body).
Decisión
- La auditoría sensible en la nube se ejecuta a través de triggers de base de datos que extraen el usuario directamente del JWT verificado mediante la función de Supabase
auth.uid()/auth.jwt(). - Jamás se registran valores quemados o provistos por el cliente en campos de identidad auditora.
- Hallazgo abierto / Pendiente: La verificación de implementación del trigger de auditoría con JWT verificado específicamente para el evento de borrado físico de solicitudes de licencia (
license_requests) se encuentra pendiente de confirmación forense en el Table Editor / migraciones.
Consecuencias
- Qué habilita:
- Registro de auditoría con validez forense y no repudiable.
- Imposibilidad de que un atacante suplante la identidad en los logs de mutaciones de datos.
- Qué cuesta:
- Las operaciones ejecutadas desde el backend mediante Service Role (que no tienen JWT de usuario final) deben contemplar un fallback controlado o registrar explícitamente la acción de sistema.
ADR-007: Anti-spam en formulario demo: OTP + filtro de dominios corporativos
- Número: ADR-007
- Fecha: 2026-09-21
- Estado: Vigente
Contexto
El formulario público de solicitud de demo era susceptible a spam automatizado, registros basura y agotamiento de recursos en Edge Functions y cuotas de envío en Resend.
Decisión
Implementar un doble cerrojo anti-spam asimétrico:
- Formulario de DEMO:
- Requiere verificación por código OTP enviado al correo antes de crear el entorno demo.
- Aplica filtro de dominios públicos masivos (bloqueo preventivo de
@gmail.com,@outlook.com,@yahoo.com,@hotmail.com, etc.), exigiendo correos de dominio propio/institucional o administración para demos automáticos.
- Formulario de COMPRA / CONTRATACIÓN:
- Requiere verificación por código OTP para evitar direcciones inválidas.
- NO filtra dominios: cualquier administrador de condominio puede contratar formalmente con su correo personal (ej. Gmail), ya que se trata de un cliente pagador verificado por OTP.
Consecuencias
- Qué habilita:
- Reducción drástica de demos bot y correos basura en la base de datos.
- Protección de la reputación del dominio emisor en Resend.
- Máxima flexibilidad comercial para clientes reales que usan cuentas personales de correo.
- Qué cuesta:
- Fricción mínima necesaria (1 paso de OTP) para el prospecto que solicita una demostración.
ADR-008: Protocolo anti-deadlock para DDL en producción
- Número: ADR-008
- Fecha: 2026-09-22
- Estado: Vigente
Contexto
Las sentencias DDL en PostgreSQL (ALTER TABLE, ADD CONSTRAINT, creación de triggers, cambios de tipo de datos) adquieren bloqueos exclusivos de tabla (ACCESS EXCLUSIVE LOCK). Si existen transacciones largas abiertas o alta concurrencia de residentes/administradores, la migración puede entrar en deadlock o dejar congelada la base de datos en producción.
Decisión
Toda migración DDL en producción debe cumplir el siguiente protocolo:
- Definir siempre un tiempo de espera de bloqueo estricto antes de ejecutar sentencias pesadas (
SET lock_timeout = '2s';). - Adicionar columnas sin bloqueos pesados (usar
DEFAULT NULLo valores constantes optimizados en Postgres moderno). - Creación de índices en modo no bloqueante (
CREATE INDEX CONCURRENTLY). - Ejecutar ventanas de mantenimiento en horarios de baja concurrencia y verificar que no existan conexiones colgadas en
pg_stat_activity. - Si un lock falla por timeout, la transacción aborta limpiamente sin derribar la aplicación.
Consecuencias
- Qué habilita:
- Cero tiempo de inactividad inesperado por tablas bloqueadas.
- Protección de las sesiones de los administradores y residentes durante despliegues de esquema.
- Qué cuesta:
- Los scripts de migración no pueden ejecutarse de manera descuidada; exigen revisión y preparación previa en el SQL Editor siguiendo el checklist formal.
ADR-009: Política de supresión de Resend: prohibición de casillas inexistentes
- Número: ADR-009
- Fecha: 2026-09-22
- Estado: Vigente
Contexto
El servicio transaccional Resend implementa mecanismos automáticos de protección de reputación. Si se envían correos a casillas inexistentes o direcciones sintéticas de prueba (ej. test@test.com, correo_falso_123@noexiste.com), los servidores receptores devuelven un Hard Bounce. Resend añade de inmediato esa dirección a su Lista de Supresión permanente y, si la tasa de rebote supera el 2%, suspende la cuenta de envío del proyecto.
Decisión
- Regla de oro: Jamás realizar pruebas de envío de correos (invitaciones, cobros, OTPs) utilizando direcciones inventadas o casillas inactivas.
- Toda prueba debe realizarse con correos reales controlados por el equipo (
test-inboxpropio o cuentas personales de testing). - Si un correo entra a la lista de supresión de Resend, la aplicación no podrá enviarle mensajes hasta que se tramite su remoción manual en el dashboard de Resend.
Consecuencias
- Qué habilita:
- Reputación impecable del dominio
itecelgs.com(alta entregabilidad en bandejas de entrada, evitando spam). - Continuidad operativa del canal de notificaciones críticas.
- Reputación impecable del dominio
- Qué cuesta:
- Obliga a una disciplina estricta durante el testing manual y las baterías de validación.
ADR-010: Wiki: fuente de verdad en repo (Markdown), visor y chatbot desacoplados
- Número: ADR-010
- Fecha: 2026-09-27
- Estado: Vigente
Contexto
La documentación del proyecto se encontraba fragmentada entre conversaciones, reportes parciales y archivos con distintos propósitos. Se evaluó implementar de inmediato plataformas SaaS de documentación o chatbots acoplados al código fuente, con riesgo de dispersión y desactualización.
Decisión
Se adopta una estrategia desacoplada en tres fases claras:
- Fase W-1 (Actual): La única y absoluta fuente de verdad reside en archivos Markdown nativos dentro de la carpeta
docs/del repositorio Git. Todo cambio de comportamiento exige actualizar su.mden el mismo turno (Regla R14). - Fase W-2 (Futura): Capa de lectura desacoplada mediante un visor estático (VitePress) desplegado en Cloudflare Pages protegido por Cloudflare Zero Trust (acceso privado para operadores y clientes autorizados).
- Fase W-3 (Futura): Agente de asistencia / Chatbot desacoplado que consume el contenido validado de la wiki en Markdown como base de conocimiento embebida (RAG / Context injection).
Consecuencias
- Qué habilita:
- Control de versiones estricto de la documentación sincronizado con los commits de código.
- Independencia total de herramientas de terceros para redactar y consultar la verdad del sistema.
- Arquitectura limpia y modular para incorporar el visor y el asistente inteligente sin tocar el core de la aplicación.
- Qué cuesta:
- Disciplina operativa permanente para mantener al día los archivos
.mden cada turno de desarrollo.
- Disciplina operativa permanente para mantener al día los archivos
ADR-011: Doble despliegue: separación estricta entre Vercel y Supabase
- Número: ADR-011
- Fecha: 2026-09-14
- Estado: Vigente
Contexto
Un commit y push a la rama main de GitHub dispara automáticamente la compilación y despliegue del frontend estático en Vercel. Existía la falsa presunción de que dicho despliegue actualizaba toda la plataforma.
Decisión
Regla R1 de Gobernanza codificada en arquitectura:
- El despliegue de ITECEL ADM es un proceso dual y asíncrono:
- Superficie Frontend: Automatizada en Vercel vía GitHub push.
- Superficie Backend / Datos: Manual e intencional en Supabase.
- Los cambios en Edge Functions requieren el ritual de copiado/despliegue en el dashboard de Supabase (o Supabase CLI).
- Los cambios en Esquema SQL, Triggers, RLS y Funciones requieren el ritual de ejecución manual en el SQL Editor de Supabase.
- Siempre debe auditarse en cada turno qué piezas requieren despliegue manual antes de dar una fase por concluida.
Consecuencias
- Qué habilita:
- Control total sobre migraciones de base de datos críticas; previene alteraciones accidentales de esquemas durante simples fixes de UI.
- Capacidad de probar endpoints y funciones de forma aislada antes de conectar el frontend.
- Qué cuesta:
- No existe despliegue con "un solo clic" para cambios full-stack; el operador debe seguir el runbook operativo rigurosamente.
ADR-012: Vínculos por email en cadena de identidad y riesgo de orfandad
- Número: ADR-012
- Fecha: 2026-09-27
- Estado: Vigente (con deuda técnica declarada 10.2 / D-NUEVA-2)
Contexto
Durante la auditoría forense de arquitectura se constató que la asignación de licencias de administración (public.licenses) y los accesos de residentes (public.housing_units) se resuelven mediante comparaciones de texto de correo (.ilike('email', normalizedEmail) o campos JSON), en lugar de claves foráneas relacionales hacia auth.users(id) (UUID).
Decisión
- Se reconoce y documenta formalmente el acoplamiento por dirección de correo en la cadena de identidad.
- Todo procedimiento de cambio o actualización de correo electrónico para usuarios con licencia o residencia debe ser orquestado atómicamente en backend: debe mutar en una sola transacción
auth.users,app_users,licensesy los contactos dehousing_units. - Queda prohibido permitir que el usuario cambie su correo desde el cliente de Supabase Auth sin la migración satélite de sus licencias y contextos.
Consecuencias
- Qué habilita:
- Prevención de desasociaciones catastróficas donde administradores pierden el acceso a su condominio tras un simple cambio de email.
- Trazabilidad clara de las dependencias antes de encarar la refactorización relacional a UUIDs.
- Qué cuesta:
- Mantiene viva la deuda técnica D-NUEVA-2 hasta su resolución integral en backend.
ADR-013: Auditoría Vía B: trigger de BD para DELETE en license_requests
- Número: ADR-013
- Fecha: 2026-09-27
- Estado: Vigente
Contexto
El método deleteLicenseRequest en la aplicación ejecutaba un DELETE directo sobre la tabla public.license_requests. La tabla carecía de triggers en base de datos para capturar el borrado, provocando que la eliminación de solicitudes físicas no dejara rastro forense en public.supabase_audit_log, dependiendo exclusivamente de que el cliente reportara voluntariamente su acción (Vía A).
Decisión
Implementar la Vía B (Auditoría Inviolable en Base de Datos) para eventos DELETE sobre license_requests:
- Crear una función trigger
SECURITY DEFINERque se ejecuteAFTER DELETEenpublic.license_requests. - El trigger extrae el correo verificado del operador directamente desde el token JWT de la sesión activa (
auth.jwt() ->> 'email'). - Registra inmediatamente una fila inmutable en
public.supabase_audit_logcon el registro serializado (row_to_json(OLD)), garantizando auditoría no repudiable independientemente de si la eliminación se dispara desde la interfaz web, el SQL Editor o llamadas de API externas.
Consecuencias
- Qué habilita:
- Cero puntos ciegos forenses en la eliminación de solicitudes comerciales y de demo.
- Cumplimiento estricto de la regla R10 de gobernanza (JWT verificado del operador).
- Qué cuesta:
- Requiere el despliegue del script DDL correspondiente en el SQL Editor de Supabase en la Fase L-1.
ADR-014: Sistema unificado de límites basado en plan_limits
- Número: ADR-014
- Fecha: 2026-09-27
- Estado: Vigente
Contexto
Los límites del sistema se encontraban fragmentados: el límite de viviendas en un trigger de housing_units, el límite de correos demo disperso entre columnas de licenses y Edge Functions, y los posts/documentos y almacenamiento sin enforcement unificado en base de datos.
Decisión
Unificar la gobernanza de límites en el servidor con public.plan_limits como fuente única de verdad:
- Comunicaciones (Posts y Documentos): Conteo de filas vivas por condominio en el mes calendario (
date_trunc('month', now())). El borrado de posts o documentos libera cupo automáticamente (D1). Enforcement mediante triggersBEFORE INSERTindependientes que emiten excepción en español con códigoP0003. - Almacenamiento (Storage Híbrido D7 / D8): Límite sobre el acervo acumulado mediante trigger server-side en
storage.objects(evalúaSUM(size)por prefijo${condoId}/contramax_storage_mb), complementado con comprobación preventiva en cliente antes de iniciar la transferencia de red. - Cuota Mensual de Correos (D2 / D3): Cuota mensual calculada mediante cupo total único $5N$ (Lite 150, Standard 375, Pro 750, Enterprise 1500; Demo 10). Descuentan invitaciones y estados de cuenta aceptados por Resend; si un envío falla, se ejecuta reembolso atómico (
refund_email_quota). Exclusivo para envíos del sistema; el resto de la app permanece operativo. - Valores Canónicos de
plan_limits(ANEXO A):- demo: 30 viv | 4 posts | 4 docs | 60 MB | 10 correos
- lite: 30 viv | 20 posts | 30 docs | 300 MB | 150 correos
- standard: 75 viv | 50 posts | 75 docs | 1000 MB | 375 correos
- pro: 150 viv | 100 posts | 150 docs | 2500 MB | 750 correos
- enterprise: 300 viv | 200 posts | 300 docs | 5000 MB | 1500 correos
- perpetua:
NULLen todas las columnas (capacidad ilimitada).
Consecuencias
- Qué habilita:
- Unificación completa de la lógica de límites en PostgreSQL: un solo catálogo (
plan_limits), reglas consistentes y prevención de desbordes de costos de infraestructura. - Facilidad para representar medidores de consumo circulares en la tarjeta de Configuración (Fase L-2).
- Unificación completa de la lógica de límites en PostgreSQL: un solo catálogo (
- Qué cuesta:
- Retiro ordenado del contador de correos demo suelto actual para evitar duplicidad de topes.
- Despliegue coordinado de migraciones SQL y actualización de Edge Functions en Fase L-1.
- Nota de Implementación L-2:
- El fallback de transición hacia
get_demo_dispatch_quotaensrc/lib/demoQuotaService.tsfue completamente retirado en Fase L-2 (H2). Todo el frontend y la tarjeta de licencia consumen exclusivamente la RPC unificadaget_condo_limits_summary, manteniendo las columnasdemo_*_usedenlicensesúnicamente como histórico no destructivo deprecado.
- El fallback de transición hacia
ADR-015: Tres estados de licencia y regla de purga post-caducidad a 30 días
- Número: ADR-015
- Fecha: 2026-09-27
- Estado: Vigente (con deuda declarada para purga)
Contexto
Existía ambigüedad sobre cómo tratar a un condominio que nunca tuvo licencia frente a uno cuya licencia expiró o fue suspendida. Además, se planteó la política de purga de datos para condominios abandonados tras caducar.
Decisión
- Definición Canónica de Tres Estados de Licencia (D5):
- a) Sin Licencia Asignada (
sin_licencia): El condominio nunca ha tenido una licencia registrada (típico de pruebas iniciales de creación). Se trata como ILIMITADO, permitiendo operar sin bloqueos. - b) Licencia Activa (
activa): Condominio con licencia en estado'activa'y dentro de su periodo de vigencia. Aplican estrictamente los topes de su tier enpublic.plan_limits. - c) Licencia No Activa (
no_activa): Condominio al que se le otorgó licencia pero su estado es'vencida'o'suspendida', o expiró por fecha. Se aplica un BLOQUEO TOTAL de inserciones nuevas (viviendas, posts, documentos, correos, storage) con mensaje explícito de reactivación. Jamás se le degrada a "sin licencia".
- a) Sin Licencia Asignada (
- Función Centralizada de Resolución: Implementada en PostgreSQL como
public.resolve_condo_license_state(p_condo_id)para garantizar paridad absoluta en todos los triggers. - Regla de Negocio de Purga a 30 Días (D11):
- Transcurridos 30 días continuos en estado no-activo, el condominio califica para purga de datos.
- Prohibición de Purga Automática: Queda terminantemente prohibido implementar purgas mediante triggers automáticos de base de datos.
- Deuda Técnica Declarada: La purga debe contar con diseño propio que incluya: avisos previos por correo, periodo de gracia, respaldo central automático (
central_backups) y ejecución mediante script manual o cron de mantenimiento auditado.
Consecuencias
- Qué habilita:
- Certeza absoluta en las reglas de acceso comercial y protección de la propiedad intelectual del SaaS.
- Seguridad de que un cliente moroso no pueda seguir consumiendo recursos ni eludiendo el pago.
- Qué cuesta:
- Requiere que la UI capture el estado no-activo y muestre las vías de reactivación o contacto con el administrador.
Nota de Implementación Post-L-2 (Fix Tier Demo): Los espacios demo escriben explícitamente
tier='demo'al crearse y resuelven a la fila'demo'deplan_limits(30 viviendas, 4 posts, 4 documentos, 60 MB, 10 correos). Enresolve_condo_license_state, elCOALESCE(v_tier, 'lite')se mantiene intencionalmente como red de seguridad conservadora y defensiva ante filas heredadas o tiers desconocidos, garantizando que ante cualquier dato no reconocido se asigne el tier comercial más restrictivo sin romper la ejecución.