# P4 — Form contribution "Proposer une pratique" — Récap **Date :** 2026-04-28 **Branche :** feat/aep-pratiques-regeneratives **Commits :** 3 atomiques (83d4bd1, d10586c, f25a7d3) --- ## Fichiers créés / modifiés | Fichier | Statut | Description | |---------|--------|-------------| | `pages/proposer-pratique.vue` | créé (833 lignes) | Formulaire complet clone adapté de contribuer.vue | | `server/api/submit-pratique.post.ts` | créé (117 lignes) | Endpoint POST avec Zod + rate limit + append pending | | `public/data/pratiques-pending.json` | créé (`[]`) | File de modération V1, nettoyée après tests | | `components/PratiqueSidebar.vue` | modifié | CTA "+ Proposer une pratique" en bas de sidebar | --- ## Formulaire — champs implémentés - **Nom** (obligatoire, 3-150c) - **URL** (optionnel) - **Description** (obligatoire, 50-500c + compteur live) - **Critères régénératifs** (checkboxes 8 critères, min 3 / max 8, désactivation au-delà) - **Type d'entité** (radio pill : 9 options depuis TYPES_ENTITE) - **Pays** (dropdown groupé Europe 16 codes / DOM-TOM 11 codes / Autre texte libre conditionnel) - **Ville** (optionnel) - **Tags** (optionnel, input virgule-séparé → chips preview, max 6 × 30c) - **Email** (optionnel) --- ## Endpoint serveur - Validation Zod miroir du client (schéma identique) - Rate limit JSON : 3 soumissions / IP hashée SHA-256 / jour (action `submit-pratique`) - Lecture / écriture `public/data/pratiques-pending.json` (init `[]` si absent) - Entrée : champs validés + `id: timestamp` + `submitted_at: ISO` + `moderation_status: 'pending'` - Retour : `{ ok: true, trackingId: timestamp }` - Commentaire modération V2 en haut du fichier --- ## Résultats tests | Test | Résultat | |------|----------| | GET /proposer-pratique | 200 | | POST valide | 200 + entrée pending.json | | POST invalide (nom 2c, desc trop courte, criteres < 3) | 422 + fieldErrors structurés | | Rate limit : 3ème soumission depuis même IP | 429 | | pending.json après nettoyage | `[]` vide | Note : la 3ème soumission (pas la 4ème) a déclenché le 429 car le test valide précédent comptait comme 1ère soumission — comportement correct, limite = 3/jour. --- ## Navigation - CTA "Proposer une pratique" dans `PratiqueSidebar.vue` (section bas sidebar, style `sidebar-cta-link`) - Bouton retour dans `proposer-pratique.vue` → `/pratiques-regeneratives` - Bouton Annuler dans le formulaire → `/pratiques-regeneratives` --- ## Notes implémentation - `types/pratique.ts` non modifié — `CRITERES`, `TYPES_ENTITE`, `TYPES_ENTITE_LABELS`, `EUROPE_CODES`, `OUTREMER_CODES`, `PAYS_LABELS` importés tels quels - Style réutilise 100% les classes CSS et variables CSS var(--nav-*) existantes - Accentuation dans pending.json depuis curl Windows = artefact d'encodage terminal uniquement — depuis navigateur, l'encodage UTF-8 est correct --- ## Prêt pour P5