APS-Framework/aps-template

Modèle de projet APS Framework : agents, compétences, commandes et scripts pour créer des applications .NET Azure Functions et ASP.NET Core Web Apps avec les packages APS.

Qu'est-ce que aps-template ?

Ce skill guide un orchestrateur (IA) dans la **création de nouvelles fonctionnalités** (et non la modification d'existantes) pour des projets .NET utilisant le framework APS. Il est conçu pour les cas où aucune implémentation préexistante n'existe, en partant des exigences utilisateur. Le skill analyse systématiquement la réutilisation potentielle (services, méthodes, endpoints existants), détermine si la fonctionnalité nécessite une configuration (`IXxxOptions`, sections `appsettings.json`), et évalue l'impact sur l'API publique pour éviter les régressions. Il impose une phase de pré-vérification des tests de régression avant toute modification. Le processus en phases couvre la collecte des exigences, la prise de décision (réutilisation, extension ou création), la génération d'un plan de création détaillé, l'exécution via des workers spécialisés (contrats, implémentation, présentation, tests) et enfin la vérification avec commit structuré. Le skill prend en charge les hôtes `FUNCTIONS` (Azure Functions Isolated) et `WEBAPP` (ASP.NET Core), et exige une validation préalable de la structure du projet.

Compatible avec~Claude Code~Codex CLI~Cursor✓OpenCode
npx skills add APS-Framework/aps-template

Installed? Explore more Recherche et analyse de données skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Ce que je fais

Je guide l'orchestrateur pour créer de nouvelles fonctionnalités (ne pas modifier l'existant) avec une analyse préalable de réutilisation, de configuration et de compatibilité. Contrairement aux refactorisations, il n'y a aucun code préexistant à préserver : la conception part des besoins de l'utilisateur.

Quand utiliser ce skill (plutôt que refactor-protocol) :

  • L'utilisateur demande un endpoint, un service, un job, un handler, un événement ou une configuration qui N'existe PAS
  • La tâche est une création pure, pas une modification de comportement existant
  • Le résultat ajoute des fichiers au dépôt, il ne change pas la signature des fichiers existants

Quand NE PAS utiliser ce skill (utiliser refactor-protocol à la place) :

  • Modifier la signature d'un service existant
  • Changer le comportement d'un endpoint qui existe déjà
  • Renommer, extraire ou déplacer du code

PHASE 0 — Validation de la structure (toujours en premier)

  1. Charger le skill project-structure et exécuter la validation complète
  2. Détecter le type d'hôte : FUNCTIONS | WEBAPP | NUGET_LIBRARY
  3. Agir selon le résultat :
ÉtatAction
HARD_BLOCKArrêter. Informer l'utilisateur.
NUGET_LIBRARYCréer un endpoint HTTP est inattendu. Demander : "Voulez-vous ajouter une opération publique à la bibliothèque ou y a-t-il vraiment un hôte que je n'ai pas détecté ?"
PREGUNTARésoudre les questions avant de continuer
OK / WARNINGContinuer à la PHASE 1

PHASE 1 — Recueil des exigences

L'orchestrateur déduit ce qu'il peut de la description de l'utilisateur ($ARGUMENTS) et ne pose que les questions qui ne sont pas claires. Ne pas poser de questions dont la réponse est déjà dans la description.

1.1 Nom, objectif et type de fonctionnalité

  • Endpoint HTTP (Function/Controller) : [VERBE] /route — description
  • Service métier : nom du service et responsabilité
  • Job/Event handler : trigger + action
  • Option de configuration : nom de l'option et son objectif

1.2 Classification READ vs MUTATION

Déterminer si la fonctionnalité mute l'état ou est en lecture seule. Cela affecte :

  • Où vont les DTOs de réponse
  • Si une transaction / idempotence est requise
  • Quels tests sont nécessaires
TypeCaractéristiquesImplication
READ-ONLYGET, renvoie des données existantes, n'écrit pasDTOs éphémères, tests minimaux
MUTATIONPOST/PUT/DELETE, écrit ou change l'étatNécessite des tests de succès + erreur

1.3 Recueil des entrées/sorties attendues

  • Requête : structure du corps ou des paramètres de requête
  • Réponse : structure du corps de réponse, codes de statut
  • Erreurs : quelles erreurs mapper à quels codes de statut

PHASE 1.5 — Analyse de réutilisation (CRITIQUE, ne pas sauter)

Objectif : détecter si la fonctionnalité existe déjà partiellement ou totalement avant de créer quoi que ce soit.

Étapes

  1. Rechercher des services existants dans *.Impl/ avec @explore en utilisant le domaine de la fonctionnalité
  2. Rechercher des méthodes candidates qui couvrent 80%+ du comportement requis :
    • Existe-t-il une méthode qui renvoie déjà la donnée nécessaire avec un filtre trivial ?
    • Existe-t-il une méthode qui pourrait être surchargée pour ajouter le cas ?
  3. Rechercher des endpoints similaires dans *.API/ avec la même forme de requête/réponse

Arbre de décision

Existe-t-il une méthode qui couvre 100% du cas ?
└── OUI → NE PAS créer de nouvelle méthode. Créer uniquement :
        · Endpoint (Function/Controller) dans *.API/
        · DTO Request/Response exclusif dans *.API/
        · Test de la forme de la réponse

Existe-t-il une méthode quasi-idéale (filtre, pagination, ordre) ?
├── OUI → envisager :
│   ├── Ajouter un paramètre optionnel à la méthode existante (avec valeur par défaut)
│   ├── Créer une surcharge avec une signature plus spécifique
│   └── Créer une méthode d'extension qui enveloppe l'existante
└── NON → continuer avec la création d'une nouvelle méthode

Existe-t-il un service connexe mais différent (ex. responsabilité similaire) ?
├── OUI → demander à l'utilisateur : "Est-ce que j'étends [CSXxxService] ou j'en crée un nouveau [CSYyyService] ?"
└── NON → créer un nouveau service

Résultat attendu de cette phase

Une de ces trois décisions, présentée à l'utilisateur avant de continuer :

  1. Réutilisation pure : la fonctionnalité est implémentée comme un wrapper d'une méthode existante
  2. Extension : ajouter une surcharge/méthode à un service existant
  3. Création nouvelle : nouveau service et nouvelles méthodes (justifier pourquoi la réutilisation n'est pas possible)

PHASE 1.6 — Analyse de configuration (NOUVELLE)

Objectif : détecter si la fonctionnalité nécessite des paramètres configurables et, si oui, où les définir.

Questions clés

  1. La fonctionnalité a-t-elle des valeurs par défaut raisonnables sans configuration externe ?
  2. Y a-t-il des seuils, pagination, timeouts, ou indicateurs qui devraient être configurables par environnement ?
  3. Se connecte-t-elle à un système externe avec URL/clé/secret ?
  4. Nécessite-t-elle des feature flags pour un déploiement progressif ?

Arbre de décision

La fonctionnalité nécessite-t-elle une configuration ?
├── NON → ne pas créer IXxxOptions, ne pas toucher à AddCustomConfiguration
└── OUI → continuer

Quel type de configuration ?
├── Chaîne de connexion ou secret
│   └── Utiliser IConfiguration avec un nom dans appsettings.json (géré par AddCustomConfiguration)
├── Valeur simple (seuil, timeout, indicateur)
│   └── Créer IXxxOptions dans *.Impl/ (interface) + ajouter à AddCustomConfiguration<T>("clé")
└── Liste de valeurs (origines autorisées, mappings)
    └── Créer IXxxOptions avec une propriété de type IEnumerable<T>

Convention du projet

Le projet utilise AddCustomConfiguration<IXxxOptions>("section-config") dans IoCExtensions.cs (lignes 43-45 du projet actuel). Les interfaces vivent dans *.Impl/ et sont référencées depuis *.Impl/Services/.

Résultat attendu

Si la fonctionnalité nécessite une configuration, présenter à l'utilisateur :

  • Nom de l'interface (ex. IPendingPaymentOptions)
  • Propriétés avec leurs types et valeurs par défaut
  • Section dans appsettings.json (ex. "RAMBLA.PendingPayment")
  • Modification de IoCExtensions.AddCSLevelBooking()

Si NON, l'indiquer explicitement dans le plan.


PHASE 1.7 — Analyse de l'impact sur l'API publique

Objectif : éviter de casser les consommateurs existants.

Si la fonctionnalité réutilise une méthode existante

  • La méthode est-elle conservée avec la même signature ? → sans impact
  • Ajoute-t-on un paramètre optionnel ? → vérifier qu'aucun site d'appel n'est cassé
  • Ajoute-t-on une surcharge ? → vérifier que le compilateur résout sans ambiguïté
  • Renomme-t-on ? → rechercher tous les sites d'appel avec grep et migrer

Si la fonctionnalité ajoute un nouveau service

  • Le service est-il enregistré dans DI ? → assurer l'enregistrement dans IoCExtensions
  • Un service existant a-t-il une dépendance circulaire potentielle ? → vérifier

Si la fonctionnalité ajoute un nouvel endpoint

  • La route entre-t-elle en collision avec une autre route existante ? → vérifier
  • La méthode HTTP est-elle cohérente avec REST ? (GET pour la lecture, POST pour la mutation)

PHASE 1.8 — PREFLIGHT des tests de régression (obligatoire)

Objectif : avant de générer du nouveau code ou de modifier l'existant, vérifier que les composants qui vont être touchés (même tangentiellement) ont une couverture de tests. Si ce n'est pas le cas, les créer et les exécuter avant de commencer l'implémentation.

Étapes

  1. Identifier la surface tangentielle : à partir de la PHASE 1.5 (réutilisation vs extension vs nouveau), lister :

    • Services existants dont les méthodes vont être étendues ou surchargées
    • Interfaces existantes qui vont être modifiées
    • Endpoints existants qui peuvent être affectés par le routage/DI
    • Tout fichier existant qui va être édité (pas créé)
  2. Pour chaque composant existant qui va être touché :

    • Rechercher des tests dans src/*.Test*/** qui l'exercent
    • S'il a une couverture → OK, continuer
    • Si aucune couverture → HARD BLOCK :
      • Invoquer @refactor-worker-tests pour créer des tests de caractérisation du comportement actuel
      • Invoquer @refactor-verifier pour confirmer qu'ils passent au vert
      • Commit séparé :
        test(characterization): add characterization tests for <classes>
        
  3. Si la fonctionnalité est 100% création nouvelle (ne touche aucun fichier existant) :

    • Pas de surface de régression → omettre PREFLIGHT
    • Mais les tests de la nouvelle fonctionnalité sont créés en PHASE 4 et doivent passer en PHASE 5

Critère de clôture (PHASE 5)

Pour valider la fonctionnalité, @refactor-verifier doit confirmer que passent :

  1. Nouveaux tests de la fonctionnalité (service + endpoint)
  2. Tests existants des composants tangentiels (régression)

Si l'un ou l'autre échoue, la fonctionnalité ne peut pas être clôturée.


PHASE 2 — Arbre de décision : quoi créer et où

Appliquer la décision de la PHASE 1.5 (réutilisation / extension / nouveau) plus la PHASE 1.6 (config).

Pour endpoint READ-ONLY avec réutilisation

*.API/
  + {Nom}Function.cs       — Function/Controller nouveau
  + {Nom}Request.cs        — exclusif à la présentation
  + {Nom}Response.cs       — exclusif à la présentation
*.Test*/
  + {Nom}FunctionTests.cs  — test de la forme de la réponse (PAS de logique)

Pour endpoint MUTATION avec nouveau service

*.Contracts/
  + ICS{Nom}Service.cs     — interface du service
  + {Nom}Request.cs        — si Request partagé
  + {Nom}Response.cs       — si Response partagé
*.Impl/
  + CS{Nom}Service.cs      — implémentation
  + I{Nom}Options.cs       — UNIQUEMENT si la PHASE 1.6 a détecté une config
*.API/
  + {Nom}Function.cs       — Function/Controller
  + {Nom}Request.cs        — exclusif (si non mis dans Contracts)
  + {Nom}Response.cs       — exclusif (si non mis dans Contracts)
*.Test*/
  + CS{Nom}ServiceTests.cs — happy path + au moins une erreur

Pour extension d'un service existant

*.Contracts/
  ~ ICS{Nom}Service.cs     — ajouter la signature de la méthode (ou créer une surcharge)
*.Impl/
  ~ CS{Nom}Service.cs      — implémenter la nouvelle méthode/surcharge
*.API/
  + {Nom}Function.cs       — Function/Controller nouveau
  + {Nom}Request.cs        — si exclusif
  + {Nom}Response.cs       — si exclusif
*.Test*/
  + (ou ~) tests du service — ajouter un cas pour la nouvelle méthode

PHASE 3 — Plan de création

Avant d'invoquer les workers, l'orchestrateur présente ce plan à l'utilisateur et attend une confirmation explicite :

[PLAN DE CRÉATION] Fonctionnalité : <nom> — <description brève>
Hôte : <FUNCTIONS | WEBAPP>
Classification : <READ-ONLY | MUTATION>
Stratégie : <RÉUTILISATION | EXTENSION | NOUVEAU>

Analyse de réutilisation (PHASE 1.5) :
  · Service candidat : <ICSXxxService> ou "aucun"
  · Méthode candidate : <XxxService.YyyMethod> ou "aucun"
  · Décision : <RÉUTILISATION | EXTENSION | NOUVEAU>

Analyse de configuration (PHASE 1.6) :
  · Nécessite config : <OUI | NON>
  · Si oui : <IXxxOptions + section appsettings>

Impact sur l'API publique (PHASE 1.7) :
  · Sites d'appel affectés : <liste> ou "aucun"
  · Breaking change : <OUI | NON>

Artefacts à créer :

  *.Contracts/ ([N] fichiers) :
    + ICS{Nom}Service.cs    — nouvelle interface (ou : ajouter une méthode à IXxx)
    + {Nom}Request.cs       — si type partagé
    + {Nom}Response.cs      — si type partagé

  *.Impl/ ([N] fichiers) :
    + CS{Nom}Service.cs     — implémentation du service
    + I{Nom}Options.cs      — UNIQUEMENT si nécessite config (PHASE 1.6)

  *.API/ ([N] fichiers) :
    + {Nom}Function.cs      — Azure Function (ou : {Nom}Controller.cs)
    + {Nom}Request.cs       — si type exclusif
    + {Nom}Response.cs      — si type exclusif

  *.Test*/ ([N] fichiers) :
    + CS{Nom}ServiceTests.cs — tests du service (happy path + erreur)
    + {Nom}FunctionTests.cs  — tests de l'endpoint (si applicable)

Modifications aux fichiers existants :
  ~ src/.../IoCExtensions.cs   — enregistrer le service et les options (si applicable)

Ordre d'exécution : Contracts → Impl → Présentation → Tests

Dois-je procéder ?

Sans approbation explicite de l'utilisateur, n'invoquer aucun worker.


PHASE 4 — Exécution

Ordre des workers

  1. @refactor-worker-contracts — seulement s'il y a de nouveaux types ou signatures dans *.Contracts/
  2. @refactor-worker-impl — chaque fois qu'il y a du code dans *.Impl/
  3. @refactor-worker-presentation — chaque fois qu'il y a un endpoint
  4. @refactor-worker-tests — toujours à la fin

Remarque : N'invoquez PAS @refactor-worker-crosscutting sauf si la fonctionnalité expose une nouvelle Service Gateway. C'est un cas rare lors de la création ; cela arrive généralement lors de refactorisations.

Instructions à chaque worker

Inclure dans le prompt :

  • Le plan complet (PHASE 3)
  • Les patrons du projet : lire un fichier similaire avant de créer
  • La liste exacte des fichiers avec leur contenu attendu
  • Si la PHASE 1.6 a détecté une config : le chemin de IXxxOptions et la section de configuration

PHASE 5 — Vérification et commit

  1. Invoquer @refactor-verifier
  2. Si PASS → proposer un commit avec le format :
    feat(<scope>): add <nom-court> feature
    
    - Added ICS{Nom}Service interface and CS{Nom}Service implementation
    - Added {VERBE} /{route} Function/Controller
    - Added {Nom}Request/{Nom}Response contracts
    - Added I{Nom}Options for new configuration (si applicable)
    - Added unit tests for CS{Nom}Service
    
  3. Si FAIL → identifier la couche défaillante, ré-invoquer le worker, re-vérifier

Patrons par hôte

FUNCTIONS — Azure Functions Isolated Worker

Avant de créer la Function, lire une Function HTTP existante et copier son style. Exemple typique :

public class {Nom}Function
{
    private readonly I{Nom}Service _{champ};

    public {Nom}Function(I{Nom}Service {champ}) => _{champ} = {champ};

    [Function("{Nom}Function")]
    public async Task<HttpResponseData> RunAsync(
        [HttpTrigger(AuthorizationLevel.Function, "post", Route = "{route}")] HttpRequestData req)
    {
        var request = await req.ReadFromJsonAsync<{Nom}Request>();
        var result = await _{champ}.ExecuteAsync(request);
        var response = req.CreateResponse(HttpStatusCode.OK);
        await response.WriteAsJsonAsync(result);
        return response;
    }
}

Vérifier avant de créer :

  • AuthorizationLevel.Function ou AuthorizationLevel.Anonymous ?
  • Le verbe HTTP correspond-il au comportement (lecture/écriture) ?
  • Les noms des paramètres respectent-ils la convention (req, request, etc.) ?

WEBAPP — ASP.NET Core Controllers

[ApiController]
[Route("api/[controller]")]
public class {Nom}Controller : ControllerBase
{
    private readonly I{Nom}Service _{champ};

    public {Nom}Controller(I{Nom}Service {champ}) => _{champ} = {champ};

    [HttpPost("{route}")]
    public async Task<ActionResult<{Nom}Response>> ExecuteAsync({Nom}Request request)
    {
        var result = await _{champ}.ExecuteAsync(request);
        return Ok(result);
    }
}

Vérifier avant de créer :

  • Le routage correspond-il à la convention existante ?
  • Les attributs [FromBody], [FromQuery], etc., sont-ils présents si nécessaire ?
  • La méthode de retour est-elle cohérente (Ok, Created, etc.) ?

Résumé des types par couche

CoucheRôlesExemples
*.Contracts/Interfaces de service, DTOs partagés (Request/Response)ICSBookingService, BookingRequest
*.Impl/Implémentations de services, options de configurationCSBookingService, IBookingOptions
*.Impl/Services/Implémentations concrètes avec logique métierCSBookingService, CSPaymentService
*.API/Endpoints HTTP (Functions ou Controllers), DTOs exclusifsGetBookingFunction, BookingRequest
*.Test*/Tests unitaires et d'intégrationCSBookingServiceTests, GetBookingFunctionTests

Skills associés