The legacy chart was a stacked BarChart, not a LineChart — the initial 'line'
naming was misleading. Rename internal type, i18n key (chartLine -> chartBar,
Lignes -> Barres, Lines -> Bars) and icon. Legacy 'line' in localStorage is
migrated to 'bar' on read.
Adds a segmented chart-type toggle to the /reports/trends "By category"
sub-view that switches between the existing stacked bars (default,
unchanged) and a new Recharts AreaChart with stackId="1" showing total
composition over time. Both modes share the same category palette and
SVG grayscale patterns so the visual signature is preserved.
- CategoryOverTimeChart gains a chartType: 'line' | 'area' prop
(default 'line' for backward compatibility with the dashboard usage).
- New TrendsChartTypeToggle component, persisted in localStorage under
"reports-trends-category-charttype".
- Toggle only renders in the "By category" sub-view with chart view
mode selected; hidden otherwise.
- i18n keys reports.trends.chartLine / chartArea / chartTypeAria in
FR and EN.
- CHANGELOG entries in both languages.
Mirror the BudgetVsActualTable structure in the Actual-vs-Actual compare
mode so MoM and YoY both surface a Monthly block (reference month vs
comparison month) and a Cumulative YTD block (progress through the
reference month vs progress through the previous window).
- CategoryDelta gains cumulative{Previous,Current}Amount and
cumulativeDelta{Abs,Pct}. Legacy previousAmount / currentAmount /
deltaAbs / deltaPct are kept as aliases of the monthly block so the
Highlights hub, Cartes dashboard and ComparePeriodChart keep working
unchanged.
- getCompareMonthOverMonth: cumulative-previous window ends at the end
of the previous month within the SAME year; when the reference month
is January, the previous window sits entirely in the prior calendar
year (Jan → Dec).
- getCompareYearOverYear: now takes an optional reference month
(defaults to December for backward compatibility). Monthly block
compares the single reference month across years; cumulative block
compares Jan → refMonth across years.
- ComparePeriodTable rebuilt with two colspan header groups, four
sub-columns each, a totals row and month/year boundary sub-labels.
- ComparePeriodChart unchanged: still reads the monthly primary fields.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Swap the native <select> in CategoryZoomHeader for the reusable
CategoryCombobox. Enhances the combobox with ARIA compliance
(combobox, listbox, option roles + aria-expanded, aria-controls,
aria-activedescendant) and hierarchy indentation based on parent_id
depth. Adds reports.category.searchPlaceholder in FR/EN.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Remove the non-functional PeriodSelector from /reports/cartes — the Cartes
report is by design a "month X vs X-1 vs X-12" snapshot, so the
reference-month picker is the only control needed.
- Simplify useCartes to drop its useReportsPeriod dependency; the hook now
only exposes the reference year/month and its setter.
- Add a (?) help bubble (lucide HelpCircle) next to the savings-rate KPI
title, wired up via a new `tooltip?: string` prop on KpiCard.
- Propagate `number | null` through CartesKpi.current and buildKpi so
savings rate is now null (rendered as "—") when reference-month income
is 0 instead of a misleading "0 %". Use refExpenses directly for
seasonality.referenceAmount since it is always numeric.
- Update the cartes snapshot tests to expect null for the zero-income case.
- Add FR/EN strings reports.cartes.savingsRateTooltip + CHANGELOG entries
in both locales.
Closes#67
Add opt-in Feedback Hub widget integrated into the Settings Logs card. Routes through a Rust command to bypass CORS and centralize privacy audit. First submission triggers a one-time consent dialog; three opt-in checkboxes (context, logs, identify with Maximus account) all unchecked by default. Wording and payload follow the cross-app conventions in la-compagnie-maximus/docs/feedback-hub-ops.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New /reports/cartes page surfaces a dashboard-style snapshot of the
reference month:
- 4 KPI cards (income / expenses / net / savings rate) showing MoM and
YoY deltas simultaneously, each with a 13-month sparkline highlighting
the reference month
- 12-month income vs expenses overlay chart (bars + net balance line)
- Top 5 category increases + top 5 decreases MoM, clickable through to
the category zoom report
- Budget adherence card: on-target count + 3 worst overruns with
progress bars
- Seasonality card: reference month vs same calendar month averaged
over the two previous years, with deviation indicator
All data is fetched in a single getCartesSnapshot() service call that
runs four queries concurrently (25-month flow, MoM category deltas,
budget-vs-actual, seasonality). Missing months are filled with zeroes
in the sparklines but preserved as null in the MoM/YoY deltas so the UI
can distinguish "no data" from "zero spend".
- Exported pure helpers: shiftMonth, defaultCartesReferencePeriod
- 13 vitest cases covering zero data, MoM/YoY computation, January
wrap-around, missing-month handling, division by zero for the
savings rate, seasonality with and without history, top mover sign
splitting and 5-cap
Note: src/components/reports/CompareReferenceMonthPicker.tsx is a
temporary duplicate — the canonical copy lives on the issue-96 branch
(refactor: compare report). Once both branches merge the content is
identical and git will dedupe. Keeping the local copy here means the
Cartes branch builds cleanly on main without depending on #96.
Closes#97
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Collapse the three Compare tabs (MoM / YoY / Budget) into two modes. The
new "Actual vs actual" mode exposes an explicit reference-month dropdown
in the header (defaults to the previous month, wraps around January) and
a MoM/YoY sub-toggle. The chart is rewritten to a grouped side-by-side
BarChart with two bars per category (reference period vs comparison
period) so both values are visible at a glance instead of just the
delta. The URL PeriodSelector stays in sync with the reference month.
- useCompare: state splits into { mode: "actual"|"budget", subMode:
"mom"|"yoy", year, month }. Pure helpers previousMonth(),
defaultReferencePeriod(), comparisonMeta() extracted for tests
- CompareModeTabs: 2 modes instead of 3
- New CompareSubModeToggle and CompareReferenceMonthPicker components
- ComparePeriodChart: grouped bars via two <Bar dataKey="..."/> on a
vertical BarChart
- i18n: modeActual / subModeMoM / subModeYoY / referenceMonth (FR+EN),
retire modeMoM / modeYoY
- 9 new vitest cases covering the pure helpers (January wrap-around for
both MoM and YoY, default reference period, month/year arithmetic)
Closes#96
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Delete legacy src/hooks/useReports.ts (the monolithic hook is now fully
replaced by the per-domain hooks from #70)
- Delete src/components/reports/ReportFilterPanel.tsx (last caller was the
pre-refactor ReportsPage; no longer referenced anywhere)
- Update docs/architecture.md: reports hook list now lists the 5 per-domain
hooks, reports service entry lists every new endpoint, routing section
lists the 4 sub-routes, categorizationService entry mentions the new
keyword-editing helpers, components folder count + page count updated
- Update docs/guide-utilisateur.md section 9: rewrite around hub + 4
sub-reports, explain bookmarkable period via query string, walk through
the right-click keyword editing flow, remove stale pivot section
- Rewrite in-app docs.reports.* i18n in both FR and EN to match the new
UX (hub, sub-reports, contextual keywords)
- New ADR docs/adr/0007-reports-hub-refactor.md: context, decision (hub +
four routes, per-domain hooks, URL period, security guarantees on the
keyword dialog, bounded recursive CTE for category zoom), consequences,
alternatives considered
- CHANGELOG.md + CHANGELOG.fr.md: Unreleased entries describing the hub,
each sub-report, contextual keyword editing, bookmarkable period, view
mode persistence, useReports split, pivot removal, and the security
posture of AddKeywordDialog / getCategoryZoom
Fixes#76
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wire the ContextMenu + AddKeywordDialog pair onto the remaining per-transaction
surfaces. No new business logic — pure composition of #69 / #74 pieces.
- HighlightsTopTransactionsList: optional onContextMenuRow prop, ReportsHighlightsPage
renders ContextMenu + AddKeywordDialog on right-click
- TransactionTable: optional onRowContextMenu prop on each <tr>; TransactionsPage
handles it and opens the dialog pre-filled with the row description + current
category
- Aggregate tables (HighlightsTopMoversTable, ComparePeriodTable, MonthlyTrendsTable,
CategoryOverTimeTable) are intentionally NOT wired: they show category / month
aggregates, not individual transactions, so there is no keyword to extract from
a row — the dialog would be nonsensical there
Fixes#75
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Service layer
- New reportService.getCategoryZoom(categoryId, from, to, includeChildren) —
bounded recursive CTE (WHERE ct.depth < 5) protects against parent_id cycles;
direct-only path skips the CTE; every binding is parameterised
- Export categorizationService helpers normalizeDescription / buildKeywordRegex /
compileKeywords so the dialog can reuse them
- New validateKeyword() enforces 2–64 char length (anti-ReDoS), whitespace-only
rejection, returns discriminated result
- New previewKeywordMatches(keyword, limit=50) uses parameterised LIKE + regex
filter in memory; caps candidate scan at 1000 rows to protect against
catastrophic backtracking
- New applyKeywordWithReassignment wraps INSERT (or UPDATE-reassign) +
per-transaction UPDATEs in an explicit BEGIN/COMMIT/ROLLBACK; rejects
existing keyword reassignment unless allowReplaceExisting is set; never
recategorises historical transactions beyond the ids the caller supplied
Hook
- Flesh out useCategoryZoom with reducer + fetch + refetch hook
Components (flat under src/components/reports/)
- CategoryZoomHeader — category combobox + include/direct toggle
- CategoryDonutChart — template'd from dashboard/CategoryPieChart with
innerRadius=55 and ChartPatternDefs for SVG patterns
- CategoryEvolutionChart — AreaChart with Intl-formatted axes
- CategoryTransactionsTable — sortable table with per-row onContextMenu
→ ContextMenu → "Add as keyword" action
AddKeywordDialog — src/components/categories/AddKeywordDialog.tsx
- Lives in categories/ (not reports/) because it is a keyword-editing widget
consumed from multiple sections
- Renders transaction descriptions as React children only (no
dangerouslySetInnerHTML); CSS truncation (CWE-79 safe)
- Per-row checkboxes for applying recategorisation; cap visible rows at 50;
explicit opt-in checkbox to extend to N-50 non-displayed matches
- Surfaces apply errors + "keyword already exists" replace prompt
- Re-runs category zoom fetch on success so the zoomed view updates
Page
- ReportsCategoryPage composes header + donut + evolution + transactions
+ AddKeywordDialog, fetches from useCategoryZoom, preserves query string
for back navigation
i18n
- New keys reports.category.* and reports.keyword.* in FR + EN
- Plural forms use i18next v25 _one / _other suffixes (nMatches)
Tests
- 3 reportService tests cover bounded CTE, cycle-guard depth check, direct-only fallthrough
- New categorizationService.test.ts: 13 tests covering validation boundaries,
parameterised LIKE preview, regex word-boundary filter, explicit BEGIN/COMMIT
wrapping, rollback on failure, existing keyword reassignment policy
- 62 total tests passing
Fixes#74
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Services: getCompareMonthOverMonth(year, month) and getCompareYearOverYear(year)
return CategoryDelta[] (expense-side, ABS aggregates, parameterised SQL only)
- Shared CategoryDelta type with HighlightMover now aliased to it
- Flesh out useCompare hook: reducer + fetch + automatic year/month inference
from the shared useReportsPeriod `to` date; budget mode skips fetch and
delegates to CompareBudgetView which wraps the existing BudgetVsActualTable
- Components: CompareModeTabs (MoM/YoY/Budget tabs), ComparePeriodTable (sortable
table with signed delta coloring), ComparePeriodChart (diverging horizontal
bar chart with ChartPatternDefs for SVG patterns), CompareBudgetView
(fetches budget rows for the current target year/month)
- ReportsComparePage wires everything with PeriodSelector + ViewModeToggle
(storage key reports-viewmode-compare); chart/table toggle is hidden in budget
mode since the budget table has its own presentation
- i18n keys: reports.compare.modeMoM / modeYoY / modeBudget in FR + EN
- 4 new vitest cases for the compare services: parameterised boundaries,
January wrap-around to December previous year, delta conversion with
previous=0 fallback to null pct, year-over-year spans
Fixes#73
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Flesh out ReportsTrendsPage with internal subview toggle
(global / byCategory) and ViewModeToggle (storage key reports-viewmode-trends)
- Reuse existing MonthlyTrendsChart/Table and CategoryOverTimeChart/Table
without modification; wire them through useTrends + useReportsPeriod so the
URL period is respected
- Add reports.trends.subviewGlobal / subviewByCategory keys in FR + EN
Fixes#72
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New useReportsPeriod hook reads/writes period via ?from=&to=&period= URL params,
default civil year, pure resolver exported for tests
- New per-domain hooks: useHighlights, useTrends, useCompare, useCategoryZoom
(stubs wired to useReportsPeriod, to be fleshed out in #71-#74)
- Rewire legacy useReports to consume useReportsPeriod; keep backward-compat
state shape (period/customDateFrom/customDateTo) so /reports tabs keep working
- Mark useReports @deprecated pending removal in #76
- Tests: 7 new cases covering resolveReportsPeriod defaults, bookmarks,
invalid inputs, preset resolution
Fixes#70
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Delete DynamicReport* components and pivot types (PivotConfig, PivotResult, PivotFieldId, etc.)
- Remove getDynamicReportData/getDynamicFilterValues from reportService
- Strip pivotConfig/pivotResult from useReports hook and ReportsPage
- Drop "dynamic" from ReportTab union
- Remove reports.pivot.* and reports.dynamic i18n keys in FR and EN
- Add skeletons for /reports/highlights, /trends, /compare, /category pages
- Register the 4 new sub-routes in App.tsx
- Add reports.hub, reports.viewMode, reports.empty, common.underConstruction keys
- New shared ContextMenu component with click-outside + Escape handling
- Refactor ChartContextMenu to compose generic ContextMenu
- New ViewModeToggle with localStorage persistence via storageKey
- New Sparkline (Recharts LineChart) for compact trends
- Unit tests for readViewMode helper
Fixes#69
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a close button and session-scoped dismissal flag so the banner
can be acknowledged for the current run but reappears on the next
app launch if the fallback is still active — matches the #81
acceptance criterion.
- sessionStorage key survives page navigation within the run, is
cleared on app restart.
- Graceful on storage quota errors.
- New `common.close` i18n key (FR: "Fermer", EN: "Close") used as
the aria-label of the close button.
Adds a visible warning in the Settings page when `token_store` has
landed in the file fallback instead of the OS keychain. Without this,
a user on a keychain-less system would silently lose the security
benefit introduced in #78 and never know.
- New `get_token_store_mode` service wrapper in authService.ts.
- New `TokenStoreFallbackBanner` component: fetches the mode on mount,
renders nothing when mode is `keychain` or null, renders an
amber warning card when mode is `file`.
- Mounted in SettingsPage right after AccountCard so it sits next to
the account state the user can fix (log out + log back in once the
keychain is available).
- i18n keys under `account.tokenStore.fallback.*` in fr/en.
Refs #66
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The auth callback is handled exclusively via the deep-link handler in
lib.rs — exposing it as a JS-invocable command is unnecessary attack
surface. The frontend listens for auth-callback-success/error events
instead.
Plaintext token storage documented as known limitation (see #66).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Privacy-first: remove 'https:' from img-src CSP directive to prevent
IP leaks via external avatar URLs (Google/Gravatar). AccountCard now
shows user initials instead of loading a remote image.
Also remove .keys-temp/ from .gitignore (not relevant to this PR).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both code paths that touch the updater now consult `check_entitlement`
from the Rust entitlements module before calling `check()`:
- `useUpdater.ts` adds a `notEntitled` status; on Free, the check
short-circuits and the Settings page displays an upgrade hint instead
of fetching update metadata.
- `ErrorPage.tsx` (recovery screen) does the same so the error path
matches the main path; users on Free no longer see network errors when
the updater would have run.
The gate name (`auto-update`) is the same string consumed by
`commands/entitlements.rs::FEATURE_TIERS`, so changing which tier
unlocks updates is a one-line edit in that file.
Bilingual i18n keys for the new messages are added to both `fr.json`
and `en.json`. CHANGELOG entries in both languages.
Adds the user-facing layer on top of the Rust license commands shipped
in #46.
- `licenseService.ts` thin wrapper around the new Tauri commands
- `useLicense` hook follows the project's useReducer pattern (idle,
loading, ready, validating, error) and exposes `submitKey`,
`refresh`, and `checkEntitlement` for cross-component use
- `LicenseCard` shows the current edition, the expiry date when set,
accepts a license key with inline validation feedback, and links to
the purchase page via `openUrl` from `@tauri-apps/plugin-opener`
- Card is inserted at the top of `SettingsPage` so the edition is the
first thing users see when looking for license-related actions
- i18n: new `license.*` keys in both `fr.json` and `en.json`
- Bilingual CHANGELOG entries
Both handlePinSuccess handlers (ProfileSwitcher and ProfileSelectionPage)
now catch updateProfile errors so that a failed rehash persistence does
not block switchProfile.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add automatic re-hashing of legacy SHA-256 PINs to Argon2id on
successful verification, returning new hash to frontend for persistence
- Use constant-time comparison (subtle::ConstantTimeEq) for both
Argon2id and legacy SHA-256 hash verification
- Add unit tests for hash_pin, verify_pin (Argon2id and legacy paths),
re-hashing flow, error cases, and hex encoding roundtrip
- Update frontend to handle VerifyPinResult struct and save rehashed
PIN hash via profile update
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Correct CHANGELOG to reflect default type is expense, not all types
- Validate select onChange value against allowed CategoryTypeFilter values
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Default categoryType filter to "expense" so top-N ranking is not
skewed by mixing income and expense amounts
- Remove redundant showFilterPanel condition (hasCategories already
covers the overTime tab)
- Add unit tests for getCategoryOverTime query construction and output
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Category Over Time report previously only showed expenses (t.amount < 0).
This removes that filter so all transaction types are shown by default,
and adds a type filter (expense/income/transfer) in the right filter panel.
Ref: simpl-resultat#41
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The 3-line helper was exported solely for testing. Inlining it removes the
export-for-test pattern and eliminates 50 lines of tests that were
disproportionate for a trivial filter-and-set loop.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Transaction amounts are already signed in the DB (expenses negative,
income positive). Remove Math.abs() normalization and stop multiplying
by sign at display time to avoid double negation.
Extract buildPrevYearTotalMap as a testable exported function and
rewrite tests to import the real function instead of reimplementing it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix sign bug in previous year actuals column: transaction amounts are
stored with sign in the DB (expenses negative) but budget entries are
always positive. Apply Math.abs() when building the previousYearTotal
map so the display-time sign multiplier works correctly.
Add unit tests for the normalization logic verifying that both expense
(negative in DB) and income (positive in DB) amounts are correctly
handled.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add vitest and 17 tests covering computeDateRange (all periods
including January rollover) and buildMonthOptions (length, order,
rollover, label formatting). Add test/test:watch npm scripts.
Ref #33
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace planned budget data with actual transaction totals for the
previous year column in the budget table. Add getActualTotalsForYear
helper to budgetService.
Ref #34
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove non-null assertions on bYear/bMonth in useDashboard fetchData
by making parameters required
- Extract shared computeDateRange and buildMonthOptions into
src/utils/dateRange.ts to eliminate duplication across useDashboard,
useReports, DashboardPage and ReportsPage
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add budgetYear/budgetMonth state to useDashboard hook with last
completed month as default
- Add month dropdown selector in the dashboard BudgetVsActual title
- Reduce dropdown font size in both Reports and Dashboard pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Clean up the sticky category cell className: remove the duplicated
px-3 for top-level parents and break the long ternary into readable
multi-line format.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove dead code: navigateBudgetMonth function and its export from
useReports.ts (replaced by setBudgetMonth, no longer imported anywhere)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace semi-transparent backgrounds on sticky columns with opaque
color-mix equivalents so scrolled content is fully hidden
- Add opaque background to section header sticky td
- Extract IIFE month options in ReportsPage into a useMemo
- Add sticky left-0 positioning to all category cells in BudgetVsActualTable
- Replace MonthNavigator arrows with inline title + dropdown month selector
- Default budget month to previous completed month instead of current
- Add i18n keys for new title prefix (FR/EN)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show category names permanently in compact form (text-xs) so they
are always discoverable. Percentages appear only on chart hover to
save space, matching the original request while keeping the legend
accessible without interaction.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract reorderRows into shared utility (src/utils/reorderRows.ts) to
deduplicate identical function in BudgetTable and BudgetVsActualTable
- Restore alphabetical sorting of children in budgetService.ts
- Fix styling for intermediate parent rows at depth 2+ (was only handling
depth 0-1)
- Reduce pie chart size (height 220->180, radii reduced) and padding to
give more space to the table
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Make reorderRows() recursive to support subtotals toggle at all depth
levels (not just depth 0-1)
- Restore pie chart legend (show on hover only to save space)
- Give more horizontal space to budget table (3/4 grid vs 2/3)
- Replace flat alphabetical sort with tree-order traversal so child
categories appear directly under their parent subtotal row
- Make category hierarchy recursive (supports arbitrary depth)
- Reduce pie chart width from 1/2 to 1/3 of the dashboard
- Show pie chart labels only on hover via tooltip
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tooltip was blending with the legend labels at the bottom of the chart,
especially when showing all categories at once. Added shadow and z-index
to ensure the tooltip stands out from the background.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move the pie chart title to DashboardPage as an external h2,
matching the pattern used by BudgetVsActual and ExpensesOverTime sections.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a read-only column showing the annual budget total from the
previous year for each category. This serves as a baseline reference
when planning the current year's budget.
- Add previousYearTotal field to BudgetYearRow type
- Fetch previous year budget entries in useBudget hook
- Display column between Category and Annual in BudgetTable
- Propagate totals through parent/subtotal/section/grand total rows
- Add i18n keys for FR ("Année préc.") and EN ("Prev. Year")
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- CLAUDE.md: bump version to 0.6.3
- architecture.md: update version, component counts, dashboard description
- guide-utilisateur.md: rewrite dashboard section (budget table, chart, no recent transactions)
- i18n docs: update dashboard help text in both FR and EN
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Default period changed from month to year-to-date
- Remove recent transactions section
- Add expenses over time stacked bar chart (by category/month)
- Add budget vs actual table (current month)
- Reorganize layout: cards, pie + budget table, full-width chart
Closes#15
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Section subtotals: text-sm font-semibold with more padding.
Grand totals: text-sm font-bold with border-t-2 and extra padding.
Applied consistently across BudgetTable, BudgetVsActualTable,
MonthlyTrendsTable, CategoryOverTimeTable, CategoryTable,
and DynamicReportTable.
Closes#14
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Increase category over time limit from 8 to 50 so all categories appear.
Fix category name visibility: use foreground color for bar chart Y-axis
labels and chart legend text instead of muted/inherited colors.
Closes#13
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add per-section subtotals (expenses, income, transfers) to budget table
and budget vs actual report. Fix category detail panel visibility when
scrolling through long category lists.
Closes#11, closes#12
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create CHANGELOG.fr.md with full French translation of all versions
- Add ChangelogPage (/changelog) accessible from Settings
- Replace hardcoded i18n release notes with file-based approach:
loads CHANGELOG.md or CHANGELOG.fr.md based on user language
- CI copies changelogs to public/ during release build
- Update CLAUDE.md with bilingual changelog deployment process (fixes#10)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Change chart amount labels from white to black with white stroke outline
for better contrast on all bar colors (fixes#8)
- Improve budget table editable cells: add hover background, pointer cursor,
tooltip hint, and larger click target for clearer affordance (fixes#9)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add table/chart toggle for Trends, By Category, and Over Time reports
- Add "Show amounts" toggle to display values on chart elements
- Add filter panel with category checkboxes and source dropdown
- Add source filter at SQL level for all chart report queries
- Add sticky headers on Dynamic Report and Budget vs Actual tables
- Add interactive hover: dimmed non-hovered bars, filtered tooltip, legend hover
- Fix comment icon color to match split indicator (orange) (#7)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- #1: Sortable columns (date, description, amount) in the transaction
detail modal with click-to-toggle direction
- #2: Budget table headers stay fixed when scrolling vertically
- #3: Eye/EyeOff toggle to show/hide the amounts column in the
transaction detail modal
Closes#1, closes#2, closes#3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add repair_migrations Tauri command that deletes stale migration 1
checksum from _sqlx_migrations before Database.load(). Migration 1
is idempotent (CREATE IF NOT EXISTS) so re-applying is safe.
Fixes "migration 1 was previously applied but has been modified".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Retry connectActiveProfile up to 3 times with 1s delay before showing
the error page. Persist log buffer to sessionStorage so logs survive
page refresh and are visible in the settings log viewer.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix updater: strip v-prefix from version in latest.json, and delete
old package before re-uploading to avoid 409 conflicts.
Add frontend log capture (console intercept) with a log viewer card
in the settings page (filterable, copyable, clearable).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevent infinite spinner when DB connection fails at startup by adding
a 10s timeout on connectActiveProfile(). Add ErrorBoundary to catch
React crashes and ErrorPage with refresh, update check, and contact links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Restore seed_categories.sql to its original content so the migration 2
checksum matches existing databases. Move the level-3 insurance
subcategories (310-312) into a new migration 7 using INSERT OR IGNORE.
Add .catch() on connectActiveProfile() to surface DB errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Keywords starting/ending with non-word characters (brackets, parens,
dashes) never matched because \b requires a word↔non-word transition.
Now uses smart boundaries: \b for word-char edges, (?<=\s|^)/(?=\s|$)
for non-word edges. Also pre-compiles regex patterns once per batch
instead of recreating them for every description × keyword combination.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Support up to 3 levels of categories (e.g., Dépenses récurrentes →
Assurances → Assurance-auto) while keeping SQL JOINs bounded and
existing 2-level branches fully compatible.
Changes across 14 files:
- Types: add "level3" pivot field, depth property on budget row types
- Reports: grandparent JOIN for 3-level resolution in dynamic reports
- Categories: depth validation (max 3), auto is_inputable management,
recursive tree operations, 3-level drag-drop with subtree validation
- Budget: 3-level grouping with intermediate subtotals, leaf-only
aggregation, depth-based indentation (pl-8/pl-14)
- Seed data: Assurances split into Assurance-auto/habitation/vie
- i18n: level3 translations for FR and EN
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use i18n translations for release notes when available, falling back to
the GitHub release body. Adds FR/EN notes for versions 0.3.8–0.3.11.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The dynamic report now relies exclusively on its own panel filters
instead of inheriting the global period selector date range.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Combine column dimensions into composite keys instead of using only the
first column dimension, enabling richer pivot tables and charts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a "year" period (Jan 1 to today) between "6 months" and "12 months"
in the period selector across all reports and dashboard views.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fields can now be assigned to multiple zones simultaneously (e.g. rows + filters).
Right-clicking a filter value excludes it (NOT IN), shown with strikethrough in red.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Overlay covers the full viewport while keeping the config panel
accessible. Press Escape or click the button to exit.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The table was rendering one <tr> per SQL result row instead of pivoting
the column-dimension values into a single row per unique row-key combo.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement a pivot table feature allowing users to compose custom reports
by assigning dimensions (Year, Month, Type, Level 1/2) to rows, columns,
and filters, with periodic and YTD measures as values. Includes a side
panel for configuration, a dynamic table with subtotals, and a stacked
bar chart visualization.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract changelog sections in CI to populate GitHub release bodies dynamically.
Expose the update body from tauri-plugin-updater and render it in the settings
page when an update is available. Add CHANGELOG discipline rule to CLAUDE.md.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a toggle button to BudgetVsActualTable and BudgetTable that lets
users choose whether parent subtotal rows appear before or after their
children. The preference is persisted in localStorage and shared across
both tables.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allow users to select an arbitrary date interval (e.g. Jan 1–15) in
addition to the existing preset periods. The "Custom" button opens a
dropdown with two date inputs and an Apply button. Works on both the
Reports and Dashboard pages.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add changelog entries for versions 0.2.5 through 0.3.7. Update FR/EN
user guide with profiles, transaction splits, drag-and-drop categories,
dark mode, SVG chart patterns, and context menus. Add Profiles section
to in-app docs page.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Change split icon color to orange-500 in transactions table for
better contrast in both dark and light modes
- Show split transactions at the top of the adjustments left panel
when there are no manual adjustments (instead of below empty state)
- Add a divider between manual adjustments and splits when both exist
Bumps version to 0.3.5.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a "Répartitions" section below manual adjustments listing all
split transactions. Clicking a split opens the existing modal to
view, edit, or delete it.
Fix CSV auto-detect failing on files with preamble lines (e.g.
Mastercard CSVs with metadata header). Three fixes:
- Delimiter detection uses mode of column counts instead of first-line
- Detect and skip preamble rows before header/data detection
- Exclude date-like columns from amount candidates and prefer columns
with decimal values when picking the amount column
Bumps version to 0.3.4.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allow users to split a transaction across multiple categories directly
from the transactions table. Split children are hidden from the list
and automatically included in dashboard, report, and budget aggregates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ProfileSwitcher was hidden when only one profile existed, making it
impossible to access "Manage Profiles" to create additional profiles.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Auto-fix duplicate sort_order values on load, auto-assign sort_order on
category creation, and add drag-and-drop via @dnd-kit to reorder and
reparent categories in the tree (with 2-level nesting constraint).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each profile gets its own SQLite database file for complete data isolation.
Profile selection screen at launch, sidebar switcher for quick switching,
and optional 4-6 digit PIN for privacy. Existing database becomes the
default profile with seamless upgrade.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add DocsPage with full user guide content, TOC sidebar with scroll spy,
and a print button that opens the OS print dialog for PDF export.
Print styles hide sidebars and remove layout constraints for clean output.
Link to user guide added on Settings page.
Bump version to 0.2.12.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New tabular report showing actual vs budgeted amounts per category,
with dollar and percentage variations for both the selected month
and year-to-date. Includes parent/child hierarchy, type grouping,
variation coloring, and month navigation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parent categories now display as bold read-only subtotal rows with their
children indented below. Expenses show as negative (red), income as
positive (green). Inputable parents get a "(direct)" child row for their
own budget entries.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add period buttons (This month, 3 months, 6 months, This year, All)
above the transaction filters. "This year" is selected by default so
the page no longer shows all transactions since the beginning of time.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show a delete button only when a template is selected, next to the
update button. Removes the confusing row of small X icons that could
be accidentally clicked.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Create import_sources + imported_files tracking records when importing
transactions from Settings > Data Management, so imports appear in the
Import History panel and can be deleted like CSV imports.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
selectSource had an empty dependency array, causing a stale closure
where importedFilesBySource was always the initial empty Map. This
made the new-file filter select all files including imported ones.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The template dropdown now stays on the selected value after applying,
and a new update button lets users save config changes back to the
selected template.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Change imported_files UNIQUE constraint from (source_id, file_hash) to
(source_id, filename) so files with identical content but different names
each get their own record. Update createImportedFile to look up existing
records by filename instead of hash.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add export (JSON/CSV) and import (full replace) to the Settings page.
Export supports 3 modes (transactions+categories, transactions only,
categories only) with optional password encryption using Argon2id key
derivation. Import detects encrypted .sref files, prompts for password,
and shows a destructive confirmation modal before replacing data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Detect duplicate transactions across selected files (not just against DB),
create separate imported_files records per file for proper hash tracking,
fix progress display to show current file, and exclude already-imported
files from "Select all".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>