feat(dashboard): converge / on the Cartes report model #287

Closed
maximus wants to merge 0 commits from issue-279-dashboard-cartes into main
Owner

Summary

Converges the home Dashboard (/) on the /reports/cartes presentational model, per the epic #260 "rapports uniformes" vision.

  • KPIs + deltas: replaced the old 3 flat summary cards with the 4 Cartes KpiCards (income/expenses/net/savings rate), each showing MoM/YoY deltas, sourced from getCartesSnapshot against a Dashboard-owned reference month (defaults to the last complete month via defaultReferencePeriod, same default as Compare/Cartes). No mode toggle (month/YTD) exposed yet — defaults to "month" (see Decisions below).
  • Top movers + budget adherence: reused TopMoversList (up/down) and BudgetAdherenceCard straight from Cartes, same data.
  • Income-aware trend: added IncomeExpenseOverlayChart (income vs expenses, 12 months) from the Cartes snapshot. The existing "expenses over time" chart now explicitly passes typeFilter: "expense" to getCategoryOverTime — previously it silently aggregated every category type despite its heading, so a revenue category could show up in what read as an expense-only trend.
  • Ranked bar chart: replaced the expense-only pie chart with a ranked horizontal bar chart. Reused CategoryBarChart.tsx, a fully-formed component that had been orphaned since an earlier ReportsCategoryPage rewrite — same props contract as the old CategoryPieChart, so this is a drop-in swap with zero new component code.
  • Net-worth tile: new tile shows the Balance sheet's latest total (getSnapshotTotalsByDate), reusing the exact balance.overview.latestTotal/asOf copy already shown on /balance — same words, so the label can't be confused with the account (import-source) filter below it. Hidden (never a misleading "$0") until at least one balance account has a recorded snapshot; the visibility decision reuses deriveLandingState (balanceLanding.ts) rather than re-inferring emptiness from nulls, per the review caveat. Fetched independently on mount — not scoped by the account filter (balance_accounts is a disjoint concept from import_sources).
  • Account filter: Dashboard now renders the shared <FilterPanel> (temporal slot = existing PeriodSelector, plus the import-source multi-select already used on Trends/Compare/Budget). The filter is Dashboard-local state (accountIds in useDashboard's own reducer), not routed through useReportsPeriod — the Dashboard keeps its own two temporal axes (a flexible period for the bar chart/trend, and the separate reference month for the Cartes-sourced section), matching the M1 review note that I4 deliberately left the Dashboard untouched.

New pure helper deriveNetWorthTile in dashboardService.ts (tested, 5 new cases) shapes the tile's visibility/value from the same two signals BalancePage uses.

Decisions (mid-tier ambiguity, noted per autopilot policy)

  • No YTD toggle for the Dashboard's KPI cards — Cartes exposes a month/YTD CartesPeriodModeToggle; the issue's acceptance criteria only asked for "KPIs with MoM/YoY deltas", not the toggle itself. Defaulted to mode: "month" to keep the page's control surface tighter. Rejected alternative: reuse CartesPeriodModeToggle too — deferred as a cheap follow-up if wanted, since getCartesSnapshot already supports it.
  • Old flexible-period transactional summary dropped — the previous "Balance" card (sum of all transactions over the flexible period selector) had no equivalent in the Cartes model and would have duplicated/confused the new reference-month "Net" KPI (two different "net" figures over two different windows). Treated its removal as intentional per "converge on Cartes", not a regression to preserve.
  • dashboard.balance and reports.bva.titlePrefix i18n keys removed (FR+EN) — both became orphaned by this change specifically (verified via grep: no other consumer); their sibling keys in the same namespaces remain in use elsewhere and were left untouched.
  • getDashboardSummary left in place, unused by the page — no longer called from useDashboard, but still exported/untested-elsewhere; removing it outright felt like unrelated scope creep for a same-file, still-public function.
  • CategoryPieChart.tsx left in place, now orphaned — mirrors how CategoryBarChart.tsx itself sat unused for a long time before this PR resurrected it; kept in case a future "chart type toggle" wants it back.

Reviewer caveats

  • The Cartes snapshot's own fetchMonthlyFlows/fetchSeasonality series remain un-filtered by accountIds (only its two sub-reports — top movers, budget adherence — respect the filter, per the pre-existing getCartesSnapshot doc comment from #273/#276). Dashboard reuses that same snapshot as-is; the KPI cards' current/deltas and the overlay chart therefore do not reflect the account filter, only top movers and budget adherence do. Flagged as pre-existing, out of scope for this issue (the M1 review note explicitly scoped that gap to a future issue).
  • The KPI-row net-worth tile sits in a flex flex-wrap container (not the fixed 4-column grid Cartes uses for its own KPI row) specifically so the layout degrades cleanly to 4 items when the tile is hidden (no empty grid cell).

Generated autonomously by /autopilot run of 2026-07-11

Test plan

  • npm run build (tsc + vite) green
  • npm test — 796 passed (baseline 791 + 5 new deriveNetWorthTile cases), 0 regressions
  • cargo check green (no Rust touched)
  • Manual smoke test in the running app (not performed — autopilot, no display)
## Summary Converges the home Dashboard (`/`) on the `/reports/cartes` presentational model, per the epic #260 "rapports uniformes" vision. - **KPIs + deltas**: replaced the old 3 flat summary cards with the 4 Cartes `KpiCard`s (income/expenses/net/savings rate), each showing MoM/YoY deltas, sourced from `getCartesSnapshot` against a Dashboard-owned reference month (defaults to the last complete month via `defaultReferencePeriod`, same default as Compare/Cartes). No mode toggle (month/YTD) exposed yet — defaults to `"month"` (see Decisions below). - **Top movers + budget adherence**: reused `TopMoversList` (up/down) and `BudgetAdherenceCard` straight from Cartes, same data. - **Income-aware trend**: added `IncomeExpenseOverlayChart` (income vs expenses, 12 months) from the Cartes snapshot. The existing "expenses over time" chart now explicitly passes `typeFilter: "expense"` to `getCategoryOverTime` — previously it silently aggregated every category type despite its heading, so a revenue category could show up in what read as an expense-only trend. - **Ranked bar chart**: replaced the expense-only pie chart with a ranked horizontal bar chart. Reused `CategoryBarChart.tsx`, a fully-formed component that had been orphaned since an earlier `ReportsCategoryPage` rewrite — same props contract as the old `CategoryPieChart`, so this is a drop-in swap with zero new component code. - **Net-worth tile**: new tile shows the Balance sheet's latest total (`getSnapshotTotalsByDate`), reusing the exact `balance.overview.latestTotal`/`asOf` copy already shown on `/balance` — same words, so the label can't be confused with the account (import-source) filter below it. Hidden (never a misleading "$0") until at least one balance account has a recorded snapshot; the visibility decision reuses `deriveLandingState` (`balanceLanding.ts`) rather than re-inferring emptiness from nulls, per the review caveat. Fetched independently on mount — **not** scoped by the account filter (`balance_accounts` is a disjoint concept from `import_sources`). - **Account filter**: Dashboard now renders the shared `<FilterPanel>` (temporal slot = existing `PeriodSelector`, plus the import-source multi-select already used on Trends/Compare/Budget). The filter is Dashboard-local state (`accountIds` in `useDashboard`'s own reducer), **not** routed through `useReportsPeriod` — the Dashboard keeps its own two temporal axes (a flexible period for the bar chart/trend, and the separate reference month for the Cartes-sourced section), matching the M1 review note that I4 deliberately left the Dashboard untouched. New pure helper `deriveNetWorthTile` in `dashboardService.ts` (tested, 5 new cases) shapes the tile's visibility/value from the same two signals `BalancePage` uses. ## Decisions (mid-tier ambiguity, noted per autopilot policy) - **No YTD toggle for the Dashboard's KPI cards** — Cartes exposes a month/YTD `CartesPeriodModeToggle`; the issue's acceptance criteria only asked for "KPIs with MoM/YoY deltas", not the toggle itself. Defaulted to `mode: "month"` to keep the page's control surface tighter. Rejected alternative: reuse `CartesPeriodModeToggle` too — deferred as a cheap follow-up if wanted, since `getCartesSnapshot` already supports it. - **Old flexible-period transactional summary dropped** — the previous "Balance" card (sum of all transactions over the flexible period selector) had no equivalent in the Cartes model and would have duplicated/confused the new reference-month "Net" KPI (two different "net" figures over two different windows). Treated its removal as intentional per "converge on Cartes", not a regression to preserve. - **`dashboard.balance` and `reports.bva.titlePrefix` i18n keys removed** (FR+EN) — both became orphaned by this change specifically (verified via grep: no other consumer); their sibling keys in the same namespaces remain in use elsewhere and were left untouched. - **`getDashboardSummary` left in place, unused by the page** — no longer called from `useDashboard`, but still exported/untested-elsewhere; removing it outright felt like unrelated scope creep for a same-file, still-public function. - **`CategoryPieChart.tsx` left in place, now orphaned** — mirrors how `CategoryBarChart.tsx` itself sat unused for a long time before this PR resurrected it; kept in case a future "chart type toggle" wants it back. ## Reviewer caveats - The Cartes snapshot's own `fetchMonthlyFlows`/`fetchSeasonality` series remain un-filtered by `accountIds` (only its two sub-reports — top movers, budget adherence — respect the filter, per the pre-existing `getCartesSnapshot` doc comment from #273/#276). Dashboard reuses that same snapshot as-is; the KPI cards' `current`/deltas and the overlay chart therefore do **not** reflect the account filter, only top movers and budget adherence do. Flagged as pre-existing, out of scope for this issue (the M1 review note explicitly scoped that gap to a future issue). - The KPI-row net-worth tile sits in a `flex flex-wrap` container (not the fixed 4-column grid Cartes uses for its own KPI row) specifically so the layout degrades cleanly to 4 items when the tile is hidden (no empty grid cell). Generated autonomously by /autopilot run of 2026-07-11 ## Test plan - [x] `npm run build` (tsc + vite) green - [x] `npm test` — 796 passed (baseline 791 + 5 new `deriveNetWorthTile` cases), 0 regressions - [x] `cargo check` green (no Rust touched) - [ ] Manual smoke test in the running app (not performed — autopilot, no display)
maximus added 1 commit 2026-07-11 21:14:00 +00:00
feat(dashboard): converge home page on the Cartes report model
All checks were successful
PR Check / rust (pull_request) Successful in 20m42s
PR Check / frontend (pull_request) Successful in 2m22s
193ef1d9dd
DashboardPage now reuses the Cartes report's presentational widgets
(KpiCard with MoM/YoY deltas, top movers, budget adherence) sourced from
getCartesSnapshot against a Dashboard-owned reference month (defaults to
the last complete month). The expense-only pie chart is replaced by a
ranked bar chart of top expense categories (resurrecting the previously
unused CategoryBarChart), and the account (import-source) filter
introduced on Trends/Compare/Budget now also applies to the Dashboard's
own transactional widgets via a Dashboard-local accountIds state (kept
separate from useReportsPeriod, since the Dashboard owns its own two
temporal axes).

A new net-worth tile surfaces the Balance sheet's latest total
(getSnapshotTotalsByDate) — a distinct metric from every transactional
card here, so it stays hidden (never a misleading "$0") until at least
one balance account has a recorded snapshot, reusing deriveLandingState
rather than re-inferring emptiness from nulls. It is not scoped by the
account filter (balance_accounts is a disjoint concept from
import_sources) and is fetched independently on mount.

The category-over-time trend chart now passes typeFilter "expense",
fixing a latent mismatch where a revenue category could silently show
up in a chart titled "expenses over time".

Resolves #279
maximus added the
autopilot:pending-human
label 2026-07-11 21:14:22 +00:00
Author
Owner

/pr-review — PR #287 (issue #279) : converge / sur le modèle Cartes

Verdict révisé : REQUEST_CHANGES

Note : ce commentaire remplace le passage APPROVE précédent. Après une trace détaillée du point de vigilance I7 (propagation de accountIds dans toutes les séries de getCartesSnapshot), l'incohérence de filtrage se confirme comme réelle et rendue visible par cette PR — pas seulement héritée. La PR est propre par ailleurs ; un seul défaut bloquant reste, avec un correctif court.

La convergence est bien faite : contrats résolus, types concordants, i18n complète FR/EN, deriveNetWorthTile pur et testé (5 cas), tuile valeur nette correctement découplée du filtre, retraits de clés orphelines vérifiés, CategoryBarChart en vrai drop-in. Le problème est ailleurs.


🔴 Bloquant — le filtre de comptes ne s'applique pas aux KPIs ni au graphe overlay, et cette PR est la première page à exposer le filtre

Fait (tracé dans le code de la branche) : getCartesSnapshot (src/services/reportService.ts:1250) ne transmet accountIds qu'à ses deux sous-rapports :

const [seasonalityRows, flowRows, momRows, budgetRows] = await Promise.all([
  fetchSeasonality(referenceMonth, referenceYear - 2, referenceYear - 1), // ← ligne 1264, PAS d'accountIds
  fetchMonthlyFlows(windowStartIso, refEnd),                              // ← ligne 1265, PAS d'accountIds
  getCompareMonthOverMonth(referenceYear, referenceMonth, accountIds),    // ← filtré (top movers)
  getBudgetVsActualData(referenceYear, referenceMonth, accountIds),       // ← filtré (adhérence budget)
]);

fetchMonthlyFlows (reportService.ts:1186) et fetchSeasonality (reportService.ts:1209) ne prennent aucun paramètre accountIds — leur SQL est un FROM transactions WHERE date … non filtré par source_id. Or les 4 KPI cards (revenus / dépenses / net / taux d'épargne) sont calculés depuis flowByMonth, lui-même construit à partir de flowRows = fetchMonthlyFlows. Le graphe IncomeExpenseOverlayChart consomme flow12Months, dérivé du même flowByMonth. Ces widgets ignorent donc accountIds.

En parallèle, sur la même page, ces widgets respectent le filtre :

  • barres classées → getExpensesByCategory(dateFrom, dateTo, accountIds) (useDashboard.ts)
  • tendance par catégorie → getCategoryOverTime(…, accountIds, "expense")
  • top movers + adhérence budget (via les deux sous-rapports ci-dessus)

Scénario d'échec concret : l'utilisateur sélectionne un seul compte dans le <FilterPanel> que cette PR ajoute au Dashboard (DashboardPage.tsx, accountIds={state.accountIds}). La KPI « Dépenses » reste le total tous comptes, alors que les barres de dépenses par catégorie juste en dessous sont filtrées sur ce compte. Les deux ne réconcilient pas : la somme des barres ≠ la KPI Dépenses. Dans une app de finances personnelles, deux chiffres contradictoires sous un même filtre que l'utilisateur vient de poser est un défaut de correction, pas une coquetterie cosmétique.

Pourquoi c'est cette PR (et pas un héritage à ignorer) : la page /reports/cartes n'a jamais exposé ce filtre — useCartes.ts:81 appelle getCartesSnapshot(year, month, mode) sans accountIds, et ReportsCartesPage.tsx ne rend aucun FilterPanel. Le gap était donc dormant en prod (tout non filtré = cohérent). Cette PR est la première et seule page à la fois à exposer le multi-select de comptes et à passer accountIds à getCartesSnapshot. C'est elle qui rend l'incohérence visible — le planning M2 avait justement flaggé ce risque (I7) à vérifier en review, précisément pour cette raison.

Aggravant — le CHANGELOG affirme le contraire de la réalité. CHANGELOG.md:21 / CHANGELOG.fr.md:9 :

« le filtre de comptes … s'applique désormais aussi aux widgets transactionnels du tableau de bord »

Les KPI cards et l'overlay sont des widgets transactionnels et ne respectent pas le filtre. Cette note ship aux utilisateurs — elle doit être vraie.

Correctif (court, ~6 lignes, motif M1 déjà en place) : ajouter accountIds?: number[] à fetchMonthlyFlows et fetchSeasonality, appliquer const p = inPlaceholders(accountIds, N) puis AND source_id IN (${p}) (colonne transactions.source_id, cf. getExpensesByCategory:80), et transmettre accountIds depuis les deux appels de getCartesSnapshot:1264-1265. Le helper inPlaceholders retourne null sur filtre vide → requête byte-identique quand aucun compte n'est sélectionné (aucune régression du cas défaut). Un test dans reportService.cartes.test.ts sur le passage d'accountIds aux 4 branches verrouillerait le contrat.

Alternative acceptable si filtrer les séries est délibérément différé : rendre l'UI + le CHANGELOG honnêtes — dire explicitement que les KPIs et l'overlay restent « tous comptes » pour l'instant (et idéalement une petite affordance UI pour que l'utilisateur ne soit pas induit en erreur). Moins bien, mais au moins la note de version cesse d'être fausse. À trancher par toi.


Non bloquant (suggestions)

  1. Corps de PR sans mot-clé de fermeture — pas de Resolves #279 : l'issue ne se fermera pas au merge. À ajouter.
  2. getDashboardSummary devient du code mort (0 consommateur après la PR). Conservé sciemment ; ok, mais à noter pour un futur ménage.
  3. UX de CategoryBarChart : masquage par clic-droit seulement (plus de légende cliquable), infobulle sans « % du total » vs l'ancien camembert. Vérifier que la perte est acceptée.
  4. Toggle mois/YTD (CartesPeriodModeToggle) non exposé — déjà noté comme différé par l'auteur, ok.

Une fois les séries filtrées (ou le CHANGELOG corrigé) + le Resolves #279 ajouté, cette PR est prête. Elle est solide à 95 %.

## /pr-review — PR #287 (issue #279) : converge `/` sur le modèle Cartes **Verdict révisé : REQUEST_CHANGES** > Note : ce commentaire remplace le passage APPROVE précédent. Après une trace détaillée du point de vigilance I7 (propagation de `accountIds` dans **toutes** les séries de `getCartesSnapshot`), l'incohérence de filtrage se confirme comme réelle **et** rendue visible par cette PR — pas seulement héritée. La PR est propre par ailleurs ; un seul défaut bloquant reste, avec un correctif court. La convergence est bien faite : contrats résolus, types concordants, i18n complète FR/EN, `deriveNetWorthTile` pur et testé (5 cas), tuile valeur nette correctement découplée du filtre, retraits de clés orphelines vérifiés, `CategoryBarChart` en vrai drop-in. Le problème est ailleurs. --- ### 🔴 Bloquant — le filtre de comptes ne s'applique pas aux KPIs ni au graphe overlay, et cette PR est la première page à exposer le filtre **Fait (tracé dans le code de la branche) :** `getCartesSnapshot` (`src/services/reportService.ts:1250`) ne transmet `accountIds` qu'à ses deux sous-rapports : ``` const [seasonalityRows, flowRows, momRows, budgetRows] = await Promise.all([ fetchSeasonality(referenceMonth, referenceYear - 2, referenceYear - 1), // ← ligne 1264, PAS d'accountIds fetchMonthlyFlows(windowStartIso, refEnd), // ← ligne 1265, PAS d'accountIds getCompareMonthOverMonth(referenceYear, referenceMonth, accountIds), // ← filtré (top movers) getBudgetVsActualData(referenceYear, referenceMonth, accountIds), // ← filtré (adhérence budget) ]); ``` `fetchMonthlyFlows` (`reportService.ts:1186`) et `fetchSeasonality` (`reportService.ts:1209`) ne prennent **aucun** paramètre `accountIds` — leur SQL est un `FROM transactions WHERE date … ` non filtré par `source_id`. Or les **4 KPI cards** (revenus / dépenses / net / taux d'épargne) sont calculés depuis `flowByMonth`, lui-même construit à partir de `flowRows` = `fetchMonthlyFlows`. Le graphe `IncomeExpenseOverlayChart` consomme `flow12Months`, dérivé du même `flowByMonth`. **Ces widgets ignorent donc `accountIds`.** En parallèle, sur la même page, ces widgets **respectent** le filtre : - barres classées → `getExpensesByCategory(dateFrom, dateTo, accountIds)` (`useDashboard.ts`) - tendance par catégorie → `getCategoryOverTime(…, accountIds, "expense")` - top movers + adhérence budget (via les deux sous-rapports ci-dessus) **Scénario d'échec concret :** l'utilisateur sélectionne un seul compte dans le `<FilterPanel>` que cette PR ajoute au Dashboard (`DashboardPage.tsx`, `accountIds={state.accountIds}`). La KPI « Dépenses » reste le total **tous comptes**, alors que les barres de dépenses par catégorie juste en dessous sont filtrées **sur ce compte**. Les deux ne réconcilient pas : la somme des barres ≠ la KPI Dépenses. Dans une app de finances personnelles, deux chiffres contradictoires sous un même filtre que l'utilisateur vient de poser est un défaut de correction, pas une coquetterie cosmétique. **Pourquoi c'est cette PR (et pas un héritage à ignorer) :** la page `/reports/cartes` n'a **jamais** exposé ce filtre — `useCartes.ts:81` appelle `getCartesSnapshot(year, month, mode)` sans `accountIds`, et `ReportsCartesPage.tsx` ne rend aucun `FilterPanel`. Le gap était donc **dormant** en prod (tout non filtré = cohérent). Cette PR est la **première et seule** page à la fois à exposer le multi-select de comptes **et** à passer `accountIds` à `getCartesSnapshot`. C'est elle qui rend l'incohérence visible — le planning M2 avait justement flaggé ce risque (I7) à vérifier en review, précisément pour cette raison. **Aggravant — le CHANGELOG affirme le contraire de la réalité.** `CHANGELOG.md:21` / `CHANGELOG.fr.md:9` : > « le filtre de comptes … **s'applique désormais aussi aux widgets transactionnels du tableau de bord** » Les KPI cards et l'overlay **sont** des widgets transactionnels et ne respectent pas le filtre. Cette note ship aux utilisateurs — elle doit être vraie. **Correctif (court, ~6 lignes, motif M1 déjà en place) :** ajouter `accountIds?: number[]` à `fetchMonthlyFlows` et `fetchSeasonality`, appliquer `const p = inPlaceholders(accountIds, N)` puis `AND source_id IN (${p})` (colonne `transactions.source_id`, cf. `getExpensesByCategory:80`), et transmettre `accountIds` depuis les deux appels de `getCartesSnapshot:1264-1265`. Le helper `inPlaceholders` retourne `null` sur filtre vide → requête byte-identique quand aucun compte n'est sélectionné (aucune régression du cas défaut). Un test dans `reportService.cartes.test.ts` sur le passage d'`accountIds` aux 4 branches verrouillerait le contrat. **Alternative acceptable** si filtrer les séries est délibérément différé : rendre l'UI + le CHANGELOG honnêtes — dire explicitement que les KPIs et l'overlay restent « tous comptes » pour l'instant (et idéalement une petite affordance UI pour que l'utilisateur ne soit pas induit en erreur). Moins bien, mais au moins la note de version cesse d'être fausse. À trancher par toi. --- ### Non bloquant (suggestions) 1. **Corps de PR sans mot-clé de fermeture** — pas de `Resolves #279` : l'issue ne se fermera pas au merge. À ajouter. 2. **`getDashboardSummary` devient du code mort** (0 consommateur après la PR). Conservé sciemment ; ok, mais à noter pour un futur ménage. 3. **UX de `CategoryBarChart`** : masquage par clic-droit seulement (plus de légende cliquable), infobulle sans « % du total » vs l'ancien camembert. Vérifier que la perte est acceptée. 4. Toggle mois/YTD (`CartesPeriodModeToggle`) non exposé — déjà noté comme différé par l'auteur, ok. --- Une fois les séries filtrées (ou le CHANGELOG corrigé) + le `Resolves #279` ajouté, cette PR est prête. Elle est solide à 95 %.
maximus added 1 commit 2026-07-12 01:16:12 +00:00
fix(reports): thread accountIds into Cartes KPI + seasonality series
All checks were successful
PR Check / rust (pull_request) Successful in 21m29s
PR Check / frontend (pull_request) Successful in 2m24s
9ee5ad353f
getCartesSnapshot forwarded the account filter only to the top-movers and
budget sub-reports, leaving fetchMonthlyFlows (KPIs, sparklines, 12-month
overlay) and fetchSeasonality unfiltered. The Dashboard is the first page to
expose the account filter over these series, so its KPI cards showed
unfiltered totals while the category bars / trend / top-movers respected the
filter — figures that did not reconcile on the same screen.

Thread an optional accountIds through both fetchers (parameterized
`source_id IN (...)` via inPlaceholders) and pass it from getCartesSnapshot,
so the whole dashboard honours the filter — which is what the #279 CHANGELOG
entry already promises. No CHANGELOG change: the code now matches the note.

Resolves #279

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author
Owner

/pr-review — PR #287 : suivi du fix (blocage levé)

Verdict : RESOLVED → APPROVE — commit 9ee5ad3.

Le point bloquant #1 (incohérence de filtrage I7) est corrigé. getCartesSnapshot propageait accountIds uniquement aux sous-rapports top-movers et budget ; les séries fetchMonthlyFlows (KPIs, sparklines, overlay 12 mois) et fetchSeasonality l'ignoraient. Sur le Dashboard — première page à exposer ce filtre par-dessus ces séries — les KPI affichaient des totaux non filtrés pendant que les barres/tendance/top-movers respectaient le filtre.

Correctif :

  • reportService.tsfetchMonthlyFlows et fetchSeasonality acceptent un accountIds?: number[] optionnel et ajoutent une clause paramétrée source_id IN (...) (via inPlaceholders, aux index $3 / $4) ; getCartesSnapshot les câble. Doc-comment mis à jour.
  • Point bloquant #2 (CHANGELOG faux) résolu par le code, sans toucher le texte : l'entrée #279 promettait déjà que le filtre s'applique « aux widgets transactionnels du tableau de bord » — le code honore désormais cette promesse (au lieu de réécrire la note à la baisse).

Vérification :

  • 2 nouvelles assertions dans reportService.cartes.test.ts : filtre propagé à la série mensuelle (source_id IN ($3, $4)) et à la saisonnalité (source_id IN ($4, $5)) ; le test de régression « aucun source_id sans filtre » tient (clause ajoutée seulement si accountIds présent).
  • tsc --noEmit clean · 798 vitest verts (47 fichiers).
  • Resolves #279 ajouté au commit (l'issue se fermera au merge).

Suggestion non bloquante restante : getDashboardSummary devient du code mort — à retirer dans un suivi.

## /pr-review — PR #287 : suivi du fix (blocage levé) **Verdict : RESOLVED → APPROVE** — commit `9ee5ad3`. Le point bloquant #1 (incohérence de filtrage I7) est corrigé. `getCartesSnapshot` propageait `accountIds` uniquement aux sous-rapports top-movers et budget ; les séries `fetchMonthlyFlows` (KPIs, sparklines, overlay 12 mois) et `fetchSeasonality` l'ignoraient. Sur le Dashboard — première page à exposer ce filtre par-dessus ces séries — les KPI affichaient des totaux non filtrés pendant que les barres/tendance/top-movers respectaient le filtre. **Correctif** : - `reportService.ts` — `fetchMonthlyFlows` et `fetchSeasonality` acceptent un `accountIds?: number[]` optionnel et ajoutent une clause paramétrée `source_id IN (...)` (via `inPlaceholders`, aux index `$3` / `$4`) ; `getCartesSnapshot` les câble. Doc-comment mis à jour. - Point bloquant #2 (CHANGELOG faux) **résolu par le code, sans toucher le texte** : l'entrée #279 promettait déjà que le filtre s'applique « aux widgets transactionnels du tableau de bord » — le code honore désormais cette promesse (au lieu de réécrire la note à la baisse). **Vérification** : - 2 nouvelles assertions dans `reportService.cartes.test.ts` : filtre propagé à la série mensuelle (`source_id IN ($3, $4)`) et à la saisonnalité (`source_id IN ($4, $5)`) ; le test de régression « aucun `source_id` sans filtre » tient (clause ajoutée seulement si `accountIds` présent). - `tsc --noEmit` clean · **798 vitest** verts (47 fichiers). - `Resolves #279` ajouté au commit (l'issue se fermera au merge). Suggestion non bloquante restante : `getDashboardSummary` devient du code mort — à retirer dans un suivi.
maximus closed this pull request 2026-07-12 01:25:43 +00:00
Author
Owner

Mergée localement dans main dans le cadre de la pile M2 (a982f9e) — merge --no-ff + résolution des conflits CHANGELOG (union #277/#278/#279). Forgejo ne marque pas les merges locaux comme merged ; fermeture manuelle. Issue liée auto-fermée via Resolves #N. Tip cumulé validé : tsc + vite build, 811 vitest, cargo check + 98 tests Rust.

Mergée localement dans `main` dans le cadre de la pile M2 (`a982f9e`) — merge `--no-ff` + résolution des conflits CHANGELOG (union #277/#278/#279). Forgejo ne marque pas les merges locaux comme *merged* ; fermeture manuelle. Issue liée auto-fermée via `Resolves #N`. Tip cumulé validé : tsc + vite build, 811 vitest, cargo check + 98 tests Rust.
All checks were successful
PR Check / rust (pull_request) Successful in 21m29s
PR Check / frontend (pull_request) Successful in 2m24s

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: maximus/Simpl-Resultat#287
No description provided.