{ "name": "Cruce de Cuentas GLM - Reporte de Usuario Seguro", "nodes": [ { "parameters": { "httpMethod": "POST", "path": "cruce-cuentas-reportar", "responseMode": "responseNode", "options": { "allowedOrigins": "*" } }, "type": "n8n-nodes-base.webhook", "typeVersion": 2.1, "position": [ -1300, 0 ], "id": "81186759-27e6-4ebe-9ac8-ff366beb688a", "name": "Webhook - Reportar" }, { "parameters": { "jsCode": "const body = $json.body ?? {};\nconst clean = (value, max = 5000) => typeof value === 'string' ? value.trim().slice(0, max) : '';\nlet payload = {};\ntry {\n payload = typeof body.payload === 'string' ? JSON.parse(body.payload) : (body.payload ?? body);\n} catch {\n throw new Error('El reporte contiene datos inválidos.');\n}\nconst accessToken = clean(body.access_token ?? payload.access_token, 12000);\nif (!accessToken) throw new Error('Falta sesión Supabase.');\nconst message = clean(payload.message, 5000);\nif (!message) throw new Error('El reporte no contiene descripción.');\nconst country = clean(payload.country, 10).toUpperCase();\nconst countryName = clean(payload.countryName, 120);\nconst section = clean(payload.section, 160);\nconst pageUrl = clean(payload.pageUrl, 1200);\nconst claimedEmail = clean(payload.userEmail, 320).toLowerCase();\nconst claimedName = clean(payload.userName, 200);\nconst submittedAt = clean(payload.submittedAt, 100) || new Date().toISOString();\nconst appSessionId = clean(payload.appSessionId, 250) || `report-${Date.now()}`;\nreturn [{json:{accessToken,auth:`Bearer ${accessToken}`,message,country,countryName,section,pageUrl,claimedEmail,claimedName,submittedAt,appSessionId}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -860, 0 ], "id": "27b7c774-8dfa-445f-afc3-11a93e50f560", "name": "Normalizar reporte" }, { "parameters": { "method": "GET", "url": "https://dbit.digitalcompass.agency/auth/v1/user", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "apikey", "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE" }, { "name": "Authorization", "value": "={{ $json.auth }}" } ] }, "options": { "timeout": 20000 } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ -660, 0 ], "id": "c2e85c6f-8afc-4fb2-b068-0a6493025778", "name": "Supabase - validar JWT", "continueOnFail": true }, { "parameters": { "jsCode": "const req = $node[\"Normalizar reporte\"].json;\nconst u = $json ?? {};\nconst id = String(u.id || '');\nconst email = String(u.email || '').trim().toLowerCase();\nconst jwtValid = Boolean(id && email.endsWith('@gomezleemarketing.com') && (!req.claimedEmail || req.claimedEmail === email));\nreturn [{json:{...req,userId:id,verifiedEmail:email,jwtValid}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -440, 0 ], "id": "05b99e78-b980-43c9-9cf5-3032bd415c1f", "name": "Validar identidad" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "a9aae0ad-df78-43c8-8bee-eea1e1575b5b", "leftValue": "={{ $json.jwtValid }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -220, 0 ], "id": "0766f1f7-f2e8-4145-b341-28aa6df055a3", "name": "JWT válido?" }, { "parameters": { "respondWith": "json", "responseBody": "={{ {ok:false,message:'Sesión inválida.'} }}", "options": { "responseCode": 401 } }, "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.4, "position": [ 0, 240 ], "id": "94e6a9ad-c56c-4668-b10b-ac2a50b2c81e", "name": "Responder 401" }, { "parameters": { "method": "POST", "url": "https://dbit.digitalcompass.agency/rest/v1/rpc/cruce_cuentas_mi_acceso", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "apikey", "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE" }, { "name": "Authorization", "value": "={{ $json.auth }}" }, { "name": "Content-Type", "value": "application/json" } ] }, "sendBody": true, "contentType": "raw", "rawContentType": "application/json", "body": "={{ JSON.stringify({}) }}", "options": { "timeout": 20000 } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 0, -80 ], "id": "6d6eec3a-ccb8-45ad-83e5-d3f383515854", "name": "Supabase - acceso", "continueOnFail": true }, { "parameters": { "jsCode": "const req = $node[\"Validar identidad\"].json;\nconst access = Array.isArray($json) ? ($json[0] ?? {}) : ($json ?? {});\nconst email = String(access.email || '').trim().toLowerCase();\nconst accessAllowed = Boolean(\n access.ok === true &&\n access.autenticado === true &&\n access.autorizado === true &&\n access.activo === true &&\n access.acceso_app === true &&\n (!email || email === req.verifiedEmail)\n);\nconst fullName = String(access.nombre || req.claimedName || req.verifiedEmail).trim();\nreturn [{json:{...req,accessAllowed,fullName}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 220, -80 ], "id": "ef8bb308-ff0f-46c9-ae6e-aa42d1b73f18", "name": "Validar acceso" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "69a74499-ad7d-4093-9921-133166609367", "leftValue": "={{ $json.accessAllowed }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ 440, -80 ], "id": "a52dcf62-a04e-4aa2-bbb1-bca89d4bffbe", "name": "Acceso permitido?" }, { "parameters": { "respondWith": "json", "responseBody": "={{ {ok:false,message:'No tienes acceso activo a Cruce de Cuentas GLM.'} }}", "options": { "responseCode": 403 } }, "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.4, "position": [ 660, 220 ], "id": "39556e33-18ff-4bd8-a488-50082d26f3f7", "name": "Responder 403" }, { "parameters": { "jsCode": "const x = $node[\"Validar acceso\"].json;\nconst esc = v => String(v ?? '').replace(/&/g,'&').replace(//g,'>').replace(/\"/g,'"').replace(/'/g,''');\nlet date = x.submittedAt;\ntry {\n date = new Intl.DateTimeFormat('es-DO',{dateStyle:'long',timeStyle:'short',timeZone:'America/Santo_Domingo'}).format(new Date(x.submittedAt));\n} catch {}\nconst countryLabel = x.countryName || x.country || 'No especificado';\nconst sectionLabel = x.section || 'No especificada';\nconst pageLabel = x.pageUrl || 'No especificada';\nconst html = `
\"GomezLee
CRUCE DE CUENTAS GLM · REPORTE DE USUARIO

Nuevo reporte recibido

Usuario${esc(x.fullName)}
Correo${esc(x.verifiedEmail)}
País${esc(countryLabel)}
Sección${esc(sectionLabel)}
Fecha${esc(date)}
Página${esc(pageLabel)}
DESCRIPCIÓN DEL REPORTE
${esc(x.message).replace(/\\n/g,'
')}
CONFIDENCIAL — Uso interno GomezLee Marketing · Mensaje generado automáticamente desde Cruce de Cuentas GLM.
`;\nreturn [{json:{...x,to:'iaracena@gomezleemarketing.com',subject:`[Cruce de Cuentas GLM] Reporte de usuario - ${x.fullName}`,html}}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 660, -120 ], "id": "7a5486b4-6f39-47e8-b09a-ce1ad24f26b5", "name": "Preparar correo GLM" }, { "parameters": { "sendTo": "={{ $json.to }}", "subject": "={{ $json.subject }}", "emailType": "html", "message": "={{ $json.html }}", "options": { "appendAttribution": false, "senderName": "Cruce de Cuentas GLM" } }, "type": "n8n-nodes-base.gmail", "typeVersion": 2.1, "position": [ 880, -120 ], "id": "09b4ac16-81d2-42c2-bda7-8f39b8ab418a", "name": "Enviar a Isaac", "credentials": { "gmailOAuth2": { "id": "UDcO1FLJqA453V2D", "name": "Gmail account 3" } } }, { "parameters": { "respondWith": "json", "responseBody": "={{ {ok:true,message:'Reporte enviado correctamente.'} }}", "options": { "responseCode": 200 } }, "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.4, "position": [ 1320, -120 ], "id": "de604d57-2d1f-44af-9342-d886166cb9fd", "name": "Responder OK" } ], "connections": { "Webhook - Reportar": { "main": [ [ { "node": "Normalizar reporte", "type": "main", "index": 0 } ] ] }, "Normalizar reporte": { "main": [ [ { "node": "Supabase - validar JWT", "type": "main", "index": 0 } ] ] }, "Supabase - validar JWT": { "main": [ [ { "node": "Validar identidad", "type": "main", "index": 0 } ] ] }, "Validar identidad": { "main": [ [ { "node": "JWT válido?", "type": "main", "index": 0 } ] ] }, "JWT válido?": { "main": [ [ { "node": "Supabase - acceso", "type": "main", "index": 0 } ], [ { "node": "Responder 401", "type": "main", "index": 0 } ] ] }, "Supabase - acceso": { "main": [ [ { "node": "Validar acceso", "type": "main", "index": 0 } ] ] }, "Validar acceso": { "main": [ [ { "node": "Acceso permitido?", "type": "main", "index": 0 } ] ] }, "Acceso permitido?": { "main": [ [ { "node": "Preparar correo GLM", "type": "main", "index": 0 } ], [ { "node": "Responder 403", "type": "main", "index": 0 } ] ] }, "Preparar correo GLM": { "main": [ [ { "node": "Enviar a Isaac", "type": "main", "index": 0 } ] ] }, "Enviar a Isaac": { "main": [ [ { "node": "Responder OK", "type": "main", "index": 0 } ] ] } }, "pinData": {}, "settings": { "executionOrder": "v1" }, "active": false, "meta": { "templateCredsSetupCompleted": false }, "tags": [] }