Configuration des prêts
backend/src/controllers/loan_document_requirements.controller.js + loan_field_requirements.controller.js + loan_parameters.controller.js + frontend/src/views/backoffice/LoanDocumentsConfigView.vue + LoanFieldsConfigView.vue.
Le formulaire public de prêt scolaire charge ses documents/champs/paramètres requis depuis ces trois tables, décrites comme "configurables côté backoffice" sans jamais expliquer comment — c'est l'objet de cette page.
Vérifié le 2026-08-13.
1. Trois tables indépendantes, sans lien entre elles
loan_document_requirements:loan_type, label, is_required, is_active. Un document requis par type de prêt.loan_field_requirements:loan_type, field_key, label, field_type, is_required, is_active. Un champ dynamique par type de prêt.loan_parameters:loan_type (unique), interest_rate, max_duration, max_amount, default_amount, is_active. Un seul jeu de paramètres par type.
Aucune clé étrangère entre elles ni vers loan_requests — loan_type est une simple chaîne libre, pas un enum en base.
is_active = désactivation douce (le document/champ reste en base mais disparaît du formulaire public). is_required = obligatoire ou optionnel. Pas de champ d'ordre : l'affichage backoffice trie par created_at desc, le formulaire public par created_at asc — ordres incohérents entre les deux écrans, et aucun réordonnancement manuel n'est possible.
2. field_key — généré côté frontend, jamais vérifié côté backend
LoanFieldsConfigView.vue génère automatiquement field_key depuis le libellé saisi (slug ASCII, préfixe client_), et fige ce champ (non modifiable) une fois affiché. Le backend n'impose aucune contrainte d'unicité sur field_key pour un même loan_type — deux champs avec la même clé peuvent coexister silencieusement, avec des conséquences imprévisibles côté additional_data.fields (une clé écrase l'autre selon l'ordre de saisie du client).
3. loan_parameters
Auto-seed au premier GET si la table est vide, avec des valeurs par défaut codées en dur pour 5 types (immo, auto, conso, scolaire, bancassurance). Modifiable uniquement via PUT /api/loan-parameters/:id (protégé verifyToken, corrigé le 2026-08-13 — voir ci-dessous) — loan_type, label et icon ne sont pas modifiables via cet endpoint, seuls interest_rate, max_duration, max_amount, default_amount, is_active le sont. Pas de création possible : les 5 types sont figés à la liste seedée.
loan_parameters.routes.js n'appliquait aucun middleware sur PUT /:id, contrairement aux deux autres routers de config — n'importe qui pouvait modifier un taux d'intérêt ou un plafond de prêt sans authentification. verifyToken a été ajouté sur PUT uniquement ; GET reste public (consommé par les formulaires publics).
4. Aucune protection contre la casse d'un formulaire en production
Supprimer un document ou un champ requis (DELETE) ne vérifie jamais si des demandes existantes référencent déjà ce field_key dans additional_data.fields, ni si des documents déjà uploadés correspondent à cette pièce. Seule trace : une entrée dans le journal d'activité après coup, aucune contrainte bloquante avant suppression.
5. Pièges connus pour un futur développeur
Bug de routing sur la suppression d'un document requis— corrigé le 2026-08-13 (LoanDocumentsConfigView.vueappelaitDELETE /loan-requirements/:idau lieu de/loan-document-requirements/:id).— corrigé le 2026-08-13 : les deux exigent désormais uniformémentloan_document_requirements(verifyTokenseul) vsloan_field_requirements(isSuperAdmin)verifyTokenseul (la restrictionisSuperAdmina été retirée deloan_field_requirements, pas ajoutée à l'autre — décision : cohérence avec la sensibilité réelle de cette configuration, pas de raison de la réserver aux SUPER_ADMIN).— corrigé le 2026-08-13 :bancassurancenon configurable depuis ces écransbancassuranceajouté àloanTypesdansLoanDocumentsConfigView.vueetLoanFieldsConfigView.vue(liste codée en dur côté frontend, qui l'omettait alors queloan_parametersgérait déjà ce type).