# MEMORY.md — Crowdlending App

- [Profil utilisateur](user_profile.md) — Olivier, propriétaire de l'app crowdlending, développeur qui pilote les évolutions
- [Modèle plateforme — détenteur & logo](project_plateforme_detenteur_logo.md) — Champs investisseur_id, date_ouverture, logo_filename ajoutés aux plateformes ; contrainte UNIQUE modifiée
- [Pattern investisseurForPlat](feedback_investisseur_for_plat.md) — Helper à créer dans chaque page formulaire pour synchroniser le détenteur avec la plateforme choisie
- [Fonctionnalité réinvestissements](project_reinvestissements.md) — Table reinvestissements, route /api/reinvestissements, capital_total, generateSimulWithReinvestissements, adjustSimulForActuals modifiée
- [adjustSimulForActuals — règles complètes](feedback_adjustsimul.md) — Capital effectif, capital soldé (DELETE futures), reprocess doit appeler adjustSimulForActuals après transaction
- [Calcul solde porte-monnaie](project_solde_portefeuille.md) — Formule complète : dépôts − retraits_manuels + net_recu_portefeuille + bonus − capital_investi ; implémentée backend (dashboard.js) et frontend (DepotsRetraits.jsx)
- [Pattern multiDetenteur](feedback_multi_detenteur.md) — Le détenteur ne s'affiche dans les selects plateforme que si plusieurs détenteurs distincts existent (`new Set(plats.map(p => p.investisseur_id)).size > 1`)
- [Fonctionnalité corrections de solde](project_corrections_solde.md) — Table corrections_solde, route /api/corrections, CorrectionModal dans DepotsRetraits, badge dans Remboursements, intégration fiscal2778
- [Troncature et corruption fichiers — toujours passer par Python](feedback_file_truncation.md) — Edit/Write et sed -i tronquent les fichiers volumineux ; jamais sed, toujours python3 + vérifier tail/hex
- [Composant ConfirmModal et suppressions](project_confirm_modal.md) — ConfirmModal.jsx créé ; pattern standard pour toute future suppression ; 6 fichiers déjà migrés
- [Correction intérêts nets — Investissements](project_interets_nets_investissements.md) — interets_nets_total ajouté au backend ; net_recu_total ≠ intérêts nets (inclut capital+cashback)
- [Fiscalité locale sur remboursements](project_fiscalite_locale_remboursements.md) — Champs interets_bruts_avant_local et taxe_locale ajoutés (DB + backend + 2 formulaires + tableau détail)
- [Page Centre d'aide](project_aide.md) — Route /aide, layout Settings, FAQ accordéon ; bouton dans UserMenu
- [Menus ⋮ actions sur les tableaux et blocs](project_menu_actions_tables.md) — Pattern menu contextuel fixe (position: fixed + backdrop + icônes SVG) ; scroll ferme les menus ; AdminPlateformes ajouté
- [Format menu ⋮ — règle obligatoire](feedback_menu_actions_format.md) — Tout nouveau tableau doit utiliser le menu ⋮ avec icônes SVG + label, jamais de boutons inline
- [Logo plateforme topbar InvestissementDetail](project_logo_topbar_detail.md) — logo remplace le nom si disponible ; plateforme_logo retourné par le backend ; classe logo-plateforme pour dark mode
- [onClick direct avec paramètre par défaut](feedback_onclick_default_param.md) — onClick={fn} passe l'event comme arg1, écrase les defaults ; toujours utiliser onClick={() => fn()}
- [Réinvestissement automatique des intérêts](project_auto_reinvest.md) — auto_reinvest sur investissements, source sur reinvestissements, déclencheur POST remboursement, tabs Manuel/Auto dans la modale
- [Panneau détail unifié DepotsRetraits](project_detail_panel_depots.md) — DetailPanel unifié dépôts/retraits/corrections ; libellé bouton adapté au type ; props { row, onEdit, onDeleteCorrection }
- [Menu ⋮ carte Informations du projet](project_card_menu_investissement.md) — cardMenu state séparé ; Modifier/Réinvestir/Exporter/Supprimer + Désactiver auto-reinvest ; utiliser ConfirmModal pas confirmingInvDelete
- [Méthode de remboursement sur investissements](project_methode_remboursement_investissement.md) — methode_remboursement + nom_compte_courant sur investissements ; champ conditionnel si plateforme=choix_investisseur ; retrait auto depots_retraits ; affichage fiche détail
- [Override fiscalité par investissement](project_fiscalite_override.md) — fiscalite_override='exonere' ; badge + menu ⋮ + modale confirmation ; prelev indicatifs (pas forcés à 0) ; voir [[project_istaxindicatif]]
- [Règle isTaxIndicatif + route reprocess](project_istaxindicatif.md) — prelev toujours calculés, net_recu = brut si indicatif ; POST /api/remboursements/reprocess ; bouton dans MonCompte?section=nettoyage
- [Fallback methode remboursement formulaire](feedback_remb_methode_fallback.md) — openRembFromSimul/openNewRemb : utiliser inv.methode_remboursement si plateforme=choix_investisseur, jamais 'portefeuille' en dur
- [Formulaires remboursement refactorisés](project_formulaires_remboursement.md) — Grille 3 col / 900px, sections Remboursement/Imposition/Versement, Total prélèvements, commentaire Montant versé, isIndicatif aligné
- [Tableau Remboursements enregistrés](project_tableau_remboursements_detail.md) — Fusion PS+IR→Imposition, tooltip CSS instantané (.cell-tooltip), remb-table CSS, clic ligne → modale édition
- [Graphiques Dashboard — barres + donut](project_interets_mensuels_chart.md) — InteretsMensuelsChart (barres empilées) + InteretsDonutChart (donut caps arrondis) + InteretsChartContext partagé ; mode TOUT (vue multi-années) ; layout 2/3+1/3 stretch
- [Donut interactif — tooltip, clic, mémoire, légende](project_donut_interactif.md) — Tooltip SVG, clic isole un type ou Reçu/Projeté, retour arrière via centre (↩), légende cliquable, ordre Intérêts→Capital→Cashback
- [YearSelectorKpi — sélecteur année Dashboard](project_year_selector_kpi.md) — Card violet/indigo sur la ligne KPI, dropdown custom années croissant + "Depuis le début", sync bidirectionnelle avec InteretsChartContext
- [Couleurs personnalisables des graphiques](project_chart_colors.md) — UiContext : cl_chart_interets/capital/cashback ; Settings > Apparence : palette MD2, PaletteSelector, ChartColorPicker, preview Reçu/Projeté (lightenColor 72%)
- [Préférences utilisateur en DB](project_user_preferences.md) — Table user_preferences (user_id, key, value) ; route /api/preferences GET+PATCH ; UiContext sync DB→localStorage au montage, PATCH asynchrone
- [Bibliothèque d'icônes](project_icons_library.md) — Tables app_icons + history, route /api/icons, section Admin, nettoyage fond SVG, composant AppIcon dans Settings
- [InvestissementDetail — nouvelles fonctionnalités](project_investissement_detail_features.md) — Menu simulMenu : modifier DPE + traitement en masse remboursements ; correction ConfirmModal rowDeleteConfirm manquant dans le JSX
- [PUT investissements — payload minimal](feedback_put_payload_minimal.md) — Ne jamais spread `inv` ; construire le payload champ par champ selon le schéma Zod backend
- [KPIs Dashboard — TrendBadge, logique M vs M-1](project_dashboard_kpis.md) — 5 KPIs refaits ; année N = mois courant vs M-1 ; année N-x = annuel vs N-1 ; modeGlobal = cumul sans badge
- [Tableau intérêts par plateforme](project_tableau_interets_plateforme.md) — TableauInteretsPlateforme.jsx dans Dashboard ; endpoint /api/dashboard/interets-par-plateforme ; synchronisé InteretsChartContext
- [Capital investi — formule unifiée](project_invchart_capital_encours.md) — montant_investi + reinvests(≤date) − capital_remboursé(≤date) ; dashboard.js + Investissements.jsx + InvChart
- [Timezone — ne pas utiliser .toISOString() pour dates locales](feedback_timezone_lastday.md) — `.toISOString().split('T')[0]` décale d'un jour en UTC+1 ; toujours getFullYear/getMonth/getDate
- [Vision mensuelle — capital par plateforme/mois](project_capital_mensuel_table.md) — CapitalMensuelTable.jsx, onglet entre Plateformes et Investissements, calcul frontend, classes tip-table
- [Exonération fiscale sur comptes](project_comptes_exoneration.md) — Colonne exoneration_fiscale (aucune/pfnl_5ans) sur table comptes ; DB+backend+frontend Settings
- [Vision mensuelle — dépôts/retraits par plateforme/mois](project_depots_mensuel_table.md) — DepotsMensuelTable.jsx, onglet entre Plateformes et Mouvements dans DepotsRetraits, filtres icônes dépôt/retrait
- [UX formulaires Investissement & Remboursement](project_formulaires_ux.md) — Pas de présélection plateforme/investissement ; détenteur masqué (auto) ; taux/durée/DPE requis
- [UserMenu — portail React obligatoire](feedback_usermenu_portal.md) — Popup et sous-panel via createPortal(…, document.body) pour échapper au stacking context de la sidebar sticky
- [TableauInteretsPlateforme — padding wrapper](feedback_tiptable_padding.md) — Envelopper dans `<div style={{ padding: '0 24px' }}>` dans chaque page (Dashboard, Remboursements)
- [Toggle Détaillé/Consolidé tableaux mensuels](project_toggle_consolidation.md) — Bouton dans th Plateforme, clé localStorage `cl_tip_group_by_nom`, sur 4 composants ; mergeMaps pour TableauInteretsPlateforme
- [Icônes bibliothèque — sidebar & titres pages](project_icons_sidebar_titles.md) — NavIcon dans Layout.jsx (24px, fallback SVG) ; PageIcon inline dans h2 (40px, cache module-level) ; 5 pages équipées
- [Règle icônes topbar — ne pas modifier flex](feedback_pageicon_topbar.md) — Toujours insérer PageIcon comme img inline dans le h2, jamais de wrapper div ni display:flex sur le h2
- [Pagination listes](project_pagination.md) — Hook usePagination + composant Pagination ; 15/25/50/100 items, localStorage par page, reset sur filtre
- [Export Excel SheetJS](project_xlsx_export.md) — xlsx installé dans frontend/ ; pattern json_to_sheet → book_append_sheet → write type:array ; MIME xlsx
- [TrendBadge KPIs Investissements](project_trendbadge_investissements.md) — TrendBadge sur les 5 KPIs ; platYear initialisé à l'année courante ; effectiveYear pour badges en vue "Toutes les années"
- [TrendBadge KPIs DepotsRetraits + Remboursements](project_trendbadge_depots_remb.md) — Même pattern déployé sur DepotsRetraits (4 KPIs) et Remboursements (3 KPIs)
- [Page Fiscalité — refonte TaxReport](project_taxreport.md) — Fiscal2778→TaxReport, route /taxreport, onglets dr-tabs, pagination détail, YearSelector violet autonome
- [Simulation CERFA 2561](project_cerfa2561.md) — Cerfa2561Preview.jsx, onglet inline TaxReport, cases 2TT/2TR/2BH/2CK/2TY, type_produit_fiscal sur plateformes, impression PDF
- [FK compte_id sur investissements et remboursements](project_compte_id_remboursements.md) — DB+backend+4 formulaires frontend ; resolvedMethode depuis plateforme ; auto-sélection premier compte_courant ; colonne Versement dans Remboursements
- [Déclaration 2778-SD et PFO](project_2778sd.md) — Onglet TaxReport conditionné par pfoAssujetti ; matrice mensuelle par plateforme étrangère ; simulation CERFA cases BA/IA/PQ/PV/PF1/PG1/QR ; report 2042 (2TR/2BH/2CK) ; taux dynamiques depuis taux_pfu (csg/crds/solidarite)
- [Architecture onglets fiscaux — 2042 / 2561 / 2778-SD](project_cerfa_fiscal.md) — Cerfa2042Preview (nouveau) + refonte 2561 et 2778-SD : sidebar 3 vues, suivi mensuel combiné, données 2042 mixtes avec badges auto/à déclarer, fullName helper, route /taxreport/2778 reconstruite
- [Référentiel taux crédit d'impôt 2047](project_taux_credit_impot.md) — Table taux_credit_impot (124 pays), route /api/taux-credit-impot, section Admin "Référentiels" avec TciModal, TciImportBlock, TciPromptBlock
- [Pièges CSS — fieldset min-width et checkbox width](feedback_fieldset_checkbox_css.md) — fieldset : toujours minWidth:0 ; input[type=checkbox] : toujours width:'auto'
- [Référentiel plateformes — architecture complète](project_referentiel_plateformes.md) — Tables referentiel + categories + notation, HERITABLE_FIELDS, routes push/reset/lier/importer, similarité Levenshtein 80%, frontend Settings + Admin
- [Bibliothèque logos référentiel](project_logos_referentiel.md) — Section Admin "Logos des plateformes" (id: logos-ref) ; POST/DELETE /api/referentiel/:id/logo ; auto-push logo_filename ; placeholder croix si logo manquant ; useRef pas React.useRef dans Admin.jsx
- [Recherche/filtres/pagination référentiel](project_referentiel_search_filter.md) — Recherche nom + filtre domiciliation + filtre catégorie + pagination dans ReferentielSection ; icone_filename prioritaire sur logo_filename, tous deux servis via /api/logos/
- [Catégories & secteurs d'investissement](project_categories_secteurs_inv.md) — Tables categories_inv/secteurs_inv, routes ref-categories/ref-secteurs, fusion, chips dans PlatformeProfile et RefModal, filtre référentiel via ?filterCat=
- [Catégories/secteurs utilisateur — deux niveaux](project_categories_secteurs_utilisateur.md) — user_id sur categories_inv/secteurs_inv, tables jonction plateforme+investissement, routes /api/categories-inv et /api/secteurs-inv, push admin étendu, sync auto investissements, chips formulaires, filtres liste
- [Domiciliation → codes ISO pays](project_domiciliation_iso.md) — Migration complète : Zod string libre, DB 'france'→'FR', sentinel partout, CountrySelect intégré, DOMICILIATION_LABELS supprimé, badges hérité + ConfirmModal reset
- [ResultBanner — règle bannières succès/erreur](feedback_result_banner.md) — Toujours utiliser ResultBanner (× à droite, auto-dismiss 4s) ; result toujours { ok, msg } ; redirect via onDismiss si besoin
- [Tags suggérés admin — catégories/secteurs](project_tags_suggeres_admin.md) — Section inv-suggestions dans /admin/plateformes ; 6 routes backend ; bouton compteur dans RefListSection ; promouvoir/supprimer
- [ProfilImportBlock — import IA avec tags inconnus](project_profil_import_ia_tags.md) — Flow 3 étapes (json→creation→diff) ; resolveTags Levenshtein≤2 ; création tags approuvés avant PUT ; categories_inv_ids/secteurs_inv_ids dans payload
- [Sauvegarde ZIP référentiel](project_zip_backup_referentiel.md) — zip.js pur Node (no deps) ; 3 routes export/import ; api.blob() ; boutons ReferentielSection ; images incluses ; tags résolus par nom
- [Express — ordre des routes statiques vs /:id](feedback_express_route_order.md) — Routes statiques (/export, /import-zip) TOUJOURS avant /:id ; vérifier avec grep après toute insertion
- [Héritage catégories/secteurs — merge](project_categories_secteurs_inv_heritage.md) — Tags référentiel fusionnés dans les plateformes (is_inherited) ; InvSelect.inheritedIds ; associations-inv.js re-ajoute les inherited IDs au PUT ; compteur bandeau séparé des scalaires
- [Admin sous-pages — structure](project_admin_sous_pages.md) — AdminPlateformes (garanties + notation référentiel) ; AdminFiscalite (PfuSection + TauxCreditImpotSection) ; pattern account-layout
- [Settings NAV — structure actuelle](project_settings_nav.md) — 4 groupes : Interface / Mon paramétrage / Mes tags / Mes données ; membres+nettoyage déplacés de MonCompte vers Settings ; MonCompte réduit à profil+securite
- [Refactorisation Settings.jsx + Admin.jsx](project_settings_admin_refacto.md) — Découpés en composants autonomes (pages/settings/ et pages/admin/) ; imports manquants fréquents ; bugs d'extraction documentés
- [Page Plateformes](project_plateformes_page.md) — /plateformes : vue par plateforme, 4 onglets, simul/all endpoint, sélecteurs TIP identiques, grisage tip-td-closed
- [Grisage cellules hors-période tip-table](feedback_tip_td_closed.md) — .tip-td-closed pour mois avant souscription ou après dernier remb (rembourse) ; tip-col-current prioritaire
- [Anti-doublon projection mois courant](feedback_projection_no_double_count.md) — `real === 0` requis avant d'ajouter projAmt dans buildCellValue ; corrigé dans Plateformes + TableauInteretsPlateforme
- [DrillCellPanel Dashboard + navigation croisée](project_drillcellpanel_dashboard.md) — Panel permanent mois courant sur Dashboard ; clic ligne → Remboursements (URL params) + auto-ouverture modal + retour Dashboard avec drill restauré
- [Déploiement Docker — pièges et corrections](project_docker_deployment.md) — DATA_DIR env, fallthrough:false logos, nginx upstream name, Traefik @file, volume seed icons, deploy.sh
- [Sidebar overlay — couleur parasite au survol](feedback_sidebar_expand_overlay.md) — `background: transparent !important` + appearance:none sur .sidebar-expand-overlay et ses états hover/focus/active ; effet visuel via filter:brightness sur le logo uniquement
- [Safari mobile — viewport et dvh](feedback_safari_mobile_viewport.md) — Toujours doubler height:100vh + height:100dvh ; utiliser visualViewport.height au lieu de innerHeight en JS ; écouter visualViewport resize+scroll pour les menus fixed
- [Auth email — vérification, reset, pages layout](project_auth_email.md) — smtp_config table, email_verified sur users, tokens vérification/reset, pages ForgotPassword/ResetPassword/VerifyEmail, MonCompte badges
- [2FA — TOTP + email OTP + appareils de confiance](project_2fa.md) — totp_secret/totp_enabled sur users, tables two_fa_*, routes /2fa/setup|confirm-setup|disable|send-email-code|verify, trusted-devices CRUD, Login 3 étapes, TwoFASection + TrustedDevicesSection dans MonCompte
- [otplib ESM — API fonctionnelle uniquement](feedback_otplib_esm.md) — Pas d'export `authenticator` ; utiliser `generateSecret`, `generateURI`, `verifySync` importés nommément depuis 'otplib'
- [db/index.js — export default en double](feedback_dbindex_export_duplicate.md) — Un `export default db` existe en milieu de fichier (~ligne 942) ; toujours vérifier avec grep avant d'ajouter des migrations en fin de fichier
- [Suppression détenteur — réassignation au principal](project_suppression_detenteur.md) — DELETE investisseur réassigne investissements/depots_retraits/plateformes/comptes au principal avant delete ; toute nouvelle table CASCADE doit être ajoutée à la transaction
- [Export / Restore prod→dev](project_export_restore.md) — ZIP DB+assets, stockage serveur max 10, upload externe, restauration pending-restore+process.exit, job 3h00 (autoExport.js), ExportSection.jsx
- [SQLITE_CORRUPT — VACUUM INTO obligatoire](feedback_sqlite_vacuum_into.md) — db.backup() produit un fichier WAL-mode incomplet → toujours VACUUM INTO ; valider avec integrity_check avant d'écrire le pending-restore
- [Formule montant versé + style champs calculés](feedback_montant_verse_formula.md) — montantRembourse conditionnel isIndicatif (bruts si étranger/exonéré, netRecu si flat_tax) ; champs readonly : var(--surface-2)+var(--text-muted), jamais var(--bg-input-readonly)
- [Affichage projections — montants barrés & échéances non tenues](project_projections_display.md) — matchRembsAll somme tous les rembs du mois ; barré+réel si différence >0,01€ ; "✗ Échéance non tenue" rouge si passé sans paiement
- [Bug prêt différé — recalcul date_premiere_echeance](feedback_differe_date_calcul.md) — Passage à 'differe' doit toujours recalculer DPE si duree_mois présent ; validation dans submit ; label dynamique du champ
- [DrillCellPanel — filtrage lignes à 0](project_drillcell_filtrage_zero.md) — recusVisible/projetesVisible filtrent les lignes à 0 selon critères actifs ; compteur X/Y si lignes cachées
- [CSS tip-table + DrillCell mode consolidé](project_tip_css_drillcell_consolidation.md) — tip-th-name violet comme year ; bug consolidé : _ids[] dans merge, platIds dans onCellClick, plateforme_ids CSV au backend
- [Système de notifications](project_notifications.md) — Table notifications, 8 types (system/ticket_reply/info/team/success/warning/security/announcement), cloche topbar polling 30s, page /notifications, event notif:refresh pour rechargement immédiat
- [Audience des notifications — règle obligatoire](feedback_notifications_audience.md) — Toujours demander si la notif doit être vue par tous les admins (notifyAdmins) ou un utilisateur spécifique (notifyUser) avant d'implémenter
- [Page Communication — tickets & notifications](project_communication.md) — Architecture 3 volets, filtres chips multi-select, dropdowns portal, droits, jobs autoCleanNotifs + autoTicketStatus, pièges React (is_admin=0, msg-img-wrap)
