# Déploiement Cloudflare Worker — Double opt-in MVA via Resend

Ce Worker gère le flow double opt-in du formulaire de contact :

1. **`requestVerification`** — génère un token, stocke les données du formulaire en KV, envoie un email de validation via Resend.
2. **`verifyToken`** — appelé quand le client clique sur le lien dans l'email. Crée le contact dans HubSpot (avec une référence à la volée) et envoie le welcome email avec la référence + l'adresse du dépôt Paris.

Le Worker est aussi un proxy HubSpot pour la vérification de doublon par email et la génération du prochain numéro de référence séquentiel.

L'email de bienvenue contient le **numéro de référence client** ET **l'adresse du dépôt à Paris**. Ces infos ne sont **jamais** envoyées avant validation de l'email — protection contre les bots et les expéditions de cartons vides.

---

## Étapes de déploiement (Phase D du plan WordPress → static)

### 1. Mettre à jour le code du Worker

Préférer `wrangler` :

```bash
cd cloudflare-worker
wrangler deploy
```

Ou via le dashboard Cloudflare :

1. Aller sur https://dash.cloudflare.com/
2. Workers & Pages → cliquer sur **`mva-hubspot-proxy`**
3. Onglet **Modifier le code** (ou *Quick edit*)
4. Tout sélectionner et remplacer par le contenu de `cloudflare-worker/hubspot-proxy.js`
5. Cliquer **Déployer / Save and deploy**

### 2. Secrets

Dans **Paramètres → Variables et secrets** (ou via CLI : `wrangler secret put <name>`) :

| Nom | Valeur |
|-----|--------|
| `HUBSPOT_TOKEN`        | `pat-eu1-...` (scope read+write contacts) |
| `RESEND_API_KEY`       | `re_...` (compte Resend partagé avec m4s-auth) |
| `RESEND_FROM_EMAIL`    | adresse expéditrice (domaine vérifié chez Resend) |
| `RESEND_FROM_NAME`     | nom affiché à l'expéditeur (ex: `MVA Global Fret`) |
| `PARIS_DEPOT_ADDRESS`  | **Ton adresse exacte à Paris** (rue, code postal, ville, étage, nom à indiquer sur le carton…) |
| `TURNSTILE_SECRET`     | secret Cloudflare Turnstile (anti-bot) |
| `SITE_URL`             | base URL du site (ex: `https://mva-globalfret.com`) |

> `PARIS_DEPOT_ADDRESS` est l'info la plus sensible — c'est l'adresse à protéger. Elle ne quitte jamais Cloudflare/Resend et n'arrive au client que dans le mail de bienvenue, qui n'est envoyé qu'aux contacts qui ont confirmé leur email.

### 3. Stockage KV (idempotence — empêche de spammer le welcome)

Dans **Paramètres → Stockage et bases de données → Bindings KV** :

1. Cliquer **Ajouter un binding**
2. Variable name : **`WELCOME_KV`**
3. Namespace : **Créer** un nouveau namespace nommé `mva-welcome-tracker`
4. Sauvegarder

Si déployé via `wrangler` : mettre à jour `wrangler.toml` avec l'ID du namespace KV créé (remplacer `REPLACE_AT_DEPLOY_TIME`).

### 4. Vérifier le scope HubSpot

Le token HubSpot doit avoir :

- `crm.objects.contacts.read`
- `crm.objects.contacts.write`
- `crm.lists.read`

Si tu obtiens des erreurs 403, regénère le token sur https://app-eu1.hubspot.com/private-apps/148163754/

### 5. Resend — vérifier le domaine expéditeur

Le compte Resend (partagé avec m4s-auth) doit avoir le domaine de `RESEND_FROM_EMAIL` vérifié (DNS records SPF + DKIM). Voir https://resend.com/domains.

---

## Test manuel

Une fois tout déployé, tu peux tester le flow `requestVerification` (token de test, ne pas réutiliser en prod) :

```bash
curl -X POST https://mva-hubspot-proxy.<account>.workers.dev \
  -H "Content-Type: application/json" \
  -d '{
    "action": "requestVerification",
    "firstname": "Test",
    "lastname": "User",
    "email": "test@example.com",
    "phone": "+33000000000",
    "address": "Test address",
    "turnstile_token": "<token from Turnstile widget>"
  }'
```

Réponse attendue :
```json
{ "ok": true }
```

Le client reçoit alors un email de validation. En cliquant sur le lien, il déclenche `verifyToken`, qui crée le contact dans HubSpot et envoie le welcome email avec la référence + l'adresse Paris.

---

## Logs en production

Cloudflare → ton Worker → **Logs (en temps réel)** : tu verras chaque exécution du Worker.

---

## En cas de problème

| Symptôme | Cause probable | Fix |
|---|---|---|
| `Resend 401: API key invalid` | Mauvaise valeur dans `RESEND_API_KEY` | Re-vérifier la clé sur https://resend.com/api-keys |
| `Resend 422: domain is not verified` | Domaine de `RESEND_FROM_EMAIL` pas vérifié | Vérifier le domaine sur https://resend.com/domains |
| `HubSpot 403` | Token n'a pas le scope write | Regénérer token avec scope `contacts.write` |
| `HubSpot 401` | Token invalide / expiré | Regénérer un Private App token |
| `KV not bound` | Binding `WELCOME_KV` pas créé | Vérifier *Storage & Databases → KV bindings* |
| `Turnstile validation failed` | Secret côté Worker ne match pas la sitekey côté front | Re-vérifier `TURNSTILE_SECRET` et la sitekey HTML |

---

## Architecture

```
┌──────────────────────────────────────────────────────────────────┐
│  1. User remplit le formulaire sur contact.html                  │
│     ↓                                                             │
│  2. form-handler.js → POST action: requestVerification           │
│     ↓                                                             │
│  3. Worker valide Turnstile, génère un token, stocke les         │
│     données du formulaire en KV (TTL 24h), envoie l'email         │
│     de validation via Resend                                      │
│     ↓                                                             │
│     ─────── User clique sur « Confirmer » ───────                │
│     ↓                                                             │
│  4. confirmation.html → POST action: verifyToken                 │
│     ↓                                                             │
│  5. Worker récupère les données du KV, génère la prochaine       │
│     référence client, soumet via HubSpot Forms API (= contact     │
│     créé dans le CRM), envoie le welcome email via Resend         │
│     (avec la référence + adresse Paris), marque le token          │
│     consommé en KV (TTL 7j pour idempotence).                     │
│     ↓                                                             │
│  6. Le client reçoit son welcome email avec sa référence ET       │
│     l'adresse de dépôt à Paris.                                  │
└──────────────────────────────────────────────────────────────────┘
```

**Conclusion** : il est impossible pour un bot de récupérer la référence client ou l'adresse Paris sans avoir au préalable un email valide ET cliqué sur le lien de confirmation. Anti-spam blindé.
