Bugs & failles actives connues
Contrairement à Dette technique connue (différable, pas urgent), tout ce qui est listé ici est un dysfonctionnement ou un risque de sécurité déjà actif en l'état du code — pas une amélioration future. À traiter en priorité, pas "quand l'occasion se présente".
Vérifié le 2026-08-13. Tous les points identifiés à ce jour sont corrigés.
✅ Corrigés (2026-08-13)
updateLoanStatus n'avait aucune vérification d'appartenance à une agence
backend/src/controllers/loan.controller.js, fonction updateLoanStatus (PATCH /api/loan-requests/:id) — contrairement aux 3 autres endpoints du contrôleur, celle-ci ne vérifiait jamais que req.user avait le droit d'agir sur le dossier ciblé : tout utilisateur backoffice authentifié pouvait changer le statut de n'importe quelle demande de prêt, y compris celles d'une autre agence — le point le plus sensible du contrôleur puisqu'il exécute la décision (pas juste une consultation). canAccessAgency(req.user, currentLoan.id_agence) ajouté juste après le chargement du dossier.
account_requests : lecture entièrement publique, sans authentification
backend/src/routes/account_requests.routes.js : GET / et GET /:id n'avaient aucun middleware verifyToken — n'importe qui, sans être connecté, pouvait lister l'intégralité des demandes d'ouverture de compte (identité, téléphone, email, adresse, données FATCA/TIN). verifyToken ajouté sur les deux routes, et agencyScopeWhere/canAccessAgency appliqués à getAll/getById (account_requests.controller.js, account_requests.service.js::getAll accepte désormais un where) — un utilisateur authentifié ne voit maintenant que les demandes de sa propre agence (ou de sa zone pour CHEF_ZONE), cohérent avec account.controller.js et loan.controller.js.
loan_parameters modifiable sans authentification
PUT /api/loan-parameters/:id exige désormais verifyToken (GET reste public, consommé par les formulaires publics).
Alertes lisibles sans authentification
GET /api/alertes et GET /api/alertes/:id exigent désormais verifyToken.
POST /api/users accessible à tout utilisateur authentifié
POST/PUT/DELETE /api/users exigent désormais isSuperAdmin (même middleware que /api/roles).
Le bypass 000000 de la 2FA n'existe pas (mais était documenté comme existant)
Le README backend et le commentaire dans SchoolLoanView.vue ont été corrigés pour ne plus affirmer l'existence de ce bypass. Le placeholder OTP côté prêt scolaire (000000) reste en place — c'est un mécanisme distinct, volontaire, en attendant l'intégration Sopra Banking Amplitude, voir Demande de prêt scolaire.
Mise à jour de statut d'une demande de compte : route inexistante
AccountRequestDetailView.vue/AccountRequestsView.vue appellent désormais PATCH /api/account-requests/:id/status (route réellement exposée).
LoanDocumentsConfigView.vue appelait le mauvais endpoint de suppression
Corrigé : DELETE /loan-document-requirements/:id (au lieu de /loan-requirements/:id).
CNI (signataires/bureau/promoteur) jamais enregistrées comme documents
OpenAccountView.vue les inclut désormais dans additional_data.documents (mêmes clés descriptives : signataire_N_cni, bureau_{role}_cni, promoteur_cni) — elles passent maintenant par le mécanisme générique déjà utilisé pour les autres pièces, aucun changement backend nécessaire. Voir Ouverture de compte.
Sauvegarde des slides : suppression totale sans transaction
Un nouvel endpoint PUT /api/slides (slidesService.replaceAll) remplace l'ancienne séquence DELETE/POST multiples non transactionnelle par une seule transaction Prisma (delete + recreate atomiques, éléments inclus). Voir Éditeur de bannières.
URL de setup-password codée en dur
utils/mailer.js lit désormais process.env.FRONTEND_URL (repli sur http://localhost:5173 si absent) ; FRONTEND_URL ajoutée à .env.example.
loan_field_requirements réservé SUPER_ADMIN, incohérent avec loan_document_requirements
La restriction isSuperAdmin a été retirée — les deux routers de configuration de prêt exigent maintenant uniformément verifyToken seul.
CHEF_ZONE ne filtrait pas réellement par zone
Le module agencyScopeWhere/canAccessAgency (backend/src/utils/agency-scope.js) avait bien été écrit et branché sur loan.controller.js/account.controller.js/account_requests.controller.js, mais restait inopérant pour deux raisons cumulées, découvertes seulement en testant avec un vrai compte CHEF_ZONE (login + 2FA + appels API réels) :
CHEF_ZONEavait la permissionview_all_agencies(seed/seed_roles.js) — cette permission court-circuiteagencyScopeWhere/canAccessAgencyen premier (accès total, sans restriction), rendant la logique "restreindre à la zone" écrite juste en dessous inatteignable. Retirée des permissions deCHEF_ZONE.- Une fois ce point corrigé, plus aucun dossier n'était visible pour
CHEF_ZONE(régression inverse) :id_zonen'était jamais inclus dans le JWT émis parverify2fa— seulid_agencel'était. Ajouté au payload JWT et à la sélection Prisma degetMe(auth.controller.js).
Leçon : une correction non testée en conditions réelles (vrai login, pas juste une relecture de code) peut sembler correcte tout en étant totalement inopérante.
Un CHEF_ZONE est désormais réellement restreint aux agences de sa propre zone (id_zone), vérifié par un test de bout en bout (accès accepté sur une agence de sa zone, 403 sur une agence d'une autre zone). Voir Agences, zones & GAB et Authentification & 2FA.
README backend : message de démarrage NLP trompeur
"NLP Model Trained Successfully with 26 intents" a été retiré — ce message décrivait un ancien moteur NLP (@nlpjs) que le code actuel ne charge plus (le vrai moteur actif est un système RAG + Ollama, désactivé côté serveur par choix, pas un bug — voir Chatbot (NLP + RAG)). Le serveur n'affiche désormais que UTB Backend Server running on port 3000 au démarrage, ce que le README reflète maintenant.
Doc Swagger de users.routes.js obsolète
Corrigée : password retiré des champs requis/documentés de POST /api/users (jamais utilisé par create(), qui crée le compte sans mot de passe et envoie une invitation) ; two_factor_secret/two_factor_enabled retirés (destructurés mais jamais utilisés) ; id_agence/id_zone ajoutés (réellement pris en compte, absents de la doc précédente).
seed_fields.js — entrée retirée, le fichier n'existe pas
Une version antérieure de cette page affirmait qu'un ancien script seed_fields.js traînait à la racine du dépôt backend, hérité d'avant la réorganisation des scripts de seed. Vérification faite le 2026-08-13 : ce fichier n'existe pas dans le dépôt actuel — l'affirmation provenait d'un contenu migré depuis l'ancienne doc du projet sans revérification indépendante à ce moment-là. Corrigé ici pour que l'erreur ne se propage pas plus loin.