Submission
Submission
Documentation technique
Type de ressource : Schéma Sanity (Document)
Fichier source :apps/studio/schemaTypes/submission.ts
Statut : Actif
Slice : 4 (Formulaire contact)
Version : 1.0
1. Vue d’ensemble (DOC)
1.1. Description
Schéma pour les soumissions de formulaire de contact. Contient les informations du soumetteur (nom, email, message), le statut de traitement, et les horodatages de soumission et de traitement. Créé automatiquement par le worker submission-processor.
1.2. Objectif
- Modéliser les soumissions du formulaire de contact
- Permettre le suivi du statut de traitement
- Faciliter la gestion des soumissions dans le Sanity Studio
- Supporter l’historique des soumissions avec horodatage
1.3. Cas d’usage
- Stockage des soumissions du formulaire de contact
- Suivi du statut de traitement (pending, processed, rejected)
- Historique des soumissions avec horodatage
- Interface pour la gestion des soumissions dans le Sanity Studio
1.4. Relations avec d’autres schémas
| Relation | Schéma | Type | Description |
|---|---|---|---|
| Dépend de | Aucun | - | Schéma indépendant |
| Utilisé par | Aucun | - | Créé automatiquement par workers, non référencé |
2. Structure des données (DOC)
2.1. Champs principaux
| Nom du champ | Type | Obligatoire | Description | Validation |
|---|---|---|---|---|
name |
string |
✅ | Nom du soumetteur | Rule.required().min(2).max(100) |
email |
string |
✅ | Email du soumetteur | Rule.required().email() |
message |
text |
✅ | Message du formulaire de contact | Rule.required().min(10).max(2000) |
status |
string |
✅ | Statut de traitement | Options: pending, processed, rejected |
submittedAt |
datetime |
✅ | Date et heure de soumission | initialValue: new Date().toISOString() |
processedAt |
datetime |
❌ | Date et heure de traitement | Aucune |
2.2. Champs SEO
Aucun champ SEO spécifique n’est implémenté dans ce schéma.
2.3. Champs de contenu riche
Aucun champ de contenu riche n’est implémenté dans ce schéma.
3. Contrats d’Entrée/Sortie (SPEC)
3.1. Inputs (création/modification)
| Champ | Type | Validation | Description |
|---|---|---|---|
name |
string |
Rule.required().min(2).max(100) | Nom du soumetteur |
email |
string |
Rule.required().email() | Email du soumetteur |
message |
text |
Rule.required().min(10).max(2000) | Message du formulaire |
status |
string |
Options: pending, processed, rejected |
Statut de traitement |
submittedAt |
datetime |
initialValue: new Date().toISOString() | Date de soumission |
processedAt |
datetime |
Aucune | Date de traitement (optionnel) |
3.2. Outputs (structure du document)1/2
| Champ | Type | Description |
|---|---|---|
_id |
string |
ID unique du document |
_type |
string |
Type du document (submission) |
_createdAt |
string |
Date de création (généré par Sanity) |
_updatedAt |
string |
Date de dernière modification (généré par Sanity) |
name |
string |
Nom du soumetteur |
3.2. Outputs (structure du document)2/2
| Champ | Type | Description |
|---|---|---|
email |
string |
Email du soumetteur |
message |
string |
Message du formulaire |
status |
string |
Statut de traitement |
submittedAt |
string |
Date et heure de soumission |
processedAt |
string |
Date et heure de traitement (optionnel) |
3.3. États du document
| État | Description | Transition |
|---|---|---|
pending |
Soumission en attente de traitement | → processed ou rejected |
processed |
Soumission traitée avec succès | → pending (retraitement) |
rejected |
Soumission rejetée | → pending (réexamen) |
4. Implémentation (CODE)
4.1. Code du schéma1/2
4.1. Code du schéma2/2
import { defineType, defineField } from 'sanity'
export default defineType({ name: 'submission', title: 'Form Submission', type: 'document', fields: [ defineField({ name: 'name', title: 'Name', type: 'string', description: 'Nom du soumetteur', validation: (Rule) => Rule.required().min(2).max(100), }), defineField({ name: 'email', title: 'Email', type: 'string', description: 'Email du soumetteur', validation: (Rule) => Rule.required().email(), }), defineField({ name: 'message', title: 'Message', type: 'text', description: 'Message du formulaire de contact', validation: (Rule) => Rule.required().min(10).max(2000), }), defineField({ name: 'status', title: 'Status', type: 'string', options: { list: [ { title: 'Pending', value: 'pending' }, { title: 'Processed', value: 'processed' }, { title: 'Rejected', value: 'rejected' }, ], layout: 'radio', }, initialValue: 'pending', }), defineField({ name: 'submittedAt', title: 'Submitted At', type: 'datetime', description: 'Date et heure de soumission', initialValue: () => new Date().toISOString(), }), defineField({ name: 'processedAt', title: 'Processed At', type: 'datetime', description: 'Date et heure de traitement', }), ], preview: { select: { title: 'name', subtitle: 'email', description: 'message', }, prepare({ title, subtitle, description }) { return { title, subtitle: `${subtitle} - ${description?.substring(0, 50)}...`, } }, }, orderings: [ { title: 'Submitted At (Newest)', name: 'submittedAtDesc', by: [{field: 'submittedAt', direction: 'desc'}], }, { title: 'Submitted At (Oldest)', name: 'submittedAtAsc', by: [{field: 'submittedAt', direction: 'asc'}], }, ],})4.2. Requêtes GROQ associées
Requête principale (soumissions pending)
*[_type == "submission" && status == "pending"] { _id, name, email, message, submittedAt} | order(submittedAt desc)Requête détaillée (page unitaire)
*[_type == "submission" && _id == $id][0] { _id, name, email, message, status, submittedAt, processedAt}4.3. Types TypeScript (génération automatique)
Non implémenté - sanity-typegen n’est pas configuré dans le projet actuel.
// Types à implémenter manuellement si nécessaireexport type Submission = { _id: string; _type: 'submission'; name: string; email: string; message: string; status: 'pending' | 'processed' | 'rejected'; submittedAt: string; processedAt?: string;};5. Tests attendus (TEST)
5.1. Tests unitaires
| Scénario | Description | Résultat attendu |
|---|---|---|
| Validation du nom | Créer une soumission sans nom | Erreur de validation |
| Validation de l’email | Créer une soumission avec email invalide | Erreur de validation |
| Validation du message | Créer une soumission avec message < 10 caractères | Erreur de validation |
| Limite du message | Créer une soumission avec message > 2000 caractères | Erreur de validation |
| Status par défaut | Créer une soumission sans status | Valeur par défaut pending appliquée |
5.2. Tests d’intégration
| Scénario | Dépendances | Description | Résultat attendu |
|---|---|---|---|
| Création par worker | Form-handler → Queue → Submission-processor | Soumettre un formulaire via l’API | Document créé dans Sanity |
| Validation Zod | Frontend + Worker | Validation des entrées côté frontend | Erreur retournée si validation échoue |
| Stockage dans Sanity | Submission-processor + Sanity API | Création du document dans Sanity | Document créé avec tous les champs |
5.3. Tests E2E
| Scénario | Parcours utilisateur | Description | Résultat attendu |
|---|---|---|---|
| Soumission → Traitement | Formulaire → API → Sanity → Studio | Soumettre un formulaire complet | Document visible dans Sanity Studio |
| Traitement manuel | Studio → Changement status | Passer le status de pending à processed |
Status changé avec succès |
| Tri par date | Studio → Ordering | Trier les soumissions par date | Soumissions triées correctement |
6. Intégration (INTÉG)
6.1. Intégration avec les composants
| Composant | Type | Rôle | Méthode d’intégration |
|---|---|---|---|
| Form-handler Worker | L3 | Validation et mise en queue | Reçoit la soumission et l’envoie dans la Queue |
| Submission-processor Worker | L3 | Création du document Sanity | Consomme la Queue et crée le document |
| Sanity Studio | L1 | Gestion des soumissions | Interface pour visualiser et traiter les soumissions |
| Formulaire contact | L2 | Soumission du formulaire | Envoie les données vers l’API submit |
6.2. Points d’attention
- Ce schéma est créé automatiquement par le worker
submission-processor - Le champ
submittedAtest initialisé par le frontend,processedAtpar le worker - Les orderings personnalisés permettent un tri par date de soumission
- Le preview affiche un résumé du message (50 premiers caractères)
- Validation stricte des entrées côté frontend (Zod) et backend (Sanity)
- Le flux complet : Formulaire → API → form-handler → Queue → submission-processor → Sanity
6.3. Vérification de cohérence
- Le schéma ne casse aucun schéma existant
- Les requêtes GROQ retournent les données attendues
- Les types TypeScript sont générés correctement (à implémenter)
- Le flux de soumission fonctionne de bout en bout
7. Sécurité
7.1. Mécanismes de sécurité
- ✅ Validation stricte des entrées côté frontend (Zod)
- ✅ Validation des entrées côté backend (Sanity)
- ✅ Les permissions Sanity sont configurées par rôle
- ✅ Les emails sont validés automatiquement
7.2. Validation des entrées
- ✅ Le champ name est validé (min 2, max 100 caractères)
- ✅ Le champ email est validé (format email)
- ✅ Le champ message est validé (min 10, max 2000 caractères)
- ✅ Le champ status est limité aux options valides
8. Performance et limites
8.1. Limites Sanity
| Limite | Valeur | Stratégie d’optimisation |
|---|---|---|
| Taille du document | 16 MB | Éviter les messages trop volumineux |
| Profondeur des références | 10 niveaux | Pas applicable (pas de références) |
8.2. Optimisations appliquées
- ✅ Utilisation de Queue Cloudflare pour le traitement asynchrone
- ✅ Limitation de la taille du message (max 2000 caractères)
- ✅ Orderings personnalisés pour un tri efficace
9. Débogage et troubleshooting
9.1. Problèmes courants
| Symptôme | Cause probable | Solution |
|---|---|---|
| Soumission non créée | Queue non configurée | Vérifier la configuration Queue dans wrangler.toml |
| Document sans processedAt | Worker échoué | Vérifier les logs du worker submission-processor |
| Validation échoue | Données invalides | Vérifier les règles de validation Zod et Sanity |
| Status ne change pas | Permissions insuffisantes | Vérifier les permissions Sanity Studio |
9.2. Commandes de debug
# Extraire le schéma depuis Sanitynpx sanity schema extract
# Générer les types TypeScript (à implémenter)npx sanity typegen generate
# Logs du worker submission-processorwrangler tail submission-processor10. Bonnes pratiques
10.1. Architecture
- ✅ Toujours utiliser des types générés par sanity-typegen (à implémenter)
- ✅ Centraliser les requêtes GROQ dans
src/lib/queries.ts(à implémenter) - ✅ Documenter les champs et leurs validations
10.2. Code
- ✅ Utiliser
defineFieldpour chaque champ - ✅ Configurer le preview pour une meilleure UX dans Studio
- ✅ Utiliser des validations appropriées
- ✅ Configurer les orderings pour un tri efficace
10.3. Maintenance
- ✅ Mettre à jour ce fichier lors de toute modification du schéma
- ✅ Régénérer les types après modification (à implémenter)
- ✅ Tester le flux de soumission après modification
11. Évolutions et roadmap
11.1. Améliorations planifiées
- Implémentation de sanity-typegen pour la génération de types
- Ajout de champs pour les pièces jointes
- Notification automatique lors de nouvelles soumissions
- Centralisation des requêtes GROQ dans un fichier dédié
11.2. Limitations connues
- ❌ Pas de champs SEO spécifiques
- ❌ Types TypeScript non générés automatiquement
- ❌ Pas de support pour les pièces jointes
- ❌ Pas de notification automatique
12. Ressources liées1/2
- Documentation Sanity : Schema Types
- DAT L1 : §4 - Modélisation et Schémas des Données
- Schémas dépendants : Aucun (schéma indépendant)
- Workers associés :
services/form-handler,services/submission-processor
12. Ressources liées2/2
- Pages Astro :
apps/web/src/pages/contact.astro,apps/web/src/pages/api/submit.ts - Queue Cloudflare :
submissions-queue-dev/submissions-queue-prod - Configuration :
services/form-handler/wrangler.toml,services/submission-processor/wrangler.toml
13. Historique des modifications
| Date | Version | Description | Auteur |
|---|---|---|---|
| 2026-09-15 | 1.0 | Création initiale | Devin |