diff --git a/docs/ARTICLE_METHODS.md b/docs/ARTICLE_METHODS.md new file mode 100644 index 0000000..4d4943f --- /dev/null +++ b/docs/ARTICLE_METHODS.md @@ -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. diff --git a/docs/FINAL_MIGRATION_SUMMARY.md b/docs/FINAL_MIGRATION_SUMMARY.md new file mode 100644 index 0000000..c075699 --- /dev/null +++ b/docs/FINAL_MIGRATION_SUMMARY.md @@ -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 diff --git a/docs/MIGRATION_COMPLETE_SUMMARY.md b/docs/MIGRATION_COMPLETE_SUMMARY.md new file mode 100644 index 0000000..29a9a2a --- /dev/null +++ b/docs/MIGRATION_COMPLETE_SUMMARY.md @@ -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. + +═════════════════════════════════════════════════════════════════════════════ diff --git a/docs/MIGRATION_REPORT.md b/docs/MIGRATION_REPORT.md new file mode 100644 index 0000000..20f2822 --- /dev/null +++ b/docs/MIGRATION_REPORT.md @@ -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 + +═══════════════════════════════════════════════════════════════════════════════ diff --git a/docs/MIGRATION_SWAGGER_TODO.md b/docs/MIGRATION_SWAGGER_TODO.md new file mode 100644 index 0000000..837d47c --- /dev/null +++ b/docs/MIGRATION_SWAGGER_TODO.md @@ -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. diff --git a/docs/POST_MIGRATION_CHECKLIST.md b/docs/POST_MIGRATION_CHECKLIST.md new file mode 100644 index 0000000..ef9bc90 --- /dev/null +++ b/docs/POST_MIGRATION_CHECKLIST.md @@ -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 + +# 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 diff --git a/docs/SCRIPTS_MIGRATION_GUIDE.md b/docs/SCRIPTS_MIGRATION_GUIDE.md new file mode 100644 index 0000000..3e582c5 --- /dev/null +++ b/docs/SCRIPTS_MIGRATION_GUIDE.md @@ -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 diff --git a/docs/SEQUELIZE_MODELS_METHODS.md b/docs/SEQUELIZE_MODELS_METHODS.md new file mode 100644 index 0000000..ec1bdb3 --- /dev/null +++ b/docs/SEQUELIZE_MODELS_METHODS.md @@ -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 +``` diff --git a/docs/SWAGGER_GUIDE.md b/docs/SWAGGER_GUIDE.md new file mode 100644 index 0000000..2738ad6 --- /dev/null +++ b/docs/SWAGGER_GUIDE.md @@ -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.