Skip to content

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 ​

IDTítuloFechaEstado
ADR-001Límites por licencia aplicados en BASE DE DATOS (trigger), no en UI2026-09-15Vigente
ADR-002Separación identidad vs descriptivo: acceso personal ≠ ficha institucional2026-09-16Vigente
ADR-003Matriz de precios bidimensional tier × ciclo y deuda de columna tier2026-09-18Vigente (con deuda declarada)
ADR-004Licencia PERPETUA: monto 0, sin selector ciclo/tier, notas de texto libre2026-09-18Vigente
ADR-005Superadmins intocables: sin licencias, sin contextos, alcance global de por vida2026-09-18Vigente
ADR-006Auditoría de nube con JWT VERIFICADO vía trigger de BD2026-09-20Vigente (verificación en borrado PENDIENTE)
ADR-007Anti-spam en formulario demo: OTP + filtro de dominios corporativos2026-09-21Vigente
ADR-008Protocolo anti-deadlock para DDL en producción2026-09-22Vigente
ADR-009Política de supresión de Resend: prohibición de casillas inexistentes2026-09-22Vigente
ADR-010Wiki: fuente de verdad en repo (Markdown), visor y chatbot desacoplados2026-09-27Vigente
ADR-011Doble despliegue: separación estricta entre Vercel y Supabase2026-09-14Vigente
ADR-012Vínculos por email en cadena de identidad y riesgo de orfandad2026-09-27Vigente (deuda declarada)
ADR-013Auditoría Vía B: trigger de BD para DELETE en license_requests2026-09-27Vigente
ADR-014Sistema unificado de límites basado en plan_limits2026-09-27Vigente
ADR-015Tres estados de licencia y regla de purga post-caducidad a 30 días2026-09-27Vigente (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:

  1. El cliente web puede realizar validaciones UX preventivas (mostrar advertencias o inhabilitar botones), pero la BD es la autoridad final e inapelable.
  2. 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.
  3. 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:

  1. Identidad / Acceso Personal:
    • auth.users (UUID, correo personal autenticado, credenciales seguras).
    • public.app_users (UUID sincronizado con auth.users, correo personal, rol global/sistema).
    • public.condo_licenses / asignación de licencias (vinculadas a la persona o correo de acceso personal).
  2. 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.
  3. 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.
  • 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 ​

  1. 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).
  2. 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 tier y 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:

  1. Monto asignado: $0.00 invariable.
  2. Sin selectores de ciclo de facturación ni cálculo de fecha de caducidad (indefinida / permanente).
  3. 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:

  1. 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).
  2. Sin contextos de condominio: El superadmin opera con alcance global en todo el SaaS, sin estar anclado a un condo_id en particular para su funcionamiento.
  3. 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.
  4. 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.

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 ​

  1. 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().
  2. Jamás se registran valores quemados o provistos por el cliente en campos de identidad auditora.
  3. 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:

  1. 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.
  2. 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:

  1. Definir siempre un tiempo de espera de bloqueo estricto antes de ejecutar sentencias pesadas (SET lock_timeout = '2s';).
  2. Adicionar columnas sin bloqueos pesados (usar DEFAULT NULL o valores constantes optimizados en Postgres moderno).
  3. Creación de índices en modo no bloqueante (CREATE INDEX CONCURRENTLY).
  4. Ejecutar ventanas de mantenimiento en horarios de baja concurrencia y verificar que no existan conexiones colgadas en pg_stat_activity.
  5. 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 ​

  1. Regla de oro: Jamás realizar pruebas de envío de correos (invitaciones, cobros, OTPs) utilizando direcciones inventadas o casillas inactivas.
  2. Toda prueba debe realizarse con correos reales controlados por el equipo (test-inbox propio o cuentas personales de testing).
  3. 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.
  • 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:

  1. 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 .md en el mismo turno (Regla R14).
  2. 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).
  3. 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 .md en cada turno de desarrollo.

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:

  1. 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.
  2. Los cambios en Edge Functions requieren el ritual de copiado/despliegue en el dashboard de Supabase (o Supabase CLI).
  3. Los cambios en Esquema SQL, Triggers, RLS y Funciones requieren el ritual de ejecución manual en el SQL Editor de Supabase.
  4. 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 ​

  1. Se reconoce y documenta formalmente el acoplamiento por dirección de correo en la cadena de identidad.
  2. 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, licenses y los contactos de housing_units.
  3. 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:

  1. Crear una función trigger SECURITY DEFINER que se ejecute AFTER DELETE en public.license_requests.
  2. El trigger extrae el correo verificado del operador directamente desde el token JWT de la sesión activa (auth.jwt() ->> 'email').
  3. Registra inmediatamente una fila inmutable en public.supabase_audit_log con 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:

  1. 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 triggers BEFORE INSERT independientes que emiten excepción en español con código P0003.
  2. Almacenamiento (Storage Híbrido D7 / D8): Límite sobre el acervo acumulado mediante trigger server-side en storage.objects (evalúa SUM(size) por prefijo ${condoId}/ contra max_storage_mb), complementado con comprobación preventiva en cliente antes de iniciar la transferencia de red.
  3. 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.
  4. 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: NULL en 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).
  • 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_quota en src/lib/demoQuotaService.ts fue completamente retirado en Fase L-2 (H2). Todo el frontend y la tarjeta de licencia consumen exclusivamente la RPC unificada get_condo_limits_summary, manteniendo las columnas demo_*_used en licenses únicamente como histórico no destructivo deprecado.

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 ​

  1. 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 en public.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".
  2. 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.
  3. 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' de plan_limits (30 viviendas, 4 posts, 4 documentos, 60 MB, 10 correos). En resolve_condo_license_state, el COALESCE(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.

Wiki Técnica Oficial — ITECEL ADM