[Nom de la Fonctionnalité Visual Editing]
Type de ressource : Mécanisme de prévisualisation / Visual Editing
Fichier source :sanity-studio/[fichier-concerne].tsou configuration associée
Statut : [Actif / Déprécié / En développement]
1. Vue d’ensemble
Section titled “1. Vue d’ensemble”1.1. Description
Section titled “1.1. Description”[Description concise de la fonctionnalité de prévisualisation ou d’édition visuelle]
1.2. Objectif
Section titled “1.2. Objectif”- [Objectif principal pour les contributeurs]
- [Bénéfice UX ou workflow]
1.3. Périmètre concerné
Section titled “1.3. Périmètre concerné”- Types de contenu : [Liste des schémas Sanity concernés : post, project, page, etc.]
- Environnements : [Development / Staging / Production]
- Rôles utilisateurs : [Administrator, Editor, Contributor, Viewer]
2. Architecture et flux
Section titled “2. Architecture et flux”2.1. Diagramme de flux
Section titled “2.1. Diagramme de flux”[Sanity Studio] │ ▼[Action utilisateur : ex. "Open Preview"] │ ▼[Cloudflare Middleware Worker (L3)] │ • Validation du secret │ • Pose du cookie de preview │ • Redirection ▼[Astro (L2)] │ • Détection du cookie/header │ • Configuration du client Sanity │ • Rendu SSR ▼[Affichage du contenu draft]2.2. Composants impliqués
Section titled “2.2. Composants impliqués”| Composant | Rôle | Couche |
|---|---|---|
| [Nom du composant] | [Description du rôle] | [L1 / L2 / L3] |
| [Nom du composant] | [Description du rôle] | [L1 / L2 / L3] |
3. Configuration
Section titled “3. Configuration”3.1. Variables d’environnement requises
Section titled “3.1. Variables d’environnement requises”| Variable | Description | Obligatoire | Valeur par défaut |
|---|---|---|---|
SANITY_PREVIEW_SECRET |
Secret de validation de la preview | ✅ | - |
SANITY_API_READ_TOKEN |
Token API avec droits de lecture des drafts | ✅ (en preview) | - |
| [Autre variable] | [Description] | [✅/❌] | [Valeur] |
3.2. Configuration Sanity Studio
Section titled “3.2. Configuration Sanity Studio”// sanity-studio/sanity.config.ts ou fichier dédiéimport { defineConfig } from 'sanity';import { structureTool } from 'sanity/structure';
export default defineConfig({ // ... configuration de base plugins: [ // Plugins de visual editing si applicable ], document: { productionUrl: async (prev, { document, getClient }) => { // Logique de génération de l'URL de preview const secret = process.env.SANITY_PREVIEW_SECRET; const slug = document.slug?.current || '/'; return `${process.env.SITE_URL}/api/preview?secret=${secret}&slug=${slug}`; }, },});3.3. Configuration Middleware Cloudflare (L3)
Section titled “3.3. Configuration Middleware Cloudflare (L3)”// services/middleware/src/index.ts (extrait pertinent)if (url.pathname === '/api/preview') { const secret = url.searchParams.get('secret'); const rawSlug = url.searchParams.get('slug') || '/';
// Validation à temps constant if (!secret || secret !== env.SANITY_PREVIEW_SECRET) { return new Response('Jeton invalide', { status: 401 }); }
// Protection anti-open-redirect const sanitizedSlug = (rawSlug.startsWith('/') && !rawSlug.startsWith('//')) ? rawSlug : '/';
const response = Response.redirect(new URL(sanitizedSlug, url.origin).toString(), 307);
// Cookie de preview sécurisé response.headers.append( 'Set-Cookie', `sanity-preview=true; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=3600` );
return response;}3.4. Configuration Astro (L2)
Section titled “3.4. Configuration Astro (L2)”import { createClient } from '@sanity/client';import type { AstroGlobal } from 'astro';
export function getSanityClient(astro: AstroGlobal) { const isPreview = astro.cookies.get('sanity-preview')?.value === 'true' || astro.request.headers.get('x-sanity-preview') === 'true';
return createClient({ projectId: import.meta.env.PUBLIC_SANITY_PROJECT_ID, dataset: import.meta.env.PUBLIC_SANITY_DATASET, apiVersion: '2025-01-01', useCdn: !isPreview, // Désactive le CDN en preview perspective: isPreview ? 'previewDrafts' : 'published', token: isPreview ? import.meta.env.SANITY_API_READ_TOKEN : undefined, });}4. Sécurité
Section titled “4. Sécurité”4.1. Mécanismes de sécurité
Section titled “4.1. Mécanismes de sécurité”| Mécanisme | Implémentation | Rationale |
|---|---|---|
| Validation du secret | Comparaison à temps constant | Évite les attaques temporelles |
| Cookie sécurisé | HttpOnly, Secure, SameSite=Lax |
Protection XSS et CSRF |
| Durée de vie limitée | Max-Age=3600 (1 heure) |
Limite la fenêtre d’exposition |
| Anti-open-redirect | Validation stricte du slug | Évite les redirections malveillantes |
| Bypass cache Edge | cf.cacheEverything = false |
Garantit le contenu draft frais |
4.2. Tokens et permissions
Section titled “4.2. Tokens et permissions”| Token | Permissions | Stockage |
|---|---|---|
SANITY_PREVIEW_SECRET |
Validation de la requête de preview | Cloudflare Secrets + Sanity env |
SANITY_API_READ_TOKEN |
Lecture des drafts uniquement | Cloudflare Secrets (runtime uniquement) |
4.3. Règles de sécurité
Section titled “4.3. Règles de sécurité”- ✅ Le secret de preview n’est jamais exposé côté client
- ✅ Le token de lecture des drafts est uniquement disponible en runtime (Pages Functions)
- ✅ Aucune page en mode preview n’est générée en SSG
- ✅ La documentation Starlight n’est pas concernée par ce mécanisme
- ✅ Les webhooks de rebuild ne sont déclenchés que sur
publish(jamais sur les drafts)
5. Utilisation
Section titled “5. Utilisation”5.1. Workflow contributeur
Section titled “5.1. Workflow contributeur”- Création/modification : Le contributeur édite un document dans Sanity Studio
- Sauvegarde : Le document est sauvegardé en draft (statut
draft) - Prévisualisation : Le contributeur clique sur “Open Preview” dans le Studio
- Validation : Le Middleware Cloudflare valide le secret et pose le cookie
- Affichage : Astro détecte le cookie et affiche le contenu draft
- Publication : Une fois validé, le contributeur publie le document
- Rebuild : Le webhook déclenche un nouveau build SSG
5.2. Sortie du mode preview
Section titled “5.2. Sortie du mode preview”export const prerender = false;
Astro.cookies.delete('sanity-preview', { path: '/' });return Astro.redirect('/');Usage : https://votresite.com/api/exit-preview
5.3. Cas d’usage par type de contenu
Section titled “5.3. Cas d’usage par type de contenu”| Type de contenu | URL de preview | Composant de rendu |
|---|---|---|
| Article de blog | /api/preview?slug=/blog/[slug] |
src/pages/blog/[slug].astro |
| Projet portfolio | /api/preview?slug=/portfolio/[slug] |
src/pages/portfolio/[slug].astro |
| Page vitrine | /api/preview?slug=/[slug] |
src/pages/[slug].astro |
6. Débogage et troubleshooting
Section titled “6. Débogage et troubleshooting”6.1. Problèmes courants
Section titled “6.1. Problèmes courants”| Symptôme | Cause probable | Solution |
|---|---|---|
| “Jeton de prévisualisation invalide” | Secret incorrect ou manquant | Vérifier SANITY_PREVIEW_SECRET dans Cloudflare et Sanity |
| Page blanche en preview | Token de lecture des drafts manquant | Vérifier SANITY_API_READ_TOKEN dans Cloudflare Secrets |
| Contenu publié affiché au lieu du draft | Cookie non détecté | Vérifier que le navigateur accepte les cookies |
| Redirection infinie | Slug malformé ou open-redirect bloqué | Vérifier le format du slug (doit commencer par /) |
| Contenu en cache | Bypass cache non actif | Vérifier que le Middleware force cacheEverything: false |
6.2. Logs et monitoring
Section titled “6.2. Logs et monitoring”// Logs à vérifier en cas de problème// 1. Cloudflare Worker Logs (Middleware)console.log('Preview activation attempt', { secret, slug });
// 2. Astro Logs (runtime)console.log('Preview mode detected', { isPreview, cookie });
// 3. Sanity Studio Console// Vérifier les erreurs dans la console du navigateur6.3. Tests manuels
Section titled “6.3. Tests manuels”# Test de validation du secretcurl -v "https://votresite.com/api/preview?secret=INVALID&slug=/"# Attendu : 401 Unauthorized
# Test avec secret validecurl -v "https://votresite.com/api/preview?secret=VALID_SECRET&slug=/blog/test"# Attendu : 307 Redirect + Set-Cookie7. Bonnes pratiques
Section titled “7. Bonnes pratiques”7.1. Pour les développeurs
Section titled “7.1. Pour les développeurs”- ✅ Toujours utiliser la comparaison à temps constant pour valider les secrets
- ✅ Ne jamais logger les secrets ou tokens dans les logs
- ✅ Tester le mécanisme de preview en environnement de staging avant production
- ✅ Documenter les changements de configuration dans ce fichier
7.2. Pour les contributeurs
Section titled “7.2. Pour les contributeurs”- ✅ Utiliser la preview systématiquement avant publication
- ✅ Vérifier le rendu sur différents appareils (responsive)
- ✅ Ne pas partager l’URL de preview (elle contient le secret)
- ✅ Se déconnecter de la preview après utilisation (
/api/exit-preview)
7.3. Considérations de performance
Section titled “7.3. Considérations de performance”- ⚠️ Le mode preview désactive le CDN Sanity (
useCdn: false) - ⚠️ Le mode preview force le bypass du cache Edge Cloudflare
- ⚠️ Les pages en preview sont rendues en SSR (plus lent que SSG)
- ✅ Limiter la durée de vie du cookie (1 heure par défaut)
8. Évolutions et roadmap
Section titled “8. Évolutions et roadmap”8.1. Améliorations planifiées
Section titled “8.1. Améliorations planifiées”- [Évolution 1 : ex. Intégration de Sanity Visual Editing (overlays)]
- [Évolution 2 : ex. Support du mode preview pour la documentation Starlight]
- [Évolution 3 : ex. Prévisualisation multi-appareils synchronisée]
8.2. Limitations connues
Section titled “8.2. Limitations connues”- ❌ La documentation Starlight n’est pas compatible avec ce mécanisme (Git-based)
- ❌ Le mode preview ne fonctionne pas avec le SSG (SSR uniquement)
- ❌ Les médias uploadés en draft ne sont pas accessibles publiquement avant publication
9. Ressources liées
Section titled “9. Ressources liées”- Documentation Sanity : Preview Content
- Documentation Astro : Draft Mode
- DAT L1 : §4.7 - Stratégie de Preview (Draft Mode)
- DAT L2 : §5.3 - Gestion du mode Preview
- DAT L3 : §3.1 - Middleware Global (validation du secret)
- Fichiers concernés :
services/middleware/src/index.tssrc/lib/sanity.tssrc/pages/api/exit-preview.tssanity-studio/sanity.config.ts
10. Historique des modifications
Section titled “10. Historique des modifications”| Date | Version | Description | Auteur |
|---|---|---|---|
| YYYY-MM-DD | 1.0 | Création initiale | [Nom] |
| YYYY-MM-DD | 1.1 | [Modification] | [Nom] |