
# Anti-spam, attribution et analyses

Un formulaire public est un point d'écriture public. Laissé ouvert, il collecte des soumissions de robots, et les soumissions utiles s'y noient. Trois petits blocs traitent cette classe de préoccupations : `antiSpam` tient le rebut à l'écart, `submitter` régit la façon dont une même personne interagit avec un formulaire dans la durée, et `analytics` décide si les soumissions du formulaire alimentent les analyses agrégées.

```yaml
forms:
  - id: 1
    name: contact
    title: Contact Sales
    submitTo: { table: leads }
    antiSpam:
      honeypot: true
      rateLimit: { perIp: 5, perForm: 500, windowSeconds: 60 }
    analytics:
      enabled: false
    fields:
      - { kind: table-field, column: email, required: true }
```

## Propriétés anti-spam

Toutes les propriétés sont optionnelles, et toutes les valeurs par défaut sont protectrices — un formulaire sans bloc `antiSpam` est déjà défendu.

| Propriété                 | Description                                                                               | Défaut |
| ------------------------- | ----------------------------------------------------------------------------------------- | ------ |
| `honeypot`                | Affiche une saisie leurre masquée. Une soumission qui la remplit est classée indésirable. | `true` |
| `rateLimit.perIp`         | Soumissions acceptées depuis une même IP par fenêtre.                                     | `10`   |
| `rateLimit.perForm`       | Soumissions acceptées pour l'ensemble du formulaire, toutes IP confondues, par fenêtre.   | `1000` |
| `rateLimit.windowSeconds` | Durée de la fenêtre glissante, en secondes.                                               | `60`   |
| `captcha`                 | Nom d'une entrée `connections[]` fournissant la vérification CAPTCHA.                     | Aucun  |

Le pot de miel est une saisie masquée au nom conventionnel, portant tous les marqueurs qui en tiennent un humain à l'écart — `aria-hidden`, `tabindex="-1"`, `autocomplete="off"`, et aucune boîte visible. Une personne ne la voit ni ne l'atteint au clavier ; un robot naïf qui remplit chaque saisie du document la déclenche immédiatement.

`captcha` est accepté par le schéma et réservé à un vérificateur adossé à une connexion. Nommer une connexion inexistante produit un avertissement au démarrage, pas un échec de démarrage.

## À quoi ressemble un refus

| Déclencheur        | Réponse                              | `status` / `status_reason` du registre |
| ------------------ | ------------------------------------ | -------------------------------------- |
| Pot de miel rempli | `400` `{ error: 'invalid request' }` | `spam` / `honeypot`                    |
| `perIp` dépassé    | `429` avec un en-tête `Retry-After`  | `spam` / `rate_limit_per_ip`           |
| `perForm` dépassé  | `429` avec un en-tête `Retry-After`  | `spam` / `rate_limit_per_form`         |

Rien de précis n'est communiqué au client — un robot qui apprend _pourquoi_ il a été refusé apprend comment passer. La raison est consignée sur la ligne de registre, là où un modérateur peut l'examiner. Une soumission marquée indésirable n'écrit jamais dans la table liée, ne déclenche jamais l'automatisation `submitTo`, et ne compte jamais dans `availability.maxSubmissions`.

L'IP du contributeur n'est stockée que sous forme d'empreinte SHA-256 salée. L'adresse brute n'est jamais persistée.

:::callout
**L'anti-spam est actif par défaut, et un bloc partiel ne le désactive pas.** Omettre entièrement `antiSpam` affiche quand même le pot de miel et applique quand même 10 soumissions par IP et par minute. Écrire `antiSpam: { captcha: 'turnstile' }` ne remplace pas ces valeurs par défaut : cela s'y ajoute. Pour désactiver réellement le piège, il faut l'écrire : `honeypot: false`. Les formulaires de test qui envoient à répétition depuis une même adresse sont la façon habituelle dont ce point surprend.
:::

## Options du contributeur

`submitter` rassemble les règles concernant une même personne qui recroise un même formulaire.

| Propriété                 | Description                                                              | Défaut  |
| ------------------------- | ------------------------------------------------------------------------ | ------- |
| `saveAndResume`           | Permet d'enregistrer une progression partielle et d'y revenir plus tard. | `false` |
| `allowEditAfterSubmit`    | Permet de modifier ses réponses après l'envoi.                           | `false` |
| `requireUniqueSubmission` | Rejette une seconde soumission d'un contributeur ayant déjà répondu.     | `false` |

Ces trois options sont acceptées et validées par le schéma ; le pipeline de soumission ne les applique pas encore. Ne comptez pas aujourd'hui sur `requireUniqueSubmission` pour garantir l'unicité — imposez-la par une contrainte d'unicité sur la colonne de la table liée.

L'attribution, elle, fonctionne : lorsqu'une session est présente, le registre enregistre l'identifiant de l'utilisateur et la colonne « créé par » d'une table liée est renseignée. Voir [Contrôle d'accès](/fr/docs/form-access).

## Désactivation des analyses

Par défaut, chaque soumission réussie alimente le flux d'analyses agrégées : c'est ce qui permet à la surface Réponses de l'administration de représenter les soumissions par jour et l'abandon par étape.

| Propriété | Description                                                                       | Défaut |
| --------- | --------------------------------------------------------------------------------- | ------ |
| `enabled` | Passez à `false` pour exclure ce formulaire des agrégats et du flux d'événements. | `true` |

Passez-la à `false` sur les formulaires portant des données qui ne doivent pas apparaître dans des agrégats inter-soumissions — questionnaires de santé, coordonnées de paiement, tout ce qui est sous conservation légale. L'inspection soumission par soumission dans la console d'administration reste inchangée : la désactivation retire le formulaire de l'_agrégat_, pas de vos enregistrements.

L'agrégation est conditionnée à trois niveaux : un commutateur d'environnement côté opérateur, le bloc `analytics` de l'application, et ce drapeau par formulaire. Il suffit qu'un seul soit désactivé pour tenir un formulaire à l'écart.

## Pages associées

- [Disponibilité](/fr/docs/form-availability) — le plafond de soumissions dont l'indésirable est exclu.
- [Soumissions](/fr/docs/form-submissions) — le registre où le statut indésirable est consigné.
- [Contrôle d'accès](/fr/docs/form-access) — les soumissions authentifiées et leur attribution.
- [Analyses](/fr/docs/analytics) — le bloc applicatif sous lequel se range cette désactivation.
