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.

S
Description
Portal interno de GomezLee Marketing para centralizar aplicaciones corporativas, gestionar accesos, favoritos, roles y solicitudes mediante Supabase, n8n y autenticación con Google.
Readme 1.1 MiB
Languages
TypeScript 42.5%
PLpgSQL 34%
CSS 20.2%
JavaScript 2.7%
HTML 0.4%
Other 0.2%