GLM Hub Portal interno de GomezLee Marketing para centralizar las aplicaciones corporativas, administrar el catálogo compartido y gestionar solicitudes de acceso mediante Supabase, n8n y autenticación con Google. INFORMACIÓN GENERAL Campo Detalle Proyecto GLM Hub Área IT / Corporativo Estado Listo para producción Developer principal Isaac Aracena IT Manager Luis Matos Product Owner Máximo Gómez Fecha de inicio 2026-07-22 Fecha de cierre 2026-07-29 Ciclo Shape Up No definido en el repositorio Board de ejecución Pendiente de enlazar PRD del proyecto Pendiente de enlazar Repositorio https://git.digitalcompass.agency/Isaac_Aracena/glm-hub URL de producción https://home.digitalcompass.agency/ OBJETIVO Problema que resuelve Las aplicaciones internas de GomezLee Marketing estaban distribuidas en diferentes enlaces y dependían de comunicación manual para que los colaboradores pudieran encontrarlas, identificar cuál necesitaban y solicitar acceso. Además, no existía un catálogo central compartido que pudiera ser mantenido por administradores sin modificar el código. Solución implementada GLM Hub centraliza los portales corporativos en una sola interfaz, permite que los administradores creen y mantengan el catálogo desde la aplicación, muestra a todos los usuarios autorizados las mismas aplicaciones publicadas, conserva favoritos y accesos recientes por usuario, genera íconos con IA y gestiona solicitudes de acceso mediante aprobaciones por correo. Usuarios / Beneficiarios Colaboradores autorizados de GomezLee Marketing. Administradores del catálogo de aplicaciones. Equipo de IT Support que recibe las decisiones de acceso. Desarrolladores responsables de administrar los permisos dentro de cada aplicación individual. ARQUITECTURA Diagrama de flujo Usuario | v Frontend React + Vite | +--> Supabase Auth (Google OAuth) | +--> Supabase Postgres + RLS + Realtime | |-- Usuarios autorizados y roles | |-- Catálogo compartido | |-- Favoritos y recientes por usuario | `-- Solicitudes y decisiones de acceso | +--> Supabase Storage | `-- Íconos del catálogo | +--> Webhook n8n: generación de ícono | `-- Validación de administrador -> Gemini -> imagen | `--> Webhook n8n: solicitud de acceso `-- Supabase -> Gmail -> aprobación/rechazo -> IT Support Stack tecnológico Componente Tecnología Propósito Frontend React 19 + TypeScript Interfaz del Hub Build Vite 6 Desarrollo, validación y compilación UI CSS + Lucide React Estilos e iconografía Autenticación Supabase Auth + Google OAuth Inicio de sesión corporativo Base de datos Supabase / PostgreSQL Catálogo, usuarios, favoritos, recientes y solicitudes Seguridad Row Level Security Control de lectura y escritura según usuario y rol Archivos Supabase Storage Almacenamiento de íconos Sincronización Supabase Realtime Actualización del catálogo en sesiones abiertas Automatización n8n Orquestación de generación de íconos y solicitudes IA Google Gemini Generación de íconos para nuevas aplicaciones Notificaciones Gmail OAuth Envío de solicitudes y decisiones por correo Repositorio Gitea Control de versiones Hosting Servidor web GLM Publicación del contenido de dist/ Integraciones externas Sistema Tipo de integración Datos que fluyen Google OAuth OAuth 2.0 mediante Supabase Identidad, correo, nombre y foto del usuario Supabase SDK, REST, RPC, Storage y Realtime Usuarios, roles, catálogo, íconos, favoritos, recientes y solicitudes n8n Webhooks HTTPS Solicitudes del frontend y respuestas procesadas Google Gemini Credencial nativa de n8n Nombre y descripción de la app; devuelve una imagen Gmail OAuth mediante n8n Correos de aprobación y notificación a IT Support REGLAS DE NEGOCIO Solo pueden iniciar sesión usuarios activos registrados en glm_hub_authorized_users y con correo del dominio @gomezleemarketing.com. Los roles válidos son admin y member. Los administradores autorizados son: José Leopoldo Gómez — jgomez@gomezleemarketing.com Isaac Aracena — iaracena@gomezleemarketing.com Eidan Then — ethen@gomezleemarketing.com Máximo Gómez — mgomez@gomezleemarketing.com Luis Matos — lmatos@gomezleemarketing.com Solo los administradores pueden abrir el apartado Administrar, crear, editar, publicar, ocultar o eliminar aplicaciones. Todos los usuarios autorizados ven el mismo catálogo de aplicaciones publicadas. El Hub no controla el acceso interno de cada aplicación; ese permiso se administra desde el login o backend de cada portal. Las categorías disponibles son Administración, Recursos Humanos y CDC. No se puede publicar una aplicación sin ícono. El nombre debe tener entre 2 y 60 caracteres y la descripción un máximo de 180 caracteres. Los íconos admitidos son PNG, JPG o WebP y no pueden superar 1 MB. Los favoritos y accesos recientes son personales y no afectan la vista de otros usuarios. Los favoritos se ordenan antes que las demás aplicaciones antes de aplicar la paginación. Los usuarios normales pueden solicitar acceso a cualquier aplicación publicada. No se permite una segunda solicitud pendiente del mismo usuario para la misma aplicación. Las solicitudes se envían individualmente a Isaac Aracena, José Leopoldo Gómez y Máximo Gómez. La primera decisión registrada gana; cualquier intento posterior queda bloqueado y no cambia el resultado. Después de aprobar o rechazar, IT Support recibe un correo con el solicitante, la aplicación, el resultado y la persona que decidió. La generación de íconos con IA solo está disponible para administradores y requiere nombre y descripción. CONFIGURACIÓN Y SETUP Prerrequisitos Node.js y npm instalados. Acceso al proyecto Supabase de GLM. Proveedor Google habilitado en Supabase Auth. Instancia de n8n operativa. Credencial de Google Gemini configurada en n8n. Credencial Gmail OAuth configurada en n8n. Acceso al servidor o subdominio de producción. Variables de entorno Crear .env a partir de .env.example: Variable Descripción Dónde se obtiene VITE_SUPABASE_URL URL pública del proyecto Supabase Supabase / configuración del proyecto VITE_SUPABASE_ANON_KEY Clave pública anon para el frontend Supabase / API Keys VITE_ICON_GENERATOR_WEBHOOK_URL Webhook de n8n para generar íconos Workflow de generación de íconos VITE_ACCESS_REQUEST_WEBHOOK_URL Webhook de n8n para solicitudes de acceso Workflow de solicitudes y aprobación Nunca commitear credenciales reales. El archivo .env, las claves service_role, los tokens y las credenciales de Gmail o Gemini deben mantenerse fuera del repositorio. Esquema de base de datos Ejecutar en Supabase SQL Editor: SUPABASE-GLM-HUB-COMPLETO.sql El script crea o actualiza: glm_hub_authorized_users glm_hub_apps glm_hub_favorites glm_hub_recent_apps glm_hub_access_requests glm_hub_access_request_approvers Funciones RPC para validación, solicitudes y decisiones. Bucket público glm-hub-icons. Políticas RLS. Publicación Realtime del catálogo. Workflows de n8n Importar y configurar: n8n/GLM-Hub-Generar-Icono-Gemini-Nodo-Nativo.json n8n/GLM-Hub-Solicitudes-Acceso-Aprobacion.json Configuración necesaria: Seleccionar una credencial de Gemini en Generate an image. Seleccionar una credencial Gmail válida en los dos nodos de envío. Usar la clave anon donde la llamada representa al usuario autenticado. Usar service_role únicamente en los nodos internos que emiten tokens o registran decisiones. Mantener las claves únicamente en n8n; nunca enviarlas al navegador. En producción, Enviar solicitud a aprobadores debe usar ={{ $json.sendTo }}. En producción, Enviar decisión a IT Support debe enviar a itsupport@gomezleemarketing.com. Instalación local git clone https://git.digitalcompass.agency/Isaac_Aracena/glm-hub.git cd glm-hub npm install cp .env.example .env # Editar .env con los valores reales npm run typecheck npm run dev En PowerShell, puede usarse: Copy-Item .env.example .env Build npm run build La compilación se genera en: dist/ Deploy El proyecto se publica en la raíz de un subdominio, por lo que vite.config.ts debe permanecer sin una propiedad base personalizada. export default defineConfig({ plugins: [react()], }); Copiar el contenido de dist/ directamente al Document Root del subdominio: DocumentRoot/ |-- index.html |-- assets/ |-- glm-logo.png `-- archivos de favicon No colocar una carpeta dist dentro del Document Root. Para probar el mismo build con XAMPP, usar un VirtualHost que apunte directamente a la carpeta donde se copió el contenido de dist/. Servirlo como http://localhost/glm-hub/ sin configurar base hará que los assets se busquen desde una ruta incorrecta. Redirects de autenticación Registrar en Supabase las URLs permitidas que correspondan al entorno: https://home.digitalcompass.agency/ http://localhost:4173/ Si se utiliza un VirtualHost local, registrar también su URL completa. CÓMO FUNCIONA Flujo general El usuario entra al Hub y selecciona Continuar con Google. Supabase Auth valida la cuenta de Google. El frontend consulta glm_hub_authorized_users para confirmar que el usuario esté activo y conocer su rol. El catálogo compartido se carga desde glm_hub_apps. Los favoritos y recientes se cargan para el usuario autenticado. Supabase Realtime mantiene el catálogo actualizado en sesiones abiertas. Los administradores pueden crear, editar, ocultar o eliminar aplicaciones. Los usuarios normales pueden solicitar acceso a una aplicación publicada. Generación de íconos El administrador completa nombre y descripción. El frontend llama el webhook glm-hub-generar-icono. n8n valida el JWT y confirma el rol de administrador. Gemini genera una imagen cuadrada sin texto. n8n devuelve el archivo binario al frontend. El ícono se previsualiza y se guarda en Supabase Storage al publicar. Solicitud de acceso El usuario selecciona un área y una aplicación publicada. n8n registra la solicitud en Supabase. Supabase emite un token único para cada aprobador. Gmail envía un correo individual a cada aprobador. El aprobador confirma Aceptar o Rechazar. Supabase registra atómicamente la primera decisión. n8n envía el resultado a itsupport@gomezleemarketing.com. Cualquier clic posterior muestra que la solicitud ya fue atendida. Triggers Trigger Frecuencia Descripción Google OAuth Bajo demanda Inicio de sesión de un usuario Realtime de Supabase En tiempo real Actualización del catálogo compartido POST /webhook/glm-hub-generar-icono Bajo demanda Generación de ícono con Gemini POST /webhook/glm-hub-solicitar-acceso Bajo demanda Registro y envío de solicitud GET /webhook/glm-hub-confirmar-solicitud Bajo demanda Pantalla de confirmación de decisión POST /webhook/glm-hub-resolver-solicitud Bajo demanda Registro de aprobación o rechazo TESTING Casos de prueba mínimos Caso Input Output esperado Estado Login autorizado Usuario activo del dominio GLM Acceso al Hub Validado Usuario inactivo Registro con is_active = false Acceso denegado Validado Rol administrador Cuenta con role = admin Muestra Administrar Validado Rol usuario Cuenta con role = member No muestra controles administrativos Validado Catálogo compartido Admin publica una app Todos ven la misma app Validado en Supabase; realizar smoke test final con segundo usuario Publicación sin ícono Formulario sin archivo Publicación bloqueada Validado Generar ícono Nombre y descripción válidos Imagen generada y previsualizada Validado Cambio de pestaña Salir y regresar al navegador Mantiene vista y formulario Validado Favoritos Marcar una aplicación Se guarda solo para el usuario Validado Paginación Más de 10 aplicaciones Navegación compacta y usable Implementado Solicitud de acceso Usuario y app válidos Correos enviados a aprobadores Validado Primera decisión Un aprobador acepta o rechaza Registra resultado y notifica a IT Validado Segundo clic Otro aprobador intenta decidir No modifica la primera decisión Validado Build de producción npm run build Genera dist/ sin errores Validado ERRORES CONOCIDOS Y TROUBLESHOOTING Error Causa probable Solución Pantalla en blanco en XAMPP El build de raíz se sirve dentro de /glm-hub/ Usar VirtualHost o npm run preview; no agregar base para producción en subdominio raíz Assets con 404 index.html apunta a /assets/ pero el servidor usa una subcarpeta Servir el contenido de dist/ desde el Document Root Google regresa a una URL incorrecta Redirect no autorizado Agregar la URL exacta en Supabase Auth Usuario no ve Administrar Rol desactualizado o sesión antigua Confirmar role = admin, cerrar sesión y volver a entrar HTTP 401 en n8n JWT vencido o encabezado incorrecto Usar el token dinámico enviado por el frontend HTTP 403 en una RPC Clave o permisos incorrectos Verificar si el nodo requiere anon, JWT o service_role Output vacío de HTTP Request Respuesta configurada como archivo o envuelta con headers Usar Response Format: JSON y revisar la estructura esperada Solicitud duplicada Ya existe una solicitud pendiente Atender o eliminar la solicitud anterior No se genera ícono Credencial Gemini no seleccionada Revisar el nodo Generate an image Ícono rechazado Archivo mayor a 1 MB o MIME no permitido Convertir a PNG/JPG/WebP y reducir tamaño MONITOREO n8n Executions: revisar ejecuciones fallidas o detenidas en ramas de error. Supabase Logs: revisar errores de Auth, REST, RLS y Storage. Solicitudes pendientes: consultar glm_hub_access_requests filtrando status = 'pending'. Correos: confirmar entregas desde la cuenta Gmail conectada a n8n. Output normal: catálogo cargado, sesión persistente, Realtime activo y webhooks respondiendo correctamente. Alertas automáticas: no configuradas actualmente; el monitoreo se realiza desde n8n y Supabase. Consulta rápida: select requester_name, requester_email, app_name, status, decided_by_name, decided_by_email, created_at, decided_at from public.glm_hub_access_requests order by created_at desc; ESTRUCTURA DEL REPOSITORIO glm-hub/ |-- README.md |-- .env.example |-- index.html |-- package.json |-- package-lock.json |-- tsconfig.json |-- vite.config.ts |-- SUPABASE-GLM-HUB-COMPLETO.sql |-- dist/ | |-- index.html | `-- assets/ |-- n8n/ | |-- GLM-Hub-Generar-Icono-Gemini-Nodo-Nativo.json | `-- GLM-Hub-Solicitudes-Acceso-Aprobacion.json |-- public/ | `-- logos y favicons |-- scripts/ |-- src/ | |-- components/ | |-- lib/ | |-- App.tsx | `-- main.tsx `-- documentación técnica adicional node_modules/ y .env nunca deben subirse al repositorio. En el flujo actual de despliegue manual, dist/ puede mantenerse versionado para entregar una compilación ya validada. CHANGELOG 2026-07-29 — v1.0.0 Catálogo compartido en Supabase. Autenticación con Google y control de roles. Favoritos y accesos recientes por usuario. Administración completa del catálogo. Realtime para aplicaciones publicadas. Generación de íconos con Gemini mediante n8n. Solicitudes de acceso con aprobación o rechazo por correo. Primera decisión protegida de forma atómica. Paginación automática en acceso rápido, catálogo y administración. Build preparado para la raíz de un subdominio. 2026-07-28 — v0.9.0 Persistencia de pantalla al cambiar de pestaña. Correcciones de CORS y JWT para generación de íconos. Integración con el nodo nativo de Gemini en n8n. 2026-07-22 — v0.1.0 Inicio del proyecto y diseño inicial del portal. DECISIONS LOG DEC-001 — Catálogo compartido en Supabase Fecha: 2026-07-25 Contexto: El catálogo guardado en localStorage solo existía en el navegador del administrador. Opciones consideradas: localStorage vs. base de datos compartida. Decisión: Guardar aplicaciones en Supabase. Razón: Todos los usuarios deben ver el mismo catálogo y los administradores deben actualizarlo sin modificar código. DEC-002 — Acceso individual fuera del Hub Fecha: 2026-07-29 Contexto: Se evaluó controlar permisos por aplicación desde el Hub. Opciones consideradas: Permisos centralizados en el Hub vs. permisos en cada aplicación. Decisión: El Hub muestra todas las aplicaciones publicadas y cada aplicación controla su propio acceso. Razón: Evita duplicar reglas y mantiene la responsabilidad de seguridad en cada portal. DEC-003 — Favoritos y recientes por usuario Fecha: 2026-07-28 Contexto: El catálogo debe ser compartido, pero la personalización no. Decisión: Guardar favoritos y accesos recientes asociados al usuario autenticado. Razón: Cada persona conserva su propia experiencia sin afectar a los demás. DEC-004 — Generación de íconos desde n8n Fecha: 2026-07-28 Contexto: La clave de Gemini no puede exponerse en el frontend. Decisión: Usar un webhook de n8n y el nodo nativo Generate an image. Razón: Mantiene las credenciales fuera del navegador y permite validar el rol administrativo. DEC-005 — Primera decisión gana Fecha: 2026-07-29 Contexto: Tres aprobadores reciben botones para la misma solicitud. Decisión: Registrar atómicamente la primera aprobación o rechazo y bloquear las siguientes. Razón: Evita decisiones contradictorias y correos duplicados a IT Support. DEC-006 — Build sin base personalizado Fecha: 2026-07-29 Contexto: La aplicación se desplegará en la raíz de un subdominio. Decisión: No configurar base: '/glm-hub/' en Vite. Razón: Los assets deben resolverse desde / en producción. CONTACTOS DEL PROYECTO Rol Nombre Contacto Product Owner Máximo Gómez mgomez@gomezleemarketing.com IT Manager Luis Matos lmatos@gomezleemarketing.com Developer principal Isaac Aracena iaracena@gomezleemarketing.com Administrador técnico Eidan Then ethen@gomezleemarketing.com Soporte GLM IT Support itsupport@gomezleemarketing.com DEFINITION OF DONE Catálogo compartido en Supabase. Autenticación con Google operativa. Roles de administrador y usuario aplicados. RLS configurado para tablas y Storage. Favoritos y recientes por usuario. Paginación implementada. Generación de íconos con IA operativa. Workflows de n8n exportados en /n8n. SQL completo incluido en el repositorio. Variables documentadas en .env.example. Solicitudes de acceso y primera decisión validadas. Código y build listos para Gitea. Probado localmente y con webhooks reales. Ejecutar smoke test final con un segundo usuario en producción. Enlazar el board y el PRD oficiales. Registrar validación final de Luis Matos. Registrar aprobación final de Máximo Gómez. Documento mantenido por el equipo GLM IT.