Skip to content

REGISTRO DE DEUDA TÉCNICA Y MEJORAS DE ARQUITECTURA ​

Sistema de Gestión Condominial y Financiera — ITECEL ADM

Este documento centraliza las deudas técnicas identificadas y priorizadas para las siguientes fases de desarrollo, previo y posterior al primer piloto con residentes reales.

IMPORTANT

GOBERNANZA OBLIGATORIA EN TODOS LOS TURNOS: Consulte y aplique estrictamente las 6 reglas de [GOBERNANZA-SQL-Y-RITUALES.md](file:///c:/Users/Admin/ITECEL-adm/ITECEL-ADM/docs/GOBERNANZA-SQL-Y-RITUALES.md): (1) Esquema real como única fuente de verdad, (2) Funciones existentes se modifican (vía pg_get_functiondef) y no se reescriben de cero, (3) Descalces repo vs real son hallazgos, (4) Todo ritual lleva su smoke transaccional diseñado según su guard, (5) Garantía de datos en guards de Edge Functions, (6) Huecos de instrucción declarados como hallazgos obligatorios.


Priorización de Deuda Técnica Activa ​

1. Unificar Reset de Contraseña vía Edge Function + Resend ​

  • Estado: ✅ IMPLEMENTADO (Fase 2.1) — Código creado en /supabase/functions/send-password-recovery/index.ts y conectado en ForgotPasswordModal.tsx. Pendiente despliegue manual en dashboard de Supabase.
  • Prioridad previa: ALTA (Resuelto).
  • Detalle de la solución implementada:
    • Se creó la Edge Function dedicada send-password-recovery que genera el enlace seguro con supabaseAdmin.auth.admin.generateLink({ type: 'recovery', email, options: { redirectTo: cleanRedirect } }) y envía el correo con la plantilla institucional de ITECEL a través de Resend.
    • Implementa rate limit de 60 segundos por correo en backend y cliente.
    • Protegido contra enumeración de usuarios: si el correo no existe en Supabase Auth, la función y la UI devuelven un mensaje genérico idéntico de confirmación.
    • La URL limpia redirige a https://adm.itecelgs.com/reset-password sin # previo, permitiendo que Supabase inyecte su hash de sesión temporal y se active SetNewPasswordModal.

1.1 Claridad de Acciones y Estados en Invitaciones (Fase 2.2) ​

  • Estado: ✅ IMPLEMENTADO — Distinción clara en la UI y backend entre "Sin invitar", "Invitado" y "Activo".
  • Detalle de la solución:
    • send-invitation: Soporta action: "get-user-statuses" para consultar de forma segura last_sign_in_at en Supabase Auth con service_role sin exponerlo al cliente. Soporta emailType: "invite" | "reinvite" | "reset_active" con plantillas de correo y asuntos contextuales.
    • ResidentInvitationsModal: Expone en cada fila el último acceso ("Último acceso: dd/mm/aaaa hh:mm" o "Nunca ha ingresado"), estados inequívocos con badges diferenciados, y botones de acción contextuales:
      • Sin invitar: Botón Invitar (azul).
      • Invitado (sin login): Botón Re-enviar invitación (gris/azul con modal confirmatorio y plantilla contextual de recordatorio).
      • Activo: Botón Restablecer acceso (ámbar) con modal de confirmación advirtiendo que reemplazará la contraseña actual.
    • Filtros en barra superior actualizados: Todos, Sin invitar, Invitados y Activos.

1.2 Cobranza Masiva: Envío de Estados de Cuenta por Correo (Fase 2.3) ​

  • Estado: ✅ IMPLEMENTADO — Módulo de cobranza masiva e individual mediante Edge Function send-statement + Resend.
  • Detalle de la arquitectura y decisiones de diseño:
    • Default de Vista en Estados de Cuenta: El filtro onlyUnpaidFilter ahora inicializa por defecto en true ("Solo no saldados"). La generación e impresión de PDFs respeta el filtro activo y el usuario puede alternar manualmente a "Todos los Movimientos" en cualquier momento.
    • Resolución de Contacto Principal para Cobranza: Prioridad estricta al contacto en unit.contacts con isMainContact: true y correo válido; en su defecto unit.email; en su defecto el primer contacto registrado con correo electrónico. Si la vivienda carece de correo, se aísla en la pestaña "Sin correo — notificar manualmente" para atención presencial o impresa, excluyéndola de envíos por correo.
    • Exclusión de Viviendas al Día: Las unidades con saldo pendiente acumulado menor o igual a $0.00 se marcan como "Al día (Sin saldo pendiente)" y son excluidas de los lotes de cobranza masiva.
    • Registro de Envíos: Implementado mediante statement_dispatches en Supabase con espejo local resiliente en localStorage (itecel_statement_dispatches_[condoId]). Registra email, condo_id, unit_id, unit_number, total_pending, last_sent_at e incrementos en send_count.
    • Edge Function send-statement:
      • Recibe el detalle de adeudos no saldados ya computados por el cliente para evitar discrepancias de cálculo.
      • Autorización y Anti-Abuso (JWT): Valida la sesión activa de Supabase Auth mediante el header Authorization: Bearer <token> y verifica que el usuario posea rol admin (app_metadata, user_metadata, app_users o titular admin en housing_units). Rechaza con HTTP 401 si no hay sesión o HTTP 403 si el invocador no es administrador.
      • Rate Limit: Cooldown estricto de 60 segundos por correo electrónico en memoria.
      • Plantilla Corporativa (Modelo B): Saludo al titular, tabla con conceptos, fechas y montos no saldados, caja destacada con el TOTAL PENDIENTE DE PAGO, botón de acción hacia la app e instrucciones de pago configuradas en el perfil del condominio. Asunto formal: Estado de cuenta — [Condominio] — [Vivienda].
    • Seguridad en UI: La sección en Configuración y el botón "Enviar por correo" en el módulo Estados de Cuenta son visibles de forma exclusiva para el rol admin (ocultos para committee y resident).

2. RLS Real en Todas las Tablas + Eliminación de Políticas Permisivas (Fase 4-A) ​

  • Estado: ✅ IMPLEMENTADO (Fase 4-A — Cambio de Paradigma) — Script de migración idempotente en /supabase/migrations/20260913_rls_real_phase4a.sql y /supabase/schema.sql.
  • Prioridad previa: ALTA (Resuelto).
  • Detalle de la arquitectura y decisiones de diseño:
    • Eliminación Total de Políticas Dev: Se retiraron las 15 políticas permisivas USING (true) en condos, sections, housing_units, bank_accounts, suppliers, debt_templates, generated_debts, payment_records, expenses, bank_movements, yearly_budgets, unit_payments, app_users, user_invitations y statement_dispatches.
    • Funciones de Seguridad Postgres (SECURITY DEFINER): Creadas get_auth_email(), is_superadmin(), is_condo_admin(condo_id), is_condo_committee(condo_id), e is_condo_resident(condo_id, unit_id). Se ejecutan con SECURITY DEFINER SET search_path = public previniendo la recursión infinita de políticas RLS y aprovechando índices.
    • Vinculación de Identidad: Función RPC sync_current_user_auth_id() y trigger trg_on_auth_user_created en auth.users para asociar de manera transparente auth.uid() a app_users.auth_user_id.
    • Matriz de Control Granular:
      • admin del condominio X: Total control (SELECT, INSERT, UPDATE, DELETE) en filas con condo_id = X.
      • committee: Lectura completa (SELECT) en su condominio, mutaciones estrictamente prohibidas (0 permisos de I/U/D).
      • resident: Lectura restringida a su propia vivienda (unit_id), sus propios adeudos y pagos, y datos generales del condominio. Tablas financieras y otras unidades bloqueadas (0 filas). Mutaciones prohibidas.
      • superadmin: Alcance global total en todas las tablas (app_users.role = 'admin' AND app_users.condo_id IS NULL).
      • Anónimo: 0 filas devueltas en todas las tablas.
      • Edge Functions (service_role): Inmunes a RLS gracias al atributo nativo BYPASSRLS de PostgreSQL.
    • Documentación Forense y Pruebas:
      • Matriz completa incorporada en docs/module-table-map.md.
      • Batería de 6 pruebas adversarias obligatorias creada en docs/pruebas-adversarias-obligatorias.md.

2.1 Entregables de la Fase 4 (Cambio de Paradigma) ​

  • 4-A: RLS Real en Todas las Tablas:
    • ✅ IMPLEMENTADO — Migración 20260913_rls_real_phase4a.sql y eliminación de políticas permisivas.
  • 4-B: Panel de Licencias del Superadmin:
    • ✅ IMPLEMENTADO — Tabla licenses con RLS, servicio licensesService.ts, modal interactivo LicensesPanelModal.tsx con soporte para activar, suspender, renovar y crear licencias (1 correo = 1 licencia = 1 condominio administrado). Pantalla SuspendedLicenseScreen para cuentas suspendidas.
  • 4-C: Selector Multi-Contexto (Identidad Unificada):
    • ✅ IMPLEMENTADO — Resolución unificada en resolveUserRole, vista UserContextSelectorScreen.tsx para alternar entre roles/condominios cuando un mismo correo administra o reside en más de una copropiedad. Botón "Cambiar de Rol / Condominio" en Navbar.
  • 4-D: Respaldos Centrales del Proveedor:
    • ✅ IMPLEMENTADO — Tabla central_backups con RLS para superadmin, servicio centralBackupService.ts, modal CentralBackupsModal.tsx con backups manuales y programados automáticos diarios, descarga de snapshots y restauración instantánea.
  • Mejoras Derivadas de RLS (M1 y M2):
    • ✅ IMPLEMENTADO — M1: Nomenclatura normalizada en Estado de Cuenta de Bancos (Pago — [contacto] (Vivienda X) — $monto — fecha — método [conceptos + anticipo]). M2: Estandarización documental y arquitectónica de Identidad (auth.users / app_users) vs. Campos Descriptivos (condos.email).
  • 4-E: Validación y Estreno del Condominio #2:
    • Siguiente paso: Estreno en producción con cuenta licenciada sin depender de respaldos locales.

2.2 Deuda Técnica Derivada de Fase 4 (A abordar antes de escalar clientes) ​

  1. Migrar Operaciones Sensibles del Panel de Superadmin a Edge Functions con Service Role:

    • Estado: PENDIENTE (Tolerable en fase piloto).
    • Diagnóstico: Actualmente, las operaciones críticas del superadmin (crear/suspender/reactivar licencias en licenses, generar/restaurar snapshots completos en central_backups) se ejecutan desde el navegador (cliente) mediante la sesión de Supabase Auth validada por RLS (is_superadmin()).
    • Riesgo: Mientras exista un único superadmin (el proveedor/fundador), el riesgo es mínimo y manejable. Sin embargo, para entornos con múltiples operadores o auditoría estricta, las operaciones maestras no deben delegarse al cliente HTTP ni depender del ensamblado de datos en memoria del navegador.
    • Solución futura: Encapsular create_license, toggle_license_status y create_central_backup en Edge Functions dedicadas que validen la identidad del superadmin mediante JWT en servidor y operen con service_role.
  2. pg_cron / Cron HTTP para Respaldos Centrales Independientes de Usuario:

    • Estado: PENDIENTE (Aceptable para piloto y estreno Condominio #2; Obligatorio antes de comercialización masiva).
    • Diagnóstico: El respaldo automático actual opera mediante un disparador de frontend (checkAndRunDailyAutomatedBackup): se ejecuta cada 24 horas únicamente cuando un superadmin abre la aplicación. La colaboradora del Condominio #2 no es superadmin, por lo que los respaldos en la nube dependen de la disciplina operativa del superadmin de ingresar a diario durante el período de estreno. Si ningún superadmin abre el sistema en un día determinado, ese día no se registra snapshot central.
    • Riesgo: Inviable para producción comercial (ej. 10+ condominios con superadmin de vacaciones o ausente).
    • Solución futura: Implementar un cron autónomo en PostgreSQL mediante la extensión nativa pg_cron de Supabase o un cron job HTTP (GitHub Actions / Cloud Scheduler) que invoque periódicamente una Edge Function run-scheduled-backup a una hora fija (ej. 03:00 AM UTC) con cero dependencia de sesiones de usuario activas.
  3. Sincronización Diferencial para Residentes y Comité (Optimización de Ancho de Banda - L5):

    • Estado: PENDIENTE (Deuda técnica documentada formalmente en Fase 4).
    • Diagnóstico: Actualmente, la sincronización entre Supabase y los clientes (residentes y comité) descarga el estado completo del condominio (FullBackupPayload / todas las entidades según RLS).
    • Riesgo: En condominios pequeños el consumo es insignificante, pero en condominios grandes con años de transacciones o cientos de unidades, la descarga completa consume ancho de banda redundante y degrada el tiempo de carga en conexiones móviles.
    • Solución futura: Implementar sincronización diferencial granular por entidad (debts, payments, notifications, etc.) utilizando filtros temporales basados en updated_at o cursor de versión (last_synced_version), transmitiendo únicamente las mutaciones delta ocurridas desde la última sincronización del dispositivo cliente.

3. Limpieza de Columnas Legacy en el Esquema ​

  • Estado: ✅ RESUELTO EN FASE 5 (Bloque 1 — Purga Legacy de la Base de Datos).
  • Detalle de la solución y migración (20260920_legacy_cleanup_phase5.sql):
    • Inventario forense previo: Scripts de auditoría para verificar conteos en housing_units (section_id, section_name, password, last_login), sections y unit_payments.
    • Limpieza de datos: UPDATE housing_units SET section_id = NULL, section_name = NULL; eliminando datos decorativos históricos muertos.
    • Eliminación de columnas: ALTER TABLE housing_units DROP COLUMN IF EXISTS password; (las contraseñas residen 100% en auth.users) y DROP COLUMN IF EXISTS last_login;.
    • Eliminación de tabla huérfana: DROP TABLE IF EXISTS public.unit_payments CASCADE; (todo el ecosistema de cobros opera en payment_records).
    • Custodia de sections: Se mantiene sellada como tabla pasiva vacía (TRUNCATE) para evitar discrepancias en parsers de backups históricos que esperan el campo sections.
    • Documentación: supabase/schema.sql y docs/TECHNICAL_DEBT.md completamente actualizados y sincronizados.

4. Dominio Propio y Verificación en Resend ​

  • Prioridad: MEDIA (Requisito para salida a producción real).
  • Justificación:
    • En la fase de pruebas, Resend opera con el remitente de testing (onboarding@resend.dev), el cual solo permite envíos a la dirección del propietario de la cuenta de Resend.
    • Para despachar invitaciones y notificaciones a residentes reales en cualquier correo electrónico (Gmail, Outlook, dominios corporativos), es necesario vincular y verificar un dominio propio (DNS: DKIM, SPF, DMARC).
  • Acción a implementar:
    • Configurar registros DNS en el proveedor de dominio del cliente (ej. mail.itecel.com o notificaciones.itecel.com).
    • Actualizar la variable de entorno RESEND_FROM_EMAIL en las Edge Functions de Supabase.

5. Migración SQL de tabla statement_dispatches y Deprecación Definitiva de Secciones ​

  • Prioridad: MEDIA.
  • Justificación:
    • Se implementó la persistencia y auditoría de envíos de estados de cuenta vía Supabase con fallback local (statement_dispatches), cuyo DDL fue agregado a supabase/schema.sql. Requiere ejecución en el panel SQL de Supabase para activar la persistencia remota completa.
    • La entidad "Secciones/Torres" se encuentra deprecada y oculta en la interfaz de usuario ("Generar Cuotas" ahora muestra únicamente Vivienda y Contacto), manteniéndose las columnas en base de datos exclusivamente por compatibilidad con condominios preexistentes.
  • Acción a implementar:
    • Ejecutar el script CREATE TABLE IF NOT EXISTS public.statement_dispatches en el SQL Editor de Supabase.
    • Diseñar el script de migración para desvincular definitivamente las referencias a section_id cuando concluya el ciclo de soporte legacy.

6. Mejoras de UI/UX y Ergonomía Visual (Fase 5) ​

  • Modo Oscuro (Dark Mode) y Paletas de Interfaz:

    • Estado: ✅ RESUELTO EN FASE 5 (Bloques 2 y 3).
    • Alcance: Modos Día y Noche integrales con ThemeContext reactivo, inicialización anti-parpadeo (blocking script en index.html) y persistencia en localStorage (itecel_theme_mode, itecel_color_palette).
    • Paletas de la Barra de Navegación: Slate Ejecutivo (Predeterminado), Océano Corporativo, Verde Esmeralda y Púrpura Itecel.
    • Controles de Usuario: Acceso directo desde el Navbar (botón rápido sol/luna), Cajón Lateral Administrativo (AdminRightDrawer) y sección de Personalización en Configuración (SettingsView).
    • Restricciones estrictas respetadas: Contraste AA en cifras financieras, correos en formato claro institucional y reportes en PDF / impresiones forzadas al 100% sobre fondo blanco con texto oscuro.
  • Branding del Portal de Residentes:

    • Estado: ✅ RESUELTO EN FASE 5 (Bloque 4).
    • Alcance: Identidad primaria del condominio (logo_url y nombre del edificio) en Navbar y cabecera del Estado de Cuenta para residentes y miembros del directorio, con mención secundaria institucional "Powered by / Administrado con Itecel Condominios".

7. Arquitectura de Almacenamiento (Bucket condo-community) — Fase 6 ​

  • Estado: ✅ OPERATIVO / DEUDA TÉCNICA DOCUMENTADA.
  • Detalle de la arquitectura actual:
    • Bucket condo-community: Público de lectura por URL directa, sin listado público (public = true).
    • Políticas de Storage RLS aplicadas:
      • SELECT restringido exclusivamente a usuarios autenticados (authenticated).
      • INSERT, UPDATE y DELETE restringidos exclusivamente a usuarios autenticados (authenticated).
      • Política de listado anónimo (SELECT para public) intencionalmente eliminada.
    • Advertencia de Supabase ("Clients can list all files"): Queda IGNORADA DOCUMENTADAMENTE. Activar el listado anónimo o público rompería la política estricta de aislamiento entre condominios (1 condominio = 1 espacio), permitiendo a usuarios ajenos enumerar los archivos de todas las comunidades.
    • Evolución futura: Migración a URLs firmadas (bucket privado con tokens de expiración temporal) cuando los documentos de alta sensibilidad jurídica lo exijan (actas extraordinarias confidenciales, contratos laborales de conserjería) o al escalar a clientes corporativos de gran escala.

8. Pregunta Abierta de Negocio: Superadmin con Contextos Adicionales de Condominio ​

  • Contexto y Caso Real de Producción:
    • El correo de un superadmin (itecelecuador@gmail.com) fue ingresado en el Directorio de un condominio del piloto (Edificio Juliana) con la marca referencial de administrador.
    • El sistema resolvió temporalmente su sesión como administrador de ese condominio individual, sustituyendo su vista global de Cockpit por la vista local de ese condominio.
  • Solución Estructural Aplicada (Fase 7 - Fix Crítico):
    • REGLA DE IDENTIDAD G1/G2 AMPLIADA: Los superadmins son INTOCABLES.
    • Su alcance global (role='admin', condo_id IS NULL) prevalece de forma absoluta.
    • La resolución en cliente (resolveUserRole) y en base de datos (get_user_contexts) omite la compilación de contextos de condominio para superadmins (availableContexts = []), garantizando que siempre ingresen directamente al Cockpit Global.
    • Sus apariciones en el Directorio son estrictamente descriptivas (propietario o contacto de vivienda).
    • El sistema de licencias rechaza cualquier intento de crear o aprobar licencias asociadas a superadmins.
  • Pregunta Abierta de Negocio:
    • ¿Debe permitirse a futuro que un socio-superadmin, que resida o sea copropietario en un condominio del piloto, alterne voluntariamente entre el "Alcance Global Superadmin" y su perfil residencial de unidad específica mediante un conmutador de sesión explícito?
  • Decisión Vigente:
    • MUTUAMENTE EXCLUYENTES. Por el momento, el superadmin permanece 100% en su alcance global sin selector de contextos. La administración o revisión de cualquier condominio individual se realiza a través del "Modo Operador" desde el Cockpit Central. Si la operación futura lo exige formalmente, se diseñará un selector de contexto especial con separación clara de tokens de sesión.

9. Canal Comercial y Gobernanza de Correo (Fase 7 - Post-Diagnóstico) ​

  1. Flujo de Demo Refinado: Verificación OTP por Resend con Marca + Restricción de Dominios + Unicidad (IMPLEMENTADO):

    • Diagnóstico: El código numérico OTP mostrado en pantalla en el flujo comercial de compras web operaba como un fallback simulado. Además, el flujo de demos públicas requería protección anti-abuso estricta frente a spam y creación masiva de bases de datos.
    • Solución Definitiva Implementada (Fase 7 Refinada):
      • Envío Real de OTP vía Resend: El código de 6 dígitos se genera en el backend y se envía exclusivamente a través de Resend con la plantilla oficial de marca ITECEL ("Tu código de verificación ITECEL ADM es: [código]"), desde el remitente institucional verificado (notificaciones@itecelgs.com). Jamás se retorna el código en las respuestas JSON de red ni se expone en DevTools.
      • Almacenamiento Seguro Hasheado: Tabla public.email_verification_codes en Supabase con código HASHEADO en SHA-256 (nunca texto plano), TTL estricto de 10 minutos, y límite de 3 intentos máximos por código.
      • Rate Limit & Fuerza Bruta: Cada intento fallido descuenta un intento. Al alcanzar 0 intentos, el código se bloquea y el usuario debe solicitar uno nuevo.
      • Cooldown de Reenvío: El botón de reenvío en la interfaz de usuario cuenta con un temporizador de bloqueo de 60 segundos para evitar saturación de la API de Resend.
      • Restricción de Dominios Permitidos (Anti-Spam): Para registros de demo únicamente se aceptan correos de @gmail.com, @outlook.com y @hotmail.com (con doble verificación: feedback visual inmediato en el formulario y rechazo estricto en el backend vía RPC). La lista es configurable por el superadmin desde la pestaña de Ajustes Comerciales de la plataforma (persistida en itecel_settings bajo la clave 'demo_allowed_email_domains').
      • Registro de Demos por Correo (Unicidad Estricta - No Renovable): Un correo = UNA demo gratuita de 30 días. Si el correo ya tiene una demo registrada (activa, suspendida o vencida), se rechaza con: "Este correo ya registró una demo gratuita. Contacte a ITECEL para activar su licencia completa." Si ya cuenta con licencia completa, se rechaza con: "Este correo ya tiene una licencia activa en ITECEL ADM."
      • Regla Intocable de Seguridad en Modo DEV: Se eliminó por completo el código OTP visible en pantalla del entorno comercial. Queda normado de forma permanente: "el modo dev de códigos visibles se limita a entornos de desarrollo interno — jamás en producción con usuarios reales".
  2. Gobernanza de Cobranza e Invitaciones en Espacios Demo — Pool Unificado de Cortesía (IMPLEMENTADO):

    • Diagnóstico: Los condominios en modalidad Demo disponen de 30 días de prueba y no deben saturar la cuota de correo transaccional de Resend ni ser utilizados para spam masivo. Sin embargo, bloquear totalmente la salida de correos impedía a los prospectos comprobar la entregabilidad y la experiencia de usuario antes de contratar.
    • Solución Implementada:
      • Se implementó un Pool ÚNICO de cortesía demo de 10 envíos exitosos por ciclo de licencia demo, consumibles indistintamente por cualquier combinación de invitaciones a residentes (iniciales o reenvíos) y estados de cuenta / avisos de cobranza.
      • Centralización en DEMO_DISPATCH_LIMIT = 10 en src/types/license.ts.
      • Persistencia de balance en tabla licenses (demo_dispatch_used, demo_invites_used, demo_statements_used).
      • RPCs canónicas: get_demo_dispatch_quota(p_condo_id) y consume_demo_dispatch(p_condo_id, p_count, p_kind).
      • Guards transaccionales en backend en Edge Functions send-statement y send-invitation (con validación de cupo y consumo exclusivo por envíos con estatus 'sent').
      • En conversión a licencia completa (convertDemoToFullLicense y RPC convert_demo_to_full_license), los contadores se resetean a 0 de forma atómica.
      • En la interfaz de usuario, los modales ResidentInvitationsModal y StatementDispatchModal exhiben un semáforo visual con el desglose exacto ("X de 10 envíos disponibles (Y invitaciones · Z estados de cuenta)"), bloqueando proactivamente envíos que superen el remanente.
  3. Redirección de Comprobantes a Canales Directos y Futura Arquitectura de Storage:

    • Decisión de Negocio (Propietario & Socio): Se canceló la subida pública digital de comprobantes en la landing comercial abierta. La recepción y validación de transferencias se canaliza de forma conversacional 1-a-1 vía WhatsApp, Correo Oficial y Telegram con el superadministrador. Se descartó la apertura de políticas RLS anónimas en el bucket condo-community.
    • Estado en Código: La subida digital queda confinada tras la bandera inactiva ENABLE_DIGITAL_PROOF_UPLOAD = false en PublicCommercialLanding.tsx. En el panel de superadmin, las solicitudes sin comprobante adjunto exhiben el distintivo "Comprobante por canal directo", y el visor modal (selectedProofUrl) se mantiene preservado e inactivo para activación futura. Ninguna lógica exige comprobante_url para aprobar.
    • Deuda Técnica para Escalabilidad Comercial: Si en el futuro el volumen de transacciones justifica la automatización de adjuntos sin intervención humana, la arquitectura exigirá un bucket estrictamente privado (ej. private-billing-proofs) con subida mediada por Edge Function autenticada/firmada y generación de URLs firmadas temporales para visualización exclusiva del superadministrador, evitando exponer Storage a subidas públicas no autenticadas.
  4. Gobernanza y Automatización del Diario de Respaldos (Backup Diario):

    • Estado en Código Actual: El respaldo diario ya se encuentra implementado y activo en el cliente (src/App.tsx:516-530). Cuando un usuario autenticado con privilegios de superadmin accede al sistema, un temporizador en segundo plano (cada 30 min) evalúa si han transcurrido $\ge 24\text{ horas}$ desde el último respaldo registrado en central_backups. De cumplirse el intervalo, ejecuta automáticamente performDailyBackup() (src/lib/backupService.ts), exportando el snapshot centralizado en Supabase y notificando al superadmin.
    • Deuda Técnica para Automatización Headless (Server-Side Cron): Actualmente el respaldo diario depende de que al menos un superadmin inicie sesión en la plataforma una vez al día en un navegador. Para desacoplar el respaldo diario de la presencia activa del operador humano, se recomienda migrar el disparador a un trabajo programado headless (vía extensión pg_cron en PostgreSQL o una GitHub Action periódica) que invoque una Edge Function con service_role encargada de generar y persistir el snapshot en la nube de forma desatendida.
  5. Modalidad de Cobro Escalonada por Cuota de Viviendas y Planes Customizados (Diseño Incorporado - Deuda Operativa):

    • Visión de Negocio: Transición planificada de un modelo de precio fijo plano hacia una tarificación escalonada donde el costo de la licencia incremente en proporción directa a la cuota estimada de almacenamiento y recursos que el condominio demandará en la base de datos (PostgreSQL/Supabase). Dicha cuota se estimará algorítmicamente en función del número de viviendas/unidades habitacionales que el cliente registre.
    • Condición Previa Obligatoria (Periodo de Calibración Piloto):
      • Esta valoración no se implementará en el motor de facturación de inmediato. Para definir los límites de viviendas de básico a avanzado con exactitud matemática, es indispensable mantener a los condominios pilotos operando en producción continua por al menos 2 meses.
      • Tras los 2 meses de operación real, se recopilarán datos empíricos de ocupación en disco por vivienda (alícuotas, recibos emitidos, comprobantes, actas) para fijar los rangos y precios definitivos sin sobreestimar ni subestimar costos de infraestructura.
    • Incorporación a Nivel Diseño (Fase 7):
      • Nomenclatura profesional establecida: Plan Lite (mensual), Plan Standard (trimestral), Plan Pro (semestral) y Plan Enterprise (anual), descartando denominaciones informales (tipo Spark).
      • Incorporación visual en tarjetas de precios de la capacidad referencial (Hasta 30 viviendas, Hasta 75 viviendas, Hasta 150 viviendas y Viviendas y torres ilimitadas).
      • Incorporación del componente visual Plan Customizado / A Medida, permitiendo cotizar de forma directa para macro-condominios o administraciones con alta demanda de unidades habitacionales.
  6. Gobernanza de Actualización de Correo de Acceso Posterior (Licencias Completas vs Demos):

    • Regla de Negocio Establecida:
      • El usuario de una demo no puede actualizar su correo de acceso durante el periodo de prueba de 30 días (el correo original garantiza la trazabilidad y la no-renovación).
      • El administrador con licencia completa SÍ podrá actualizar su correo de acceso a cualquiera (sin restricción de dominio @gmail/@outlook/@hotmail), manteniendo el 100% de los datos contables, unidades, residentes e historial del condominio intactos.
    • Deuda Técnica para Migración Atómica sin Riesgo de Login:
      • En Supabase Auth, cambiar el email de un usuario involucra actualizar auth.users, invalidar o regenerar tokens JWT y actualizar en cascada las claves foráneas y columnas email en public.app_users y public.licenses.
      • Para asegurar que los cambios de correo JAMÁS rompan los logins, sesiones activas ni el selector multi-contexto de los administradores existentes, la implementación de la edición de correo en caliente se preserva como deuda técnica planificada. Se implementará mediante una RPC atómica con re-autenticación y sincronización coordinada con supabase.auth.updateUser({ email }).
  7. Corrección del Tier en Espacios Demo y Desacoplamiento de la Suposición Histórica "Demo = Lite" (RESUELTO):

    • Diagnóstico: Históricamente, antes de la existencia de la fila 'demo' en plan_limits, el sistema asumía que un espacio demo equivalía a un plan Lite. Al agregar la columna tier a public.licenses con DEFAULT 'lite', la creación de demos (create_verified_demo_space) omitió especificar la columna tier, provocando que las nuevas licencias demo se persistieran con tier='lite' y resolvieran a los límites del plan Lite (30 viviendas / 20 posts / 30 docs / 300 MB / 150 correos) en lugar de los límites estrictos de la fila demo (30 viviendas / 4 posts / 4 docs / 60 MB / 10 correos), introduciendo un riesgo anti-abuso de salida de correos.
    • Solución Implementada:
      • En RPC create_verified_demo_space, se escribe explícitamente tier = 'demo'.
      • En RPC convert_demo_to_full_license y servicio convertDemoToFullLicense, se recibe y persiste el tier comercial elegido (lite, standard, pro, enterprise).
      • En la interfaz modal de conversión (LicensesPanelModal.tsx), se agregó el selector de tier comercial con cotizador automático de precio según matriz comercial.
      • Se entregó migración SQL con ajuste preventivo de CHECK constraint y backfill idempotente para alinear licencias demo existentes.
      • En resolve_condo_license_state, el COALESCE(v_tier, 'lite') se conserva como red de seguridad ante registros anómalos o tiers no catalogados.

10. Experiencia de Usuario y Gobernanza de Acceso (Fase 7 - Cierre de Turno) ​

  1. Tour didáctico de bienvenida:

    • Descripción: Tarjetas pequeñas con navegación siguiente/anterior/omitir recorriendo los módulos al iniciar sesión, explicando sus funciones básicas.
    • Prioridad: Media (Onboarding didáctico post-activación).
    • Alcance planificado: Componente flotante contextual no invasivo para nuevos administradores en su primer inicio de sesión, con estado de completado persistido en localStorage o perfil de usuario.
  2. Cambio de correo para administradores regulares con licencia NO demo:

    • Descripción: Permitir actualizar el correo de acceso sin perder datos del condominio.
    • Prioridad: Media / Operativa (Entrada formalizada complementaria a 9.6).
    • Alcance planificado: Flujo de cambio de correo de acceso para administradores con licencia completa activa, mediante procedimiento atómico en backend (auth.users, licenses, app_users) asegurando continuidad de sesión y preservación total de la información contable y condominal.
  3. Tour didáctico propio para RESIDENTES (D-NUEVA-1):

    • Descripción: Recorrido didáctico guiado con los módulos y vistas específicas del rol residente (Mis Deudas, Comprobantes de Pago, Estado de Cuenta Personal, Directorio/Comunicaciones y perfil), totalmente diferenciado del flujo de administración.
    • Prioridad: Media / UX Residentes.
    • Alcance planificado: Onboarding inicial para residentes al aceptar invitación o iniciar sesión por primera vez, con componente no invasivo y persistencia en su propio perfil/metadata.
  4. Botón (i) informativo contextual y Guía/README por módulo (D-NUEVA-2):

    • Descripción: Botón informativo flotante o en cabecera/pie de cada módulo que despliega un mini-tour contextual exclusivo de dicha sección, con enlace directo para consultar una guía extendida / README integral (a documentarse por el propietario mediante Google CODEWIKI).
    • Prioridad: Media / Autoayuda y Soporte Operativo.
    • Alcance planificado: Integración de ícono informativo (i) en cada vista principal de la administración regular, con mini-guion local de 1-2 pasos y modal/drawer de documentación detallada.
  5. Difusión Multicanal y Exportación Gráfica de Posts en Cartelera (D-NUEVA-3):

    • Descripción: Extensión funcional para el módulo de Cartelera y Comunicaciones:
      • a) Notificación selectiva/masiva por correo electrónico: Opción de despachar el post a todos los correos registrados en el directorio o a una selección de unidades/residentes.
      • b) Descarga gráfica y documental (JPG / PDF): Toda vez publicado el post, brindar al administrador la opción de descargarlo como imagen o documento formateado para difundirlo manualmente por canales externos (WhatsApp, Telegram, carteleras físicas).
    • Prioridad: Media / Comunicaciones y Difusión Comunitaria.
    • Alcance planificado: Generación de plantilla de exportación visual y servicio de despacho por correo reutilizando el motor de invitaciones/estados de cuenta.
  6. Gobernanza de Storage en Cuentas Demo — Cuota Máxima de 3 Documentos en Posts (D-NUEVA-4):

    • Descripción: Para proteger la cuota de almacenamiento en Supabase Storage frente a cuentas de prueba efímeras, restringir la carga de archivos adjuntos en posts y documentos a un límite máximo de 3 archivos en condominios que operen bajo licencia demo.
    • Prioridad: Media / Gobernanza y Costos de Infraestructura.
    • Alcance planificado: Validación proactiva en frontend (con contador informativo visual tipo X de 3 documentos utilizados) y guard RLS / RPC en backend bloqueando subidas adicionales tras alcanzar la cuota demo.
  7. Reducción de peso máximo por documento individual (D-NUEVA-5):

    • Descripción: Reducir el peso máximo permitido por documento individual de 25 MB a 15 MB en la validación de subida.
    • Estado actual (L-1/L-2): Lado cliente IMPLEMENTADO (15 MB en DocumentUploadModal.tsx, communityService.ts en L-1/L-2); lado servidor (validación de peso individual en trigger de storage) queda PENDIENTE.
    • Prioridad: Media / Optimización de Almacenamiento y Red.
    • Alcance remanente: Incorporar validación de peso individual máximo (NEW.metadata->>'size' <= 15 * 1024 * 1024) en el trigger de almacenamiento de Postgres (storage.objects).

Wiki Técnica Oficial — ITECEL ADM