Exposer Des Cas D'usage Et Des Features¶
arclith-cli expose-usecase prépare un contrat de transport, un mapper et un
enregistrement typé à partir d'un port inbound existant. FastAPI, FastMCP,
LangGraph et RabbitMQ exécutent ainsi le même execute, sans enveloppe JSON
intermédiaire pour les appels locaux.
arclith-cli expose-feature est le niveau supérieur pour prévalider puis
projeter en lot un blueprint applicatif complet. Il réutilise le même pipeline
de contrats et de bindings, sans déplacer la notion de CRUD dans l'adapter.
Pour une feature CRUD déclarée :
| Bash | |
|---|---|
Les cinq routes sont prévalidées contre un unique manifeste de bindings avant
toute écriture. Les use cases générés autour d'un BaseService[Entity] sont
composés depuis le container de la feature ; expose-usecase les refuse seuls,
car reconstruire cinq services indépendants casserait le partage du repository.
Chaque adapter dispose de son arborescence fermée dès son installation, dont
contracts/. Une exposition ajoute uniquement la feature et les fichiers nommés
de l'opération. Le contrat d'entrée est une copie du modèle Pydantic applicatif
au moment de la génération. Son mapper valide ensuite la Command ou Query attendue
par le port. Le résultat est projeté dans un DTO de réponse propre au transport :
un modèle de domaine n'est jamais publié directement.
Composition explicite et typée¶
L'agrégateur adapters/inbound/fastapi/bindings_generated.py compose chaque
router de feature exactement une fois et reçoit les ports depuis
ApplicationUseCases :
| Python | |
|---|---|
Le CLI régénère en parallèle infrastructure/use_cases_generated.py :
| Python | |
|---|---|
Cette composition automatique est limitée aux cas sûrs générés par la CLI : un
use case sans dépendance, avec une unique dépendance Repository[Entity], ou
les ports BaseService[Entity] réunis par le container déclaré d'une feature.
Une composition plus riche reste un bootstrap développeur explicite. Les autres
transports reçoivent le même port applicatif. Les lectures
Query utilisent GET par défaut dans FastAPI. Les commandes utilisent POST.
Les opérations FastMCP sont des tools ; resources et prompts restent des
primitives MCP distinctes dans les dossiers déjà créés.
Pour LangGraph, composer le BindingState généré dans l'état du graphe avant
d'enregistrer le node. Ses clés sont préfixées par le use case pour éviter les
collisions. Le registre ajoute le node ; graph.py définit explicitement ses
edges et sa politique de reprise. La sortie reste typée. Une query ne peut pas
être exposée sur le bus RabbitMQ sans contrat RPC explicite.
Propriété, collisions et recettes¶
- Les contrats, routes, tools et nodes sont des fichiers développeur créés une fois.
bindings_generated.py,infrastructure/use_cases_generated.pyet.arclith/bindings/<transport>.jsonsont détenus par le CLI.- Une deuxième exposition ajoute un import et un paramètre typé à l'agrégateur.
- Rejouer une exposition identique préserve les modifications manuelles.
- Un même nom public, type de commande ou couple méthode/chemin ne peut appartenir à deux bindings.
--dry-runaffiche les créations, mises à jour et fichiers préservés sans écrire de recette.- La recette enregistre
expose-usecaseouexpose-featureet permet leur replay. - Un test de contrat généré détecte la dérive du modèle applicatif depuis sa copie initiale.
Le scan est AST et n'exécute aucun module projet. Il prend en charge un port
execute(self, request: CommandOrQuery) -> Result, synchrone ou asynchrone,
avec un modèle Pydantic local héritant directement de BaseModel. Un modèle
hérité, générique, décoré ou comportant des méthodes/validateurs nécessite un
mapper explicite ; la commande refuse ces cas avant toute écriture. Les imports
relatifs, annotations différées et constantes littérales de module sont pris en
charge. Les dépendances locales non résolues ne sont pas copiées silencieusement.
Les paramètres HTTP GET/DELETE doivent être scalaires ou des listes de scalaires ;
les objets imbriqués nécessitent une route explicite. Un paramètre de chemin
FastAPI peut cibler un champ scalaire de la Command ou Query : il est retiré du
DTO body/query et réinjecté par le mapper pur avant l'appel du port.
Les use cases synchrones conservent une fonction de transport synchrone pour
permettre l'exécution hors de la boucle événementielle par le framework. Le
handler RabbitMQ utilise asyncio.to_thread pour ce cas. Avant l'application du
plan, le CLI revalide les chemins et le contenu des fichiers existants : une
modification concurrente annule l'écriture, sans écraser le travail développeur.
Le runtime RabbitMQ conserve les enveloppes, ACK, retry et DLX. Le binding valide le payload puis appelle le port typé ; il ne transmet pas les headers du broker au métier. Les tests du CLI exécutent les bindings HTTP, MCP, RabbitMQ et un graphe LangGraph avec interruption/reprise contre le même contrat applicatif.