Modules Forge¶
Un module Forge est un dossier lisible contenant au minimum un fichier
module.json. Il décrit ce qu'il fournit et Forge installe ce contenu
par étapes explicites et contrôlées.
Modules — Principe général¶
Un module Forge doit rester lisible, copiable, auditable et modifiable.
Règles fondamentales :
- un module est un dossier, pas une boîte noire ;
- le manifeste central est
module.json; - aucun code de module n'est exécuté pendant son installation ;
- l'installation est déclarative : elle enregistre, puis copie, puis génère ;
- le développeur garde la maîtrise des fichiers copiés et du branchement des routes ;
- aucun écrasement silencieux n'est autorisé ;
- aucune marketplace ni téléchargement distant n'existe.
Modules — Structure d'un module¶
Structure minimale :
Structure complète possible :
Règles :
module.jsonest obligatoire ;- les autres dossiers et fichiers sont optionnels ;
- seuls les éléments déclarés dans
providessont pris en compte par Forge ; - les chemins réels vers ces éléments sont définis dans
paths.
Modules — Format module.json¶
Exemple complet :
{
"name": "agenda",
"label": "Agenda",
"version": "0.1.0",
"description": "Module générique d'agenda.",
"provides": [
"entities",
"controllers",
"views",
"routes",
"docs"
],
"paths": {
"entities": "entities",
"controllers": "controllers",
"views": "views",
"routes": "routes.py",
"docs": "docs"
}
}
Modules — Champs obligatoires¶
| Champ | Rôle |
|---|---|
name |
nom technique du module |
label |
libellé humain |
version |
version du module |
description |
description courte |
Règles de validation :
name: snake_case minuscule, ne commence pas par un chiffre, sans chemin ni URL ni HTML ;version: formatMAJOR.MINOR.PATCH(ex.0.1.0) ;labeletdescription: sans HTML.
Modules — Champs optionnels¶
| Champ | Type | Valeur par défaut |
|---|---|---|
provides |
liste | [] |
paths |
dictionnaire | {} |
Modules — provides¶
provides liste les types de contenu fournis par le module.
| Valeur | Rôle |
|---|---|
entities |
définitions d'entités |
controllers |
contrôleurs |
views |
templates Jinja |
routes |
fichier de routes |
docs |
documentation |
static |
fichiers statiques (réservé) |
migrations |
migrations SQL (réservé) |
forge module:files traite entities, controllers, views et docs.
routes est traité séparément par forge module:routes.
static et migrations sont réservés pour de futurs tickets.
Modules — paths¶
paths associe chaque type déclaré dans provides à un chemin relatif à l'intérieur du dossier du module.
"paths": {
"entities": "entities",
"controllers": "controllers",
"views": "views",
"routes": "routes.py",
"docs": "docs"
}
Règles de validation :
- chemins relatifs uniquement ;
- pas de
..; - pas de chemin absolu (Unix ou Windows) ;
- pas d'URL.
Modules — Registre forge_modules.json¶
forge_modules.json est le registre des modules installés.
Il est créé ou mis à jour par forge module:install.
Exemple après installation et copie des fichiers :
{
"installed": {
"agenda": {
"name": "agenda",
"label": "Agenda",
"version": "0.1.0",
"description": "Module générique d'agenda.",
"source": "modules/agenda",
"provides": ["entities", "controllers", "views", "routes", "docs"],
"files_installed": [
"mvc/entities/event/event.json",
"mvc/controllers/agenda_controller.py",
"mvc/views/agenda/index.html",
"docs/modules/agenda/agenda.md"
]
}
}
}
Règles du registre :
- la source est stockée comme chemin relatif au projet ;
files_installedest ajouté aprèsforge module:files;- ne contient pas le contenu des fichiers ;
- ne doit pas contenir de chemin absolu ;
- ne doit pas devenir une base de données.
Modules — Lister les modules¶
forge module:list scanne un dossier et liste les modules détectés par la
présence d'un fichier module.json valide dans chaque sous-dossier direct.
Le dossier par défaut est modules/.
Exemple de sortie :
Modules Forge disponibles :
- agenda 0.1.0 — Agenda
- patrimoine 0.1.0 — Patrimoine
Modules invalides :
- broken — label: champ obligatoire manquant
Si le dossier n'existe pas :
Règles :
- lit uniquement les fichiers
module.json; - n'installe rien, ne copie aucun fichier, n'injecte aucune route ;
- signale les modules invalides sans bloquer l'affichage des valides ;
- ne crée pas le dossier
modules/s'il est absent.
Modules — Installer déclarativement un module¶
forge module:install agenda
forge module:install agenda --path modules
forge module:install agenda --dry-run
forge module:install valide le module et l'inscrit dans forge_modules.json.
Règles :
- valide le
module.jsonavant toute écriture ; - refuse l'installation d'un module déjà présent dans le registre ;
- écrit uniquement dans
forge_modules.json; - ne copie aucun fichier dans
mvc/; - n'injecte aucune route ;
- n'exécute aucun code du module ;
--dry-runsimule sans écrire.
Modules — Installer les fichiers d'un module¶
forge module:files copie les fichiers déclarés d'un module déjà enregistré
avec forge module:install.
Mappage des dossiers :
| Module | Projet cible |
|---|---|
entities/ |
mvc/entities/ |
controllers/ |
mvc/controllers/ |
views/ |
mvc/views/ |
docs/ |
docs/modules/<nom_module>/ |
Règles :
- copie uniquement les fichiers déclarés dans
providesetpaths; - crée les dossiers cibles si nécessaire ;
- refuse d'écraser un fichier existant ;
--dry-runaffiche les copies prévues sans écrire ;- ignore les caches, fichiers temporaires et dossiers cachés ;
- ne modifie pas
mvc/routes.py; - ne lance aucun SQL ;
- n'exécute aucun code du module.
Après une installation réelle, Forge trace les fichiers copiés dans
forge_modules.json avec la clé files_installed.
Modules — Activer les routes d'un module¶
forge module:routes génère un fichier de routes dédié pour un module déjà
enregistré dans forge_modules.json.
Prérequis : le module doit déclarer "routes" dans provides et un chemin
valide dans paths.routes.
Forge ne modifie jamais mvc/routes.py (principe 9 de la charte v2 : pas
d'écriture invisible dans le code utilisateur).
La commande :
- Crée
mvc/routes_<nom>.py(fichier dédié par module, write-if-new) ; - Affiche sur stdout les lignes à ajouter dans
mvc/routes.py.
# Contenu généré dans mvc/routes_agenda.py :
from modules.agenda.routes import register_routes as register_agenda_routes
__all__ = ["register_agenda_routes"]
Pour activer les routes, ajoutez dans mvc/routes.py :
Règles :
- le module doit être installé avant génération ;
--dry-runaffiche ce qui serait créé sans modifier de fichier ;- si
mvc/routes_<nom>.pyexiste déjà, la commande refuse et affiche un message ; supprimez le fichier manuellement pour le régénérer ; - aucun chemin absolu,
..ou URL n'est accepté pourpaths.routes; - Forge n'importe pas dynamiquement
routes.pydu module pendant la génération ; - ne copie aucun fichier d'entité, vue, contrôleur ou doc.
Modules — Dépendance runtime des routes¶
Les routes de modules référencent le dossier source du module (modules/<nom>/).
# Dans mvc/routes_agenda.py, après génération :
from modules.agenda.routes import register_routes as register_agenda_routes
Conséquences pratiques :
- un module qui expose des routes doit rester présent dans
modules/<nom>/tant que ses routes sont utilisées par l'application ; - supprimer
modules/<nom>/aprèsforge module:routesprovoque une erreur d'import au démarrage de l'application ; forge module:filescopie les entités, contrôleurs et vues dansmvc/, mais pas les routes — c'est délibéré.
Raisons de ce choix :
- les fichiers de routes sont du code Python importé, pas des ressources statiques copiables sans précaution ;
- le dossier
modules/est déjà une source contrôlée du projet — ce n'est pas un dépôt externe ; - évite de dupliquer du code Python entre
modules/etmvc/, ce qui rendrait les mises à jour de module risquées.
Modules — Cycle recommandé¶
forge module:list
forge module:install agenda --dry-run
forge module:install agenda
forge module:files agenda --dry-run
forge module:files agenda
forge module:routes agenda --dry-run
forge module:routes agenda
Schéma du cycle :
module.json
→ forge module:list
→ forge module:install
→ forge_modules.json
→ forge module:files
→ fichiers copiés dans mvc/ et docs/modules/
→ forge module:routes
→ mvc/routes_<nom>.py généré (fichier dédié par module)
→ lignes à copier dans mvc/routes.py affichées
Chaque étape est indépendante et explicite. Aucune étape n'en déclenche automatiquement une autre.
Modules — Désinstaller un module¶
forge module:remove désinstalle un module installé par Forge lorsque les fichiers
et routes sont encore traçables.
module:remove = retrait des fichiers inchangés + retrait des routes marquées + mise à jour du registre
Règle centrale : Forge ne supprime que ce qu'il peut prouver avoir installé sans modification.
Comportement par fichier tracé dans forge_modules.json :
| Situation | Action |
|---|---|
| Fichier identique à la source | Supprimé |
| Fichier modifié manuellement | Conservé — signalé |
| Source introuvable | Conservé — signalé |
| Fichier absent (déjà supprimé) | Ignoré |
Comportement sur les routes :
| Situation | Action |
|---|---|
mvc/routes_<nom>.py existe |
Conservé — à retirer manuellement |
Marqueurs forge-module-routes:<nom>:start/end présents (anciens projets) |
Bloc retiré de mvc/module_routes.py (compat arrière) |
| Marqueurs absents | Nettoyage manuel requis — signalé |
Fichier mvc/module_routes.py absent |
Ignoré |
Contrat explicite :
forge module:removene supprime pasmvc/routes_<nom>.pyni les lignes que vous avez ajoutées dansmvc/routes.py. Ces éléments restent sur le disque — à retirer manuellement si souhaité.
Règles :
--dry-runaffiche les suppressions prévues sans rien écrire ;- les dossiers parents ne sont jamais supprimés ;
- les fichiers non tracés dans
forge_modules.jsonne sont jamais touchés ; - le module est retiré du registre même si des fichiers ont été conservés ;
- pas de suppression forcée ;
- pas de fusion intelligente avec fichiers modifiés.
Limites :
- pas de rollback complet ;
- pas de suppression des fichiers modifiés ;
- pas de suppression des fichiers dont la source est absente.
Modules — API Python (core.modules)¶
from core.modules import (
# Manifeste
ModuleManifest,
ModuleManifestError,
ALLOWED_PROVIDES,
validate_module_name,
validate_module_version,
validate_module_manifest,
load_module_manifest,
# Découverte
discover_module_manifests,
list_module_manifests,
# Registre
MODULE_REGISTRY_FILE,
ModuleRegistryError,
ModuleAlreadyInstalledError,
ModuleInstallResult,
load_installed_modules_registry,
save_installed_modules_registry,
is_module_installed,
prepare_module_installation,
install_module_manifest,
# Routes
ModuleRouteInjectionError,
ModuleRoutesAlreadyGeneratedError,
ModuleRouteGenerationResult,
generate_module_routes,
# Fichiers
INSTALLABLE_PROVIDES,
ModuleFileInstallError,
ModuleFileConflictError,
ModuleFileInstallResult,
prepare_module_file_installation,
install_module_files,
)
Modules — Sécurité de copie des fichiers¶
forge module:files copie uniquement les fichiers déclarés dans les répertoires autorisés. Les garanties suivantes s'appliquent :
- seuls les types
entities,controllers,viewsetdocssont copiables parmodule:files—routes,static,migrationssont exclus ; - les chemins absolus sont refusés (
/etc/...,C:\...) ; - les chemins contenant
..sont refusés ; - les URL sont refusées (
https://,ftp://,file://) ; - les liens symboliques sont refusés — un symlink dans un module entraîne un arrêt immédiat de l'installation, même s'il pointe vers un fichier interne au module ;
- les fichiers cachés sensibles sont ignorés :
.env,.DS_Store,Thumbs.db; - les caches et fichiers de build sont ignorés :
__pycache__/,*.pyc,.git/,.venv/; - les fichiers temporaires sont ignorés :
*.tmp,*.bak; - aucun fichier existant n'est écrasé ;
- aucun code module n'est exécuté pendant la copie ;
--dry-runpermet de contrôler les copies prévues sans écriture.
Les routes restent traitées exclusivement par forge module:routes.
Cibles autorisées :
| Provide | Cible |
|---|---|
entities |
mvc/entities/ |
controllers |
mvc/controllers/ |
views |
mvc/views/ |
docs |
docs/modules/<nom_module>/ |
Si un symlink est détecté, l'installation est refusée entièrement — aucun fichier n'est copié et un message d'erreur explicite est affiché.
Modules — Sécurité et limites actuelles¶
Limites fonctionnelles :
- pas de
forge module:update; - pas de fusion automatique de fichiers ;
- pas d'option
--forcepour écraser des fichiers existants ; forge module:filesne gère pas encorestaticetmigrations;- pas de gestion de dépendances entre modules ;
- pas de marketplace ni de téléchargement de modules ;
- pas de module officiel livré par Forge.
Sécurité :
- aucun code de module n'est exécuté pendant l'installation ;
- les chemins absolus,
..et URL sont refusés à chaque étape ; - les fichiers caches et temporaires sont ignorés lors de la copie ;
- les routes de modules restent à clarifier côté dépendance runtime dans
MODULE-ROUTES-RUNTIME-AUDIT-001; - la sécurité de la copie des fichiers de modules sera auditée dans
MODULE-FILES-SECURITY-001.
Modules — Cycle de vie¶
Ce qui est supporté¶
| Étape | Commande | Ce que Forge fait |
|---|---|---|
| Découverte | forge module:list |
Scanne un dossier, liste les modules valides et invalides |
| Enregistrement | forge module:install |
Valide le manifeste, inscrit le module dans forge_modules.json |
| Copie des fichiers | forge module:files |
Copie les fichiers déclarés dans mvc/ et docs/modules/ |
| Génération des routes | forge module:routes |
Génère mvc/routes_<nom>.py et affiche les lignes à ajouter dans mvc/routes.py |
| Désinstallation contrôlée | forge module:remove |
Supprime les fichiers inchangés, retire les routes marquées, met à jour le registre |
Chaque étape est indépendante, explicite, et dotée d'un mode --dry-run. Aucune étape n'en déclenche automatiquement une autre.
Garanties lors de l'installation :
- aucun fichier existant n'est écrasé — les conflits sont signalés et stoppent l'opération ;
- aucun code du module n'est exécuté pendant l'installation ;
- les chemins absolus,
..et URL sont refusés à toutes les étapes ; - les fichiers copiés sont tracés dans
forge_modules.jsonavec la cléfiles_installed; forge module:routesgénèremvc/routes_<nom>.pyet affiche les lignes à ajouter dansmvc/routes.py— il ne modifie jamaismvc/routes.py.
Ce qui n'est pas encore supporté¶
Forge ne fournit pas encore les opérations suivantes :
| Opération | Statut | Ticket prévu |
|---|---|---|
forge module:remove — désinstallation contrôlée |
Disponible (voir section dédiée) | MODULE-REMOVE-001 ✅ |
forge module:update — mise à jour contrôlée |
Non disponible | MODULE-UPDATE-001 |
| Rollback automatique complet | Non disponible | — |
| Fusion intelligente avec fichiers modifiés | Non disponible | — |
| Registre distant de modules | Non disponible | — |
| Gestion de dépendances entre modules | Non disponible | — |
| Marketplace de modules | Non disponible | — |
Copie de static et migrations par module:files |
Non disponible | — |
Risques connus¶
La suppression contrôlée ne couvre que les fichiers traçables.
forge module:remove supprime uniquement les fichiers dont le contenu est identique à la source. Les fichiers modifiés sont conservés et signalés. Si la source est absente, les fichiers sont conservés. Après forge module:routes, retirer le dossier source modules/<nom>/ sans supprimer mvc/routes_<nom>.py et les lignes correspondantes dans mvc/routes.py provoque une erreur d'import au démarrage.
Pas de rollback sur fichiers partiellement copiés.
Si une copie de fichiers échoue en cours d'opération, les fichiers déjà copiés ne sont pas annulés. Le registre forge_modules.json peut indiquer une installation partielle.
Modifications manuelles empêchent la suppression automatique future.
Si les fichiers copiés par forge module:files sont modifiés après l'installation, une éventuelle commande forge module:remove ne pourra pas les supprimer en toute sécurité sans risquer de perdre du code utilisateur.
Régénération refusée — suppression manuelle requise.
forge module:routes refuse de régénérer mvc/routes_<nom>.py si le fichier existe déjà. Supprimez-le manuellement pour le régénérer.
Bonnes pratiques¶
- Toujours tester avec
--dry-runavant une installation réelle. - Versionner
forge_modules.jsonpour garder la traçabilité des modules installés. - Ne pas modifier les fichiers copiés par
forge module:filessi vous souhaitez garder la possibilité de supprimer ou mettre à jour le module proprement. - Conserver le dossier
modules/<nom>/tant que ses routes sont actives dans l'application. - Ajouter manuellement les lignes affichées par
forge module:routesdansmvc/routes.pyaprès génération.
Tickets futurs¶
MODULE-UPDATE-001— ajouter une mise à jour contrôlée : comparaison des fichiers, signalement des conflits, mise à jour sélective.
Référence croisée — Modules Forge¶
Principe général¶
La Phase 7 regroupe trois briques orthogonales livrées après Forge 1.5.0 :
- Workflow — modélisation déclarative des statuts et transitions métier d'une entité ;
- Statistiques — collecte légère d'événements et calcul d'indicateurs agrégés ;
- Modules — système d'empaquetage et d'installation de briques Forge réutilisables.
Ces trois briques partagent les mêmes principes : pas d'ORM, pas de runtime caché, déclaration explicite, zéro dépendance nouvelle.
Workflow — Socle livré¶
Le workflow Forge permet de gérer les transitions d'état d'une entité sans imposer de machine à états globale.
Briques livrées :
- déclaration des statuts et transitions dans
workflow.json(par entité) ; - validation des transitions autorisées ;
- helpers Jinja
workflow_status_label(),workflow_allowed_transitions(); - intégration CRUD : boutons de transition dans les vues
showetlist; - pas de callbacks automatiques — les hooks sont à écrire dans le contrôleur.
La documentation complète est dans la section Workflow de cette référence.
Statistiques — Socle livré¶
Le module statistiques fournit une collecte d'événements bruts et des agrégats calculés à la demande, sans base de données dédiée ni service externe.
Briques livrées :
StatsEvent— enregistrement d'un événement horodaté dansstats_events;stats_count(),stats_sum(),stats_average()— agrégats sur la table des événements ;stats_by_day(),stats_by_month()— agrégats temporels ;- helpers Jinja pour afficher les indicateurs dans les templates ;
- pas de dashboard généré automatiquement — les vues sont à créer dans le contrôleur.
La documentation complète est dans la section Statistiques de cette référence.
Modules — Socle livré¶
Le système de modules permet d'empaqueter des entités, contrôleurs, vues et docs sous forme de dossier autonome et de les installer dans un projet Forge.
Briques livrées :
| Ticket | Commande / brique |
|---|---|
MODULE-SYSTEM-001 |
Format module.json, structure standard d'un module |
MODULE-SYSTEM-002 |
forge module:list — découverte locale |
MODULE-SYSTEM-003 |
forge module:install — installation déclarative dans forge_modules.json |
MODULE-SYSTEM-004 |
forge module:routes — génération de mvc/routes_<nom>.py et affichage des lignes à ajouter |
MODULE-SYSTEM-005 |
forge module:files — copie des fichiers dans mvc/entities, mvc/controllers, mvc/views, docs/modules/ |
Le cycle recommandé est décrit dans la section Modules Forge — Cycle recommandé de cette référence.
Cycle d'utilisation recommandé¶
Usage typique combinant les trois briques :
- Déclarer les statuts d'une entité dans
workflow.jsonet câbler les transitions dans le contrôleur CRUD. - Enregistrer un événement statistique à chaque transition (
StatsEvent.record(...)). - Empaqueter l'entité, son contrôleur et ses vues dans un module (
module.json) pour les réutiliser dans un autre projet. - Installer le module dans le projet cible avec
forge module:install,forge module:files,forge module:routes.
Les trois briques sont indépendantes : Workflow ne dépend pas des Statistiques, les Modules ne dépendent pas du Workflow.
Limites actuelles¶
Workflow :
- pas de callbacks automatiques sur les transitions ;
- pas de journalisation native des changements d'état ;
- pas de transitions parallèles ni de fork/join.
Statistiques :
- pas d'agrégation en temps réel ;
- pas d'export CSV ni d'API JSON dédié ;
- les événements sont stockés dans la base applicative, sans partitionnement.
Modules :
- pas de
forge module:updateni deforge module:uninstall; - pas de gestion de dépendances entre modules ;
- pas de marketplace ni de téléchargement distant ;
- les audits de durcissement (
MODULE-ROUTES-RUNTIME-AUDIT-001,MODULE-FILES-SECURITY-001) sont prévus avant les starters.