diff --git a/MEMORY.md b/MEMORY.md index 4460810..7f0793a 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -1,5 +1,5 @@ # MEMORY.md — Crowdlending Tracker -*Dernière mise à jour: 2026-07-13 (session 13)* +*Dernière mise à jour: 2026-07-14 (session 14)* --- @@ -633,3 +633,50 @@ Le champ `type` est prévu pour réutiliser la table plus tard (ex. `'rendement_ ### Piège outillage — vérification syntaxique de fichiers JSX volumineux Le mount bash reste périmé (cf. sessions précédentes). Pour vérifier un **nouveau** composant JSX isolé (pas une édition dans un fichier existant de 1000+ lignes), la méthode fiable trouvée cette session : `npm init -y && npm install esbuild` dans `/tmp` (indépendant du node_modules Windows du projet, incompatible avec le sandbox Linux), copier le contenu exact du fichier via `cat > fichier << 'EOF'` puis `esbuild fichier.jsx --bundle --format=esm --jsx=automatic --external:react --outfile=...`. Pour une **édition ponctuelle** dans un gros fichier existant, la relecture `Read` ciblée des zones modifiées (comptage d'accolades/balises JSX) reste suffisante et plus rapide. + +--- + +## Session 14 — Import IA (prompt + bugs), modale doublons, purge plateforme, job données incomplètes (2026-07-14) + +### Prompt IA import Remboursements — itérations successives (`ImportsSection.jsx`, `buildReferenceSection`/`FIELD_HINTS_OVERRIDE`) +1. **Plateforme unique** : si une seule plateforme existe, le prompt l'assigne directement à toutes les lignes sans poser de question (branche `plats.length === 1` dans `buildReferenceSection`). +2. **Règle CAPITAL vs INTÉRÊTS** : distingue une ligne "remboursement mensualité" unique (montant mêlant capital+intérêts) via le ratio (prélèvements sociaux + IR) ÷ montant total : proche de 30 % → intérêts purs ; nettement inférieur → reconstitue `interets_bruts ≈ moyenne(prelev_sociaux/0.172, prelev_forfaitaire/0.128)` puis `capital = total − interets_bruts` ; aucun prélèvement adjacent → capital pur (échéance finale in fine/différé). +3. **Identification cashback/bonus** (ajoutée suite à un cas réel : "Rémunération code cadeau") : reconnue par le **libellé** (mots-clés "cashback", "bonus", "prime", "code cadeau", "parrainage"...), jamais par l'absence de prélèvement seule (un remboursement de capital pur n'a lui non plus aucun prélèvement adjacent — ne pas confondre). Si le libellé ne référence aucun projet suivi (ex. parrainage global) → ligne exclue du JSON (le module d'import exige un `investissement_id`). +4. **Règle critique présence systématique des champs** : imposer que les 5 champs (`capital`, `cashback`, `interets_bruts`, `prelev_sociaux`, `prelev_forfaitaire`) soient toujours explicitement présents sur CHAQUE ligne (valeur 0 si non applicable), jamais omis — corrige un vrai bug de détection (voir ci-dessous). +5. Suppression de la consigne "génère aussi `net_recu`" (champ jamais lu par le backend, recalculé côté serveur depuis capital/cashback/intérêts/prélèvements) — source de confusion sans utilité. + +### 🔴 Bug trouvé et corrigé — détection des colonnes basée uniquement sur la 1ère ligne du JSON +- **Symptôme réel** : un remboursement de capital final (250 €) importé à 0,00 € partout dans l'app, alors que le JSON source contenait bien `"capital": 250`. +- **Cause** : `POST /imports/preview` calcule `headers = Object.keys(rows[0])` — seule la première ligne du fichier sert à détecter les colonnes disponibles pour l'auto-mapping. Si un champ (ex. `capital`) est absent de la première ligne (fréquent avec les JSON générés par IA où seules certaines lignes ont telle ou telle info) mais présent plus loin, il n'est **jamais mappé** pour tout le fichier — donc toujours lu comme `0`, silencieusement, même sur les lignes où il est renseigné. +- **Fix** : uniquement via le prompt (règle 4 ci-dessus, pas de changement de code) — imposer à l'IA génératrice de toujours inclure tous les champs optionnels sur chaque ligne, à 0 par défaut. + +### 🔴 Bug trouvé et corrigé — champ `cashback` absent du schéma d'import Remboursements +- **Symptôme réel** : une ligne de cashback (`"cashback": 2.5`) importée avec `cashback: 0,00 €` alors que tous les autres champs de mapping fonctionnaient. +- **Cause, différente du bug précédent** : `MODULES.remboursements.optional` (`ImportsSection.jsx`) ne listait jamais `cashback` parmi les champs du module — ni pour l'auto-mapping (`runPreview`), ni pour le mapping manuel (`