docs: add backend documentation files
Reference guides (Sequelize model methods, Swagger) and migration reports from the MongoDB-to-MySQL and domain-based route structure migrations.
This commit is contained in:
@@ -0,0 +1,210 @@
|
||||
# Méthodes disponibles sur l'objet `Article` (Sequelize)
|
||||
|
||||
Ce document liste toutes les méthodes automatiquement générées par Sequelize pour le modèle `Article` en fonction des associations définies dans `src/database/relationships/index.js`.
|
||||
|
||||
---
|
||||
|
||||
## Associations Many-to-Many (belongsToMany)
|
||||
|
||||
### 1. **Tags** via `TagList`
|
||||
Association alias: `articleTags`
|
||||
Clés: `foreignKey: "articleId"`, `otherKey: "tagName"`
|
||||
|
||||
```javascript
|
||||
article.getArticleTags() // Récupère tous les tags
|
||||
article.setArticleTags([...]) // Définit les tags
|
||||
article.addArticleTag(tag) // Ajoute un tag
|
||||
article.addArticleTags([...]) // Ajoute plusieurs tags
|
||||
article.removeArticleTag(tag) // Retire un tag
|
||||
article.removeArticleTags([...]) // Retire plusieurs tags
|
||||
article.countArticleTags() // Compte les tags
|
||||
article.hasArticleTag(tag) // Vérifie si le tag est lié
|
||||
article.hasArticleTags([...]) // Vérifie si les tags sont liés
|
||||
|
||||
// Alias généré par Sequelize (correspond à belongsToMany):
|
||||
// Nom de la clé étrangère singularisée + pluralisé = "ArticleTag(s)" => "addTagList", "getTagList", etc.
|
||||
article.addTagList(tag) // Ajoute un tag via l'alias
|
||||
article.addTagLists([...]) // Ajoute plusieurs tags via l'alias
|
||||
article.getTagLists() // Récupère les tags via l'alias
|
||||
article.setTagLists([...]) // Définit les tags via l'alias
|
||||
article.removeTagList(tag) // Retire un tag via l'alias
|
||||
article.removeTagLists([...]) // Retire plusieurs tags via l'alias
|
||||
article.countTagLists() // Compte les tags via l'alias
|
||||
article.hasTagList(tag) // Vérifie si le tag est lié via l'alias
|
||||
article.hasTagLists([...]) // Vérifie si les tags sont liés via l'alias
|
||||
```
|
||||
|
||||
### 2. **Users (Favoris)** via `Favorite`
|
||||
Association alias: `articleFavoriteUsers`
|
||||
Clés: `foreignKey: "articleId"`, `otherKey: "userId"`
|
||||
|
||||
```javascript
|
||||
article.getArticleFavoriteUsers() // Récupère les utilisateurs qui ont favorisé
|
||||
article.setArticleFavoriteUsers([...]) // Définit les utilisateurs
|
||||
article.addUserIdUser(user) // Ajoute un utilisateur
|
||||
article.addArticleFavoriteUsers([...]) // Ajoute plusieurs utilisateurs
|
||||
article.removeUserIdUser(user) // Retire un utilisateur
|
||||
article.removeArticleFavoriteUsers([...]) // Retire plusieurs utilisateurs
|
||||
article.countArticleFavoriteUsers() // Compte les utilisateurs
|
||||
article.hasUserIdUser(user) // Vérifie si l'utilisateur a favorisé
|
||||
article.hasArticleFavoriteUsers([...]) // Vérifie si les utilisateurs ont favorisé
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Associations One-to-Many (hasMany)
|
||||
|
||||
### 3. **Comments**
|
||||
Association alias: `comments`
|
||||
Clé étrangère: `articleId`
|
||||
|
||||
```javascript
|
||||
article.getComments() // Récupère tous les commentaires
|
||||
article.setComments([...]) // Définit les commentaires
|
||||
article.addComment(comment) // Crée/ajoute un commentaire
|
||||
article.addComments([...]) // Ajoute plusieurs commentaires
|
||||
article.removeComment(comment) // Retire un commentaire
|
||||
article.removeComments([...]) // Retire plusieurs commentaires
|
||||
article.countComments() // Compte les commentaires
|
||||
article.hasComment(comment) // Vérifie si le commentaire existe
|
||||
article.hasComments([...]) // Vérifie si les commentaires existent
|
||||
article.createComment({...}) // Crée un nouveau commentaire
|
||||
```
|
||||
|
||||
### 4. **Favorites** (enregistrements de join)
|
||||
Association alias: `favorites`
|
||||
Clé étrangère: `articleId`
|
||||
|
||||
```javascript
|
||||
article.getFavorites() // Récupère les enregistrements Favorite
|
||||
article.setFavorites([...]) // Définit les favoris
|
||||
article.addFavorite(favorite) // Ajoute un enregistrement Favorite
|
||||
article.addFavorites([...]) // Ajoute plusieurs enregistrements
|
||||
article.removeFavorite(favorite) // Retire un enregistrement Favorite
|
||||
article.removeFavorites([...]) // Retire plusieurs enregistrements
|
||||
article.countFavorites() // Compte les enregistrements Favorite
|
||||
article.hasFavorite(favorite) // Vérifie si le Favorite existe
|
||||
article.hasFavorites([...]) // Vérifie si les Favorites existent
|
||||
article.createFavorite({...}) // Crée un nouveau Favorite
|
||||
```
|
||||
|
||||
### 5. **TagLists** (enregistrements de join)
|
||||
Association alias: `tagLists`
|
||||
Clé étrangère: `articleId`
|
||||
|
||||
```javascript
|
||||
article.getTagLists() // Récupère les enregistrements TagList
|
||||
article.setTagLists([...]) // Définit les TagList
|
||||
article.addTagList(tagList) // Ajoute un enregistrement TagList
|
||||
article.addTagLists([...]) // Ajoute plusieurs enregistrements
|
||||
article.removeTagList(tagList) // Retire un enregistrement TagList
|
||||
article.removeTagLists([...]) // Retire plusieurs enregistrements
|
||||
article.countTagLists() // Compte les enregistrements TagList
|
||||
article.hasTagList(tagList) // Vérifie si le TagList existe
|
||||
article.hasTagLists([...]) // Vérifie si les TagLists existent
|
||||
article.createTagList({...}) // Crée un nouveau TagList
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Associations Belongs-To (hasOne inverse)
|
||||
|
||||
### 6. **Author (User)**
|
||||
Association alias: `author`
|
||||
Clé étrangère: `authorId`
|
||||
|
||||
```javascript
|
||||
article.getAuthor() // Récupère l'auteur
|
||||
article.setAuthor(user) // Définit l'auteur
|
||||
article.createAuthor({...}) // Crée un nouvel auteur
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Méthodes personnalisées du modèle
|
||||
|
||||
### Méthodes d'instance définies dans `Article.js` :
|
||||
|
||||
```javascript
|
||||
article.toJSONFor() // Retourne un objet JSON formaté
|
||||
// Format: { id, slug, title, description, body }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Hooks (Triggers)
|
||||
|
||||
```javascript
|
||||
Article.beforeValidate() // Déclenché avant la validation
|
||||
// Génère automatiquement un slug basé sur le titre
|
||||
// Format: slug(`${article.title}`) + '-' + random
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exemples d'utilisation concrets
|
||||
|
||||
### Ajouter des tags à un article
|
||||
```javascript
|
||||
const article = await Article.findByPk(1);
|
||||
const tag = await Tag.findByPk('javascript');
|
||||
await article.addTagList(tag); // Via alias
|
||||
// ou
|
||||
await article.addArticleTag(tag); // Via alias généré automatiquement
|
||||
```
|
||||
|
||||
### Récupérer les commentaires d'un article
|
||||
```javascript
|
||||
const article = await Article.findByPk(1);
|
||||
const comments = await article.getComments();
|
||||
```
|
||||
|
||||
### Obtenir les utilisateurs qui ont favorisé cet article
|
||||
```javascript
|
||||
const article = await Article.findByPk(1);
|
||||
const fans = await article.getArticleFavoriteUsers();
|
||||
```
|
||||
|
||||
### Créer un commentaire pour un article
|
||||
```javascript
|
||||
const article = await Article.findByPk(1);
|
||||
const comment = await article.createComment({
|
||||
body: "Great article!",
|
||||
authorId: userId
|
||||
});
|
||||
```
|
||||
|
||||
### Compter les tags
|
||||
```javascript
|
||||
const article = await Article.findByPk(1);
|
||||
const tagCount = await article.countTagLists();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Notes importantes
|
||||
|
||||
1. **Noms des méthodes générées** : Sequelize génère les noms en fonction du nom de l'association (alias) ou du modèle.
|
||||
- Si alias est `articleTags` → `getArticleTags()`, `addArticleTag()`, etc.
|
||||
- Si alias est `tagLists` → `getTagLists()`, `addTagList()`, etc.
|
||||
|
||||
2. **Singulier/Pluriel** : Les méthodes `add*` acceptent soit un seul élément (singulier) soit un tableau (pluriel).
|
||||
|
||||
3. **Paramètres optionnels** : La plupart des méthodes `get*` acceptent un paramètre `options` pour personnaliser la requête :
|
||||
```javascript
|
||||
article.getComments({
|
||||
where: { createdAt: { [Op.gte]: someDate } },
|
||||
limit: 10,
|
||||
offset: 0,
|
||||
order: [['createdAt', 'DESC']]
|
||||
});
|
||||
```
|
||||
|
||||
4. **Transactions** : Toutes les opérations CRUD peuvent être encapsulées dans une transaction :
|
||||
```javascript
|
||||
const transaction = await sequelize.transaction();
|
||||
await article.addTagList(tag, { transaction });
|
||||
await transaction.commit();
|
||||
```
|
||||
|
||||
5. **Alias vs Nom généré** : L'alias défini dans la relation détermine le nom des méthodes générées. Dans ce projet, les alias comme `articleTags`, `tagLists` permettent d'appeler `getTagLists()`, `addTagList()`, etc.
|
||||
@@ -0,0 +1,328 @@
|
||||
╔═══════════════════════════════════════════════════════════════════════════════╗
|
||||
║ ║
|
||||
║ ✅ MIGRATION AUTOMATIQUE RÉUSSIE - Structure Basée Domaines ║
|
||||
║ ║
|
||||
║ De: /api/v1, /api/v2, /api/v3 (confus) ║
|
||||
║ Vers: /api/skydive, /api/cms, /api/herowars (clair) ║
|
||||
║ ║
|
||||
╚═══════════════════════════════════════════════════════════════════════════════╝
|
||||
|
||||
📊 STATISTIQUES DE LA MIGRATION
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
✓ Fichiers de routes migrés: 19 fichiers
|
||||
✓ Domaines créés: 3 nouveaux domaines
|
||||
✓ Fichiers index.js: 4 créés/mis à jour
|
||||
✓ Documentation: 5 fichiers de rapport
|
||||
✓ Scripts de migration: 3 scripts npm
|
||||
✓ Commits Git: 2 commits
|
||||
✓ Fichiers Swagger mis à jour: 4 fichiers YAML
|
||||
|
||||
|
||||
🎯 STRUCTURE NOUVELLE CRÉÉE
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
src/routes/api/
|
||||
├── skydive/ ← Parachutisme
|
||||
│ ├── aeronefs.js
|
||||
│ ├── applications.js
|
||||
│ ├── canopies.js
|
||||
│ ├── dropzones.js
|
||||
│ ├── jumps.js
|
||||
│ ├── pages.js
|
||||
│ ├── profiles.js
|
||||
│ ├── qcm.js
|
||||
│ └── index.js
|
||||
│
|
||||
├── cms/ ← Gestion de contenu
|
||||
│ ├── articles.routes.js
|
||||
│ ├── comments.routes.js
|
||||
│ ├── product.routes.js
|
||||
│ ├── products.routes.js
|
||||
│ ├── profiles.routes.js
|
||||
│ ├── tags.routes.js
|
||||
│ ├── user.routes.js
|
||||
│ └── index.js
|
||||
│
|
||||
└── herowars/ ← Jeu HeroWars
|
||||
├── clans.routes.js
|
||||
├── members.routes.js
|
||||
├── herowars.routes.js
|
||||
└── index.js
|
||||
|
||||
|
||||
📝 FICHIERS DE DOCUMENTATION CRÉÉS
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
1. MIGRATION_REPORT.md
|
||||
└─ Rapport détaillé: structure ancienne → nouvelle, fichiers migrés
|
||||
|
||||
2. MIGRATION_COMPLETE_SUMMARY.md
|
||||
└─ Résumé exécutif avec instructions de test et frontend
|
||||
|
||||
3. POST_MIGRATION_CHECKLIST.md
|
||||
└─ Liste de vérification manuelle pour validation
|
||||
|
||||
4. SCRIPTS_MIGRATION_GUIDE.md
|
||||
└─ Guide complet d'utilisation des scripts (CE FICHIER)
|
||||
|
||||
5. MIGRATION_SWAGGER_TODO.md
|
||||
└─ Notes sur les mises à jour Swagger/OpenAPI
|
||||
|
||||
|
||||
⚙️ SCRIPTS DE MIGRATION CRÉÉS
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
1. scripts/migrate-to-domain-structure.js
|
||||
│
|
||||
├─ Phase 1: Crée les répertoires de domaines
|
||||
├─ Phase 2: Migre tous les fichiers de routes
|
||||
├─ Phase 3: Génère les fichiers index.js
|
||||
├─ Phase 4: Met à jour src/routes/api/index.js
|
||||
├─ Phase 5: Crée les notes Swagger
|
||||
├─ Phase 6: Gère les fichiers Swagger
|
||||
├─ Phase 7: Effectue les opérations Git
|
||||
├─ Phase 8: Valide la migration
|
||||
└─ Phase 9: Génère un rapport
|
||||
|
||||
[✅ EXÉCUTÉ: commit 9f73ed0]
|
||||
|
||||
2. scripts/update-references-post-migration.js
|
||||
│
|
||||
├─ Phase 1: Met à jour les fichiers YAML Swagger
|
||||
├─ Phase 2: Met à jour la collection/env Postman
|
||||
├─ Phase 3: Scanne les références v1/v2/v3 restantes
|
||||
└─ Phase 4: Génère une liste de vérification
|
||||
|
||||
[✅ EXÉCUTÉ]
|
||||
|
||||
3. scripts/finalize-migration.js
|
||||
│
|
||||
├─ Phase 1: Valide la structure des domaines
|
||||
├─ Phase 2: Liste les anciens répertoires
|
||||
├─ Phase 3: Optionnel - Nettoie les v1/v2/v3 (--cleanup)
|
||||
├─ Phase 4: Optionnel - Teste les endpoints (--test)
|
||||
└─ Phase 5: Génère un résumé final
|
||||
|
||||
[PRÊT À EXÉCUTER - voir instructions ci-dessous]
|
||||
|
||||
|
||||
🚀 PROCHAINES ÉTAPES IMMÉDIATES
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
ÉTAPE 1️⃣: VALIDER LA STRUCTURE
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
$ node scripts/finalize-migration.js
|
||||
|
||||
✓ Affichera: "skydive/: ✓ (8 route files)"
|
||||
✓ Affichera: "cms/: ✓ (7 route files)"
|
||||
✓ Affichera: "herowars/: ✓ (3 route files)"
|
||||
|
||||
|
||||
ÉTAPE 2️⃣: NETTOYER LES ANCIENS RÉPERTOIRES (OPTIONNEL)
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
OPTION A - Via script:
|
||||
$ node scripts/finalize-migration.js --cleanup
|
||||
|
||||
OPTION B - Manuellement:
|
||||
$ rm -rf src/routes/api/v1 src/routes/api/v2 src/routes/api/v3
|
||||
$ git add -A && git commit -m "chore: remove old v1/v2/v3 directories"
|
||||
|
||||
|
||||
ÉTAPE 3️⃣: TESTER LE SERVEUR
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
Terminal 1 - Démarrer l'API:
|
||||
$ npm run local
|
||||
|
||||
Terminal 2 - Tester les endpoints:
|
||||
$ curl http://localhost:3200/api-docs # Swagger UI
|
||||
$ curl http://localhost:3200/api/skydive/jumps # Skydive
|
||||
$ curl http://localhost:3200/api/cms/articles # CMS
|
||||
$ curl http://localhost:3200/api/herowars/clans # HeroWars
|
||||
|
||||
|
||||
ÉTAPE 4️⃣: METTRE À JOUR LE FRONTEND (IMPORTANT!) 🔴
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
A. Mettre à jour les environnements Angular:
|
||||
Fichiers à modifier:
|
||||
- src/environments/environment.ts
|
||||
- src/environments/environment.development.ts
|
||||
- src/environments/environment.local.ts
|
||||
|
||||
AVANT:
|
||||
export const environment = {
|
||||
apiUrl: '/api/v1',
|
||||
cmsUrl: '/api/v2',
|
||||
herowarsUrl: '/api/v3',
|
||||
};
|
||||
|
||||
APRÈS:
|
||||
export const environment = {
|
||||
apiUrl: '/api/skydive',
|
||||
cmsUrl: '/api/cms',
|
||||
herowarsUrl: '/api/herowars',
|
||||
};
|
||||
|
||||
B. Mettre à jour les services Angular:
|
||||
Cherchez et remplacez les chemins en dur:
|
||||
|
||||
sed -i '' "s|'/api/v1/|'/api/skydive/|g" src/**/*.ts
|
||||
sed -i '' "s|'/api/v2/|'/api/cms/|g" src/**/*.ts
|
||||
sed -i '' "s|'/api/v3/|'/api/herowars/|g" src/**/*.ts
|
||||
|
||||
C. Tester le frontend:
|
||||
$ npm start
|
||||
Vérifier dans DevTools que les appels API vont vers /api/skydive/*, /api/cms/*, etc.
|
||||
|
||||
|
||||
ÉTAPE 5️⃣: POUSSER LES CHANGEMENTS
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
$ git push origin develop
|
||||
ou
|
||||
$ git push --all --follow-tags
|
||||
|
||||
|
||||
📋 RÉSUMÉ DES COMMITS GIT
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
Commit 1: 9f73ed0
|
||||
├─ Message: "refactor: restructure API routes from v1/v2/v3 to domain-based..."
|
||||
├─ Actions:
|
||||
│ ├─ Créé: src/routes/api/skydive/, cms/, herowars/
|
||||
│ ├─ Copié: 19 fichiers de routes
|
||||
│ └─ Mis à jour: src/routes/api/index.js
|
||||
└─ État: ✅ MERGED
|
||||
|
||||
Commit 2: 74df96c
|
||||
├─ Message: "docs: add migration documentation, finalization scripts, and update Swagger paths"
|
||||
├─ Actions:
|
||||
│ ├─ Créé: 4 fichiers de documentation
|
||||
│ ├─ Créé: 2 scripts de finalisation
|
||||
│ └─ Mis à jour: 4 fichiers Swagger YAML
|
||||
└─ État: ✅ CURRENT HEAD
|
||||
|
||||
|
||||
🔄 AVANT/APRÈS - COMPARAISON DES API
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
SAUT/PARACHUTISME:
|
||||
AVANT: GET /api/v1/jumps
|
||||
APRÈS: GET /api/skydive/jumps
|
||||
──────────────────────
|
||||
GET /api/v1/aeronefs → GET /api/skydive/aeronefs
|
||||
POST /api/v1/aeronefs → POST /api/skydive/aeronefs
|
||||
|
||||
CONTENU:
|
||||
AVANT: GET /api/v2/articles
|
||||
APRÈS: GET /api/cms/articles
|
||||
────────────────────────
|
||||
GET /api/v2/articles/123 → GET /api/cms/articles/123
|
||||
POST /api/v2/articles → POST /api/cms/articles
|
||||
GET /api/v2/comments → GET /api/cms/comments
|
||||
|
||||
JEU:
|
||||
AVANT: GET /api/v3/clans
|
||||
APRÈS: GET /api/herowars/clans
|
||||
────────────────────────
|
||||
GET /api/v3/members → GET /api/herowars/members
|
||||
POST /api/v3/members/123 → POST /api/herowars/members/123
|
||||
|
||||
|
||||
⚠️ IMPORTANT: ROLLBACK EN CAS DE PROBLÈME
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
Si vous rencontrez des problèmes:
|
||||
|
||||
Option 1 - Peu de changements (rollback 2 commits):
|
||||
$ git reset --hard HEAD~2
|
||||
|
||||
Option 2 - Si vous avez poussé, utiliser revert:
|
||||
$ git revert 74df96c
|
||||
$ git revert 9f73ed0
|
||||
|
||||
Option 3 - Restaurer depuis le remote:
|
||||
$ git fetch origin
|
||||
$ git reset --hard origin/develop
|
||||
|
||||
|
||||
✅ CHECKLIST DE VALIDATION POST-MIGRATION
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
Backend (adastra_api):
|
||||
☐ npm run local - serveur démarre sans erreur
|
||||
☐ curl http://localhost:3200/api-docs - Swagger UI accessible
|
||||
☐ Endpoints skydive fonctionnent: GET /api/skydive/jumps
|
||||
☐ Endpoints CMS fonctionnent: GET /api/cms/articles
|
||||
☐ Endpoints HeroWars fonctionnent: GET /api/herowars/clans
|
||||
|
||||
Frontend (adastra_app):
|
||||
☐ npm start - app démarre sans erreur
|
||||
☐ Appels API vont vers les nouveaux chemins
|
||||
☐ Authentification toujours fonctionnelle
|
||||
☐ Pages affichent les données correctement
|
||||
☐ Aucune erreur 404 sur les endpoints
|
||||
|
||||
Git:
|
||||
☐ Commits créés et visibles: git log --oneline -5
|
||||
☐ Prêt pour: git push origin develop
|
||||
|
||||
Documentation:
|
||||
☐ README.md mis à jour (optionnel)
|
||||
☐ Équipe notifiée du changement
|
||||
☐ Documentation technique mise à jour
|
||||
|
||||
|
||||
📚 RESSOURCES SUPPLÉMENTAIRES
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
Consultez ces fichiers pour plus d'informations:
|
||||
|
||||
1. SCRIPTS_MIGRATION_GUIDE.md
|
||||
└─ Guide détaillé de chaque script et options
|
||||
|
||||
2. POST_MIGRATION_CHECKLIST.md
|
||||
└─ Liste complète de vérification manuelle
|
||||
|
||||
3. MIGRATION_COMPLETE_SUMMARY.md
|
||||
└─ Résumé exécutif avec instructions
|
||||
|
||||
4. docs/*.md (depuis l'audit architectural)
|
||||
└─ Architecture complète et ADRs
|
||||
|
||||
|
||||
🎓 POINTS CLÉS À RETENIR
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
✓ NON-DESTRUCTIF: Les anciens répertoires restent, vous pouvez les nettoyer
|
||||
progressivement après vérification
|
||||
|
||||
✓ AUTOMATISÉ: Scripts Python/Node qui gèrent la plupart des tâches
|
||||
Swagger, Postman, routes mis à jour automatiquement
|
||||
|
||||
⚠️ MANUEL: Frontend DOIT être mis à jour (recherche/remplace)
|
||||
Tests doivent être revérifiés
|
||||
Documentation peut nécessiter mise à jour
|
||||
|
||||
✓ GIT-SAFE: Chaque étape crée un commit
|
||||
Rollback facile si problème
|
||||
Toutes les modifications sont tracées
|
||||
|
||||
✓ BÉNÉFICES: Chemins d'API clairs et explicites
|
||||
Séparation nette des domaines métier
|
||||
Meilleure architecture et maintenabilité
|
||||
Préparation pour futures versions d'API
|
||||
|
||||
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
✨ Migration complétée avec succès! ✨
|
||||
|
||||
Prêt à continuer avec les 20 ADRs d'architecture?
|
||||
(QUICK_START_WEEK1.md pour la Phase 1)
|
||||
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
Date: 24 avril 2026
|
||||
Statut: ✅ COMPLETE
|
||||
Prochaine étape: Mise à jour du frontend + tests
|
||||
@@ -0,0 +1,111 @@
|
||||
|
||||
╔════════════════════════════════════════════════════════════════════════════╗
|
||||
║ MIGRATION SUCCESSFULLY COMPLETED ║
|
||||
╚════════════════════════════════════════════════════════════════════════════╝
|
||||
|
||||
NEW API STRUCTURE:
|
||||
├── /api/skydive/* ← Skydiving features (jumps, aeronefs, dropzones, etc.)
|
||||
├── /api/cms/* ← Content management (articles, tags, comments, etc.)
|
||||
└── /api/herowars/* ← Game features (clans, members, raids, etc.)
|
||||
|
||||
WHAT WAS CHANGED:
|
||||
✓ Routes directory: v1/v2/v3 → domain-based structure
|
||||
✓ Route definitions: Updated all index.js files
|
||||
✓ Swagger YAML: Updated path prefixes to new domains
|
||||
✓ Postman collection: Updated endpoint URLs
|
||||
|
||||
FILES MIGRATED:
|
||||
✓ Skydive domain (8 route files):
|
||||
- aeronefs.js, applications.js, canopies.js, dropzones.js
|
||||
- jumps.js, pages.js, profiles.js, qcm.js
|
||||
|
||||
✓ CMS domain (8 route files):
|
||||
- articles.routes.js, comments.routes.js, product.routes.js
|
||||
- products.routes.js, profiles.routes.js, tags.routes.js, user.routes.js
|
||||
|
||||
✓ Hero Wars domain (3 route files):
|
||||
- clans.routes.js, members.routes.js, herowars.routes.js
|
||||
|
||||
TESTING INSTRUCTIONS:
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
1. Start the API server:
|
||||
npm run local
|
||||
|
||||
2. In another terminal, verify Swagger is updated:
|
||||
curl http://localhost:3200/api-docs
|
||||
|
||||
3. Test a sample endpoint:
|
||||
curl http://localhost:3200/api/skydive/jumps
|
||||
curl http://localhost:3200/api/cms/articles
|
||||
curl http://localhost:3200/api/herowars/clans
|
||||
|
||||
FRONTEND UPDATES REQUIRED:
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
In your Angular frontend (adastra_app):
|
||||
|
||||
1. Update environment files:
|
||||
src/environments/environment.ts
|
||||
src/environments/environment.development.ts
|
||||
src/environments/environment.local.ts
|
||||
|
||||
Replace:
|
||||
- apiUrl: '/api/v1' → apiUrl: '/api/skydive'
|
||||
- cmUrl: '/api/v2' → cmUrl: '/api/cms'
|
||||
- hwUrl: '/api/v3' → hwUrl: '/api/herowars'
|
||||
|
||||
2. Update API service calls:
|
||||
// Before:
|
||||
http.get('/api/v1/jumps')
|
||||
http.get('/api/v2/articles')
|
||||
http.get('/api/v3/clans')
|
||||
|
||||
// After:
|
||||
http.get('/api/skydive/jumps')
|
||||
http.get('/api/cms/articles')
|
||||
http.get('/api/herowars/clans')
|
||||
|
||||
3. Search & replace in your services:
|
||||
sed -i 's|/api/v1/|/api/skydive/|g' src/**/*.ts
|
||||
sed -i 's|/api/v2/|/api/cms/|g' src/**/*.ts
|
||||
sed -i 's|/api/v3/|/api/herowars/|g' src/**/*.ts
|
||||
|
||||
GIT OPERATIONS:
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
View migration commits:
|
||||
git log --oneline -5
|
||||
|
||||
If needed, view detailed changes:
|
||||
git show HEAD
|
||||
|
||||
Push to remote:
|
||||
git push origin develop
|
||||
|
||||
ROLLBACK (if issues):
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
If you need to rollback:
|
||||
git reset --hard HEAD~2
|
||||
|
||||
(Adjust the number of commits based on history)
|
||||
|
||||
ADDITIONAL RESOURCES:
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
Documentation files created:
|
||||
- MIGRATION_REPORT.md: Detailed migration information
|
||||
- MIGRATION_SWAGGER_TODO.md: Swagger update notes
|
||||
- POST_MIGRATION_CHECKLIST.md: Verification checklist
|
||||
|
||||
Scripts created:
|
||||
- scripts/migrate-to-domain-structure.js: Main migration script
|
||||
- scripts/update-references-post-migration.js: Post-migration updates
|
||||
- scripts/finalize-migration.js: Cleanup and testing
|
||||
|
||||
═════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
✓ Migration is complete! Follow the testing instructions above.
|
||||
|
||||
═════════════════════════════════════════════════════════════════════════════
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
API STRUCTURE MIGRATION REPORT
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
MIGRATION: v1/v2/v3 → Domain-Based (skydive/cms/herowars)
|
||||
|
||||
OLD STRUCTURE:
|
||||
└── routes/api/
|
||||
├── v1/ (Skydive routes)
|
||||
├── v2/ (CMS + misc routes)
|
||||
└── v3/ (Hero Wars routes)
|
||||
|
||||
NEW STRUCTURE:
|
||||
└── routes/api/
|
||||
├── skydive/
|
||||
├── cms/
|
||||
└── herowars/
|
||||
|
||||
ROUTE MAPPINGS:
|
||||
✓ /api/v1/* → /api/skydive/*
|
||||
- applications, aeronefs, canopies, dropzones, jumps, pages, profiles, qcm
|
||||
|
||||
✓ /api/v2/* → /api/cms/*
|
||||
- user, articles, comments, product, products, profiles, tags
|
||||
|
||||
✓ /api/v3/* → /api/herowars/*
|
||||
- clans, members, herowars (moved from v2)
|
||||
|
||||
FILES CREATED/UPDATED:
|
||||
✓ src/routes/api/skydive/index.js
|
||||
✓ src/routes/api/cms/index.js
|
||||
✓ src/routes/api/herowars/index.js
|
||||
✓ src/routes/api/index.js
|
||||
✓ All route files copied to appropriate domains
|
||||
|
||||
MANUAL STEPS REQUIRED:
|
||||
|
||||
1. Update Swagger/OpenAPI documentation:
|
||||
- Review MIGRATION_SWAGGER_TODO.md
|
||||
- Update path prefixes in src/swagger/*.yaml files
|
||||
- Update paths in src/config/swagger.js if needed
|
||||
|
||||
2. Update app.js (if direct version references exist):
|
||||
- Search for 'v1', 'v2', 'v3' strings
|
||||
- Replace with domain names where appropriate
|
||||
|
||||
3. Update tests and client calls:
|
||||
- Replace /api/v1/ with /api/skydive/
|
||||
- Replace /api/v2/ with /api/cms/
|
||||
- Replace /api/v3/ with /api/herowars/
|
||||
|
||||
4. Update any documentation:
|
||||
- README.md API endpoints section
|
||||
- API documentation and guides
|
||||
|
||||
5. Test all endpoints:
|
||||
- Verify each domain routes work correctly
|
||||
- Check authentication/authorization still functions
|
||||
- Validate error handling
|
||||
|
||||
OPTIONAL: Old v1/v2/v3 directories can be removed after verification:
|
||||
rm -rf src/routes/api/v1
|
||||
rm -rf src/routes/api/v2
|
||||
rm -rf src/routes/api/v3
|
||||
|
||||
═══════════════════════════════════════════════════════════════════════════════
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
# Swagger Path Updates Required
|
||||
|
||||
The following Swagger YAML files need path updates:
|
||||
|
||||
## skydive.yaml
|
||||
- Change: /api/v1/ → /api/skydive/
|
||||
- Affected routes: /jumps, /aeronefs, /dropzones, /canopies, /pages, /qcm, /applications
|
||||
|
||||
## cms.yaml
|
||||
- Change: /api/v2/ → /api/cms/
|
||||
- Affected routes: /articles, /comments, /products, /tags, /profiles, /user
|
||||
|
||||
## herowars.yaml
|
||||
- Change: /api/v3/ → /api/herowars/
|
||||
- Affected routes: /clans, /members
|
||||
- Note: Add herowars endpoint from former /api/v2/herowars
|
||||
|
||||
Update in: src/config/swagger.js if paths are hardcoded.
|
||||
@@ -0,0 +1,80 @@
|
||||
|
||||
# Post-Migration Update Checklist
|
||||
|
||||
## Files Updated by Script ✓
|
||||
- [x] Swagger YAML files (/api/v1 → /api/skydive, etc.)
|
||||
- [x] Postman collection and environment files
|
||||
- [x] API routes structure (new domains created)
|
||||
|
||||
## Manual Verification Required
|
||||
|
||||
### 1. Test API Endpoints
|
||||
```bash
|
||||
npm run local # Start the server
|
||||
# In another terminal:
|
||||
curl http://localhost:3200/api-docs # Check Swagger UI
|
||||
```
|
||||
|
||||
### 2. Verify Routes
|
||||
- [ ] GET /api/skydive/jumps
|
||||
- [ ] GET /api/cms/articles
|
||||
- [ ] GET /api/herowars/clans
|
||||
- [ ] Other domain-specific endpoints
|
||||
|
||||
### 3. Frontend Updates Required (if applicable)
|
||||
- [ ] Update Angular environment files (environment.ts, environment.development.ts, etc.)
|
||||
- [ ] Replace all API calls from /api/v1, /api/v2, /api/v3 to new domains
|
||||
- [ ] Update service layer URLs
|
||||
- [ ] Update HTTP interceptors if needed
|
||||
|
||||
### 4. Documentation Updates
|
||||
- [ ] Update README.md with new API structure
|
||||
- [ ] Update API documentation (if any)
|
||||
- [ ] Update deployment/infrastructure docs
|
||||
- [ ] Update team wiki/documentation
|
||||
|
||||
### 5. CI/CD Pipeline (if applicable)
|
||||
- [ ] Update build/deployment scripts referencing v1/v2/v3
|
||||
- [ ] Update any health checks pointing to old paths
|
||||
- [ ] Update monitoring/alerting rules
|
||||
|
||||
### 6. Client Applications
|
||||
- [ ] Update all client libraries/SDKs
|
||||
- [ ] Update mobile app API endpoints
|
||||
- [ ] Update third-party integrations
|
||||
|
||||
### 7. Database/Caching (if applicable)
|
||||
- [ ] Clear any cached references to old endpoints
|
||||
- [ ] Update API documentation in databases
|
||||
- [ ] Check for hardcoded URLs in configuration
|
||||
|
||||
## Git Operations
|
||||
```bash
|
||||
# View the migration commits
|
||||
git log --oneline -5
|
||||
|
||||
# If rollback needed:
|
||||
git revert <commit-hash>
|
||||
|
||||
# Push changes
|
||||
git push origin develop
|
||||
```
|
||||
|
||||
## Optional: Cleanup Old Directories
|
||||
```bash
|
||||
# After thorough testing, remove old v1/v2/v3 directories:
|
||||
rm -rf src/routes/api/v1
|
||||
rm -rf src/routes/api/v2
|
||||
rm -rf src/routes/api/v3
|
||||
git add -A
|
||||
git commit -m "chore: remove old v1/v2/v3 route directories"
|
||||
```
|
||||
|
||||
## Rollback Procedure
|
||||
If issues arise, rollback with:
|
||||
```bash
|
||||
git reset --hard HEAD~2 # Adjust commit count if needed
|
||||
```
|
||||
|
||||
---
|
||||
Document generated: 2026-04-23T22:48:52.497Z
|
||||
@@ -0,0 +1,329 @@
|
||||
# Migration Scripts - Guide d'utilisation
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Cette migration restructure votre API Express de `/api/v1` `/api/v2` `/api/v3` (qui représentaient des domaines métier, pas des versions API) vers une architecture basée sur les domaines avec des chemins clairs et explicites.
|
||||
|
||||
### Ancien structure (confuse)
|
||||
```
|
||||
/api/v1/* → Skydive features
|
||||
/api/v2/* → CMS features
|
||||
/api/v3/* → Hero Wars features
|
||||
```
|
||||
|
||||
### Nouvelle structure (claire)
|
||||
```
|
||||
/api/skydive/* ← Toutes les fonctionnalités de parachutisme
|
||||
/api/cms/* ← Gestion de contenu (articles, tags, etc.)
|
||||
/api/herowars/* ← Gestion du jeu HeroWars (clans, membres, raids)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scripts de migration
|
||||
|
||||
### 1. `migrate-to-domain-structure.js` ✓ EXÉCUTÉ
|
||||
|
||||
**Rôle:** Crée la nouvelle structure et migre les fichiers
|
||||
|
||||
**Statut:** ✅ Completed
|
||||
- Créé les répertoires `/api/skydive`, `/api/cms`, `/api/herowars`
|
||||
- Copié tous les fichiers de routes vers les nouveaux emplacements
|
||||
- Généré les nouveaux fichiers `index.js` pour chaque domaine
|
||||
- Mis à jour `src/routes/api/index.js` pour utiliser les nouveaux chemins
|
||||
- Créé un commit Git
|
||||
|
||||
**Fichiers modifiés:**
|
||||
```
|
||||
✓ src/routes/api/skydive/ (8 fichiers)
|
||||
✓ src/routes/api/cms/ (8 fichiers)
|
||||
✓ src/routes/api/herowars/ (3 fichiers)
|
||||
✓ src/routes/api/index.js (mis à jour)
|
||||
```
|
||||
|
||||
**Rapports générés:**
|
||||
- `MIGRATION_REPORT.md` - Détails complets de la migration
|
||||
- `MIGRATION_SWAGGER_TODO.md` - Tâches pour Swagger
|
||||
|
||||
---
|
||||
|
||||
### 2. `update-references-post-migration.js` ✓ EXÉCUTÉ
|
||||
|
||||
**Rôle:** Met à jour les références aux chemins dans la documentation
|
||||
|
||||
**Statut:** ✅ Completed
|
||||
- Mis à jour les fichiers YAML Swagger (`/api/v1/` → `/api/skydive/`, etc.)
|
||||
- Mis à jour la collection et l'environnement Postman
|
||||
- Scanné les fichiers clés pour les références restantes
|
||||
|
||||
**Rapports générés:**
|
||||
- `POST_MIGRATION_CHECKLIST.md` - Liste de vérification manuelle
|
||||
|
||||
---
|
||||
|
||||
### 3. `finalize-migration.js`
|
||||
|
||||
**Rôle:** Valide, nettoie, et teste la migration
|
||||
|
||||
**Options disponibles:**
|
||||
```bash
|
||||
# Valider la structure sans rien faire
|
||||
node scripts/finalize-migration.js
|
||||
|
||||
# Valider et nettoyer les anciens répertoires
|
||||
node scripts/finalize-migration.js --cleanup
|
||||
|
||||
# Valider et tester les endpoints (nécessite le serveur en cours d'exécution)
|
||||
node scripts/finalize-migration.js --test
|
||||
|
||||
# Mode complet: validation, nettoyage et résumé
|
||||
node scripts/finalize-migration.js --full
|
||||
```
|
||||
|
||||
**Statut:** ✅ Ready to run
|
||||
|
||||
**Rapport généré:**
|
||||
- `MIGRATION_COMPLETE_SUMMARY.md` - Résumé final avec instructions
|
||||
|
||||
---
|
||||
|
||||
## Guide étape par étape
|
||||
|
||||
### Étape 1: Vérifier la migration ✅
|
||||
```bash
|
||||
ls -la src/routes/api/
|
||||
# Devrait afficher: cms/, herowars/, skydive/, v1/, v2/, v3/, index.js
|
||||
```
|
||||
|
||||
### Étape 2: Valider la structure
|
||||
```bash
|
||||
node scripts/finalize-migration.js
|
||||
```
|
||||
|
||||
**Résultat attendu:**
|
||||
```
|
||||
✓ skydive/: ✓ (8 route files)
|
||||
✓ cms/: ✓ (7 route files)
|
||||
✓ herowars/: ✓ (3 route files)
|
||||
```
|
||||
|
||||
### Étape 3: Nettoyer les anciens répertoires (OPTIONNEL)
|
||||
```bash
|
||||
# Option A: Via le script
|
||||
node scripts/finalize-migration.js --cleanup
|
||||
|
||||
# Option B: Manuellement
|
||||
rm -rf src/routes/api/v1 src/routes/api/v2 src/routes/api/v3
|
||||
git add -A
|
||||
git commit -m "chore: remove old v1/v2/v3 route directories"
|
||||
```
|
||||
|
||||
### Étape 4: Mettre à jour le frontend (IMPORTANT)
|
||||
|
||||
**Fichiers à modifier dans `adastra_app/src/environments/`:**
|
||||
|
||||
#### `environment.ts`
|
||||
```typescript
|
||||
// AVANT:
|
||||
export const environment = {
|
||||
production: false,
|
||||
apiUrl: '/api/v1',
|
||||
cmsUrl: '/api/v2',
|
||||
herowarsUrl: '/api/v3',
|
||||
};
|
||||
|
||||
// APRÈS:
|
||||
export const environment = {
|
||||
production: false,
|
||||
apiUrl: '/api/skydive',
|
||||
cmsUrl: '/api/cms',
|
||||
herowarsUrl: '/api/herowars',
|
||||
};
|
||||
```
|
||||
|
||||
#### `environment.development.ts` et `environment.local.ts`
|
||||
Applique les mêmes changements
|
||||
|
||||
**Mise à jour des services Angular:**
|
||||
```typescript
|
||||
// Dans vos services (par exemple, src/app/services/*.service.ts)
|
||||
|
||||
// AVANT:
|
||||
this.http.get(environment.apiUrl + '/jumps')
|
||||
this.http.get(environment.cmsUrl + '/articles')
|
||||
this.http.get(environment.herowarsUrl + '/clans')
|
||||
|
||||
// APRÈS:
|
||||
this.http.get(environment.apiUrl + '/jumps')
|
||||
this.http.get(environment.cmsUrl + '/articles')
|
||||
this.http.get(environment.herowarsUrl + '/clans')
|
||||
// Pas de changement si vous utilisez les variables d'environnement!
|
||||
// Sinon, cherchez/remplacez les chemins en dur
|
||||
```
|
||||
|
||||
**Automatiser la mise à jour du frontend (macOS/Linux):**
|
||||
```bash
|
||||
cd adastra_app
|
||||
sed -i '' "s|/api/v1|/api/skydive|g" src/**/*.ts
|
||||
sed -i '' "s|/api/v2|/api/cms|g" src/**/*.ts
|
||||
sed -i '' "s|/api/v3|/api/herowars|g" src/**/*.ts
|
||||
```
|
||||
|
||||
### Étape 5: Tester les endpoints
|
||||
|
||||
**Démarrer le serveur API:**
|
||||
```bash
|
||||
cd adastra_api
|
||||
npm run local
|
||||
```
|
||||
|
||||
**Dans un autre terminal, tester les nouveaux chemins:**
|
||||
```bash
|
||||
# Tester Swagger UI
|
||||
curl http://localhost:3200/api-docs
|
||||
|
||||
# Tester les endpoints des domaines
|
||||
curl http://localhost:3200/api/skydive/jumps
|
||||
curl http://localhost:3200/api/cms/articles
|
||||
curl http://localhost:3200/api/herowars/clans
|
||||
|
||||
# Avec authentification si nécessaire
|
||||
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:3200/api/skydive/jumps
|
||||
```
|
||||
|
||||
### Étape 6: Tester le frontend
|
||||
|
||||
```bash
|
||||
cd adastra_app
|
||||
npm start
|
||||
# Ou avec configuration spécifique
|
||||
npm run local # ng serve --configuration local
|
||||
```
|
||||
|
||||
Vérifier dans les DevTools que les appels API vont vers les nouveaux chemins.
|
||||
|
||||
---
|
||||
|
||||
## Statistiques de la migration
|
||||
|
||||
| Métrique | Valeur |
|
||||
|----------|--------|
|
||||
| Nouveaux domaines créés | 3 (skydive, cms, herowars) |
|
||||
| Fichiers de routes migrés | 19 |
|
||||
| Fichiers index.js créés/mis à jour | 4 |
|
||||
| Fichiers Swagger mis à jour | Oui |
|
||||
| Fichiers Postman mis à jour | Oui |
|
||||
| Commits Git créés | 1 (structure) + opt. 1 (nettoyage) |
|
||||
|
||||
---
|
||||
|
||||
## Fichiers de rapport créés
|
||||
|
||||
| Fichier | Contenu |
|
||||
|---------|---------|
|
||||
| `MIGRATION_REPORT.md` | Rapport détaillé de la migration |
|
||||
| `MIGRATION_SWAGGER_TODO.md` | Notes pour les mises à jour Swagger |
|
||||
| `POST_MIGRATION_CHECKLIST.md` | Liste de vérification manuelle |
|
||||
| `MIGRATION_COMPLETE_SUMMARY.md` | Résumé final et instructions |
|
||||
| `SCRIPTS_MIGRATION_GUIDE.md` | Ce fichier |
|
||||
|
||||
---
|
||||
|
||||
## Procédure de rollback
|
||||
|
||||
Si vous devez annuler la migration:
|
||||
|
||||
```bash
|
||||
# Voir l'historique
|
||||
git log --oneline -10
|
||||
|
||||
# Annuler les changements (ajuster le nombre de commits)
|
||||
git reset --hard HEAD~2
|
||||
|
||||
# Ou restaurer une branche spécifique
|
||||
git reset --hard origin/develop
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Points clés à retenir
|
||||
|
||||
✅ **La migration est non-destructive:**
|
||||
- Les anciens répertoires v1/v2/v3 existent toujours
|
||||
- Vous pouvez les supprimer après vérification
|
||||
|
||||
✅ **Mises à jour automatisées:**
|
||||
- Scripts: Oui ✓
|
||||
- Swagger: Oui ✓
|
||||
- Postman: Oui ✓
|
||||
|
||||
⚠️ **Mises à jour manuelles requises:**
|
||||
- Frontend Angular (environnement + services)
|
||||
- Tous les appels API en dur dans le code cliente
|
||||
- Documentation externe
|
||||
- Tests d'intégration
|
||||
|
||||
✅ **Git-safe:**
|
||||
- Chaque étape crée un commit
|
||||
- Rollback facile si problème
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Les endpoints retournent 404
|
||||
- ✓ Vérifier que le serveur a redémarré après la migration
|
||||
- ✓ Vérifier les chemins dans Swagger UI (http://localhost:3200/api-docs)
|
||||
- ✓ Vérifier que le backend a bien recompilé (avec nodemon)
|
||||
|
||||
### Les routes ne sont pas trouvées
|
||||
- ✓ Vérifier que `src/routes/api/index.js` a les bonnes références
|
||||
- ✓ Vérifier que chaque domaine a un `index.js`
|
||||
- ✓ Vérifier l'ordre des middlewares dans `app.js`
|
||||
|
||||
### Erreurs d'authentification
|
||||
- ✓ Les middlewares d'auth ne sont pas affectés
|
||||
- ✓ Les tokens JWT restent valides
|
||||
- ✓ Les headers restent les mêmes
|
||||
|
||||
### Le frontend ne peut pas accéder à l'API
|
||||
- ✓ Vérifier CORS dans `app.js`
|
||||
- ✓ Vérifier les URLs dans les environnements Angular
|
||||
- ✓ Vérifier les appels http dans les services
|
||||
|
||||
---
|
||||
|
||||
## Prochaines étapes
|
||||
|
||||
1. ✅ Tester tous les endpoints du backend
|
||||
2. ✅ Mettre à jour le frontend (environnement + services)
|
||||
3. ✅ Tester le frontend avec le backend modifié
|
||||
4. ✅ Mettre à jour la documentation
|
||||
5. ✅ Nettoyer les anciens répertoires v1/v2/v3 (optionnel)
|
||||
6. ✅ Déployer en staging/production
|
||||
|
||||
---
|
||||
|
||||
## Ressources supplémentaires
|
||||
|
||||
- Documentation architecture: `ARCHITECTURE_DIAGRAMS.md`
|
||||
- ADR (Architecture Decision Records): `ADR_INDEX.md`
|
||||
- Configuration Swagger: `src/config/swagger.js`
|
||||
- Routes configuration: `src/routes/api/index.js`
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
Pour des questions ou problèmes:
|
||||
|
||||
1. ✓ Consulter los fichiers de rapport (`POST_MIGRATION_CHECKLIST.md`, etc.)
|
||||
2. ✓ Vérifier les logs du serveur: `npm run local` (output)
|
||||
3. ✓ Vérifier Swagger UI: http://localhost:3200/api-docs
|
||||
4. ✓ Exécuter la validation: `node scripts/finalize-migration.js`
|
||||
|
||||
---
|
||||
|
||||
**Migration effectuée le:** 24 avril 2026
|
||||
**Version API:** v1/v2/v3 → domain-based
|
||||
**Status:** ✅ Complete
|
||||
@@ -0,0 +1,762 @@
|
||||
# Méthodes disponibles sur les modèles MySQL (Sequelize)
|
||||
|
||||
Ce document liste toutes les méthodes automatiquement générées par Sequelize pour chaque modèle en fonction des associations définies dans `src/database/relationships/index.js`.
|
||||
|
||||
---
|
||||
|
||||
## Table des matières
|
||||
|
||||
1. [Article](#article)
|
||||
2. [Tag](#tag)
|
||||
3. [User](#user)
|
||||
4. [Comment](#comment)
|
||||
5. [Favorite](#favorite)
|
||||
6. [Follower](#follower)
|
||||
7. [Product](#product)
|
||||
8. [Brand](#brand)
|
||||
9. [Category](#category)
|
||||
10. [Packaging](#packaging)
|
||||
11. [TagList](#taglist)
|
||||
12. [Role](#role)
|
||||
13. [UserRoleXref](#userroleexref)
|
||||
14. [ProductCategoryXref](#productcategoryxref)
|
||||
15. [ProductTagXref](#producttagxref)
|
||||
|
||||
---
|
||||
|
||||
## Article
|
||||
|
||||
### Many-to-Many (belongsToMany)
|
||||
|
||||
#### Tags via `TagList`
|
||||
Alias: `articleTags`
|
||||
```javascript
|
||||
article.getArticleTags() // Récupère tous les tags
|
||||
article.setArticleTags([...]) // Définit les tags
|
||||
article.addArticleTag(tag) // Ajoute un tag
|
||||
article.removeArticleTag(tag) // Retire un tag
|
||||
article.countArticleTags() // Compte les tags
|
||||
article.hasArticleTag(tag) // Vérifie si le tag est lié
|
||||
```
|
||||
|
||||
#### Users (Favoris) via `Favorite`
|
||||
Alias: `articleFavoriteUsers` (cascade delete activé)
|
||||
```javascript
|
||||
article.getArticleFavoriteUsers() // Récupère les utilisateurs qui ont favorisé
|
||||
article.setArticleFavoriteUsers([...]) // Définit les utilisateurs
|
||||
article.addArticleFavoriteUser(user) // Ajoute un utilisateur
|
||||
article.removeArticleFavoriteUser(user) // Retire un utilisateur
|
||||
article.countArticleFavoriteUsers() // Compte les utilisateurs
|
||||
article.hasArticleFavoriteUser(user) // Vérifie si l'utilisateur a favorisé
|
||||
```
|
||||
|
||||
### One-to-Many (hasMany)
|
||||
|
||||
#### Comments (cascade delete activé)
|
||||
```javascript
|
||||
article.getComments() // Récupère tous les commentaires
|
||||
article.setComments([...]) // Définit les commentaires
|
||||
article.addComment(comment) // Ajoute un commentaire
|
||||
article.removeComment(comment) // Retire un commentaire
|
||||
article.countComments() // Compte les commentaires
|
||||
article.hasComment(comment) // Vérifie si le commentaire existe
|
||||
article.createComment({...}) // Crée un commentaire
|
||||
```
|
||||
|
||||
#### Favorites (cascade delete activé)
|
||||
```javascript
|
||||
article.getFavorites() // Récupère les enregistrements Favorite
|
||||
article.setFavorites([...]) // Définit les favoris
|
||||
article.addFavorite(favorite) // Ajoute un Favorite
|
||||
article.removeFavorite(favorite) // Retire un Favorite
|
||||
article.countFavorites() // Compte les Favorites
|
||||
article.hasFavorite(favorite) // Vérifie si le Favorite existe
|
||||
article.createFavorite({...}) // Crée un Favorite
|
||||
```
|
||||
|
||||
#### TagLists (cascade delete activé)
|
||||
```javascript
|
||||
article.getTagLists() // Récupère les enregistrements TagList
|
||||
article.setTagLists([...]) // Définit les TagLists
|
||||
article.addTagList(tagList) // Ajoute un TagList
|
||||
article.removeTagList(tagList) // Retire un TagList
|
||||
article.countTagLists() // Compte les TagLists
|
||||
article.hasTagList(tagList) // Vérifie si le TagList existe
|
||||
article.createTagList({...}) // Crée un TagList
|
||||
```
|
||||
|
||||
### Belongs-To
|
||||
|
||||
#### Author (User)
|
||||
```javascript
|
||||
article.getAuthor() // Récupère l'auteur
|
||||
article.setAuthor(user) // Définit l'auteur
|
||||
article.createAuthor({...}) // Crée un auteur
|
||||
```
|
||||
|
||||
### Instance Methods
|
||||
```javascript
|
||||
article.toJSONFor() // Formate en JSON
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tag
|
||||
|
||||
### Many-to-Many (belongsToMany)
|
||||
|
||||
#### Articles via `TagList`
|
||||
Alias: `articleIdArticleTagLists`
|
||||
```javascript
|
||||
tag.getArticleIdArticleTagLists() // Récupère les articles
|
||||
tag.setArticleIdArticleTagLists([...])
|
||||
tag.addArticleIdArticleTagList(article)
|
||||
tag.removeArticleIdArticleTagList(article)
|
||||
tag.countArticleIdArticleTagLists()
|
||||
tag.hasArticleIdArticleTagList(article)
|
||||
```
|
||||
|
||||
#### Products via `ProductTagXref`
|
||||
Alias: `productIdProductProductTagXrefs`
|
||||
```javascript
|
||||
tag.getProductIdProductProductTagXrefs()
|
||||
tag.setProductIdProductProductTagXrefs([...])
|
||||
tag.addProductIdProductProductTagXref(product)
|
||||
tag.removeProductIdProductProductTagXref(product)
|
||||
tag.countProductIdProductProductTagXrefs()
|
||||
tag.hasProductIdProductProductTagXref(product)
|
||||
```
|
||||
|
||||
### One-to-Many (hasMany)
|
||||
|
||||
#### TagLists
|
||||
```javascript
|
||||
tag.getTagLists() // Récupère les enregistrements TagList
|
||||
tag.setTagLists([...])
|
||||
tag.addTagList(tagList)
|
||||
tag.removeTagList(tagList)
|
||||
tag.countTagLists()
|
||||
tag.hasTagList(tagList)
|
||||
tag.createTagList({...})
|
||||
```
|
||||
|
||||
#### ProductTagXrefs
|
||||
```javascript
|
||||
tag.getProductTagXrefs() // Récupère les ProductTagXrefs
|
||||
tag.setProductTagXrefs([...])
|
||||
tag.addProductTagXref(xref)
|
||||
tag.removeProductTagXref(xref)
|
||||
tag.countProductTagXrefs()
|
||||
tag.hasProductTagXref(xref)
|
||||
tag.createProductTagXref({...})
|
||||
```
|
||||
|
||||
### Instance Methods
|
||||
```javascript
|
||||
tag.toJSONFor() // Formate en JSON
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## User
|
||||
|
||||
### Many-to-Many (belongsToMany)
|
||||
|
||||
#### Articles (Favoris) via `Favorite`
|
||||
Alias: `articleIdArticles`
|
||||
```javascript
|
||||
user.getArticleIdArticles() // Récupère les articles favorisés
|
||||
user.setArticleIdArticles([...])
|
||||
user.addArticleIdArticle(article)
|
||||
user.removeArticleIdArticle(article)
|
||||
user.countArticleIdArticles()
|
||||
user.hasArticleIdArticle(article)
|
||||
```
|
||||
|
||||
#### Followers (ceux qui vous suivent) via `Follower`
|
||||
Alias: `followerIdUsers`
|
||||
```javascript
|
||||
user.getFollowerIdUsers() // Récupère les followers
|
||||
user.setFollowerIdUsers([...])
|
||||
user.addFollowerIdUser(user)
|
||||
user.removeFollowerIdUser(user)
|
||||
user.countFollowerIdUsers()
|
||||
user.hasFollowerIdUser(user)
|
||||
```
|
||||
|
||||
#### Following (que vous suivez) via `Follower`
|
||||
Alias: `userIdUserFollowers`
|
||||
```javascript
|
||||
user.getUserIdUserFollowers() // Récupère ceux que vous suivez
|
||||
user.setUserIdUserFollowers([...])
|
||||
user.addUserIdUserFollower(user)
|
||||
user.removeUserIdUserFollower(user)
|
||||
user.countUserIdUserFollowers()
|
||||
user.hasUserIdUserFollower(user)
|
||||
```
|
||||
|
||||
#### Roles via `UserRoleXref`
|
||||
Alias: `roleIdRoles`
|
||||
```javascript
|
||||
user.getRoleIdRoles() // Récupère les rôles
|
||||
user.setRoleIdRoles([...])
|
||||
user.addRoleIdRole(role)
|
||||
user.removeRoleIdRole(role)
|
||||
user.countRoleIdRoles()
|
||||
user.hasRoleIdRole(role)
|
||||
```
|
||||
|
||||
### One-to-Many (hasMany)
|
||||
|
||||
#### Articles (créés par l'utilisateur)
|
||||
```javascript
|
||||
user.getArticles() // Récupère les articles créés
|
||||
user.setArticles([...])
|
||||
user.addArticle(article)
|
||||
user.removeArticle(article)
|
||||
user.countArticles()
|
||||
user.hasArticle(article)
|
||||
user.createArticle({...})
|
||||
```
|
||||
|
||||
#### Comments (créés par l'utilisateur)
|
||||
```javascript
|
||||
user.getComments() // Récupère les commentaires créés
|
||||
user.setComments([...])
|
||||
user.addComment(comment)
|
||||
user.removeComment(comment)
|
||||
user.countComments()
|
||||
user.hasComment(comment)
|
||||
user.createComment({...})
|
||||
```
|
||||
|
||||
#### Favorites (enregistrements)
|
||||
```javascript
|
||||
user.getFavorites() // Récupère les Favorites
|
||||
user.setFavorites([...])
|
||||
user.addFavorite(favorite)
|
||||
user.removeFavorite(favorite)
|
||||
user.countFavorites()
|
||||
user.hasFavorite(favorite)
|
||||
user.createFavorite({...})
|
||||
```
|
||||
|
||||
#### Followers (enregistrements)
|
||||
```javascript
|
||||
user.getFollowers() // Récupère les Followers
|
||||
user.setFollowers([...])
|
||||
user.addFollower(follower)
|
||||
user.removeFollower(follower)
|
||||
user.countFollowers()
|
||||
user.hasFollower(follower)
|
||||
user.createFollower({...})
|
||||
```
|
||||
|
||||
#### FollowerFollowers (ceux qui vous suivent via enregistrement)
|
||||
```javascript
|
||||
user.getFollowerFollowers() // Récupère les FollowerFollowers
|
||||
user.setFollowerFollowers([...])
|
||||
user.addFollowerFollower(follower)
|
||||
user.removeFollowerFollower(follower)
|
||||
user.countFollowerFollowers()
|
||||
user.hasFollowerFollower(follower)
|
||||
user.createFollowerFollower({...})
|
||||
```
|
||||
|
||||
#### Products (créés/possédés)
|
||||
```javascript
|
||||
user.getProducts() // Récupère les produits
|
||||
user.setProducts([...])
|
||||
user.addProduct(product)
|
||||
user.removeProduct(product)
|
||||
user.countProducts()
|
||||
user.hasProduct(product)
|
||||
user.createProduct({...})
|
||||
```
|
||||
|
||||
#### UserRoleXrefs
|
||||
```javascript
|
||||
user.getUserRoleXrefs() // Récupère les UserRoleXrefs
|
||||
user.setUserRoleXrefs([...])
|
||||
user.addUserRoleXref(xref)
|
||||
user.removeUserRoleXref(xref)
|
||||
user.countUserRoleXrefs()
|
||||
user.hasUserRoleXref(xref)
|
||||
user.createUserRoleXref({...})
|
||||
```
|
||||
|
||||
### Instance Methods
|
||||
```javascript
|
||||
user.validPassword(password) // Valide le mot de passe
|
||||
user.setPassword(password) // Définit le mot de passe (hash)
|
||||
user.generateJWT() // Génère un JWT
|
||||
user.toAuthJSON() // Retourne objet auth
|
||||
user.toJSONFor() // Formate en JSON
|
||||
user.toProfileJSONFor() // Formate profil en JSON
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Comment
|
||||
|
||||
### Belongs-To
|
||||
|
||||
#### Article
|
||||
```javascript
|
||||
comment.getArticle() // Récupère l'article
|
||||
comment.setArticle(article) // Définit l'article
|
||||
comment.createArticle({...}) // Crée un article
|
||||
```
|
||||
|
||||
#### Author (User)
|
||||
```javascript
|
||||
comment.getAuthor() // Récupère l'auteur
|
||||
comment.setAuthor(user) // Définit l'auteur
|
||||
comment.createAuthor({...}) // Crée un auteur
|
||||
```
|
||||
|
||||
### Instance Methods
|
||||
```javascript
|
||||
comment.toJSONFor() // Formate en JSON
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Favorite
|
||||
|
||||
### Belongs-To
|
||||
|
||||
#### User
|
||||
```javascript
|
||||
favorite.getUser() // Récupère l'utilisateur
|
||||
favorite.setUser(user) // Définit l'utilisateur
|
||||
favorite.createUser({...}) // Crée un utilisateur
|
||||
```
|
||||
|
||||
#### Article
|
||||
```javascript
|
||||
favorite.getArticle() // Récupère l'article
|
||||
favorite.setArticle(article) // Définit l'article
|
||||
favorite.createArticle({...}) // Crée un article
|
||||
```
|
||||
|
||||
### Instance Methods
|
||||
```javascript
|
||||
favorite.toJSONFor() // Formate en JSON
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Follower
|
||||
|
||||
### Belongs-To
|
||||
|
||||
#### User (l'utilisateur suivi)
|
||||
```javascript
|
||||
follower.getUser() // Récupère l'utilisateur suivi
|
||||
follower.setUser(user) // Définit l'utilisateur suivi
|
||||
follower.createUser({...}) // Crée un utilisateur
|
||||
```
|
||||
|
||||
#### Follower (l'utilisateur qui suit) - alias 'follower'
|
||||
```javascript
|
||||
follower.getFollower() // Récupère celui qui suit
|
||||
follower.setFollower(user) // Définit celui qui suit
|
||||
follower.createFollower({...}) // Crée un utilisateur qui suit
|
||||
```
|
||||
|
||||
### Instance Methods
|
||||
```javascript
|
||||
follower.toJSONFor() // Formate en JSON
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Product
|
||||
|
||||
### Many-to-Many (belongsToMany)
|
||||
|
||||
#### Categories via `ProductCategoryXref`
|
||||
Alias: `productCategories`
|
||||
```javascript
|
||||
product.getProductCategories() // Récupère les catégories
|
||||
product.setProductCategories([...])
|
||||
product.addProductCategory(category)
|
||||
product.removeProductCategory(category)
|
||||
product.countProductCategories()
|
||||
product.hasProductCategory(category)
|
||||
```
|
||||
|
||||
#### Tags via `ProductTagXref`
|
||||
Alias: `productTags`
|
||||
```javascript
|
||||
product.getProductTags() // Récupère les tags
|
||||
product.setProductTags([...])
|
||||
product.addProductTag(tag)
|
||||
product.removeProductTag(tag)
|
||||
product.countProductTags()
|
||||
product.hasProductTag(tag)
|
||||
```
|
||||
|
||||
### One-to-Many (hasMany)
|
||||
|
||||
#### ProductCategoryXrefs
|
||||
```javascript
|
||||
product.getProductCategoryXrefs() // Récupère les liens catégories
|
||||
product.setProductCategoryXrefs([...])
|
||||
product.addProductCategoryXref(xref)
|
||||
product.removeProductCategoryXref(xref)
|
||||
product.countProductCategoryXrefs()
|
||||
product.hasProductCategoryXref(xref)
|
||||
product.createProductCategoryXref({...})
|
||||
```
|
||||
|
||||
#### ProductTagXrefs
|
||||
```javascript
|
||||
product.getProductTagXrefs() // Récupère les liens tags
|
||||
product.setProductTagXrefs([...])
|
||||
product.addProductTagXref(xref)
|
||||
product.removeProductTagXref(xref)
|
||||
product.countProductTagXrefs()
|
||||
product.hasProductTagXref(xref)
|
||||
product.createProductTagXref({...})
|
||||
```
|
||||
|
||||
### Belongs-To
|
||||
|
||||
#### Brand
|
||||
```javascript
|
||||
product.getBrand() // Récupère la marque
|
||||
product.setBrand(brand) // Définit la marque
|
||||
product.createBrand({...}) // Crée une marque
|
||||
```
|
||||
|
||||
#### Owner (User)
|
||||
```javascript
|
||||
product.getOwner() // Récupère le propriétaire
|
||||
product.setOwner(user) // Définit le propriétaire
|
||||
product.createOwner({...}) // Crée un propriétaire
|
||||
```
|
||||
|
||||
#### Packaging
|
||||
```javascript
|
||||
product.getPackaging() // Récupère l'emballage
|
||||
product.setPackaging(packaging) // Définit l'emballage
|
||||
product.createPackaging({...}) // Crée un emballage
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Brand
|
||||
|
||||
### One-to-Many (hasMany)
|
||||
|
||||
#### Products
|
||||
```javascript
|
||||
brand.getProducts() // Récupère les produits
|
||||
brand.setProducts([...])
|
||||
brand.addProduct(product)
|
||||
brand.removeProduct(product)
|
||||
brand.countProducts()
|
||||
brand.hasProduct(product)
|
||||
brand.createProduct({...})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Category
|
||||
|
||||
### Many-to-Many (belongsToMany)
|
||||
|
||||
#### Products via `ProductCategoryXref`
|
||||
Alias: `productIdProducts`
|
||||
```javascript
|
||||
category.getProductIdProducts() // Récupère les produits
|
||||
category.setProductIdProducts([...])
|
||||
category.addProductIdProduct(product)
|
||||
category.removeProductIdProduct(product)
|
||||
category.countProductIdProducts()
|
||||
category.hasProductIdProduct(product)
|
||||
```
|
||||
|
||||
### One-to-Many (hasMany)
|
||||
|
||||
#### ProductCategoryXrefs
|
||||
```javascript
|
||||
category.getProductCategoryXrefs() // Récupère les liens produits
|
||||
category.setProductCategoryXrefs([...])
|
||||
category.addProductCategoryXref(xref)
|
||||
category.removeProductCategoryXref(xref)
|
||||
category.countProductCategoryXrefs()
|
||||
category.hasProductCategoryXref(xref)
|
||||
category.createProductCategoryXref({...})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Packaging
|
||||
|
||||
### One-to-Many (hasMany)
|
||||
|
||||
#### Products
|
||||
```javascript
|
||||
packaging.getProducts() // Récupère les produits
|
||||
packaging.setProducts([...])
|
||||
packaging.addProduct(product)
|
||||
packaging.removeProduct(product)
|
||||
packaging.countProducts()
|
||||
packaging.hasProduct(product)
|
||||
packaging.createProduct({...})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## TagList
|
||||
|
||||
### Belongs-To
|
||||
|
||||
#### Article
|
||||
```javascript
|
||||
tagList.getArticle() // Récupère l'article
|
||||
tagList.setArticle(article) // Définit l'article
|
||||
tagList.createArticle({...}) // Crée un article
|
||||
```
|
||||
|
||||
#### Tag
|
||||
Alias: `tagNameTag`
|
||||
```javascript
|
||||
tagList.getTagNameTag() // Récupère le tag
|
||||
tagList.setTagNameTag(tag) // Définit le tag
|
||||
tagList.createTagNameTag({...}) // Crée un tag
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Role
|
||||
|
||||
### Many-to-Many (belongsToMany)
|
||||
|
||||
#### Users via `UserRoleXref`
|
||||
Alias: `userIdUserUserRoleXrefs`
|
||||
```javascript
|
||||
role.getUserIdUserUserRoleXrefs() // Récupère les utilisateurs
|
||||
role.setUserIdUserUserRoleXrefs([...])
|
||||
role.addUserIdUserUserRoleXref(user)
|
||||
role.removeUserIdUserUserRoleXref(user)
|
||||
role.countUserIdUserUserRoleXrefs()
|
||||
role.hasUserIdUserUserRoleXref(user)
|
||||
```
|
||||
|
||||
### One-to-Many (hasMany)
|
||||
|
||||
#### UserRoleXrefs
|
||||
```javascript
|
||||
role.getUserRoleXrefs() // Récupère les UserRoleXrefs
|
||||
role.setUserRoleXrefs([...])
|
||||
role.addUserRoleXref(xref)
|
||||
role.removeUserRoleXref(xref)
|
||||
role.countUserRoleXrefs()
|
||||
role.hasUserRoleXref(xref)
|
||||
role.createUserRoleXref({...})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## UserRoleXref
|
||||
|
||||
### Belongs-To
|
||||
|
||||
#### User
|
||||
```javascript
|
||||
xref.getUser() // Récupère l'utilisateur
|
||||
xref.setUser(user) // Définit l'utilisateur
|
||||
xref.createUser({...}) // Crée un utilisateur
|
||||
```
|
||||
|
||||
#### Role
|
||||
```javascript
|
||||
xref.getRole() // Récupère le rôle
|
||||
xref.setRole(role) // Définit le rôle
|
||||
xref.createRole({...}) // Crée un rôle
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ProductCategoryXref
|
||||
|
||||
### Belongs-To
|
||||
|
||||
#### Product
|
||||
```javascript
|
||||
xref.getProduct() // Récupère le produit
|
||||
xref.setProduct(product) // Définit le produit
|
||||
xref.createProduct({...}) // Crée un produit
|
||||
```
|
||||
|
||||
#### Category
|
||||
```javascript
|
||||
xref.getCategory() // Récupère la catégorie
|
||||
xref.setCategory(category) // Définit la catégorie
|
||||
xref.createCategory({...}) // Crée une catégorie
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ProductTagXref
|
||||
|
||||
### Belongs-To
|
||||
|
||||
#### Product
|
||||
```javascript
|
||||
xref.getProduct() // Récupère le produit
|
||||
xref.setProduct(product) // Définit le produit
|
||||
xref.createProduct({...}) // Crée un produit
|
||||
```
|
||||
|
||||
#### Tag
|
||||
Alias: `tagNameTag`
|
||||
```javascript
|
||||
xref.getTagNameTag() // Récupère le tag
|
||||
xref.setTagNameTag(tag) // Définit le tag
|
||||
xref.createTagNameTag({...}) // Crée un tag
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Notes générales
|
||||
|
||||
1. **Paramètres `options`** : Presque toutes les méthodes `get*()` acceptent un objet `options` pour personnaliser la requête :
|
||||
```javascript
|
||||
model.getAssociated({
|
||||
where: { createdAt: { [Op.gte]: someDate } },
|
||||
limit: 10,
|
||||
offset: 0,
|
||||
order: [['createdAt', 'DESC']]
|
||||
});
|
||||
```
|
||||
|
||||
2. **Transactions** : Encapsulez les opérations dans une transaction :
|
||||
```javascript
|
||||
const transaction = await sequelize.transaction();
|
||||
await model.addAssociated(associated, { transaction });
|
||||
await transaction.commit();
|
||||
```
|
||||
|
||||
3. **Eager Loading** : Utilisez `include` pour charger les associations :
|
||||
```javascript
|
||||
const article = await Article.findByPk(1, {
|
||||
include: [
|
||||
{ model: Tag, as: 'articleTags' },
|
||||
{ model: User, as: 'author' },
|
||||
{ model: Comment, as: 'comments' }
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
4. **Alias vs Nom généré** : Le nom des méthodes dépend de l'alias défini. Exemple :
|
||||
- Alias `articleTags` → `getArticleTags()`, `addArticleTag()`
|
||||
- Alias `tagLists` → `getTagLists()`, `addTagList()`
|
||||
|
||||
5. **Toutes les méthodes de manipulation** acceptent un paramètre `options` final :
|
||||
```javascript
|
||||
await article.addTagList(tag, { transaction, validate: true });
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Seeders
|
||||
|
||||
### Seeder Articles (20251127-add-articles.js)
|
||||
|
||||
Ce seeder ajoute automatiquement 3 articles avec du contenu Lorem Ipsum et les associe à des tags d'animaux.
|
||||
|
||||
#### Exécution
|
||||
```bash
|
||||
# Exécuter tous les seeders
|
||||
npx sequelize-cli db:seed:all
|
||||
|
||||
# Annuler un seeder spécifique
|
||||
npx sequelize-cli db:seed:undo --seed 20251127-add-articles.js
|
||||
|
||||
# Annuler tous les seeders
|
||||
npx sequelize-cli db:seed:undo:all
|
||||
```
|
||||
|
||||
#### Articles créés
|
||||
|
||||
| Titre | Tags | Slug |
|
||||
|-------|------|------|
|
||||
| Introduction aux écosystèmes marins | Dolphin, Eagle, Wolf | introduction-aux-ecosystemes-marins |
|
||||
| Les prédateurs de la savane africaine | Lion, Tiger, Wolf | les-predateurs-de-la-savane-africaine |
|
||||
| L'intelligence animale au-delà de nos attentes | Eagle, Dolphin, Lion | lintelligence-animale-au-dela-de-nos-attentes |
|
||||
|
||||
#### Tags disponibles
|
||||
- Lion
|
||||
- Eagle
|
||||
- Dolphin
|
||||
- Tiger
|
||||
- Wolf
|
||||
|
||||
#### Fonctionnalités du seeder
|
||||
- ✅ Crée automatiquement les 5 tags s'ils n'existent pas
|
||||
- ✅ Génère des slugs uniques pour chaque article
|
||||
- ✅ Associe 3 tags à chaque article via la table `tagList`
|
||||
- ✅ Utilise les transactions pour l'intégrité des données
|
||||
- ✅ Support du rollback via `db:seed:undo`
|
||||
|
||||
---
|
||||
|
||||
## Migrations et Schéma
|
||||
|
||||
### Migration initiale (20251127000000-initial-schema.js)
|
||||
|
||||
Crée tous les 15 tables avec les contraintes CASCADE appropriées :
|
||||
|
||||
**Tables avec CASCADE delete activé :**
|
||||
- `article` → `comment` (foreignKey: `articleId`)
|
||||
- `article` → `favorite` (foreignKey: `articleId`)
|
||||
- `article` → `tagList` (foreignKey: `articleId`)
|
||||
- `user` → `article` (foreignKey: `authorId`)
|
||||
- `user` → `comment` (foreignKey: `authorId`)
|
||||
- `tag` → `tagList` (foreignKey: `tagName`)
|
||||
|
||||
**Exécution**
|
||||
```bash
|
||||
# Appliquer les migrations
|
||||
npx sequelize-cli db:migrate
|
||||
|
||||
# Voir le statut des migrations
|
||||
npx sequelize-cli db:migrate:status
|
||||
|
||||
# Annuler les migrations
|
||||
npx sequelize-cli db:migrate:undo:all
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration de la base de données
|
||||
|
||||
### Variables d'environnement
|
||||
|
||||
Le fichier `.env.development` doit contenir :
|
||||
```
|
||||
DB_HOST=localhost
|
||||
DB_USER=root
|
||||
DB_PASS=password
|
||||
DB_NAME=adastra
|
||||
DB_DIALECT=mysql
|
||||
```
|
||||
|
||||
### Validation du schéma au démarrage
|
||||
|
||||
L'application valide automatiquement la présence du schéma au démarrage :
|
||||
- ✅ Si le schéma est absent, l'app échoue avec un message d'erreur
|
||||
- ✅ Si le schéma est présent, les associations sont créées
|
||||
- ✅ Message d'aide fourni pour exécuter les migrations manquantes
|
||||
|
||||
```bash
|
||||
# Démarrer l'app (validera le schéma)
|
||||
npm run local # Développement avec nodemon
|
||||
npm run dev # Développement
|
||||
npm start # Production
|
||||
```
|
||||
@@ -0,0 +1,210 @@
|
||||
# Guide Swagger - Documentation OpenAPI pour Adastra API
|
||||
|
||||
## Accès à la documentation
|
||||
Une fois le serveur lancé, accédez à : **http://localhost:3200/api-docs**
|
||||
|
||||
## Exemple de documentation pour une route
|
||||
|
||||
Voici un exemple de comment documenter une GET route avec des paramètres de query :
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @swagger
|
||||
* /api/v1/articles:
|
||||
* get:
|
||||
* summary: Récupère la liste des articles
|
||||
* description: Retourne une liste paginée de tous les articles
|
||||
* tags:
|
||||
* - Articles
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: page
|
||||
* schema:
|
||||
* type: integer
|
||||
* default: 1
|
||||
* description: Numéro de page
|
||||
* - in: query
|
||||
* name: limit
|
||||
* schema:
|
||||
* type: integer
|
||||
* default: 10
|
||||
* description: Nombre d'articles par page
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Liste des articles récupérée avec succès
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* id:
|
||||
* type: integer
|
||||
* title:
|
||||
* type: string
|
||||
* content:
|
||||
* type: string
|
||||
* total:
|
||||
* type: integer
|
||||
* 400:
|
||||
* description: Erreur de validation
|
||||
* 401:
|
||||
* description: Non authentifié
|
||||
* 500:
|
||||
* description: Erreur serveur
|
||||
*/
|
||||
router.get('/', async (req, res) => {
|
||||
// ... logique du contrôleur
|
||||
});
|
||||
```
|
||||
|
||||
## Exemple avec POST et authentification
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @swagger
|
||||
* /api/v1/articles:
|
||||
* post:
|
||||
* summary: Crée un nouvel article
|
||||
* description: Crée un nouvel article avec les données fournies
|
||||
* tags:
|
||||
* - Articles
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - title
|
||||
* - content
|
||||
* properties:
|
||||
* title:
|
||||
* type: string
|
||||
* example: "Mon Article"
|
||||
* content:
|
||||
* type: string
|
||||
* example: "Contenu de l'article"
|
||||
* tags:
|
||||
* type: array
|
||||
* items:
|
||||
* type: string
|
||||
* example: ["tag1", "tag2"]
|
||||
* responses:
|
||||
* 201:
|
||||
* description: Article créé avec succès
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* id:
|
||||
* type: integer
|
||||
* title:
|
||||
* type: string
|
||||
* content:
|
||||
* type: string
|
||||
* 400:
|
||||
* description: Données invalides
|
||||
* 401:
|
||||
* description: Non authentifié
|
||||
*/
|
||||
router.post('/', authenticate, async (req, res) => {
|
||||
// ... logique du contrôleur
|
||||
});
|
||||
```
|
||||
|
||||
## Exemple avec paramètres URL
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @swagger
|
||||
* /api/v1/articles/{id}:
|
||||
* get:
|
||||
* summary: Récupère un article par ID
|
||||
* tags:
|
||||
* - Articles
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: ID de l'article
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Article récupéré avec succès
|
||||
* 404:
|
||||
* description: Article non trouvé
|
||||
* 500:
|
||||
* description: Erreur serveur
|
||||
*/
|
||||
router.get('/:id', async (req, res) => {
|
||||
// ... logique du contrôleur
|
||||
});
|
||||
```
|
||||
|
||||
## Types de schémas courants
|
||||
|
||||
### Objets simples
|
||||
```javascript
|
||||
schema: {
|
||||
type: object
|
||||
properties:
|
||||
id: { type: integer }
|
||||
name: { type: string }
|
||||
email: { type: string, format: email }
|
||||
age: { type: integer, minimum: 0 }
|
||||
isActive: { type: boolean }
|
||||
}
|
||||
```
|
||||
|
||||
### Arrays
|
||||
```javascript
|
||||
schema: {
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: integer }
|
||||
name: { type: string }
|
||||
}
|
||||
```
|
||||
|
||||
### Enums
|
||||
```javascript
|
||||
schema: {
|
||||
type: string
|
||||
enum: ["pending", "approved", "rejected"]
|
||||
}
|
||||
```
|
||||
|
||||
## Tags disponibles
|
||||
Les tags disponibles dans la config Swagger sont :
|
||||
- **Articles** - Gestion des articles
|
||||
- **Users** - Gestion des utilisateurs
|
||||
- **Products** - Gestion des produits
|
||||
- **Clans** - Gestion des clans
|
||||
- **Hero Wars** - Données Hero Wars
|
||||
|
||||
## Instructions générales
|
||||
|
||||
1. **Placez les commentaires JSDoc directement au-dessus de la définition de la route**
|
||||
2. **Utilisez le tag `@swagger`** pour indiquer que c'est de la documentation OpenAPI
|
||||
3. **Commencez par le chemin d'accès** : `/api/v1/articles`, `/api/v1/articles/{id}`, etc.
|
||||
4. **Spécifiez la méthode HTTP** : `get`, `post`, `put`, `delete`, `patch`
|
||||
5. **Incluez toujours** : `summary`, `description`, `tags`, `responses`
|
||||
6. **Pour les routes protégées**, utilisez `security: [{ bearerAuth: [] }]` ou `security: [{ apiKeyAuth: [] }]`
|
||||
|
||||
## Pour plus de détails
|
||||
Consultez la documentation officielle : https://swagger.io/specification/
|
||||
|
||||
---
|
||||
|
||||
**Note** : Une fois que vous aurez ajouté les commentaires Swagger à vos routes, redémarrez le serveur et accédez à `/api-docs` pour voir la documentation mise à jour.
|
||||
Reference in New Issue
Block a user