Assessment Funnel · Documento di Bordo · Fase 3 di 7

Relay + API GHL — collegare il funnel a GHL

Il funnel calcola già tutto lato browser (invariato). Qui costruisci il piccolo endpoint che prende quel risultato e lo scrive davvero su GHL — senza mai esporre la chiave segreta nel browser.

Ruolo: IT Tempo stimato: 3-6 ore Dipende da: Fase 1 per i valori reali (token/ID campi), ma il codice si scrive anche prima con placeholder
Aggiornamento — il relay esiste già. 05_Template/functions/api/assessment-submit.js è nel repo, con le 5 pagine reali già collegate (start.html, survey.html, outcome.html, apply.html, thank-you-apply.html) tramite fetch(), fallback su localStorage se la chiamata fallisce. Resta da fare solo lo step 3 sotto: impostare le variabili d'ambiente reali su Cloudflare Pages (token, location ID, i 23 ID campo da Fase 1) — senza quelle il codice esiste ma non scrive ancora su GHL.
Come si usa questa pagina per un nuovo cliente: il prompt allo step 2 resta valido per rigenerare l'endpoint da zero (es. in un repo nuovo) — leggi i 4 step, copialo così com'è in Claude Code, non riscriverlo. Per Doc Marketing questo passaggio è già stato fatto: vai direttamente allo step 3.
01
Decidi dove gira il relay

Dipende da dove sarà hostato il funnel (deciso in Fase 6, ma puoi anticipare la scelta qui). Le opzioni compatibili con hosting statico su Cloudflare Pages:

  • Cloudflare Pages Functions (consigliato se hosti su Cloudflare, come da decisione già presa per questo progetto) — il relay vive in una cartella /functions dentro lo stesso repo del sito
  • Vercel Function o Netlify Function, se il funnel finisse per essere hostato lì invece
02
Copia il prompt qui sotto in Claude Code

Non aggiungerci nulla di tuo sull'ID dei campi o gli scope del token — quelli li fornisci tu come variabili quando li hai (Fase 1), il prompt li lascia esplicitamente come placeholder da configurare.

Prompt — Genera l'endpoint relay

Genera un endpoint serverless Cloudflare Pages Function (cartella /functions, es. /functions/api/assessment-submit.js) per il mio Assessment Funnel.

━━ COSA RICEVE ━━
Riceve via POST il payload JSON già calcolato dal survey lato browser (non ricalcolare nulla, è già tutto pronto):
{
  overall: number,
  pillars: { "Posizionamento Strategico": number, "Funnel di Vendita": number, "Gestione Advertising": number, "Tracking & Analisi Dati": number, "Ottimizzazione Continua": number, "Direzione Operativa": number },
  profile: { code, name, risk, secondaryCode, secondaryName, secondaryRisk },
  positiveAnswers: number,
  contact: { name, email, phone },
  eventType: "assessment_completed" | "apply_clicked" | "apply_submitted" | "apply_ty_viewed"
}

━━ VALIDAZIONE (obbligatoria, prima di chiamare GHL) ━━
- profile.code deve essere uno tra "P1_FOUNDATIONS","P2_ACQUISITION","P3_FOUNDER","P4_SCALE" — se manca o è diverso, rispondi 400 e NON chiamare GHL.
- contact.email deve essere presente e valida — se manca, rispondi 400.
- Se eventType non è uno dei 4 valori sopra, rispondi 400.

━━ COSA FA, IN ORDINE ━━
1. Mappa profile.code al numero Outcome: P1_FOUNDATIONS=1, P2_ACQUISITION=2, P3_FOUNDER=3, P4_SCALE=4.
2. Se eventType === "assessment_completed":
   a. Upsert del contatto su GHL (match su email) con TUTTI i 23 custom field mappati sui loro ID reali (leggili da variabili d'ambiente, una per campo, io te li fornirò — non inventarli).
   b. Rimuovi dal contatto gli eventuali tag "DM | Profile | P1 Foundations / P2 Acquisition / P3 Founder / P4 Scale" già presenti (prova a rimuovere tutti e 4, GHL non si lamenta se un tag non c'è).
   c. Aggiungi il tag "DM | Assessment | Completed" e il tag "DM | Profile | ..." corrispondente al profile.code (non "DM | Outcome | N" — nome superato, mai usato nel codice reale, vedi architecture.html).
3. Se eventType === "apply_clicked": aggiorna il campo dm_apply_status a "clicked" e aggiungi il tag "DM | Apply | Clicked". Nessun altro campo da toccare.
4. Se eventType === "apply_submitted": aggiorna dm_apply_status a "submitted", dm_apply_submitted_at a ora corrente (ISO), dm_apply_source a "assessment_outcome", aggiungi il tag "DM | Apply | Submitted".
5. Se eventType === "apply_ty_viewed": aggiorna dm_apply_status a "thank_you_viewed", aggiungi il tag "DM | Apply | TY Viewed".

━━ AUTENTICAZIONE ━━
Usa un Bearer token (GHL Private Integration Token) e un Location ID, letti da variabili d'ambiente (GHL_PRIVATE_TOKEN, GHL_LOCATION_ID) — mai hardcoded nel codice, mai loggati. L'endpoint e la versione esatti dell'API GHL vanno verificati sulla documentazione ufficiale aggiornata al momento in cui scrivi il codice: non inventare path o versioni, cercali o chiedimeli se non sei sicuro.

━━ GESTIONE ERRORI ━━
Se una qualunque chiamata a GHL fallisce (timeout, 4xx, 5xx), rispondi al chiamante con un errore chiaro (status + messaggio), senza far crashare la function. Il browser ha già un fallback su localStorage se questa chiamata fallisce — non serve altro retry lato server.

━━ COSA NON FARE ━━
- Non ricalcolare punteggi o profilo: sono già nel payload.
- Non inventare ID di custom field, scope del token, o endpoint API: lasciali come TODO/variabili chiaramente commentate.
- Non loggare email, telefono o il token in chiaro nei log della function.

Alla fine, dimmi in una riga dove devo impostare le variabili d'ambiente su Cloudflare Pages, e mostrami un esempio di payload di test per ciascuno dei 4 eventType.
03
Configura le variabili d'ambiente e collega il submit

Su Cloudflare Pages: Settings → Environment variables del progetto. Aggiungi GHL_PRIVATE_TOKEN, GHL_LOCATION_ID, e una variabile per ciascuno dei 23 ID campo (es. GHL_FIELD_DM_PROFILE_CODE=1c0f — valore illustrativo, non un ID reale osservato) — i valori vengono dalla Fase 1.

Nel JS di start.html/survey.html (fine Q40) e in apply.html/thank-you-apply.html, dopo il salvataggio in localStorage, aggiungi una fetch() verso /api/assessment-submit con il payload giusto per ciascun evento. Non rimuovere il salvataggio in localStorage — resta come rete di sicurezza se la chiamata fallisce.

04
Test con i payload di esempio

Usa gli esempi di payload che Claude Code ti ha dato al punto 2 per testare i 4 eventType uno per uno (con Postman, curl, o direttamente compilando l'assessment vero) prima di passare alla Fase 5.

Checklist di chiusura Fase 3