Skip to content

Contact

Contact

Documentation technique

Type de ressource : Route Astro (Page SSR avec Preview)
Fichier source : src/pages/contact.astro
Statut : Actif

1. Vue d’ensemble

1.1. Description

Page de contact avec formulaire de soumission. Supporte le mode preview pour visualiser les drafts. Le formulaire envoie les données vers l’endpoint /api/submit qui utilise le backend L3 (Cloudflare Workers).

1.2. Objectif

  • Fournir un formulaire de contact fonctionnel
  • Tester l’intégration L1+L2+L3 (Sanity + Astro + Cloudflare Workers)
  • Supporter le mode preview
  • Afficher le message AMN (test d’intégration)

1.3. Caractéristiques

Propriété Valeur
URL publique /contact
Mode de rendu SSR
Type Page HTML
Méthode HTTP GET
Authentification requise Preview uniquement (cookie)
Cache Non configuré

2. Architecture et flux

[Requête utilisateur]
│
▼
[Cloudflare Pages / Edge]
│ • Middleware (cookie sanity-preview)
▼
[Astro Route (contact.astro)]
│ • Détection du mode preview (cookie)
│ • Récupération du message AMN via getAmn(isPreview)
│ • Rendu du formulaire
▼
[Réponse HTML]
│
▼
[Formulaire soumis]
│
▼
[Endpoint /api/submit]
│ • Validation Zod
│ • Envoi vers form-handler Worker
▼
[Queue Cloudflare]
│
▼
[Submission-processor Worker]
│ • Création du document Sanity
▼
[Sanity CMS]

2.2. Composants impliqués

Composant Rôle Couche
contact.astro Définition de la route L2 (Astro)
getAmn() Récupération du message AMN L2 (Astro)
/api/submit Endpoint de soumission L2 (Astro)
Form-handler Worker Validation et mise en queue L3 (Cloudflare)
Submission-processor Worker Création document Sanity L3 (Cloudflare)

3. Implémentation

3.1. Code de la route1/2

3.1. Code de la route2/2

---
import { getAmn } from '../lib/sanity'
export const prerender = false
const isPreview = Astro.cookies.get('sanity-preview')?.value === 'true'
const amn = await getAmn(isPreview)
---
<html lang="fr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Contact - AMN</title>
</head>
<body>
{isPreview && (
<div class="preview-banner">
⚠️ <strong>Mode Preview Activé</strong> — Visualisation des brouillons Sanity non publiés (Drafts).
<a href="/api/exit-preview" class="exit-link">Quitter la preview</a>
</div>
)}
<main>
<h1>Contactez-nous</h1>
<p class="subtitle">Formulaire de contact - Test d'intégration L1+L2+L3</p>
{amn && (
<div class="amn-message">
<p><strong>Message AMN:</strong> {amn.message}</p>
</div>
)}
<form id="contact-form" class="contact-form">
<div class="form-group">
<label for="name">Nom *</label>
<input type="text" id="name" name="name" required minlength="2" maxlength="100" />
</div>
<div class="form-group">
<label for="email">Email *</label>
<input type="email" id="email" name="email" required />
</div>
<div class="form-group">
<label for="message">Message *</label>
<textarea id="message" name="message" required minlength="10" maxlength="2000" rows="5"></textarea>
</div>
<button type="submit" id="submit-btn" class="submit-btn">
Envoyer
</button>
</form>
<div id="form-status" class="form-status"></div>
</main>
<script is:inline>
const form = document.getElementById('contact-form');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(form);
const data = {
name: String(formData.get('name') ?? ''),
email: String(formData.get('email') ?? ''),
message: String(formData.get('message') ?? ''),
};
const response = await fetch('/api/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
const result = await response.json();
// ... gestion de la réponse
});
</script>
</body>
</html>

4. Données et requêtes GROQ

4.1. Requête principale

*[_type == "amn" && status == "active"][0]

4.2. Requêtes secondaires

Aucune requête secondaire n’est utilisée.

4.3. Types TypeScript associés

// Type AMN (manuel, sanity-typegen non implémenté)
export type Amn = {
_id: string;
_type: 'amn';
message: string;
status: 'active' | 'inactive';
};

5. Paramètres et validation

5.1. Paramètres d’URL

Aucun paramètre d’URL n’est utilisé.

5.2. Query strings

Aucune query string n’est utilisée.

5.3. Gestion des erreurs

Code HTTP Condition Réponse
200 Succès Page HTML
500 Erreur Sanity (getAmn) Page HTML avec message d’erreur

6. Stratégie de cache

6.1. En-têtes de cache

Mode Cache-Control CDN-Cache-Control Rationale
SSR Preview Non configuré Non configuré À configurer (no-store recommandé)
SSR standard Non configuré Non configuré Par défaut Cloudflare

6.2. Implémentation dans la route

Non implémenté - pas de headers de cache explicites.

7. SEO et métadonnées

7.1. Balises meta

Balise Source Fallback
<title> Hardcodé “Contact - AMN” -
<meta name="viewport"> Hardcodé -

7.2. Sitemap

  • ✅ Cette route est-elle incluse dans le sitemap ? Oui
  • ✅ Fréquence de mise à jour : monthly
  • ✅ Priorité : 0.5

7.3. Indexation Pagefind

  • ❌ Cette route est-elle indexée par Pagefind ? Non (Pagefind non configuré)

8. Composants UI utilisés

Aucun composant UI n’est utilisé (page simple avec formulaire inline).

9. Sécurité

9.1. Accès et authentification

Condition Comportement
Accès public Page accessible sans authentification
Mode Preview Cookie sanity-preview requis pour voir les drafts

9.2. Validation des entrées

  • ✅ Validation HTML5 (required, minlength, maxlength, type=“email”)
  • ✅ Validation côté serveur via Zod (endpoint /api/submit)

9.3. En-têtes de sécurité

Non implémenté dans cette route (à configurer via Middleware Cloudflare).

10. Débogage et troubleshooting

10.1. Problèmes courants

Symptôme Cause probable Solution
Soumission échoue Endpoint /api/submit inaccessible Vérifier que le form-handler Worker est démarré
Erreur 500 Token Sanity manquant Vérifier les variables d’environnement
Preview non fonctionnel Cookie manquant Vérifier le cookie sanity-preview

10.2. Logs et monitoring

Terminal window
# Logs de développement
npm run dev
# Logs du form-handler Worker
wrangler tail form-handler
# Logs du submission-processor Worker
wrangler tail submission-processor

10.3. Tests manuels

Terminal window
# Test de la route en local
curl -I http://localhost:4321/contact
# Test du mode preview
curl -I -b "sanity-preview=true" http://localhost:4321/contact
# Test du formulaire
# Soumettre le formulaire via l'interface web

11. Bonnes pratiques

11.1. Architecture

  • ✅ Détection automatique du mode preview via cookie
  • ✅ Validation côté client (HTML5)
  • ✅ Validation côté serveur (Zod)
  • ✅ Affichage conditionnel de la bannière preview

11.2. Performance

  • ✅ Script inline (is:inline) pour éviter les charges supplémentaires
  • ✅ Pas de JavaScript externe

11.3. Maintenance

  • ✅ Tester le flux de soumission régulièrement
  • ✅ Vérifier l’intégration L1+L2+L3

12. Évolutions et roadmap

12.1. Améliorations planifiées

  • Configuration des headers de cache (no-store en preview)
  • Ajout de structured data (JSON-LD)
  • Amélioration du design du formulaire
  • Ajout de CAPTCHA pour la protection anti-spam

12.2. Limitations connues

  • ❌ Pas de structured data (JSON-LD)
  • ❌ Headers de cache non configurés
  • ❌ Pas de protection anti-spam
  • ❌ Langue hardcodée en ‘fr’

13. Ressources liées

  • Documentation Astro : Routing
  • Fichiers concernés :
    • src/pages/contact.astro
    • src/pages/api/submit.ts
    • src/lib/sanity.ts (getAmn)
    • services/form-handler/src/index.ts
    • services/submission-processor/src/index.ts

14. Historique des modifications

Date Version Description Auteur
2026-09-15 1.0 Création initiale Devin
Switch to normal mode

Contents