Projet alternance — BTS SIO SLAM

WAChangeLogUrgence — Fiche technique

Application web de gestion des notes de mise à jour (changelogs) pour les logiciels Urgence, Akostp et Akosone. Développée en alternance avec une architecture découplée frontend/backend.

Backend (C#) Frontend (Angular) Démo live
Identifiants démo — login : keryan  |  mot de passe : Test1234!
ASP.NET Core 8 Angular 17 MySQL Entity Framework Core JWT REST API
Captures d'écran
Page de connexion
Page de connexion WAChangeLogUrgence
Liste des changelogs
Liste des changelogs WAChangeLogUrgence
Inscription
Page d'inscription WAChangeLogUrgence
Stack technique et choix
Backend

ASP.NET Core 8 (C#)

Framework Microsoft open-source, performant et typé. Choisi car c'est la technologie principale utilisée en entreprise. Permet de créer une API REST claire avec contrôleurs, services et modèles bien séparés.

Frontend

Angular 17 (TypeScript)

Framework SPA (Single Page Application) de Google. TypeScript apporte un typage fort qui réduit les bugs. Angular structure le code en composants réutilisables — choix imposé par l'entreprise pour cohérence avec les autres projets.

Base de données

MySQL + Entity Framework Core

MySQL est un SGBD relationnel éprouvé, open-source. Entity Framework Core est l'ORM utilisé pour éviter d'écrire du SQL brut et gérer les migrations de schéma via le code C#.

Sécurité

JWT (JSON Web Token)

Authentification stateless : à la connexion, le serveur délivre un token signé (valide 15 min) et un refresh token (7 jours). Chaque requête protégée transporte ce token — le serveur n'a pas besoin de stocker de session.

Architecture 3-tiers
┌─────────────────────────────────────────────────────┐ │ NAVIGATEUR (Client) │ │ Angular SPA — TypeScript / HTML │ │ Composants : ChangeLog list, formulaire, login... │ └────────────────────┬────────────────────────────────┘ │ Requêtes HTTP/HTTPS (JSON) │ + Token JWT dans l'en-tête ┌────────────────────▼────────────────────────────────┐ │ SERVEUR APPLICATIF │ │ ASP.NET Core 8 — API REST (C#) │ │ Controllers → Services → Entity Framework Core │ └────────────────────┬────────────────────────────────┘ │ Requêtes SQL (via ORM) ┌────────────────────▼────────────────────────────────┐ │ BASE DE DONNÉES │ │ MySQL 8 │ │ Tables : AspNetUsers, ChangeLogs │ └─────────────────────────────────────────────────────┘ Avantages de cette séparation : • Le frontend peut être modifié sans toucher au backend • L'API peut être consommée par d'autres clients (mobile, etc.) • Chaque couche est testable indépendamment
Pattern MVC — Model View Controller
Qu'est-ce que le pattern MVC et comment est-il appliqué ici ?
MVC (Model-View-Controller) est un patron d'architecture qui divise une application en 3 couches :

  • Model : les données et la logique métier
  • View : l'interface présentée à l'utilisateur
  • Controller : l'intermédiaire qui reçoit les actions, interroge le Model et renvoie la View

Dans ce projet, l'architecture est une variante MVC découplée (API REST + SPA) : la View est entièrement gérée par Angular côté client, et le backend ASP.NET ne renvoie plus de HTML mais du JSON.
MVC dans WAChangeLogUrgence ── MODEL (C# — ASP.NET Core) ──────────────────────────────────── ChangeLog.cs → classe C# représentant une entrée changelog ApplicationUser.cs → classe C# représentant un utilisateur (hérite IdentityUser) AppDbContext.cs → pont entre les modèles et MySQL via Entity Framework ── CONTROLLER (C# — ASP.NET Core) ────────────────────────────── ChangeLogController → reçoit GET/POST/DELETE, appelle les services, renvoie JSON AuthController → gère /login /register /refresh-token Exemple de flux : Angular → POST /api/ChangeLog (JSON) → ChangeLogController.CreateOrUpdate() → AppDbContext.SaveChanges() → retourne 200 OK + objet JSON ── VIEW (TypeScript/HTML — Angular) ───────────────────────────── ChangeLog.component.html → tableau des changelogs, pagination, recherche login.component.html → formulaire de connexion ChangeLog.service.ts → service HTTP qui appelle l'API REST auth.interceptor.ts → injecte automatiquement le JWT dans chaque requête
Pourquoi parle-t-on de MVC "découplé" ici ?
Dans un MVC classique (ex: PHP/Laravel, Ruby on Rails), le Controller génère directement du HTML et le renvoie au navigateur. Le Model, la View et le Controller sont tous sur le même serveur.

Ici, la View est séparée physiquement du Controller :
  • Le Controller (ASP.NET) tourne sur le serveur et ne produit que du JSON
  • La View (Angular) tourne dans le navigateur du client et consomme ce JSON

Ce découplage permet de faire évoluer le frontend et le backend indépendamment, et d'avoir plusieurs clients possibles (app mobile, autre frontend) qui consomment la même API.
Quel est le rôle des Services par rapport aux Controllers ?
Pour garder les Controllers légers, la logique métier est extraite dans des Services :

  • AuthController reçoit la requête HTTP et délègue à AuthService
  • AuthService contient la vraie logique : vérification du mot de passe, génération du token JWT, mise à jour du refresh token...

Le Controller ne fait que router la requête et formater la réponse. C'est le principe de séparation des responsabilités (Single Responsibility Principle).
Compétences BTS SIO mobilisées (Annexe 8-3)
Compétence du bloc E5 Comment elle est mobilisée dans ce projet
Travailler en mode projet Analyse du besoin (gérer les versions logicielles), planification des fonctionnalités (CRUD, auth, pagination), livraison itérative.
Mettre à disposition un service informatique Livraison du service à l'entreprise, tests fonctionnels manuels effectués (connexion, CRUD, pagination, cas d'erreur).
Répondre aux demandes d'évolution Application existante modifiée et adaptée pour usage local : suppression restriction domaine email, adaptation BDD, encodage utf8mb4.
Gérer le patrimoine informatique Gestion des habilitations via système de comptes (ASP.NET Identity), tokens JWT avec expiration, refresh tokens sécurisés.
Organiser son développement professionnel Découverte autonome d'ASP.NET Core et Angular en alternance, veille sur les pratiques REST et sécurité API (JWT, HTTPS).
Interaction avec la base de données — de la requête HTTP au SQL

1. Vue d'ensemble : qui fait quoi ?

Angular → HTTP GET /api/ChangeLog?logiciel=1&pageNumber=1 ↓ ChangeLogsController (reçoit la requête, extrait les paramètres) ↓ ChangeLogService (logique métier — construit la requête LINQ) ↓ AppDbContext (Entity Framework Core — traduit LINQ → SQL) ↓ MySQLSELECT * FROM ChangeLogs WHERE Logiciel=1 ORDER BY NumVersion LIMIT 10AppDbContext (mappe les lignes SQL → objets C# ChangeLog) ↑ Controller → JSON → Angular

Il n'y a aucun SQL écrit manuellement dans le code. C'est Entity Framework Core qui génère le SQL à partir du code C#.

2. Le modèle ChangeLog — classe C# = table MySQL

Chaque propriété C# correspond à une colonne en base. Les annotations ([Required], [MaxLength]) définissent les contraintes SQL.

public class ChangeLog { public int Id { get; set; } // colonne INT AUTO_INCREMENT PK public LogicielType Logiciel { get; set; } // colonne INT (enum stocké en int) public int NumVersion { get; set; } // colonne INT + INDEX [MaxLength(255)] public string Titre { get; set; } // colonne VARCHAR(255) public string Contenu { get; set; } // colonne LONGTEXT public DateTime DateAjout { get; set; } // colonne DATETIME public string CreePar { get; set; } // nom d'utilisateur depuis le JWT } // L'enum LogicielType est stocké comme un entier en BDD : public enum LogicielType { Urgence = 1, Akostp = 2, Akosone = 3 }

3. L'AppDbContext — le pont entre C# et MySQL

AppDbContext hérite d'IdentityDbContext (qui gère déjà les tables utilisateurs ASP.NET Identity) et expose un DbSet<ChangeLog> — c'est la représentation C# de la table MySQL.

public class AppDbContext : IdentityDbContext<ApplicationUser> { // DbSet = représentation de la table "ChangeLogs" en C# public DbSet<ChangeLog> ChangeLogs { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // tables Identity (AspNetUsers etc.) modelBuilder.Entity<ChangeLog>(entity => { entity.HasKey(e => e.Id); // PRIMARY KEY entity.HasIndex(e => e.NumVersion); // CREATE INDEX sur NumVersion entity.Property(e => e.Titre) .HasMaxLength(255).IsRequired(); // VARCHAR(255) NOT NULL }); } }

Pourquoi hériter d'IdentityDbContext ? ASP.NET Identity a besoin de ses propres tables (AspNetUsers, AspNetRoles…). En héritant d'IdentityDbContext, EF Core génère et gère automatiquement ces tables en plus de ChangeLogs — une seule migration couvre tout.

4. Le Service — LINQ traduit en SQL par EF Core

Le ChangeLogService reçoit le AppDbContext par injection de dépendance (configuré dans Program.cs). Il utilise LINQ — une syntaxe de requête C# que EF Core traduit automatiquement en SQL.

// Code C# dans ChangeLogService.cs : var query = _context.ChangeLogs.AsQueryable(); // Filtre optionnel → EF ajoute : WHERE Logiciel = 1 if (logiciel.HasValue) query = query.Where(cl => cl.Logiciel == logiciel.Value); // Comptage total → SELECT COUNT(*) FROM ChangeLogs WHERE ... var total = await query.CountAsync(); // Pagination → ORDER BY NumVersion LIMIT 10 OFFSET 0 var results = await query .OrderBy(cl => cl.NumVersion) .Skip((pageNumber - 1) * pageSize) // OFFSET .Take(pageSize) // LIMIT .ToListAsync(); // ← c'est ICI que le SQL est exécuté // SQL généré par EF Core : -- SELECT * FROM `ChangeLogs` WHERE `Logiciel`=1 ORDER BY `NumVersion` LIMIT 10

Important : AsQueryable() ne déclenche pas de requête SQL immédiatement — il construit une expression. Le SQL n'est exécuté qu'à ToListAsync() ou CountAsync(). C'est ce qu'on appelle l'exécution différée (deferred execution).

5. Créer / modifier — EF Core détecte les changements

// Création d'un nouveau ChangeLog : _context.ChangeLogs.Add(changeLog); // EF marque l'objet "Added" await _context.SaveChangesAsync(); // → INSERT INTO ChangeLogs (...) VALUES (...) // Modification d'un existant : _context.ChangeLogs.Update(changeLog); // EF marque l'objet "Modified" await _context.SaveChangesAsync(); // → UPDATE ChangeLogs SET ... WHERE Id=5 // Suppression : _context.ChangeLogs.Remove(changeLog); // EF marque l'objet "Deleted" await _context.SaveChangesAsync(); // → DELETE FROM ChangeLogs WHERE Id=5 // Cas particulier du projet — détacher avant de mettre à jour pour éviter le conflit : _context.Entry(existingChangeLog).State = EntityState.Detached; // évite "already tracked" _context.ChangeLogs.Update(changeLog);

6. Les migrations — versionnement du schéma de base de données

Les migrations permettent de faire évoluer le schéma MySQL sans jamais l'écrire manuellement. EF Core compare le modèle C# actuel à l'état précédent et génère le SQL de transition.

# 1. On modifie la classe C# (ex : on ajoute une propriété) # 2. On génère la migration : dotnet ef migrations add AjoutColonnePriorite # → crée un fichier C# avec Up() et Down() # 3. On applique la migration en base : dotnet ef database update # → exécute : ALTER TABLE ChangeLogs ADD COLUMN Priorite INT # Dans Program.cs, au démarrage de l'appli : dbContext.Database.Migrate(); // applique automatiquement toutes les migrations en attente

Pourquoi c'est important : sans migrations, modifier le schéma en production nécessite d'écrire du SQL à la main et de le synchroniser avec le code. Avec les migrations, le fichier C# est la source de vérité — Git versionne le schéma comme le reste du code.

7. Injection de dépendance — comment le contexte arrive dans le service

// Program.cs — enregistrement du contexte dans le conteneur IoC : builder.Services.AddDbContext<AppDbContext>(options => options.UseMySQL(builder.Configuration.GetConnectionString("DefaultConnection"))); builder.Services.AddScoped<ChangeLogService>(); // une instance par requête HTTP // ChangeLogService — reçoit le contexte via le constructeur : public class ChangeLogService { private readonly AppDbContext _context; public ChangeLogService(AppDbContext context) // ← injecté automatiquement { _context = context; } }

AddScoped signifie qu'une nouvelle instance de ChangeLogService (et de son AppDbContext) est créée à chaque requête HTTP, puis détruite à la fin. Cela évite les problèmes de concurrence entre requêtes parallèles.

FAQ — Questions probables du jury
Qu'est-ce qu'une API REST et pourquoi l'avoir utilisée ?
Une API REST (Representational State Transfer) est un style d'architecture web où chaque ressource est accessible via une URL et des verbes HTTP standards :

  • GET /api/ChangeLog → récupérer la liste
  • POST /api/ChangeLog → créer ou modifier
  • DELETE /api/ChangeLog/5 → supprimer l'ID 5

Pourquoi REST ? Parce que le frontend (Angular) et le backend (ASP.NET) sont sur des origines différentes. REST permet de les séparer complètement — Angular envoie des requêtes HTTP, le backend répond en JSON. Cela rend aussi l'API réutilisable par d'autres clients.
Qu'est-ce que JWT et pourquoi ce choix plutôt que des sessions ?
JWT (JSON Web Token) est un standard pour échanger des informations d'identité de façon sécurisée. Il se compose de 3 parties encodées en Base64 séparées par des points : header.payload.signature.

Fonctionnement dans le projet :
  • À la connexion, le serveur génère un JWT (valide 15 min) + un refresh token (7 jours)
  • Le frontend stocke les deux en cookie et envoie le JWT dans chaque requête via Authorization: Bearer <token>
  • Quand le JWT expire, Angular appelle automatiquement /api/auth/refresh-token pour en obtenir un nouveau

Avantage vs sessions : Authentification stateless — le serveur ne stocke pas de session en mémoire. Chaque token est auto-suffisant et vérifiable par signature cryptographique (HMAC SHA-256).
Qu'est-ce qu'un ORM et à quoi sert Entity Framework Core ?
Un ORM (Object-Relational Mapper) fait le lien entre les objets du code et les tables de la base de données. Au lieu d'écrire du SQL brut, on manipule des objets C# :

var logs = await _context.ChangeLogs.Where(c => c.Logiciel == 1).ToListAsync();

L'ORM génère automatiquement le SQL correspondant. Entity Framework Core permet aussi de gérer les migrations : quand on modifie le modèle C#, EF génère un script SQL pour faire évoluer la base sans la recréer à la main.
Qu'est-ce qu'une SPA (Single Page Application) ?
Une SPA est une application web qui charge une seule page HTML au démarrage, puis met à jour dynamiquement le contenu sans rechargement complet. Angular est un framework SPA.

Avantages : navigation fluide (pas de rechargement), expérience proche d'une application native.
Inconvénient : le premier chargement peut être plus lent (bundle JS important), et le référencement SEO est plus complexe.

Dans ce projet, le routing Angular gère les URLs (/changelogs, /login, /new-changelog) côté client. Le serveur doit renvoyer index.html pour toutes ces routes — c'est Angular qui gère ensuite la navigation sans rechargement de page.
Qu'est-ce qu'une migration de base de données ?
Une migration est un fichier de code (ou SQL) qui décrit comment faire évoluer le schéma de la base de données d'une version à une autre — de façon incrémentale et traçable.

Avec Entity Framework Core :
  • dotnet ef migrations add NomDeLaMigration → génère un fichier C# décrivant les changements
  • dotnet ef database update → applique les migrations en attente sur la BDD

Intérêt : on versionne l'évolution du schéma dans Git, on peut revenir en arrière (rollback), et on peut déployer sur un nouveau serveur en rejouant toutes les migrations depuis zéro.
Comment avez-vous géré la sécurité des accès ?
Deux niveaux de sécurité :

1. Authentification via ASP.NET Identity (hachage bcrypt des mots de passe) + JWT. Sans token valide, toutes les routes protégées renvoient 401 Unauthorized.

2. Autorisation : l'attribut [Authorize] sur les controllers ASP.NET bloque les requêtes sans token. Le token contient l'ID utilisateur en claim, ce qui permet de savoir qui fait quelle action.

Refresh token : stocké en base, comparé à l'envoi — si le token ne correspond pas ou est expiré, la demande est rejetée.
Quelle est votre contribution personnelle dans ce projet ?
Ce projet est une application réalisée en alternance. Ma contribution a porté sur :

  • La conception et le développement du backend ASP.NET Core : modèles, controllers, services, authentification JWT
  • Le développement du frontend Angular : composants, services HTTP, intercepteur de token, routing
  • La conception de la base de données (modèle, migrations EF Core)
Comment avez-vous testé l'application ?
Des tests manuels fonctionnels ont été effectués :

  • Tests de l'API via les formulaires Angular en situation réelle
  • Vérification des cas d'erreur : identifiants incorrects, champs manquants, token expiré
  • Tests de pagination avec différentes tailles de données
  • Vérification de l'encodage des caractères spéciaux (accents français — utf8mb4)

Pas de tests unitaires automatisés dans ce projet — c'est une limite identifiée. En production, on pourrait ajouter des tests xUnit (backend) et Jasmine/Karma (Angular).
Pourquoi Angular et pas React ou Vue.js ?
Choix imposé par l'entreprise pour cohérence avec les autres projets existants. Angular présente cependant des avantages pour un projet d'entreprise :

  • Framework opinionné : structure imposée, facilitant la lecture du code par d'autres développeurs
  • TypeScript natif : typage fort qui évite des bugs à l'exécution
  • Injection de dépendances intégrée (services, guards...)
  • Angular CLI : génération de composants et services standardisée

React serait plus flexible mais moins structuré. Vue.js est plus simple à prendre en main mais moins répandu en entreprise.
Qu'est-ce que CORS et pourquoi est-ce un problème dans une SPA ?
CORS (Cross-Origin Resource Sharing) est une politique de sécurité des navigateurs qui bloque les requêtes HTTP entre origines différentes (domaines, ports, protocoles différents).

Quand le frontend Angular et le backend ASP.NET sont servis depuis des origines différentes, le navigateur bloque les réponses sans en-tête CORS approprié.

Configuration dans ASP.NET Core : la politique CORS est déclarée dans Program.cs via builder.Services.AddCors() en autorisant explicitement les origines connues du frontend. Sans ça, les requêtes Angular seraient rejetées par le navigateur avant même d'atteindre le code de l'API.