# Cruces GLM Aplicación interna de GomezLee Marketing para centralizar los cruces administrativos. ## Arquitectura - React 19 + Vite + TanStack Router. - Supabase Auth con Google. - Supabase como **fuente de verdad** de usuarios, permisos, formularios y métricas. - RPCs de Supabase para todas las lecturas/mutaciones sensibles. - n8n para los formularios de cruces y el botón **Reportar**. ## Desarrollo local Requisitos: Node.js 22+ y npm. ```bash npm install npm run dev ``` La app usa el subpath `/cruces-glm/`. ## Build ```bash npm run build ``` La salida se genera en `dist/`. ## Variables de entorno ```env VITE_SUPABASE_URL="https://dbit.digitalcompass.agency" VITE_SUPABASE_ANON_KEY="YOUR_SUPABASE_ANON_KEY" VITE_REPORT_WEBHOOK_URL="https://TU-N8N/webhook/cruces-glm-reportar" VITE_DEMO_AUTH="false" ``` ### Google + Supabase real La versión final viene con `VITE_DEMO_AUTH="false"`, por lo que **Continuar con Google** usa directamente Supabase Auth y Google OAuth. El modo demostrativo queda únicamente como opción de emergencia si se cambia explícitamente la variable a `true`. No existe una allowlist de correos dentro del frontend. Después de autenticarse, Cruces GLM consulta la RPC `cruces_glm_get_my_access()` y Supabase decide si el usuario puede entrar y si puede administrar formularios. Para el despliegue bajo `/cruces-glm/`, la URL de retorno de la app es: ```text https://digitalcompass.agency/cruces-glm/ ``` En desarrollo local se usa: ```text http://localhost:5173/cruces-glm/ ``` Ambas deben estar autorizadas en la configuración de redirects de Supabase Auth cuando quieras usar ambos entornos. El callback del proveedor Google hacia Supabase continúa siendo: ```text https://dbit.digitalcompass.agency/auth/v1/callback ``` ## Supabase Ejecuta una vez en SQL Editor: ```text supabase/Cruces_GLM_Supabase_Completo.sql ``` El script deja creados: - `cruces_glm_permissions`: acceso a la app y permiso de administración. - `cruces_glm_forms`: todos los cruces/formularios del Hub. - `cruces_glm_metrics_summary`: totales globales. - `cruces_glm_form_metrics`: métricas por cruce. - `cruces_glm_user_metrics`: métricas por usuario. - `cruces_glm_metric_events`: historial de login/creación/apertura. - RPCs para login, formularios, permisos y consultas de métricas. Las tablas no necesitan acceso directo desde el navegador; el frontend trabaja mediante RPCs protegidas. ## Administración del login desde Supabase Los correos autorizados están en `public.cruces_glm_permissions`. Campos principales: - `is_allowed = true`: puede entrar a Cruces GLM. - `is_allowed = false`: no puede entrar. - `can_manage_forms = true`: ve **Agregar formulario**, Editar y Eliminar. - `can_manage_forms = false`: usa los cruces, pero no administra el catálogo. ### Quitar acceso a una persona ```sql update public.cruces_glm_permissions set is_allowed = false where email = 'correo@gomezleemarketing.com'; ``` ### Volver a darle acceso ```sql update public.cruces_glm_permissions set is_allowed = true where email = 'correo@gomezleemarketing.com'; ``` ### Dar permiso para administrar formularios ```sql update public.cruces_glm_permissions set can_manage_forms = true where email = 'correo@gomezleemarketing.com'; ``` ## Formularios en Supabase En login real, `public.cruces_glm_forms` es la única fuente de verdad de los cruces. Crear, editar, activar/desactivar y eliminar se ejecuta mediante RPCs: - `cruces_glm_get_forms()` - `cruces_glm_get_form(p_form_id)` - `cruces_glm_save_form(...)` - `cruces_glm_delete_form(p_form_id)` - `cruces_glm_record_form_open(p_form_id)` ### Migración automática del localStorage anterior La aplicación conserva una migración de una sola ejecución para evitar perder los formularios que ya hayas creado durante las pruebas. En el **primer inicio de sesión real de un usuario con `can_manage_forms = true`**: 1. La app consulta Supabase. 2. Si `cruces_glm_forms` todavía está vacío, revisa el antiguo `localStorage` (`glm-hub-formularios-v1`). 3. Si encuentra formularios, los guarda en Supabase mediante `cruces_glm_save_form()`. 4. Marca esa migración como completada para no volver a importar elementos eliminados posteriormente. En modo real, después de esa migración, crear/editar/eliminar formularios **ya no escribe la configuración de los cruces en localStorage**. Solo favoritos y usados recientemente permanecen como preferencias locales del navegador. > Si los formularios actuales existen únicamente en un navegador/origen específico (por ejemplo `localhost:5173`), haz el primer login real desde ese mismo navegador/origen antes de limpiar sus datos para que la migración pueda leerlos. ## RPCs de métricas Para un futuro dashboard administrativo quedan listas: - `cruces_glm_get_metrics_summary()` - `cruces_glm_get_form_metrics()` - `cruces_glm_get_user_metrics()` - `cruces_glm_get_recent_events(p_limit)` Solo usuarios con `can_manage_forms = true` pueden ejecutar esas consultas. También quedan preparadas para una futura pantalla de accesos: - `cruces_glm_admin_get_access_list()` - `cruces_glm_admin_save_access(...)` ## Métricas guardadas Supabase registra: - Total histórico de formularios colocados. - Total de formularios abiertos. - Total de logueos. - Aperturas por formulario. - Logueos y aperturas por usuario. - Eventos detallados de login, creación y apertura. Una edición no vuelve a incrementar `total_formularios_colocados`; solamente una creación nueva. ## Reportes de usuario Importa `Cruces_GLM_Reporte_Usuario_n8n.json`, selecciona la credencial Gmail correspondiente y coloca la Production URL del webhook en `VITE_REPORT_WEBHOOK_URL` antes del build de producción. ## Sesión y navegación en producción - La sesión de Supabase se renueva automáticamente antes de que expire. - Cada RPC comprueba que el access token siga vigente; si Supabase responde `JWT expired`, la app renueva el token y repite esa RPC una sola vez. - Al volver a una pestaña que estuvo en segundo plano, la sesión se valida de inmediato. - Un clic normal en **Abrir** mantiene la vista integrada dentro de Cruces GLM. - `Ctrl+click` / `Cmd+click` (y abrir el enlace en otra pestaña desde el navegador) usa directamente la URL real del formulario n8n, evitando rutas SPA que un servidor estático podría responder con 404.