Aller au contenu

Rapport — Field Test App 001

Ticket : FIELD-TEST-APP-001
Date : 2026-05-20
Objectif : Valider le flux complet Forge sur une application réelle minimaliste (Article ↔ Tag many-to-many avec champs pivot).


1. Contexte

Première application de terrain Forge créée en dehors du dépôt framework.
Dossier : /home/roger/Projets/forge-field-test-app/

Entités déclarées :
- Article : title, slug, content, published, created_at
- Tag : name, slug
- Relation : many_to_many Article ↔ Tag, pivot article_tag avec champs position (integer) et note (string, nullable)

RBAC : rôles admin (CRUD complet) et reader (list + show).


2. Séquence exécutée

Commande Résultat
schema:list OK
schema:doctor OK
entity:validate OK (après correction, voir frictions)
build:model OK (après corrections, voir frictions)
make:crud Article OK (après correction position nullable, voir frictions)
make:crud Tag OK
make:pivot-crud Article tags --dry-run OK
make:pivot-crud Article tags OK
rbac:validate OK
rbac:audit OK

3. Frictions observées

F-001 — Clé "name" vs "entity" dans les JSON d'entité

Symptôme : entity:validate échoue avec 'name' is a required property et
Additional properties are not allowed ('entity' was unexpected).

Cause : Documentation interne non synchronisée avec entity.schema.json.
La clé attendue est "name", pas "entity".

Résolution : Correction manuelle dans Article.json et Tag.json.

Suggestion : Ajouter un exemple canonique dans docs/entities/ ou dans le
message d'erreur d'entity:validate.


F-002 — Structure de dossiers implicite pour build:model

Symptôme : build:model échoue avec
mvc/entities/media/media.json: fichier JSON d'entite introuvable
suite à la création involontaire d'un sous-dossier media/.

Cause : build:model scanne tous les sous-dossiers de mvc/entities/
(sauf ceux débutant par __) et attend <nom_dossier>/<nom_dossier>.json.
Un sous-dossier vide ou orphelin déclenche l'erreur.

Second symptôme : Les fichiers JSON d'entité étaient initialement placés
directement dans mvc/entities/ (Article.json). build:model ignore ces
fichiers racine — seuls les sous-dossiers sont scannés.

Résolution :
- Renommage media/__media/ (ignoré par le scanner)
- Déplacement Article.jsonmvc/entities/article/article.json
- Les noms de dossier doivent être en minuscule (snake_case) pour correspondre
à la convention name.lower() attendue par le validateur.

Suggestion : Documenter la structure attendue dans docs/entities/
(sous-dossier obligatoire, nom en minuscule). Améliorer le message d'erreur
pour indiquer que les fichiers JSON à la racine sont ignorés.


F-003 — Garde make:crud se déclenche sur les deux côtés de la relation

Symptôme : make:crud Article ET make:crud Tag échouent tous les deux
avec : le pivot article_tag contient des champs obligatoires non gérés par le CRUD simple : position.

Cause : Le garde est déclenché sur toute entité impliquée dans la relation
(côté from ET côté to), même si l'entité Tag n'est pas le propriétaire
de la création du pivot.

Comportement attendu : Le garde est correct du côté Article (qui crée le
pivot). Côté Tag, le lien inverse articles n'implique pas de gestion du
pivot par le CRUD Tag — le blocage est donc conservateur.

Résolution : position rendu nullable: true pour les besoins du test.

Suggestion : Évaluer si le garde doit s'appliquer uniquement côté from
de la relation many-to-many, ou si le comportement symétrique est intentionnel
(documentation à compléter).


4. Fichiers générés

build:model

mvc/entities/article/article.sql
mvc/entities/article/article_base.py
mvc/entities/article/article.py  (créé)
mvc/entities/article/__init__.py  (créé)
mvc/entities/tag/tag.sql
mvc/entities/tag/tag_base.py
mvc/entities/tag/tag.py  (créé)
mvc/entities/tag/__init__.py  (créé)
mvc/entities/relations.sql

make:crud Article

mvc/controllers/article_controller.py
mvc/models/article_model.py
mvc/forms/__init__.py
mvc/forms/article_form.py
mvc/views/layouts/app.html
mvc/views/partials/form_errors.html
mvc/views/article/{index,show,form,bulk_delete_confirm}.html
mvc/views/article/{_table,_pagination,_results}.html

make:crud Tag

mvc/controllers/tag_controller.py
mvc/models/tag_model.py
mvc/forms/tag_form.py
mvc/views/tag/{index,show,form,bulk_delete_confirm}.html
mvc/views/tag/{_table,_pagination,_results}.html
(layouts/app.html et forms/__init__.py : PRÉSERVÉS — write-if-new respecté)

make:pivot-crud Article tags

mvc/controllers/pivot/article_tags_pivot_controller.py
mvc/templates/pivot/article_tags/index.html
mvc/templates/pivot/article_tags/form.html

5. Points de validation positifs

  • write-if-new respecté : app.html et forms/__init__.py préservés lors
    de make:crud Tag après make:crud Article.
  • rbac:validate + rbac:audit : 2 rôles, 2 entités, 0 avertissement.
  • make:pivot-crud --dry-run : liste correcte des 3 fichiers cibles avant
    génération.
  • relations.sql généré automatiquement par build:model (table pivot
    article_tag avec clés étrangères, champs position et note).

6. Verdict

FIELD TEST OK — Le flux complet Forge (déclaration → modèle → CRUD → pivot
→ RBAC) fonctionne de bout en bout. Trois frictions documentées, aucune
bloquante au fond. F-001 et F-002 relèvent de la documentation ; F-003 mérite
évaluation.


7. Corrections documentaires — FIELD-FIX-001

Les frictions F-001 et F-002 ont été traitées dans le ticket FIELD-FIX-001.

  • F-001 : la documentation rappelle désormais que la clé canonique racine
    est "name", pas "entity". Les pages entity_architecture.md,
    15-minutes.md et app-complete-tutorial.md ont été corrigées ou signalées.
  • F-002 : la page docs/entities/json-canonique.md décrit explicitement
    la structure mvc/entities/<nom>/<nom>.json, l'emplacement de
    mvc/entities/relations.json, et le comportement de build:model vis-à-vis
    des sous-dossiers.

F-003 reste ouvert et sera traité par FIELD-AUDIT-M2M-GUARD-001.