C# et .NET : développement web moderne

Se connecter pour s'inscrire

De la LTS en vigueur à l'API en production

Maîtriser C# moderne et ASP.NET Core : nullabilité vérifiée par le compilateur, asynchrone avec annulation, architecture en couches, injection de dépendances, Entity Framework Core, tests et mise en production. Le cours s'ancre sur la version LTS en vigueur, dont la date de fin de support est un critère d'architecture.

  1. Public cible

    Débutants, étudiants et professionnels qui souhaitent acquérir une pratique structurée dans ce domaine.

  2. Objectifs

    Comprendre les notions essentielles et les appliquer dans un projet vérifiable.

  3. Prérequis

    Aucune connaissance préalable n’est strictement obligatoire ; les prérequis détaillés sont précisés dans les ateliers.

  4. Niveau

    Tous niveaux

  5. Ressources

    • Documentation officielle et références citées dans les ateliers.
    • Exercices, examens et projet de synthèse du catalogue.
  6. Validation des compétences

    La validation repose sur les évaluations actives et les livrables pratiques du cours.

  7. Besoins techniques

    Un ordinateur, un navigateur et les outils indiqués dans le premier atelier sont suffisants pour commencer.

Exercices, examens et projets

C# moderne et le runtime .NET

Exercice

Atelier ASP.NET Core

Écrire une API avec transaction, annulation et tests de cas limites.

Obligatoire Consulter
Examen

Examen C# et .NET

Évaluer conception, concurrence, requêtes et déploiement.

Obligatoire Consulter

Architecture : SOLID et injection de dépendances

Exercice

Atelier ASP.NET Core

Écrire une API avec transaction, annulation et tests de cas limites.

Obligatoire Consulter
Examen

Examen C# et .NET

Évaluer conception, concurrence, requêtes et déploiement.

Obligatoire Consulter

ASP.NET Core et Entity Framework Core

Exercice

Atelier ASP.NET Core

Écrire une API avec transaction, annulation et tests de cas limites.

Obligatoire Consulter
Examen

Examen C# et .NET

Évaluer conception, concurrence, requêtes et déploiement.

Obligatoire Consulter

Tests, concurrence et qualité

Exercice

Atelier ASP.NET Core

Écrire une API avec transaction, annulation et tests de cas limites.

Obligatoire Consulter
Examen

Examen C# et .NET

Évaluer conception, concurrence, requêtes et déploiement.

Obligatoire Consulter

Mise en production

Exercice

Atelier ASP.NET Core

Écrire une API avec transaction, annulation et tests de cas limites.

Obligatoire Consulter
Examen

Examen C# et .NET

Évaluer conception, concurrence, requêtes et déploiement.

Obligatoire Consulter

Projet final

Exercice

Atelier ASP.NET Core

Écrire une API avec transaction, annulation et tests de cas limites.

Obligatoire Consulter
Examen

Examen C# et .NET

Évaluer conception, concurrence, requêtes et déploiement.

Obligatoire Consulter
  1. C# moderne et le runtime .NET

    1. Choisir sa version : ce qui n'est pas négociable

      Une version sortie de support ne reçoit plus de correctifs de sécurité. C'est le seul critère qui doit décider, parce qu'il conditionne l'extérieur du projet : la conformité, la sécurité, la responsabilité contractuelle.

      Le rythme des versions

      Une version majeure par an, en novembre. L'alternance est fixe : les années impaires donnent une version LTS (support de trois ans), les années paires une version STS (deux ans). La qualité est identique dans les deux cas — seule la durée de support diffère. Un cours qui laisse croire qu'une version STS est moins bonne se trompe.

      L'état réel, relevé en septembre 2026

      VersionTypePhaseFin de support
      .NET 10LTSactive14 novembre 2028
      .NET 9STSmaintenance10 novembre 2026
      .NET 8LTSmaintenance10 novembre 2026

      La ligne à retenir pour un projet qui démarre : viser la LTS en vigueur, ici .NET 10. Deux conséquences pratiques :

      • .NET 8, longtemps référence comme « la LTS », cesse d'être soutenue dans moins de deux mois. Un projet neuf ne doit pas y démarrer ; un projet existant doit planifier la migration ;
      • la phase « maintenance » ne corrige plus que les failles de sécurité, plus aucune fonctionnalité. Une version qui y entre reste utilisée en production par des applications qui ne peuvent pas migrer, ce qui est la situation par défaut d'une grande partie du parc .NET en entreprise.

      Le tableau se vérifie en deux clics sur la page de support officielle. Le recopier ici ne le périme pas : c'est la page qui fait foi, et c'est elle qu'un projet doit consulter au moment de son arbitrage.

    2. Types, nullabilité et unmistakable

      C# est à typage statique : le type est connu à la compilation, et le vérificateur de nullité est activé par défaut. Ce second point est un changement majeur par rapport à l'usage courant du langage.

      Les types de valeur et les types de référence

      Un type de valeur contient sa donnée ; un type de référence contient une adresse. La conséquence : copier un type de valeur duplique la donnée, copier un type de référence copie l'adresse — les deux pointent alors vers le même objet. Comprendre cette différence évite une famille entière de bugs où l'on croit modifier une copie.

      La nullabilité, compilée

      Une référence peut ne pointer vers rien. Le langage le signale dans le type : string garantit non nul, string? indique qu'il peut l'être. L'avertissement n'est pas un avertissement, c'est une erreur de compilation.

      C'est le meilleur rapport qualité/prix de l'écosystème C# moderne : impossible de déréférencer une référence nulle sans que le compilateur l'ait signalé. Ce qui n'est pas traité reste à traiter — avec un motif explicite, jamais un simple null-forgiving operator posé pour faire disparaître l'erreur.

      Les types immuables : records

      Un record définit une valeur dont l'identité est son contenu, pas sa référence. Il est par défaut immuable et fournit nativement l'égalité par valeur, que les classes ne donnent pas. Pour un objet de transfert — un résultat de calcul, une ligne de commande, une réponse d'API, c'est le bon choix par défaut, et l'expression with permet de dériver une version modifiée sans muter l'original.

      Attention à ne pas confondre : record class reste une référence, record struct est un type de valeur. Le choix change la sémantique de passage.

    3. Asynchrone : await, annulation, pièges

      Toute opération réseau ou d'entrée-sortie est asynchrone. Le mot-clé async/await libère le thread pendant l'attente, ce qui permet à un serveur de servir des milliers de requêtes avec peu de threads.

      Pourquoi await est préférable à .Result

      Bloquer sur une tâche asynchrone avec .Result ou .Wait() provoque un interblocage dans un contexte de synchronisation : le thread qui doit exécuter la suite attend un résultat qui ne peut pas être produit, parce que le thread nécessaire est bloqué. Le programme se fige, sans message d'erreur. C'est le piège le plus coûteux du langage, parce qu'il ne se manifeste qu'en application web, jamais dans un exécutable console.

      L'annulation n'est pas optionnelle

      Une opération asynchrone doit accepter un jeton d'annulation et le transmettre à toutes les opérations en aval. C'est ce qui permet, lorsqu'un utilisateur ferme un onglet ou change de page, d'interrompre le travail au lieu de le laisser s'exécuter jusqu'au bout pour un résultat que plus personne ne lira. Le serveur ne s'en rend pas compte tout seul.

      La règle : une signature asynchrone qui ne prend pas de jeton d'annulation est incomplète.

      Les deux pièges de performance

      1. l'accès concurrent à une collection : une liste ordinaire lue pendant qu'elle est écrite lève une exception ou produit un résultat faux, de façon imprévisible. La version asynchrone, prévue pour, ou un verrou explicite ;
      2. l'async sans await : une méthode marquée async sans await génère un avertissement et s'exécute de façon synchrone, ce qui crée une attente bloquante déguisée.

      La règle de conception qui évite les deux : propager le jeton d'annulation jusqu'aux feuilles de l'arbre d'appels, plutôt que de l'absorber au niveau du service. Une exception capturée et ignorée en cours de route est le moyen le plus sûr de perdre une annulation sans le voir.

  2. Architecture : principes SOLID et injection de dépendances

    1. Les principes SOLID, et ce qu'ils valent vraiment

      Les principes SOLID sont des critères de conception, pas des recettes à cocher. Savoir les nommer ne sert à rien ; savoir à quel défaut d'architecture chacun répond, oui.

      Chaque principe masque un symptôme

      PrincipeLe symptôme qu'il traite
      Responsabilité unique une classe qui change pour trois motifs non liés ; c'est elle qu'on ouvre a chaque nouvelle demande
      Ouvert/fermé chaque nouveau cas oblige à modifier un code existant qui fonctionnait
      Substitution une hiérarchie où la sous-classe casse l'attente de la classe mère
      Interface segregation un client forcé d'implémenter des méthodes qu'il n'utilise pas
      Inversion des dépendances un composant de haut niveau qui dépend d'un composant de détail

      L'erreur d'application

      Le symptôme le plus cité est « la classe trop grosse ». Le vrai problème n'est pas sa taille : c'est qu'elle change pour des raisons sans rapport. Une classe de six cents lignes qui gère une seule chose est un bon candidat ; une classe de quatre-vingts lignes dont la moitié des méthodes ne sert à personne est un mauvais.

      Le test de la responsabilité unique

      Une formulation courte : « Cette classe changerait-elle si l'exigence changeait ? » Si oui, la raison du changement est une responsabilité distincte. Appliquée à un service qui valide, calcule, enregistre et envoie un e-mail, elle isole les quatre en une réponse, sans diagramme.

      Quand ne pas appliquer le principe

      Découper systématiquement produit ce que la littérature appelle la dispersion conceptuelle : vingt fichiers pour une fonctionnalité, et plus personne ne sait où chercher. Le découpage se justifie quand la séparation correspond à deux notions qui changent pour deux raisons différentes. Sinon, on a ajouté de la complexité d'injection sans aucun bénéfice.

    2. L'injection de dépendances : inversion du contrôle

      L'injection de dépendances est le mécanisme technique qui rend possible l'inversion des dépendances. Le principe dit qu'un composant de haut niveau ne doit pas créer lui-même ce dont il dépend ; le mécanisme dit comment on lui fournit.

      Le service localisé est déjà une dépendance

      Écrire new HttpClient() dans une méthode n'est pas « utiliser une dépendance », c'est créer la dépendance sur place. Le composant est alors lié à un type concret et à son cycle de vie, et il devient impossible à tester sans déclencher un accès réseau réel.

      Le conteneur d'inversion de contrôle fourni avec l'écosystème résout ce cas : la dépendance est déclarée dans le constructeur, et le conteneur fournit l'instance. Le service ignore tout du cycle de vie, et un test lui passe une doublure.

      Portée des instances

      • transitoire : une nouvelle instance par résolution. Par défaut, et rarement justifié ;
      • avec portée : une instance partagée par demande HTTP. C'est la portée à utiliser par défaut, car elle garantit qu'un état de requête ne fuit pas vers la requête suivante ;
      • simple instance : partagée par toute l'application. À réserver aux services sans état et thread-safe — un piège classique est d'y stocker une propriété par utilisateur.

      La fuite d'état entre requêtes est le bug le plus coûteux de ce mécanisme, et il est invisible en développement mono-utilisateur. Il apparaît en production avec un second utilisateur, puis devient impossible à reproduire en recette.

    3. Du modèle métier à l'API

      Une application se lit en couches. L'erreur classique est de les confondre : le modèle métier qui connaît le format JSON, ou le contrôleur qui contient une règle de gestion.

      Le sens de la dépendance

      Les dépendances pointent toujours vers l'intérieur. La couche API connaît le service, le service connaît le domaine, le domaine ne connaît personne. Cette règle Unique et simple rend le cœur métier testable sans base de données, sans réseau et sans framework — ce qui est la définition même d'un code testable rapidement.

      L'exception qui prouve la règle

      Le domaine a besoin d'un concept externe : un identifiant unique, un horodatage, une unité monétaire. Il ne doit pas pour autant importer la bibliothèque qui le fournit. On déclare une abstraction dans le domaine, on fournit l'implémentation par injection. La règle reste respectée, et le domaine compilera seul.

      Le modèle ne doit pas exposer son stockage

      Un objet entité repris tel quel dans une réponse JSON va exposer ce qu'il ne devrait pas : un identifiant technique interne, une date de mise à jour, parfois un hash de mot de passe ou un numéro de sécurité sociale si le mapping est baclé. La séparation entre modèle de persistance et modèle d'échange n'est pas de la sur-ingénierie : c'est ce qui évite qu'une migration de base de données casse une API publique.

      Où s'arrêtent les couches

      Une couche de plus n'est pas automatiquement mieux. Trois couches — API, application, domaine — suffisent à la quasi-totalité des cas. Le critère de découpage n'est jamais le nombre de couches, mais le fait qu'une couche puisse être remplacée indépendamment : un jour où la base change, seul le dépôt doit bouger.

  3. ASP.NET Core et Entity Framework Core

    1. ASP.NET Core : le pipeline et ses interceptions

      Une requête ASP.NET Core traverse un pipeline ordonné. Chaque élément peut agir sur la requête avant qu'elle n'atteigne le contrôleur, ou sur la réponse au retour.

      L'ordre est le contrat

      Un intercepteur d'authentification placé après l'autorisation ne protège plus de rien ; une journalisation placée après le gestionnaire d'exceptions n'enregistrera pas les erreurs non gérées. Un composant mal placé est un composant inopérant, sans le moindre avertissement. C'est la première cause d'incident de production sur un pipeline d'authentification.

      Le risque direct : l'ordre des filtres

      Le piège le plus coûteux du modèle est l'exception filters : par défaut, une exception non gérée dans un contrôleur court-circuite la chaîne et part directement vers le middleware global. Le filtre d'exception placé sur le contrôleur n'est jamais appelé — la documentation le signale, et c'est la première cause d'erreurs rendues en 500 sans corps utile, alors que le gestionnaire prévu existe.

      Deux remèdes : rechercher explicitement l'exception dans le gestionnaire global, ou activer le court-circuit explicite. Le choix se documente, parce qu'il change le comportement du pipeline entier.

      La configuration : deux erreurs classiques

      • une clé de configuration en dur dans le code : le déploiement en préproduction utilise alors l'adresse de production, ou l'inverse. L'erreur apparaît au moment du test, pas avant ;
      • un secret en clair dans le fichier de configuration versionné. Les secrets passent par l'injection de variables d'environnement ou un coffre, jamais par le dépôt.

      Réflexe de vérification : la même exécution doit fonctionner avec deux fichiers de configuration différents, sans recompilation. Si le build produit exactement le même artefact partout, la configuration n'est pas injectée correctement.

      La gestion d'erreurs : la règle du statut

      Une API doit renvoyer un code de statut cohérent avec la situation : 400 pour une demande invalide, 401 pour une absence d'authentification, 403 pour un droit insuffisant, 404 pour une ressource absente, 409 pour un conflit d'état, 500 pour une erreur serveur. Le distinguer n'est pas cosmétique : 401 et 403 ne se traitent pas de la même façon côté client, et les confondre oblige le consommateur à deviner s'il doit rediriger vers une page de connexion ou afficher un message d'interdiction.

    2. Entity Framework Core : requêtes, suivi, transactions

      Entity Framework Core est un mappeur relationnel : des objets en mémoire, des tables en base. Toute la difficulté tient à la frontière entre les deux mondes.

      Différé par défaut, c'est un piège

      Une requête LINQ est évaluée au dernier moment quand le résultat est parcouru, pas à l'écriture. Deux conséquences qu'il faut connaître par cœur :

      • une requête dans une boucle produit une requête par tour — le défaut N+1, la cause de ralentissement la plus fréquente sur ce type d'ORM ;
      • le nombre de requêtes surprises est visible dans les journaux : c'est le seul contrôle fiable, et il automatise mieux qu'un test d'intégration.

      Le remède est l'inclusion explicite des relations nécessaires, ou le chargement paresseux activé par défaut avec l'inclusion de toutes les relations. Choisir l'un plutôt que l'autre est un arbitrage : le second est simple, le premier est prévisible.

      Le suivi des entités change la sémantique

      Par défaut, Entity Framework suit les entités lues : il conserve leur état initial et applique automatiquement les modifications détectées au moment de l'enregistrement. Conséquence directe et peu évidente : modifier une propriété sur un objet lu suffit à déclencher une mise à jour, sans appel explicite. C'est confortable, et c'est dangereux : une propriété de navigation qu'on touche par erreur produit une écriture inattendue en base.

      La parade : utiliser des requêtes sans suivi pour la lecture seule, et traiter l'écriture dans un composant dédié et explicite.

      Les transactions : le défaut par omission

      Par défaut, aucune transaction n'est ouverte autour d'un SaveChanges pris isolément. Dans une opération qui modifie plusieurs tables, un échec au milieu laisse un état intermédiaire incohérent : la commande est enregistrée mais pas son ligne de détail. La transaction explicite autour de l'ensemble est l'une des trois seules garanties d'intégrité, avec les clés étrangères et les contraintes d'unicité.

      Les requêtes paramétrées

      Le générateur de SQL produit toujours des requêtes paramétrées : les valeurs ne sont jamais concaténées dans le texte SQL. C'est une garantie de l'ORM, et elle protège de l'injection à condition de ne pas contourner le générateur. Dès qu'on écrit du SQL à la main, la securite redevient une responsabilité du développeur, avec le paramétrage explicite comme seule parade.

  4. Tests, concurrence et qualité

    1. Ce qui se teste, et ce qui ne se teste pas

      Le langage rend le test unitaire simple, parce que le code se décompose en méthodes pures sans état caché. Cette simplicité a un revers : il est tentant de tester des détails d'implementation, ce qui produit une suite lente et fragile sans protéger quoi que ce soit.

      La hiérarchie, du plus rapide au plus lent

      1. unitaire : une méthode, sans base ni reseau. Millisecondes, doit couvrir les cas limites et les règles de gestion ;
      2. d'intégration : avec la base réelle, dans un conteneur éphémère. Plus lents, mais ce sont eux qui détectent les défauts de transaction et de contrainte, qu'aucun test unitaire ne peut voir ;
      3. de bout en bout : peu de scénarios critiques. À traiter comme une vérification ponctuelle, pas comme une couverture.

      Le critère de décision

      La question n'est jamais « faut-il tester ça ? » mais « quel comportement doit rester vrai, et comment saurai-je qu'il est rompu ? »

      • on teste les règles de gestion : elles portent le risque métier, et une régression y coûte cher ;
      • on teste les cas limites : liste vide, dépassement de capacité, nullité, valeurs négatives. Les tests qui n'utilisent que des cas nominaux ne passent jamais par le chemin du bug ;
      • on ne teste pas un accesseur ni une propriété calculée : le test reproduirait l'implémentation, et échouerait à chaque refonte légitime.

      Test vérifié : si le comportement change et que le test échoue, il fait son travail ; s'il échoue pour une raison sans rapport avec le comportement, il coûte.

    2. Concurrence : le domaine qui produit le pire bug

      Le runtime asynchrone rend l'accès concurrent naturel : deux requêtes peuvent s'exécuter entrelacées dans le même processus. Un code écrit pour un seul utilisateur à la fois fonctionne en développement et échoue en production.

      Trois pièges, par ordre de fréquence

      1. l'état partagé entre requêtes : un service à portée d'application qui conserve une propriété par utilisateur. Les deux utilisateurs se contaminent. Invisible en recette à un seul compte ;
      2. la collection modifiée en lecture : l'accès à une liste ordinaire pendant qu'on y ajoute produit une exception ou un résultat faux, de façon imprévisible ;
      3. l'accès à une base de donnees non partagee pour une opération longue : un objet de contexte Entity Framework n'est pas thread-safe, et le partager entre tâches produit des corruptions de suivi d'entités quasi impossibles à diagnostiquer.

      La règle de portée, à retenir telle quelle

      Par défaut, un service doit être avec portée — une instance par requête. C'est la seule portée qui garantit l'isolation entre utilisateurs. La portée d'application ne se justifie que pour un service explicitement sans état, ce qui se vérifie en relisant ses champs.

      Comment trouver un bug de concurrence avant la production

      • tester avec plusieurs utilisateurs en parallèle, sur les mêmes données : c'est le seul moyen de reproduire un mélange d'état ;
      • chercher les propriétés mutables des services à portée d'application ;
      • vérifier que chaque unité de travail est confine à une requête, jamais partagée ni mise en champ statique.

      Un test de concurrence n'est pas déterministe, et c'est normal : il ne prouve pas l'absence de bug, il prouve qu'un scénario précis échoue. Un test qui passe une fois sur cent n'est pas rassurant, il est informatif.

  5. Mise en production

    1. Publier sans casser, et ce qui casse quand même

      La publication est l'étape où les hypothèses de développement se vérifient. Ce qui a été supposé disponible localement ne l'est pas forcément.

      Les quatre différences d'environnement

      1. la configuration : clés de connexion, adresses d'API, seuils. Un environnement qui lit un fichier de configuration de développement se connecte au mauvais serveur, ou échoue au démarrage. C'est le défaut le plus fréquent, et il se voit immédiatement — ce qui en fait le moins coûteux ;
      2. les secrets : jamais dans le dépôt, jamais dans un fichier versionné. Ils viennent de l'environnement d'exécution ou d'un coffre, et l'application échoue au démarrage s'ils manquent — ce qui est le comportement voulu ;
      3. les migrations de base : appliquées automatiquement, elles peuvent s'exécuter deux fois si deux instances démarrent ensemble. La parade n'est pas de désactiver les migrations, mais de les rendre idempotentes et de sérialiser leur exécution ;
      4. la culture et le fuseau horaire : une sérialisation de date qui dépend de la culture produit un décalage d'un jour ou d'une heure selon la machine. Les dates se sérialisent en un format neutre, jamais en format local.

      La séquence de vérification avant ouverture

      • le même artefact est déployé sur tous les environnements, la configuration seule change ;
      • les migrations s'appliquent sur une base de staging proche de la production ;
      • le parcours critique est testé sur l'URL réelle ;
      • les journaux sont surveillés pendant les premières minutes, pas seulement le code de retour HTTP.

      Le point qui manque le plus souvent : une réponse 200 ne prouve pas que l'application fonctionne. Un 200 avec un corps d'erreur JSON, ou une page vide parce que la requête de données a échoué silencieusement, passe tous les tests de disponibilité. La vérification utile lit la réponse.

      Ce qu'il faut surveiller

      Le taux d'erreur par route et par code de statut, la latence au 95ᵉ centile — la moyenne masque les extrêmes —, la consommation mémoire, et le nombre de requêtes base de données par requête applicative. Ce dernier ne se voit pas dans les journaux applicatifs : il faut l'outillage de la base, et c'est là que traîne l'essentiel des problèmes de performance.

  6. Projet final et évaluation

    1. Projet final et évaluation

      Le projet

      Une API web en .NET sur la LTS en vigueur, avec authentification, gestion des rôles, opérations CRUD, pagination, filtres, et une base de données réelle. Le livrable comprend les migrations, les tests et la procédure de déploiement.

      Les huit critères, dans l'ordre d'importance

      1. l'intégrité transactionnelle : une opération multi-tables est atomique, et le test le démontre en provoquant un échec à mi-parcours ;
      2. l'authentification et l'autorisation : chaque route protégée l'est réellement, les rôles sont vérifiés côté serveur, jamais côté client ;
      3. les codes de statut : 400/401/403/404/409 sont distingués, pas fusionnés en 400 ou en 500 ;
      4. la gestion de l'asynchrone : aucune attente bloquante, jeton d'annulation propagé ;
      5. la nullabilité : aucun contournement du vérificateur sans motif écrit ;
      6. les requêtes : aucun défaut N+1, le nombre de requêtes par endpoint est mesuré et consigné ;
      7. les tests : règles de gestion, cas limites, erreurs de base. Un test d'accesseur n'est pas un test ;
      8. la configuration : aucun secret dans le dépôt, le même artefact fonctionne sur deux environnements.

      Le critère qui départage

      Le jury retient une chose : l'erreur est-elle détectable et compris ? Une application qui plante proprement avec un message exploitable vaut mieux qu'une application qui semble fonctionner et livre des incohérences. Les deux premiers critères techniques après cela sont l'annulation asynchrone et la transaction — les deux défauts que les clients signalent le plus souvent après livraison.

Sources et documentation de reference

Atelier guidé

Ecrire une API sur la LTS en vigueur, en treatments qu’un client reel ne casse pas.

  1. Transaction : une operation qui ecrit dans deux tables, avec un echec a mi-parcours, et la preuve qu’il ne reste rien.
  2. Asynchrone : propager le jeton d’annulation jusqu’a la feuille, et demontrer qu’une annulation arrete le travail.
  3. Acces : verifier la propriete de l’objet sur chaque route qui porte un identifiant, et ecrire le test qui le prouve.
  4. Requetes : mesurer le nombre de requetes base par appel, et supprimer le N+1.

Restitution de l’atelier

  • Le projet, compilant sans avertissement.
  • Les tests de transaction, d’annulation et de controle d’accès.
  • La note de deploiement : configuration, migrations, retour arriere.
Validation : Le test d'annulation echoue si on retire la propagation du jeton. Aucun secret n’est dans le depot.

Publié le 29/09/2026