{
"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 = `
|  | 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": []
}