Merge remote-tracking branch 'origin/dev'
This commit is contained in:
@@ -20,4 +20,4 @@ RUN dotnet publish "./Webzine.WebApplication.csproj" -c $BUILD_CONFIGURATION -o
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "Webzine.WebApplication.dll", "--seed"]
|
||||
ENTRYPOINT ["dotnet", "Webzine.WebApplication.dll"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Dossier de configuration — Projet Webzine
|
||||
# Dossier de configuration - Projet Webzine
|
||||
|
||||
**Équipe 1**
|
||||
**Formation :** Développement .NET niveau 1 / Dr1-P4
|
||||
@@ -12,6 +12,7 @@
|
||||
| ----- | ------------- |
|
||||
| 25/03 | Clément Bobin |
|
||||
| 31/03 | Joséphine Vetu |
|
||||
| 08/04 | Joséphine Vetu |
|
||||
|
||||
---
|
||||
|
||||
@@ -24,7 +25,7 @@ Avant de lancer l'application, assurez-vous d'avoir installé les outils suivant
|
||||
| .NET SDK | 10.0 | https://dotnet.microsoft.com/download |
|
||||
| Node.js (optionnel, pour outils front) | 18+ | https://nodejs.org |
|
||||
| Git | 2.x | https://git-scm.com |
|
||||
| Un IDE | Visual Studio 2022+ ou Rider | — |
|
||||
| Un IDE | Visual Studio 2022+ ou Rider | - |
|
||||
|
||||
---
|
||||
|
||||
@@ -80,25 +81,71 @@ Ouvrir `Webzine.sln`, sélectionner le profil `https` ou `http`, puis lancer ave
|
||||
|
||||
## 5. Configuration applicative
|
||||
|
||||
Le fichier principal de configuration est `Webzine.WebApplication/appsettings.json` :
|
||||
La configuration de l'application est répartie sur plusieurs fichiers `appsettings` selon l'environnement.
|
||||
|
||||
### `appsettings.json` - configuration commune
|
||||
|
||||
Ce fichier contient les paramètres partagés entre tous les environnements :
|
||||
|
||||
- **Logging** : niveau `Information` par défaut, `Warning` pour ASP.NET Core, et `Debug` pour la couche repository afin de tracer les requêtes.
|
||||
- **Webzine** : paramètres d'affichage (nombre de chroniques et de titres sur la page d'accueil, nombre de lignes dans les vues d'administration). Ces valeurs sont injectées via `IConfiguration` et modifiables sans recompilation.
|
||||
- **ConnectionStrings** : chaînes de connexion pour SQLite (dev) et PostgreSQL (prod). L'application bascule de l'une à l'autre selon la valeur de `Repository`.
|
||||
- **SpotifySeeder** : paramètres de l'import Spotify - credentials, marché cible, genres musicaux, et limites de volumétrie (artistes par genre, albums par artiste, titres par album, commentaires par titre).
|
||||
- **EfPerformance** : seuil en millisecondes au-delà duquel une requête Entity Framework est considérée comme lente (60 ms par défaut).
|
||||
|
||||
### Configuration par environnement
|
||||
|
||||
#### Développement - `appsettings.Development.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"Webzine": {
|
||||
"NombreDerniereChronique": 3,
|
||||
"NombreDeTopTitres": 3
|
||||
"Seeder": "Spotify",
|
||||
"Repository": "Db",
|
||||
"SpotifySeeder": {
|
||||
"ClientId": "",
|
||||
"ClientSecret": ""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Propriété | Type | Description | Valeur par défaut |
|
||||
| ------------------------- | ---- | -------------------------------------------------------------------------------- | ----------------- |
|
||||
| `NombreDerniereChronique` | int | Nombre de chroniques affichées sur la page d'accueil (section "Derniers titres") | 3 |
|
||||
| `NombreDeTopTitres` | int | Nombre de titres affichés dans le bloc "Titres les plus populaires" | 3 |
|
||||
#### Production - `appsettings.Production.json`
|
||||
|
||||
Ces valeurs sont injectées dans `AccueilController` via `IConfiguration` et peuvent être modifiées sans recompilation.
|
||||
```json
|
||||
{
|
||||
"Seeder": "Local",
|
||||
"Repository": "Db",
|
||||
"SpotifySeeder": {
|
||||
"ClientId": "",
|
||||
"ClientSecret": ""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Valeurs acceptées
|
||||
|
||||
Les propriétés `Seeder` et `Repository` correspondent aux enums suivants :
|
||||
|
||||
```csharp
|
||||
public enum SeederType
|
||||
{
|
||||
Local, // Données mockées en mémoire
|
||||
Spotify, // Données récupérées depuis l'API Spotify
|
||||
}
|
||||
|
||||
public enum RepositoryType
|
||||
{
|
||||
Local, // Données en mémoire (pas de base de données)
|
||||
Db, // Base de données (SQLite en dev, PostgreSQL en prod)
|
||||
}
|
||||
```
|
||||
|
||||
| Propriété | Type | Valeurs acceptées | Description |
|
||||
|---|---|---|---|
|
||||
| `Seeder` | `SeederType` | `Local`, `Spotify` | Source des données au démarrage |
|
||||
| `Repository` | `RepositoryType` | `Local`, `Db` | Mode d'accès aux données |
|
||||
| `SpotifySeeder.ClientId` | string | - | Identifiant de l'application Spotify |
|
||||
| `SpotifySeeder.ClientSecret` | string | - | Secret de l'application Spotify |
|
||||
|
||||
Pour l'environnement de développement, les surcharges se font dans `appsettings.Development.json`.
|
||||
|
||||
---
|
||||
|
||||
@@ -175,10 +222,17 @@ Cela désactive les pages d'erreur détaillées et active les optimisations de p
|
||||
|
||||
## Ajout du pre-commit
|
||||
|
||||
Les fichiers présents dans le dossier git_hooks sont à copier dans le dossier caché .git.
|
||||
```bash
|
||||
git config core.hooksPath Webzine.Documentation/git_hooks
|
||||
```
|
||||
|
||||
Les fichiers présents dans le dossier git_hooks sont les suivants:
|
||||
Le pre-commit reformatte le code à chaque commit.
|
||||
Le commit-msg vérifie si le message du commit respecte bien les conventions du cahier des charges:
|
||||
|
||||
- le message référence un ticket
|
||||
- le message termine par un point
|
||||
- le message doit faire au moins 10 caractères
|
||||
|
||||
Il n'est pas nécessaire de les copier et de les ajouter au dossier caché .git.
|
||||
La commande ci-dessus suffit.
|
||||
28
Webzine.Documentation/Rapport/equipe 1 - 1.Introduction.md
Normal file
28
Webzine.Documentation/Rapport/equipe 1 - 1.Introduction.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Rapport d'équipe - Projet Webzine
|
||||
|
||||
**Équipe 1**
|
||||
**Formation :** Développement .NET niveau 1 / Dr1-P4
|
||||
**Date :** Mars 2026
|
||||
|
||||
---
|
||||
|
||||
## Table des modifications
|
||||
|
||||
| Date | Auteur |
|
||||
| ----- | -------------- |
|
||||
| 04/03 | Loïc Masi |
|
||||
| 05/03 | Loïc Masi |
|
||||
| 06/03 | Loïc Masi |
|
||||
| 25/03 | Clément Bobin |
|
||||
| 06/04 | Joséphine Vetu |
|
||||
| 08/04 | Joséphine Vetu |
|
||||
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
Ce rapport présente le travail réalisé par l'équipe 1 dans le cadre du projet Webzine, une application web de chroniques musicales développée avec ASP.NET Core MVC sur .NET 10. L'objectif du projet était de construire une plateforme permettant de gérer et consulter des artistes, des titres, des styles musicaux et des commentaires, avec un espace d'administration dédié.
|
||||
|
||||
Ce document ne revient pas sur le cahier des charges ni sur les fonctionnalités de l'application - ces éléments sont déjà connus de tous. Il s'attache plutôt à décrire comment l'équipe s'est organisée, ce qui a bien fonctionné, ce qui a posé problème, et les enseignements que l'on peut en tirer.
|
||||
|
||||
Les chapitres sont divisés en fichiers, comme demandé dans le cahier des charges.
|
||||
@@ -0,0 +1,94 @@
|
||||
# Rapport d'équipe - Projet Webzine
|
||||
|
||||
**Équipe 1**
|
||||
**Formation :** Développement .NET niveau 1 / Dr1-P4
|
||||
**Date :** Mars 2026
|
||||
|
||||
---
|
||||
|
||||
## Organisation de l'équipe dév
|
||||
|
||||
Chaque développeur s'est vu attribuer une responsabilité principale sur l'une des entités du domaine : `Artiste`, `Titre`, `Commentaire`, `Style`. Cette segmentation verticale a permis à chacun de maîtriser son périmètre tout en contribuant à l'ensemble. En pratique, les tâches couvraient systématiquement les trois couches : entité (avec ses annotations de validation), repository (logique de données), et contrôleur/vue (rendu web).
|
||||
|
||||
Concernant les rôles :
|
||||
|
||||
- Tout le monde a pu suivre "le cycle de la vie" d'une entité, ce qui a favorisé une bonne compréhension commune du modèle de données, de la factory aux repository.
|
||||
- Au fil du projet, chaque personne a pu se spécialiser dans un domaine particulier (voir la partie "Répartition des tâches"). Le reste de l'équipe était tenu au courant à l'aide de TOS réguliers.
|
||||
|
||||
L'équipe de développement est composée de cinq membres:
|
||||
|
||||
| Membre | Rôle principal | Domaine |
|
||||
| --------- | ------------------------------- | ------- |
|
||||
| Joséphine | Cheffe de projet & développeuse | Dev |
|
||||
| Clément B | DevOps (CI/CD) | Dev |
|
||||
| Loïc | Développeur / intégration BDD | Dev |
|
||||
| Baptiste | Développeur | Dev |
|
||||
| Mathys | Ingénieur système et réseau | Ops |
|
||||
|
||||
Mathys étant le seul membre côté ops, il a travaillé en parallèle de l'équipe de développement tout en étant intégré aux dailys et aux jalons.
|
||||
|
||||
## Méthode de gestion de projet
|
||||
|
||||
L'équipe a adopté une organisation inspirée des méthodes agiles, structurée autour de **trois jalons** correspondant à trois sprints successifs.
|
||||
|
||||
### Tickets et sprints
|
||||
|
||||
Dès le premier jour du projet (3 mars), Joséphine et Clément ont pris en charge la gestion de projet : lecture du cahier des charges, définition du sprint 1 et assignation des pages à développer. Les taches et les CRA (compte rendus d'activité) ont été centralisés sur un excel commun.
|
||||
Cette organisation s'est affinée au cours du jalon 2 : la gestion de projet se fait seulement en tickets sur Gitea, avec une priorisation explicite.
|
||||
|
||||
### Les jalons
|
||||
|
||||
Chaque jalon a été ponctué d'une **code review** encadrée, qui a joué un rôle structurant. La code review du lundi 24 mars a, par exemple, donné lieu à la création d'une branche dédiée `TODO_erreurs`, dans laquelle Joséphine a consigné toutes les corrections à effectuer. Toute la première journée du jalon 2 a été consacrée à corriger ces erreurs avant de démarrer de nouvelles fonctionnalités.
|
||||
|
||||
### Démonstrations et supports
|
||||
|
||||
Les démonstrations de fin de jalon ont imposé un moment de travail collectif. La préparation du support de démo (sur Canva) a mobilisé l'ensemble de l'équipe.
|
||||
|
||||
---
|
||||
|
||||
## Répartition des tâches
|
||||
|
||||
### Joséphine - Cheffe de projet & développeuse
|
||||
|
||||
Joséphine a endossé un double rôle tout au long du projet. D'un côté, elle a assuré la gestion de projet : rédaction des tickets, priorisation, animation des dailys, compte-rendus et revue de code. De l'autre, elle a contribué activement au développement : page artiste, repository Artiste, pagination, correction transversale des erreurs de controllers et de HTML.
|
||||
|
||||
Ce double rôle a représenté une charge de travail importante, notamment en fin de jalon où la gestion de projet et les corrections de bugs se sont superposées.
|
||||
|
||||
### Clément - Développeur mais surtout DevOps
|
||||
|
||||
Clément a posé les bases de l'architecture : initialisation du dépôt Git, mise en place du patron MVC, création des factories et des controllers de base. Il a ensuite pris en charge les repositories Style et Titre, la mise à jour de l'API, la rédaction de la documentation, et la CI/CD côté tests d'endpoints.
|
||||
|
||||
### Loïc - Développeur / intégration BDD
|
||||
|
||||
Loïc a développé la page d'accueil dès le jalon 1, en y intégrant Bootstrap, les fausses données via Faker, puis le ViewModel. Au jalon 2, il a pris en charge la configuration de la base de données SQLite, la création du seeder, et le CRUD sur les entités Style et Artiste. Il a également travaillé sur l'optimisation de la recherche et l'intégration de l'API Spotify en jalon 3.
|
||||
|
||||
### Baptiste - Développeur fonctionnel
|
||||
|
||||
Baptiste a développé les fonctionnalités liées aux commentaires (modèle, vue, controller, repository) et aux styles côté administration. Il a aussi contribué à la correction des bugs. En jalon 3, il a réalisé la refactorisation des routes dans une classe `RouteConfiguration.cs` et l'implémentation d'un middleware de logging.
|
||||
|
||||
---
|
||||
|
||||
## Outils et pratiques de collaboration
|
||||
|
||||
### Gitea comme colonne vertébrale
|
||||
|
||||
L'ensemble du code source, des tickets et de la documentation a été centralisé sur un **Gitea** hébergé par Mathys.
|
||||
|
||||
Le travail a été découpé en branches Git par fonctionnalité. Les nommages utilisés reflétaient généralement l'entité ou la fonctionnalité concernée (ex : `feat/artiste-controller`, `feat/titre-entity`, `feat/administration-dashboard`). Les merges ont été faits via des pull requests revues par au moins un autre membre de l'équipe.
|
||||
|
||||
Cette pratique a contribué à maintenir la qualité du code, mais elle a également constitué un **goulot d'étranglement**. Les reviews de code ont pris beaucoup de temps. Il y a eu quelque fois un volume important de PR ouvertes simultanément. L'équipe n'avait pas défini en amont de règles sur la taille maximale des PR ou les délais de review.
|
||||
A partir du jalon 3, les revues de code ont été réparties entre chaque membre de l'équipe.
|
||||
|
||||
### Qualité du versioning
|
||||
|
||||
La discipline de versioning s'est améliorée au fil du projet. En jalon 1, Baptiste a rencontré des difficultés à pousser son code sur Gitea et à gérer les conflits de branche. En jalon 3, Joséphine a mis en place des **commit-msg hooks** et des **pre-commit hooks**. Les commits respectaient donc les conventions du cahier des charges et le code était formatté correctement.
|
||||
|
||||
### Décisions d'architecture en daily
|
||||
|
||||
Un point notable de l'organisation est que plusieurs décisions techniques structurantes ont été prises _collectivement_, pendant les dailys en demandant à l'intervenant, plutôt qu'en amont lors d'une phase de conception :
|
||||
|
||||
- La stratégie de double repository (`repositorydb` pour la prod PostgreSQL, `repositorylocal` pour le dev SQLite) - décidée le 25 mars
|
||||
- Le découpage de `Program.cs` en sous-classes pour éviter un fichier trop long
|
||||
- Le remplacement du ViewModel Dashboard par un DTO pour respecter la séparation des couches - identifié le 1er avril
|
||||
|
||||
Cette approche a permis de s'adapter aux contraintes au fur et à mesure, mais elle a aussi engendré du refactoring qui aurait pu être évité avec une conception initiale plus approfondie.
|
||||
@@ -0,0 +1,43 @@
|
||||
# Rapport d'équipe - Projet Webzine
|
||||
|
||||
**Équipe 1**
|
||||
**Formation :** Développement .NET niveau 1 / Dr1-P4
|
||||
**Date :** Mars 2026
|
||||
|
||||
---
|
||||
|
||||
## Organisation de la collaboration dév / ops et travaux menés avec les ops
|
||||
|
||||
La collaboration avec les ops s'est concentrée principalement sur deux aspects : la configuration de l'environnement d'exécution et la mise en place des outils de qualité de code.
|
||||
|
||||
**Logging avec NLog**
|
||||
La configuration NLog (`Webzine.WebApplication/nlog.config`) a été mise en place en collaboration : les devs exprimaient leurs besoins (logs de debug pour les contrôleurs, logs d'erreur pour la prod), Les logs sont écrits dans `/Logs/` avec rotation quotidienne, ce qui s'est avéré très utile pour déboguer les problèmes d'injection de dépendances en début de projet.
|
||||
|
||||
**Configuration applicative**
|
||||
Le fichier `appsettings.json` contient des paramètres métier (`NombreDerniereChronique`, `NombreDeTopTitres`) qui peuvent être ajustés sans recompilation.
|
||||
|
||||
**Docker**
|
||||
Un `.dockerignore` est référencé dans le `.csproj` de l'application web, signe que la conteneurisation était dans la feuille de route ops. La cible Docker Linux est configurée dans le projet. La collaboration s'est arrêtée à ce stade pour notre sprint, mais les bases sont posées.
|
||||
|
||||
---
|
||||
|
||||
### Les logs applicatifs avec Loki
|
||||
|
||||
Une collaboration directe entre Baptiste et Mathys était prévue pour la récupération des logs applicatifs via Loki. Baptiste montait en compétences sur les middleware (implémentés en jalon 3), et l'objectif était de faire remonter ces logs dans les dashboards Grafana déjà en place. Cette tâche est mentionnée dans le daily du 1er avril comme conditionnelle au bon fonctionnement de la CI/CD.
|
||||
|
||||
### Le déploiement de l'application
|
||||
|
||||
Mathys a hébergé l'application on-premises dès le 25 mars, puis a provisionné la base de données PostgreSQL pour la démo du jalon 2 (27 mars). Loïc a travaillé en parallèle sur la migration du mode SQLite vers PostgreSQL, et la synchronisation entre les deux s'est faite progressivement.
|
||||
|
||||
### La CI/CD
|
||||
|
||||
La mise en place de la CI/CD a été un travail conjoint entre Clément et Mathys, initié le 26 mars et poursuivi jusqu'au jalon 3. Clément a développé les tests d'endpoints et le calcul des temps de réponse. Mathys a intégré ces pipelines dans l'infrastructure et géré le déploiement automatisé. Ce chantier est également mentionné dans le chapitre sur les problèmes techniques, car il a causé des dysfonctionnements sur Gitea lors de sa mise en place.
|
||||
|
||||
### Une communication sur les livrables ops insuffisante en amont
|
||||
|
||||
Durant le deuxième jalon, les développeurs ne savaient pas exactement ce qui était attendu côté ops pour la livraison du jalon 2. Les attendus - dashboard Grafana, schéma d'infrastructure, passage en HTTPS - ont été clarifiés pendant le daily, à deux jours de la démo. Ce manque d'anticipation sur les livrables ops a pu créer de la pression inutile en fin de sprint.
|
||||
|
||||
## Bilan
|
||||
|
||||
La collaboration dev/ops a fonctionné sur les sujets où elle était explicitement planifiée : la CI/CD avec Clément, la stratégie de base de données avec Loïc, les logs avec Baptiste.
|
||||
Mathys nous a présenté tous les éléments sur lesquels il travaillait sous la forme de TOS d'équipe plus ou moins formel.
|
||||
@@ -0,0 +1,67 @@
|
||||
# Rapport d'équipe - Projet Webzine
|
||||
|
||||
**Équipe 1**
|
||||
**Formation :** Développement .NET niveau 1 / Dr1-P4
|
||||
**Date :** Mars 2026
|
||||
|
||||
---
|
||||
|
||||
# Problèmes techniques
|
||||
|
||||
Ce chapitre liste les difficultés rencontrées pendant le projet, ce qui n'a pas fonctionné comme prévu, et ce que nous ferions différemment.
|
||||
|
||||
---
|
||||
|
||||
## Côté développement
|
||||
|
||||
### La correction des erreurs des jalons
|
||||
|
||||
La code review du jalon 1 et 2s ont mis en évidence un volume d'erreurs accumulées pendant le développement: HTML invalide, controllers inutiles, fautes dans les vues, incohérences dans les noms de routes. Joséphine a créé une branche `TODO_erreurs` pour tout recenser, et nous avons passé toute la première journée du jalon 2 à corriger ça avant de pouvoir avancer sur de nouvelles fonctionnalités. Pour le jalon 3, la correction a pris plus de temps et a été faite en parallèle du développement des autres features.
|
||||
|
||||
Nous avons pourtant passer en revue chaque PR. Ces corrections ont permis d'améliorer ce processus et de monter en compétences.
|
||||
|
||||
### Passer des factories aux repositories
|
||||
|
||||
C'est probablement le chantier le plus difficile du jalon 2. Au jalon 1, les données étaient instanciées directement dans les controllers via des classes factory. Ça fonctionnait pour afficher les vues, mais tout était couplé : il était impossible de connecter une vraie base de données sans tout réécrire.
|
||||
|
||||
La migration vers des repositories a impliqué plusieurs changements simultanés :
|
||||
|
||||
- extraire la logique de données,
|
||||
- créer des interfaces,
|
||||
- reconfigurer `Program.cs` pour gérer l'injection de dépendances.
|
||||
|
||||
Cette dernière partie a été la plus difficile à appréhender - les cycles de vie des services (`Singleton`, `Scoped`, `Transient`) et la façon dont ASP.NET Core résout les dépendances à l'exécution n'étaient pas évidents au départ.
|
||||
|
||||
La coexistence de deux environnements (SQLite en dev, PostgreSQL en prod) a ajouté une couche de complexité supplémentaire : il fallait deux implémentations concrètes des mêmes interfaces et conditionner leur enregistrement dans `Program.cs` selon l'environnement.
|
||||
|
||||
### Le seeder Spotify
|
||||
|
||||
En jalon 3, Loïc a travaillé sur un seeder pour alimenter la base avec des données réelles issues de l'API Spotify.
|
||||
|
||||
L'API Spotify ne renvoie pas toutes les informations en un seul appel. Pour récupérer des artistes avec leurs albums et leurs titres, il faut enchaîner plusieurs endpoints, chacun avec sa propre structure JSON. De nombreux DTOs ont été nécessaires pour désérialiser correctement les réponses avant de les mapper vers les entités du domaine. En plus de ça, l'API pagine ses résultats, ce qui impliquait de gérer les appels successifs et de dédoublonner les données avant insertion.
|
||||
|
||||
Nous avions mal estimé cette tâche. Une exploration rapide de l'API en amont aurait donné une bien meilleure idée de ce qu'elle impliquait réellement.
|
||||
|
||||
### Les Pull Requests
|
||||
|
||||
À partir du jalon 2, nous avons formalisé l'utilisation des branches et des Pull Requests, ce qui a amélioré la qualité du code. Mais cela a aussi créé des blocages : les reviews prenaient beaucoup de temps, plusieurs PR restaient ouvertes en parallèle, et Joséphine se retrouvait souvent à devoir les débloquer en plus de sa charge de gestion de projet.
|
||||
|
||||
Nous n'avions pas défini de règles sur la taille des PR ni sur les délais de review. Des PR trop volumineuses sont plus longues à relire, génèrent davantage de conflits, et finissent par ralentir tout le monde. C'est quelque chose à fixer dès le début d'un projet.
|
||||
|
||||
Néanmoins, toute l'équipe est montée en compétences sur la gestion des conflits (on parle bien de git) et des merge/rebase.
|
||||
|
||||
### La logique métier dans les controller
|
||||
|
||||
Lors du daily du 1er avril (jalon 3), nous avons réalisé que la logique du dashboard avait été placée dans le ViewModel plutôt que dans la couche métier. Il a fallu refactoriser : remplacer le ViewModel par un DTO et déplacer la logique au bon endroit.
|
||||
|
||||
Ce type d'erreur arrive quand les responsabilités des différentes couches ne sont pas clairement définies et partagées au sein de l'équipe. Chacun avait sa propre interprétation, et cela s'est reflété dans le code.
|
||||
|
||||
---
|
||||
|
||||
## Côté ops
|
||||
|
||||
### La CI/CD qui saturait Gitea
|
||||
|
||||
La CI/CD mise en place par Clément et Mathys teste tous les endpoints de l'application et mesure leurs temps d'exécution. C'est un choix pertinent pour surveiller les performances, mais lors de sa mise en place initiale, chaque exécution du pipeline rendait Gitea inutilisable pendant une dizaine de secondes.
|
||||
|
||||
Pour une équipe dont tout le code et tous les tickets reposent sur cette instance, c'était bloquant. Le problème venait du fait que les dépendances étaient retéléchargées à chaque run. Les mettre en cache a résolu le problème.
|
||||
26
Webzine.Documentation/Rapport/equipe 1 - 5.Conclusion.md
Normal file
26
Webzine.Documentation/Rapport/equipe 1 - 5.Conclusion.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Rapport d'équipe - Projet Webzine
|
||||
|
||||
**Équipe 1**
|
||||
**Formation :** Développement .NET niveau 1 / Dr1-P4
|
||||
**Date :** Mars 2026
|
||||
|
||||
---
|
||||
|
||||
# Conclusion
|
||||
|
||||
Ce projet a été très formateur. Nous avons pour la première fois travaillé avec un **cahier des charges** précis, ce qui nous a obligés à lire attentivement les consignes, à poser des questions, et à ne pas partir dans des directions non demandées. La présence régulière des intervenants a également joué un rôle : savoir que le travail serait relu et évalué de près nous a poussés à être plus rigoureux sur la qualité du code, la documentation et les pratiques Git.
|
||||
|
||||
Sur le plan technique, la **montée en compétences** a été réelle. En trois semaines, nous sommes passés de données mockées en dur dans les controllers à une application connectée à une base de données, avec des repositories abstraits, une CI/CD fonctionnelle, un middleware de logging et un seeder alimenté par une API externe. Ce n'était pas acquis en début de projet.
|
||||
|
||||
Pour ma part (Joséphine), c'était la première fois que j'assumais un rôle de **cheffe de projet**. Je l'ai pris très au sérieux, en essayant de structurer le travail de l'équipe sans le surcharger, de maintenir une vision d'ensemble tout en continuant à contribuer au développement. Ce dernier point a été compliqué, j'ai fait autant de revue de code que de développement pur.
|
||||
Ce qui m'importait autant que les livrables, c'était que chacun se sente bien dans l'équipe - nous avions des profils très différents, des niveaux différents, et il fallait que tout le monde puisse avancer à sa façon sans se sentir laissé de côté. Je pense que nous y sommes globalement arrivés.
|
||||
|
||||
Il reste des choses que nous ferions différemment : une conception initiale plus approfondie, des règles de contribution définies dès le départ, et une communication plus formalisée entre dev et ops.
|
||||
|
||||
### Points qui permettraient d'améliorer le Webzine
|
||||
|
||||
**Performance du dashboard**
|
||||
Le dashboard d'administration effectue plusieurs requêtes `COUNT` distinctes au chargement, ce qui le rend plus lent que le reste de l'application. Des optimisations ont été apportées en cours de projet, mais elles pourraient être encore plus efficaces.
|
||||
|
||||
**Authentification et gestion des droits**
|
||||
L'interface d'administration est accessible sans authentification. Mettre en place un système de connexion avec des rôles (administrateur / visiteur) rendrait l'application utilisable en conditions réelles. Ce point n'était néanmoins pas demandé dans le cahier des charges.
|
||||
43
Webzine.Documentation/Rapport/equipe 1 - Annexes.md
Normal file
43
Webzine.Documentation/Rapport/equipe 1 - Annexes.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Rapport d'équipe - Projet Webzine
|
||||
|
||||
**Équipe 1**
|
||||
**Formation :** Développement .NET niveau 1 / Dr1-P4
|
||||
**Date :** Mars 2026
|
||||
|
||||
---
|
||||
|
||||
## Annexes
|
||||
|
||||
### A. Structure du projet
|
||||
|
||||
```
|
||||
Webzine.Entity/ → Entités du domaine (Artiste, Titre, Style, Commentaire)
|
||||
Webzine.Entity.Tests/ → Tests unitaires sur les entités
|
||||
Webzine.Repository.Contracts/ → Interfaces des repositories
|
||||
Webzine.Repository/ → Implémentations (Local, Db - partiel)
|
||||
Webzine.Business/ → Couche métier (non utilisée dans ce sprint)
|
||||
Webzine.Business.Contracts/ → Interfaces métier
|
||||
Webzine.EntitiesContext/ → Contexte EF (non utilisé)
|
||||
Webzine.Documentation/ → Documentation, StyleCop, rapports
|
||||
Webzine.WebApplication/ → Application ASP.NET Core MVC
|
||||
```
|
||||
|
||||
### B. Tests unitaires - couverture des entités
|
||||
|
||||
| Entité | Nombre de tests |
|
||||
| ----------- | --------------- |
|
||||
| Artiste | 7 |
|
||||
| Commentaire | 13 |
|
||||
| Style | 6 |
|
||||
| Titre | 29 |
|
||||
|
||||
### C. Packages NuGet utilisés
|
||||
|
||||
| Package | Usage |
|
||||
| ------------------------------------------------- | --------------------------------------- |
|
||||
| Bogus 35.6.5 | Génération de données de test réalistes |
|
||||
| Faker.Net 2.0.163 | Génération de données fictives |
|
||||
| NLog 6.1.1 + NLog.Web.AspNetCore | Logging |
|
||||
| StyleCop.Analyzers 1.1.118 | Analyse statique du code |
|
||||
| MSTest 4.0.1 | Framework de tests unitaires |
|
||||
| Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation | Rechargement des vues à chaud |
|
||||
Binary file not shown.
@@ -7,7 +7,7 @@
|
||||
COMMIT_MSG=$(cat "$1")
|
||||
|
||||
# Skip validation for rebase or CI commits
|
||||
if echo "$COMMIT_MSG" | grep -qiE "(Rebase|rebase|CI|merge|Merge)"; then
|
||||
if echo "$COMMIT_MSG" | grep -qiE "(Rebase|rebase|CI|merge|Merge|Documentation)"; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
@@ -72,6 +72,22 @@
|
||||
/// <returns>Une collection de titres correspondant au critère de recherche, triée par libellé.</returns>
|
||||
IEnumerable<Titre> SearchByStyle(string libelle);
|
||||
|
||||
/// <summary>
|
||||
/// Retourne une liste de titre filtré par nom et paginé.
|
||||
/// </summary>
|
||||
/// <param name="offset">Nombre de titres a passer.</param>
|
||||
/// <param name="limit">Nombre de titre récupéré.</param>
|
||||
/// <param name="libelle">Nom du style.</param>
|
||||
/// <returns>Une liste de titre.</returns>
|
||||
IEnumerable<Titre> SearchByStylePaginate(int offset, int limit, string libelle);
|
||||
|
||||
/// <summary>
|
||||
/// Compter le nombre de titres au sein d'un style.
|
||||
/// </summary>
|
||||
/// <param name="libelle">Style de la musique.</param>
|
||||
/// <returns>Un entier.</returns>
|
||||
int CountByStyle(string libelle);
|
||||
|
||||
/// <summary>
|
||||
/// Met à jour un titre dans la liste des titres en fonction de son identifiant. Si aucun titre correspondant à l'identifiant du titre fourni n'est trouvé, un message d'avertissement est enregistré dans les logs et aucune mise à jour n'est effectuée.
|
||||
/// </summary>
|
||||
|
||||
@@ -314,6 +314,20 @@ public class DbTitreRepository : ITitreRepository
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<Titre> SearchByStylePaginate(int offset, int limit, string libelle)
|
||||
{
|
||||
return this.SearchByStyle(libelle).Paginate(offset, limit);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int CountByStyle(string libelle)
|
||||
{
|
||||
return this.context.Titres
|
||||
.Where(t => t.Styles.Any(s => s.Libelle.ToLower() == libelle.ToLower()))
|
||||
.Count();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int CountLike()
|
||||
{
|
||||
|
||||
@@ -112,6 +112,20 @@ public class LocalTitreRepository : ITitreRepository
|
||||
.Where(t => t.Styles.Any(s => s.Libelle == libelle));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<Titre> SearchByStylePaginate(int offset, int limit, string libelle)
|
||||
{
|
||||
return this.SearchByStyle(libelle).Paginate(offset, limit);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int CountByStyle(string libelle)
|
||||
{
|
||||
return this.dataStore.Titres
|
||||
.Where(t => t.Styles.Any(s => s.Libelle == libelle))
|
||||
.Count();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Update(Titre titre)
|
||||
{
|
||||
|
||||
@@ -1,13 +1,33 @@
|
||||
namespace Webzine.WebApplication.Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Définit les types de seeder et de repository disponibles dans l'application.
|
||||
/// </summary>
|
||||
public enum SeederType
|
||||
{
|
||||
/// <summary>
|
||||
/// Utilise des données locales pour le seeding.
|
||||
/// </summary>
|
||||
Local,
|
||||
|
||||
/// <summary>
|
||||
/// Utilise des données provenant de Spotify pour le seeding.
|
||||
/// </summary>
|
||||
Spotify,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Définit les types de repository disponibles dans l'application.
|
||||
/// </summary>
|
||||
public enum RepositoryType
|
||||
{
|
||||
/// <summary>
|
||||
/// Utilise des données locales pour les opérations de repository.
|
||||
/// </summary>
|
||||
Local,
|
||||
|
||||
/// <summary>
|
||||
/// Utilise une base de données pour les opérations de repository.
|
||||
/// </summary>
|
||||
Db,
|
||||
}
|
||||
@@ -67,17 +67,25 @@ namespace Webzine.WebApplication.Controllers
|
||||
/// Affiche les titres correspondant a un style musical donne.
|
||||
/// </summary>
|
||||
/// <param name="style">Nom du style musical.</param>
|
||||
/// <param name="page">Numéro de la page.</param>
|
||||
/// <returns>Vue contenant la liste filtree.</returns>
|
||||
public IActionResult Style(string style)
|
||||
[Route("/titres/styles/{style}", Name = "TitresParStyle")]
|
||||
public IActionResult Style(string style, int page = 0)
|
||||
{
|
||||
this.logger.LogInformation("Recherche des titres pour le style : {Style}.", style);
|
||||
var offset = page * 10;
|
||||
var limit = 10;
|
||||
var titresFiltres = this.titreRepository.SearchByStylePaginate(offset, limit, style).ToList();
|
||||
var totalTitres = this.titreRepository.CountByStyle(style);
|
||||
var totalPages = (int)Math.Ceiling((double)totalTitres / limit);
|
||||
|
||||
var titresFiltres = this.titreRepository.SearchByStyle(style).ToList();
|
||||
this.logger.LogInformation("Recherche des titres pour le style : {Style}.", style);
|
||||
|
||||
var vm = new TitreStyle
|
||||
{
|
||||
StyleName = style,
|
||||
Titres = titresFiltres.Select(MapTitreItem).ToList(),
|
||||
Page = page,
|
||||
TotalPages = totalPages,
|
||||
};
|
||||
|
||||
return this.View(vm);
|
||||
|
||||
@@ -14,4 +14,14 @@ public class TitreStyle
|
||||
/// Définit la liste des items de titre associés au style musical.
|
||||
/// </summary>
|
||||
public List<TitreStyleItem> Titres { get; set; } = new ();
|
||||
|
||||
/// <summary>
|
||||
/// Obtient ou définit le numéro de page pour la pagination des titres affichés sur la page d'accueil.
|
||||
/// </summary>
|
||||
public int Page { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Nombre total de page.
|
||||
/// </summary>
|
||||
public int TotalPages { get; set; }
|
||||
}
|
||||
@@ -29,7 +29,7 @@
|
||||
<a asp-action="Index"
|
||||
asp-route-id="@titre.IdTitre"
|
||||
class="me-3 text-black">
|
||||
<img src="@titre.UrlJaquette" alt="@titre.Libelle" width="70px" height="70px" class="object-fit-cover" loading="lazy"/>
|
||||
<img src="@titre.UrlJaquette" alt="@titre.Libelle" width="70px" height="70px" class="object-fit-cover" loading="lazy" />
|
||||
</a>
|
||||
|
||||
<!-- Infos -->
|
||||
@@ -55,6 +55,39 @@
|
||||
</div>
|
||||
}
|
||||
}
|
||||
<div class="d-flex align-items-center justify-content-between mt-3">
|
||||
@if (Model.Page > 0)
|
||||
{
|
||||
<a asp-route="TitresParStyle"
|
||||
asp-route-style="@Model.StyleName"
|
||||
asp-route-page="@(Model.Page - 1)"
|
||||
class="btn btn-secondary">
|
||||
<< Titre plus récent
|
||||
</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div></div>
|
||||
}
|
||||
|
||||
<p class="mb-0">
|
||||
Page : @(Model.Page + 1) sur @Model.TotalPages
|
||||
</p>
|
||||
|
||||
@if (Model.Page < Model.TotalPages - 1)
|
||||
{
|
||||
<a asp-route="TitresParStyle"
|
||||
asp-route-style="@Model.StyleName"
|
||||
asp-route-page="@(Model.Page + 1)"
|
||||
class="btn btn-secondary">
|
||||
Titre plus anciens >>
|
||||
</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div></div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user