Skip to content

ADR: Intégration de la Newsletter avec Loops, Cloudflare Queues et Sanity

ADR: Intégration de la Newsletter avec Loops, Cloudflare Queues et Sanity

Architecture de gestion de la newsletter du prefooter : intégration de Loops (CRM/emailing), Cloudflare Queues (asynchrone) et Sanity (contenus & audit).

  • Statut : Proposé (En attente de validation)
  • Date : 2026-10-26
  • Auteur : Antigravity & Architecture AMN
  • Projet : AMN (amn-blog, amn-studio, amn-services, amn-docs)

1. Contexte et Problématique1/2

Le composant PreFooter.astro de amn-blog contient un formulaire d’inscription à la newsletter. Les textes et libellés sont administrables depuis Sanity via le singleton prefooterSettings, mais le traitement métier de l’inscription était jusqu’ici factice ou non relié à un outil d’emailing dédié.

1. Contexte et Problématique2/2

Le projet AMN repose sur une architecture composable stricte :

  • Couche 01 (Contenu) : Sanity CMS (schémas, textes, modération et piste d’audit).
  • Couche 02 (Présentation) : Astro SSR sur Cloudflare Pages/Workers (UI responsive, micro-animations, Stega clean, accessibilité).
  • Couche 03 (Services & Backend) : Cloudflare Workers, Service Bindings et Cloudflare Queues.

Pour la gestion marketing de l’audience et des emails transactionnels, la plateforme Loops.so (forfait Free) a été retenue avec une clé API dédiée.

Exigences clés :

  1. Fluidité & Performance UI : Réponse utilisateur quasi-instantanée (< 50ms) sans latence réseau liée aux API tierces.
  2. Résilience & Tolérance aux pannes : En cas d’indisponibilité temporaire de Loops ou de Sanity, aucune inscription ne doit être perdue.
  3. Respect de l’architecture composable : Aucun secret ou clé API tierce exposée côté client, tout passe par le backend L3 Cloudflare.
  4. Outillage MCP Loops : Pouvoir interagir avec le compte Loops depuis l’environnement de développement et les agents AI via le Model Context Protocol.

2. Décisions Architecturales

2.1. Plateforme d’Emailing : Loops.so (Plan Free)

Nous intégrons Loops.so comme fournisseur de gestion des contacts, des listes d’attente et des campagnes d’envoi. Les nouveaux inscrits sont enregistrés avec le statut subscribed: true et le groupe utilisateur userGroup: "Newsletter".

2.2. Configuration du Serveur MCP Loops (Résolution Technique)1/3

L’URL distante officielle https://mcp.loops.so implémente exclusivement l’authentification OAuth 2.0 PKCE interactive via navigateur et rejette les clés API statiques (retour HTTP 401 loops rejected token: invalid token).

Décision : Pour permettre aux agents et à l’IDE d’administrer le compte Loops avec la clé API fournie (796e3ae3c6da58a59e14787256ce0507), nous configurons le serveur MCP stdio officiel de la communauté :

2.2. Configuration du Serveur MCP Loops (Résolution Technique)2/3

{
"mcpServers": {
"loops": {
"command": "npx",
"args": ["-y", "loops-mcp-server"],
"env": {
"LOOPS_API_KEY": "796e3ae3c6da58a59e14787256ce0507"
}
}
}
}

2.2. Configuration du Serveur MCP Loops (Résolution Technique)3/3

Ce serveur expose les outils loops_create_contact, loops_find_contact, loops_update_contact, loops_send_event, et loops_list_mailing_lists directement connectés à l’espace d’équipe Loops (“AmCloud”).

2.3. Pipeline Asynchrone Edge via Cloudflare Queues1/2

Pour découpler la réception du formulaire du traitement tiers, nous étendons le flux éprouvé du formulaire de contact :

  1. Frontend (amn-blog) : Le formulaire du prefooter envoie un payload { type: "newsletter", email: "..." } vers /api/submit.
  2. Relais Edge (/api/submit.ts) : Achemine la requête via Service Binding interne vers le Worker form-handler.
  3. Producteur (form-handler) : Valide le schéma Zod (union discriminée contact vs newsletter) et publie immédiatement le message dans la file SUBMISSIONS_QUEUE. Réponse immédiate { success: true, id: "..." } envoyée au navigateur.

2.3. Pipeline Asynchrone Edge via Cloudflare Queues2/2

  1. Consommateur (submission-processor) :
    • Appelle l’API Loops (POST https://app.loops.so/api/v1/contacts/create).
    • Enregistre une trace dans Sanity (_type: "submission", formType: "newsletter", statut processed).
    • En cas d’erreur transitoire (ex: rate limit HTTP 429 ou erreur 5xx), le message est renvoyé en file avec retry exponentiel automatique.

2.4. Couche Contenu Sanity (amn-studio)

  • Le document singleton prefooterSettings conserve la maîtrise éditoriale des textes du formulaire (newsletterTitle, newsletterDescription, newsletterPlaceholder, newsletterButtonLabel) et est complété par les messages d’état (newsletterSuccessMessage, newsletterErrorMessage).
  • Le schéma submission de Sanity est mis à jour pour accepter formType (contact ou newsletter) et rendre name et message optionnels lorsque le type est newsletter.

3. Justification du Choix

Critère Approche Retenue (Queue L3 + Loops + Sanity) Appel Direct Loops depuis Astro
Latence perçue < 50 ms (injection mémoire dans Cloudflare Queue) 300 - 900 ms (dépend du temps de réponse API Loops)
Résilience Maximale : retry automatique en tâche de fond en cas d’incident réseau Faible : échec visible pour l’internaute en cas de timeout Loops
Sécurité Clé API Loops confinée dans les secrets Workers Cloudflare L3 Risque de fuite si partagé avec le runtime frontend
Audit & RGPD Double enregistrement (Loops + historique d’audit centralisé dans Sanity) Enregistrement unique chez le tiers
Cohérence d’architecture Aligné à 100% avec le pattern L1 + L2 + L3 du projet AMN Brèche architecturale ad-hoc

4. Conséquences de la Décision

Effets Positifs

  • Expérience utilisateur optimale : La souscription est immédiate et non bloquante.
  • Sécurité renforcée : Les clés API sensibles (LOOPS_API_KEY, SANITY_API_WRITE_TOKEN) résident uniquement dans l’environnement du consommateur backend submission-processor.
  • Traçabilité totale : Les soumissions sont visibles dans Sanity Studio pour le monitoring éditorial.
  • Support Local & Prod : En local, l’endpoint /test-direct permet de tester la chaîne sans nécessiter de wrangler queue locale complexe.

Effets Négatifs / Points d’Attention

  • Traitement en différé : Le contact apparaît dans Loops quelques secondes après la soumission du formulaire (comportement normal et sans incidence pour une newsletter).
  • Gestion des doublons : Loops gère nativement les doublons d’email (mise à jour du contact existant sans erreur bloquante).

5. Alternatives Exclues

  1. Appel direct de Loops depuis le navigateur : Exclu car expose publiquement la clé API privée Loops.
  2. Appel synchrone de Loops dans /api/submit.ts : Exclu car viole la règle de non-blocage de l’Edge Astro et empêche le retry automatique en cas de panne de Loops.
  3. Serveur MCP Loops via URL HTTP standard sans proxy OAuth : Exclu car https://mcp.loops.so n’accepte pas les clés API d’équipe.
Switch to normal mode

Contents