Spécifications pour développer avec l'IA

16 min de lecture
Rédigé par Laurent Glesner - Consultant chez EloNeva
ia
Spécifications pour développer avec l'IA

En résumé

  • Une spécification d'écran donne à l'IA le contexte métier, les états et les limites qu'un prompt ponctuel ne contient pas.
  • Le format Markdown reste lisible par les équipes, versionnable dans Git et directement exploitable par un agent de code.
  • Les critères d'acceptation et les scénarios de test servent de contrat pour vérifier le résultat produit.

Les agents de développement produisent vite. Parfois très vite.

Le problème apparaît quelques heures plus tard, quand l’écran compile mais ne respecte pas les règles d’accès, oublie l’état vide, invente un endpoint ou traite la pagination autrement que le reste de l’application. Le code n’est pas forcément mauvais. La demande était surtout trop courte pour contenir ce que l’équipe avait en tête.

J’ai déjà vu ce décalage sans IA. Un ticket disait " ajouter la liste des utilisateurs avec recherche “. Le développeur devait retrouver seul les rôles, les filtres autorisés, le comportement en cas d’API indisponible et la page de destination après édition. Avec un agent de code, le même flou est traité en quelques minutes. Il devient donc visible plus tôt, mais il reste du flou.

Le sujet n’est plus uniquement la qualité du prompt. Il faut fournir un artefact de spécification durable, relié aux autres documents du projet et suffisamment précis pour être vérifié.

Le format présenté ici cible un écran applicatif. Il tient dans un fichier Markdown, avec un front-matter YAML. Il peut être relu par le produit, versionné dans Git, utilisé par un développeur et donné à plusieurs agents sans réécrire la demande à chaque session.

Pourquoi une demande détaillée ne suffit pas toujours

Une instruction de chat disparaît facilement dans l’historique d’une conversation. Elle se mélange avec les corrections, les essais et les changements de direction. Trois jours plus tard, il devient difficile de savoir quelle version du besoin a réellement servi au développement.

Une spécification suivie dans le dépôt apporte autre chose :

  • une identité stable ;
  • un statut de validation ;
  • des propriétaires ;
  • des liens explicites vers la stack, la base et les autres écrans ;
  • des critères qui peuvent être contrôlés après génération.

La documentation OpenAI sur le prompt engineering recommande de fournir des instructions précises, des exemples et le contexte utile. C’est nécessaire. Ce contexte gagne toutefois à vivre dans des fichiers gérés comme le code, plutôt que dans un prompt recopié manuellement.

Le projet Spec Kit de GitHub formalise une logique proche avec un flux Spec → Plan → Tasks → Implement. L’intérêt n’est pas d’adopter obligatoirement l’outil. Le point utile est la séparation entre ce que le produit doit faire, la manière de l’implémenter, les tâches et l’exécution.

Sur un projet existant, cette séparation évite qu’un agent transforme une préférence technique en règle métier ou qu’il considère une proposition d’interface comme une exigence validée.

Instructions projet et spécification fonctionnelle

Les deux documents répondent à des questions différentes.

Un fichier d’instructions projet peut imposer TypeScript strict, les conventions de nommage, la structure des composants Vue, la commande de test ou l’interdiction d’appeler directement la base depuis une page Nuxt. Ces règles restent valables pour plusieurs fonctionnalités.

La spécification d’écran décrit ce qui doit se passer pour un utilisateur donné. Elle précise les données, les états, les erreurs, les autorisations et ce qui reste hors périmètre.

Cette distinction complète le travail déjà présenté dans l’article consacré à la qualité du code WLangage généré par l’IA grâce à des instructions précises . Les conventions améliorent la forme et la compatibilité du code. Elles ne remplacent pas la description du besoin.

Un agent a donc besoin d’un petit ensemble cohérent :

specs/
├── spec-stack.md
├── spec-database.md
├── spec-security.md
├── screens/
│   ├── screen-user-list.md
│   └── screen-user-edit.md
└── decisions/
    └── adr-004-user-pagination.md

Le fichier d’écran ne doit pas recopier toute la stack. Il référence les documents utiles. Cette économie compte lorsque les agents disposent d’une fenêtre de contexte limitée ou que le dépôt devient volumineux.

Le format de spécification d’écran

Voici le format à promouvoir dans les projets. Il reste volontairement sobre.

---
id: screen-user-list
type: screen-spec
status: draft
owners: [product, dev]
related:
  - spec-stack.md
  - spec-database.md
  - screen-user-edit.md
---
# Écran : Nom de l'écran

## 1. Objectif
But métier de l'écran en 2-3 phrases.

## 2. Contexte
- Rôle utilisateur concerné.
- Entrées disponibles.
- Dépendances API / BDD / authentification.
- États initiaux attendus.

## 3. Parcours utilisateur
### 3.1 Cas nominal
Décrire le flux principal étape par étape.

### 3.2 Cas alternatifs
Lister les variantes métier.

### 3.3 Cas d'erreur
Lister les erreurs attendues et le comportement UI.

## 4. Règles métier
- Règle 1.
- Règle 2.
- Règle 3.

## 5. Contenu de l'écran
### 5.1 Composants
- Champ A.
- Bouton B.
- Tableau C.

### 5.2 Données affichées
- Source des données.
- Format.
- Tri / filtre / pagination.

## 6. États de l'écran
- Chargement.
- Vide.
- Succès.
- Erreur.
- Accès refusé.
- Données partielles.

## 7. Interactions attendues
- Clics.
- Validation de formulaire.
- Navigation.
- Raccourcis.
- Comportements responsive.

## 8. Critères d'acceptation
- [ ]- [ ]- [ ]
## 9. Scénarios de test
### 9.1 Tests fonctionnels
- Given / When / Then.
- Cas nominal.
- Cas limites.
- Cas d'erreur.

### 9.2 Tests non fonctionnels
- Accessibilité.
- Responsive.
- Performance.
- Sécurité / autorisations.

## 10. Contraintes techniques

- API.
- Reuse de composants.
- Logs / analytics.
- Gestion d'état.

## 11. Hors périmètre
Ce que l'écran ne doit pas faire.

Ce format n’essaie pas de décrire chaque pixel. Il rassemble les informations qui changent le comportement du logiciel et qui permettent de dire, après développement, si le résultat est acceptable.

Ce que le front-matter apporte à l’agent

Le front-matter n’est pas décoratif. Il rend la spécification indexable et contrôlable.

id

L’identifiant doit rester stable même si le titre de l’écran évolue. Il peut être utilisé dans les tickets, les journaux de génération, les plans techniques ou les rapports de test.

screen-user-list est plus robuste que " écran utilisateurs v2 “. Le numéro de version appartient à Git, pas au nom fonctionnel du fichier.

type

Le type permet de distinguer une spécification d’écran d’une décision d’architecture, d’un contrat API ou d’un modèle de données. Un agent peut charger uniquement les fichiers screen-spec lorsqu’il prépare une série de composants.

status

Un vocabulaire simple suffit généralement :

draft → review → approved → implemented → deprecated

Un agent ne devrait pas implémenter automatiquement un document en draft sans instruction explicite. Ce contrôle paraît basique. Il évite pourtant de transformer une note de travail en fonctionnalité.

owners

Les propriétaires indiquent qui doit répondre aux ambiguïtés et qui valide. product et dev peuvent ensuite être remplacés par des équipes, des rôles ou des identifiants internes.

La liste related construit un graphe documentaire léger. Pour l’écran des utilisateurs, l’agent sait qu’il doit consulter la stack, le modèle de données et l’écran d’édition. Il n’a pas à parcourir tout le dépôt pour deviner les dépendances.

Les sections qui changent vraiment la qualité du résultat

Toutes les sections ne demandent pas le même effort. Certaines éliminent une grande partie des erreurs habituelles.

L’objectif métier

" Afficher une table d’utilisateurs " décrit une forme d’interface.

" Permettre à un administrateur de retrouver rapidement un compte, vérifier son statut et ouvrir son édition sans exposer les comptes d’un autre établissement " donne une intention, un rôle et une limite d’accès.

L’agent peut alors arbitrer ses choix d’interface sans perdre le but. Le développeur peut aussi refuser une solution techniquement élégante qui ne répond pas au besoin.

Le contexte

Le contexte doit citer les entrées réellement disponibles. Route, paramètres, session, rôles, endpoints, tables concernées, composants déjà présents.

Écrire " authentification existante " reste trop vague. Il vaut mieux indiquer :

- Session fournie par le middleware `auth`.
- Rôle requis : `admin`.
- L'établissement courant vient de `session.organizationId`.
- API : `GET /api/admin/users`.
- Le filtrage par établissement est appliqué côté serveur.

Cette précision évite deux dérives : refaire une brique déjà disponible ou déplacer une règle de sécurité dans le navigateur.

Les parcours alternatifs et les erreurs

Les agents réussissent assez bien le cas nominal. Les oublis se trouvent ailleurs : résultat vide, rôle insuffisant, réponse partielle, réseau lent, page demandée devenue invalide après suppression.

Décrire ces cas avant le code évite que l’équipe les découvre pendant la recette.

Sur une application métier, l’état " données partielles " mérite une vraie décision. Faut-il afficher les lignes disponibles avec un avertissement ? Bloquer l’écran ? Permettre un nouvel essai ? L’IA ne peut pas déduire cette politique de manière fiable.

Les règles métier

Une règle métier doit être observable et indépendante de la présentation.

Mauvais exemple :

Le bouton Supprimer est rouge.

Meilleur exemple :

Un utilisateur ne peut pas supprimer son propre compte.
La suppression est interdite si le compte possède des écritures d'audit non archivées.

La couleur relève du design system. L’interdiction doit être appliquée dans l’interface et sur l’API.

Les états de l’écran

Cette section oblige à traiter le cycle complet. Elle sert aussi de liste de composants ou de variantes visuelles à produire.

Pour une liste, on retrouve souvent :

  • un squelette de chargement ;
  • un état vide sans filtre ;
  • un état vide après filtrage ;
  • une table remplie ;
  • une erreur récupérable ;
  • un refus d’accès ;
  • un avertissement de données incomplètes.

Un seul composant " aucune donnée " ne suffit pas toujours. L’utilisateur ne réagit pas de la même manière lorsque la base est vide et lorsque sa recherche ne retourne rien.

Le hors périmètre

Cette section est courte, mais elle limite les initiatives indésirables.

- Pas de création d'utilisateur depuis cet écran.
- Pas d'export CSV dans cette version.
- Pas de modification de rôle en ligne.
- Pas de suppression définitive.

Sans cette liste, un agent peut ajouter une action " utile " parce qu’elle semble cohérente avec la page. Ce code supplémentaire doit ensuite être relu, sécurisé et maintenu.

Un exemple rempli pour la liste des utilisateurs

L’extrait suivant montre le niveau de précision attendu. Il ne cherche pas à tout documenter.

---
id: screen-user-list
type: screen-spec
status: approved
owners: [product, dev]
related:
  - spec-stack.md
  - spec-database.md
  - spec-security.md
  - screen-user-edit.md
---

# Écran : Liste des utilisateurs

## 1. Objectif

Permettre à un administrateur de retrouver les comptes de son établissement,
de vérifier leur statut et d'ouvrir leur fiche d'édition.
Aucun compte d'un autre établissement ne doit être visible.

## 2. Contexte

- Rôle requis : `admin`.
- Route : `/admin/users`.
- Établissement courant : `session.organizationId`.
- API : `GET /api/admin/users`.
- Paramètres : `q`, `status`, `page`, `pageSize`, `sort`.
- Composants existants : `AppTable`, `AppPagination`, `StatusBadge`.
- Taille de page par défaut : 25.

## 3. Parcours utilisateur

### 3.1 Cas nominal

1. L'administrateur ouvre la route.
2. L'écran charge la première page triée par nom.
3. Il saisit au moins deux caractères dans la recherche.
4. La liste est rechargée après 300 ms sans nouvelle frappe.
5. Il ouvre une ligne et accède à `/admin/users/{id}`.

### 3.2 Cas alternatifs

- Filtrer sur les comptes actifs, suspendus ou invités.
- Modifier le tri sur le nom ou la dernière connexion.
- Revenir à la page précédente en conservant les filtres dans l'URL.

### 3.3 Cas d'erreur

- Une réponse `401` redirige vers la connexion.
- Une réponse `403` affiche l'état d'accès refusé.
- Une réponse `500` conserve les filtres et propose de réessayer.
- Une page devenue vide recharge la dernière page disponible.

## 4. Règles métier

- Le serveur filtre toujours sur `organizationId`.
- L'administrateur connecté apparaît dans la liste.
- Une invitation expirée possède le statut `expired`.
- L'email est affiché en minuscules sans être modifié en base.

## 6. États de l'écran

- Chargement initial avec squelette de huit lignes.
- Résultat vide global avec lien vers la procédure d'invitation.
- Résultat vide filtré avec action de réinitialisation.
- Succès avec total et pagination.
- Erreur récupérable.
- Accès refusé.

## 8. Critères d'acceptation

- [ ] Aucun utilisateur d'un autre établissement n'est retourné par l'API.
- [ ] Les filtres et la page sont reflétés dans l'URL.
- [ ] La recherche ne démarre pas avant deux caractères.
- [ ] Le focus clavier reste visible sur les lignes et les actions.
- [ ] Une erreur API n'efface pas la recherche saisie.

## 9. Scénarios de test

### 9.1 Tests fonctionnels

Given un administrateur de l'établissement A
And des utilisateurs existent dans les établissements A et B
When il ouvre la liste des utilisateurs
Then seuls les utilisateurs de l'établissement A sont affichés

Given une recherche active sans résultat
When l'administrateur réinitialise les filtres
Then la première page non filtrée est chargée

### 9.2 Tests non fonctionnels

- Navigation complète au clavier.
- Libellé accessible pour la recherche et les filtres.
- Réponse API sous 500 ms au percentile 95 pour 50 000 comptes.
- Contrôle d'autorisation testé côté API.

Le niveau de détail varie selon le risque. Un écran interne en lecture seule demande moins de formalisme qu’une validation de paiement ou une modification de droits.

Transformer les critères en vérifications

Les cases à cocher ne servent pas seulement à la recette.

Un agent peut les convertir en tests unitaires, tests d’API et tests de parcours. Le développeur doit néanmoins décider du bon niveau. Tester la couleur d’un badge avec un test end-to-end fragile n’apporte pas grand-chose. Tester l’isolation entre établissements au niveau API est indispensable.

La syntaxe Given / When / Then vient du langage Gherkin. La documentation Cucumber la présente comme une structure donnant du sens à des spécifications exécutables. Même sans Cucumber, ce découpage reste utile :

  • Given fixe le contexte et les données ;
  • When décrit l’action ;
  • Then exprime un résultat observable.

Évitez les scénarios qui racontent chaque clic ou chaque détail d’implémentation. " Quand l’administrateur recherche un utilisateur suspendu " résiste mieux aux changements d’interface que " quand il clique sur le troisième bouton de la barre “.

Contrôler la structure dans le dépôt

Une spécification destinée à l’IA doit aussi être valide pour les outils. Un simple contrôle en intégration continue repère les fichiers incomplets avant leur utilisation.

Le script suivant fonctionne sous Ubuntu 24.02 avec Bash et Python 3. Il vérifie le front-matter et les sections obligatoires.

#!/usr/bin/env bash
set -euo pipefail

SPEC_DIR="${1:-specs/screens}"

python3 - "$SPEC_DIR" <<'PY'
from pathlib import Path
import sys
import yaml

root = Path(sys.argv[1])
required_meta = {"id", "type", "status", "owners", "related"}
required_sections = [
    "## 1. Objectif",
    "## 2. Contexte",
    "## 3. Parcours utilisateur",
    "## 4. Règles métier",
    "## 5. Contenu de l'écran",
    "## 6. États de l'écran",
    "## 7. Interactions attendues",
    "## 8. Critères d'acceptation",
    "## 9. Scénarios de test",
    "## 10. Contraintes techniques",
    "## 11. Hors périmètre",
]

errors = []

for path in sorted(root.glob("*.md")):
    text = path.read_text(encoding="utf-8")

    if not text.startswith("---\n"):
        errors.append(f"{path}: front-matter absent")
        continue

    _, raw_meta, body = text.split("---", 2)
    meta = yaml.safe_load(raw_meta) or {}

    missing_meta = required_meta - set(meta)
    for key in sorted(missing_meta):
        errors.append(f"{path}: métadonnée absente: {key}")

    if meta.get("type") != "screen-spec":
        errors.append(f"{path}: type attendu: screen-spec")

    for section in required_sections:
        if section not in body:
            errors.append(f"{path}: section absente: {section}")

if errors:
    print("\n".join(errors))
    raise SystemExit(1)

print(f"Spécifications valides dans {root}")
PY

Le script utilise PyYAML. Sur un runner Ubuntu, l’installation peut rester explicite :

python3 -m pip install --require-hashes -r requirements-ci.txt
./scripts/validate-screen-specs.sh

Dans un dépôt sensible, verrouillez la version de la dépendance et son empreinte. La validation structurelle ne prouve pas que le besoin est juste. Elle garantit seulement que les champs nécessaires sont présents.

Donner la spécification à un agent

La demande adressée à l’agent peut rester courte puisque le contexte se trouve dans les fichiers.

Implémente `specs/screens/screen-user-list.md`.

Avant de modifier le code :
1. Lis tous les fichiers déclarés dans `related`.
2. Signale les contradictions et les informations manquantes.
3. Propose un plan avec les fichiers à créer ou modifier.
4. Attends la validation du plan.

Après validation :
- implémente uniquement le périmètre approuvé ;
- ajoute les tests reliés aux critères d'acceptation ;
- exécute lint, typecheck et tests ;
- fournis le diff, les commandes exécutées et les limites restantes.

L’étape de contradiction mérite d’être conservée. Si spec-security.md impose un contrôle serveur et que l’écran prévoit uniquement de masquer un bouton, l’agent doit remonter le conflit avant de coder.

Le plan est également utile pour repérer une mauvaise lecture. Un agent qui annonce la création d’un nouveau store alors que spec-stack.md impose les composables existants n’a probablement pas chargé le bon contexte.

Sécurité et accès aux données

Les spécifications contiennent parfois des noms de tables, des routes internes et des règles d’autorisation. Elles ne doivent pas contenir de mots de passe, de jetons, de données clients réelles ou de secrets de production.

Utilisez des identifiants fictifs dans les scénarios. Décrivez le mécanisme attendu sans copier la valeur d’un secret :

Le service lit la clé depuis le secret `USER_API_KEY`.

Pas :

La clé API vaut `sk-...`.

Les droits d’accès doivent figurer à plusieurs endroits de la spécification : contexte, règles métier, erreurs, tests non fonctionnels et contraintes techniques. Cette répétition n’est pas élégante, mais elle rend le contrôle plus difficile à oublier.

L’article sur les règles de sécurité OWASP pour les projets no-code détaille notamment les risques de contrôle d’accès, de configuration et de journalisation. Les mêmes exigences doivent être écrites avant un développement généré par IA.

Faire évoluer la spécification après livraison

Une spécification n’est pas forcément figée après la mise en production.

Un incident peut révéler un cas d’erreur absent. Une mesure de performance peut montrer que le seuil prévu était irréaliste. Une demande métier peut modifier le hors périmètre.

La mise à jour doit rester liée au changement de code. Une pull request qui ajoute l’export CSV devrait modifier la spécification, les critères d’acceptation et les tests. Sinon, l’agent suivant travaillera sur une description devenue fausse.

Je conseille aussi de conserver les décisions importantes dans un ADR séparé. La spécification dit qu’une pagination par curseur est requise. L’ADR explique pourquoi elle a été choisie et quelles options ont été écartées. Mélanger ces deux niveaux alourdit chaque écran.

Définitions utiles

Spécification d’écran

Document qui décrit le comportement attendu d’une interface pour un rôle donné, avec ses données, ses états, ses règles, ses erreurs et ses limites.

Instruction projet

Règle durable appliquée à plusieurs développements : architecture, conventions de code, outils, sécurité, commandes et contraintes d’exploitation.

Critère d’acceptation

Condition observable permettant de décider si une fonctionnalité répond au besoin validé. Il doit pouvoir être vérifié par un test, une recette ou une inspection claire.

Scénario Given / When / Then

Description d’un comportement à partir d’un contexte, d’une action et d’un résultat attendu. Elle peut rester documentaire ou être reliée à un outil de tests automatisés.

Hors périmètre

Liste explicite des comportements qui ne seront pas développés dans la version concernée. Elle protège le planning et limite les ajouts interprétés par l’agent.

Limites du format

Ce modèle ne remplace pas une maquette lorsque le placement visuel porte une part importante du besoin. Il ne remplace pas non plus un contrat OpenAPI pour décrire précisément une API, ni un modèle de données lorsque les relations deviennent complexes.

Il faut alors relier les artefacts plutôt que gonfler le fichier d’écran :

  • une maquette ou une capture annotée pour le visuel ;
  • un contrat OpenAPI pour les requêtes et réponses ;
  • un schéma de données pour les contraintes ;
  • un ADR pour les décisions d’architecture ;
  • la spécification d’écran pour le comportement utilisateur.

Un autre risque consiste à remplir toutes les rubriques avec du texte générique. " L’écran doit être performant et sécurisé " n’aide ni l’agent ni le développeur. Un seuil, un rôle, une règle d’accès ou une commande de vérification sont plus utiles.

Au final

Le développement assisté par IA raccourcit le temps entre une demande et un premier résultat. Il ne réduit pas automatiquement les ambiguïtés du besoin. Il peut même les transformer plus vite en code.

Une spécification d’écran en Markdown donne un support commun au produit, au développement et à la recette. Le front-matter organise le document. Les parcours et les états décrivent le comportement. Les critères d’acceptation permettent de vérifier ce qui a été produit. Le hors périmètre freine les initiatives inutiles.

Pour une entreprise comme EloNeva, ce format a surtout un intérêt opérationnel. Il permet d’utiliser plusieurs agents ou plusieurs technologies sans perdre la continuité du projet. Le modèle peut changer. La stack peut évoluer. Le besoin validé, ses contraintes et ses tests restent lisibles dans le dépôt.

FAQ