- New ADR-0006 documenting the OS keychain migration: context,
options considered (keyring vs stronghold vs AES-from-PIN), the
backend choice rationale (sync-secret-service vs async-secret-
service), anti-downgrade design, migration semantics, and the
subscription-tampering fix via account_cache.
- architecture.md updated: new token_store / account_cache module
entries, auth_commands descriptions now point at the keychain-
backed API, OAuth2 + deep-link flow diagram mentions the HMAC
step, command count bumped to 35.
- CHANGELOG.md + CHANGELOG.fr.md under Unreleased:
- Changed: tokens moved to keychain with transparent migration
and Settings banner on fallback.
- Changed: account cache is now HMAC-signed.
- Security: CWE-312 and CWE-345 explicitly closed.
Manual test matrix (pop-os + Windows) is tracked in issue #82 and
will be run by the release gatekeeper before the next tag.
Refs #66, #78, #79, #80, #81
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The listener `app.listen("deep-link://new-url", ...)` did not reliably
fire when tauri-plugin-single-instance (deep-link feature) forwarded a
simpl-resultat://auth/callback URL to the running instance. The user
saw the browser complete the OAuth flow, the app regain focus, and
then sit in "loading" forever because the listener never received the
URL.
Switch to the canonical Tauri v2 API — `app.deep_link().on_open_url()`
via DeepLinkExt — which is directly coupled to the deep-link plugin
and catches URLs from both initial launch and single-instance forwards.
Also surface OAuth error responses: if the callback URL contains an
`error` parameter instead of a `code`, emit `auth-callback-error` so
the UI can show the error instead of staying stuck in "loading".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The auto-update gate added in #48 requires the Base edition, but the
license server (#49) needed to grant Base does not exist yet. This
chicken-and-egg left the only current user — myself — unable to
receive the critical v0.7.1 OAuth callback fix via auto-update.
Add EDITION_FREE to the auto-update feature tiers as a temporary
measure. The gate will be restored to [BASE, PREMIUM] once paid
activation works end-to-end via the Phase 2 license server.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Maximus Account sign-in flow was broken in v0.7.0: clicking "Sign in"
opened Logto in the browser, but when the OAuth2 callback fired
simpl-resultat://auth/callback?code=..., the OS launched a second app
instance instead of routing the URL to the running one. The second
instance had no PKCE verifier in memory, and the original instance
never received the deep-link event, leaving it stuck in "loading".
Fix: register tauri-plugin-single-instance (with the deep-link feature)
as the first plugin. It forwards the callback URL to the existing
process, which triggers the existing deep-link://new-url listener and
completes the token exchange.
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
Adds .forgejo/workflows/check.yml (and a GitHub mirror) that runs on
every branch push (except main) and on every PR targeting main.
Two parallel jobs:
- rust: cargo check + cargo test, with cargo registry/git/target caches
keyed on Cargo.lock. Installs the minimal Rust toolchain and the
webkit2gtk system deps that the tauri build script needs.
- frontend: npm ci + npm run build (tsc + vite) + npm test (vitest),
with the npm cache keyed on package-lock.json.
The Forgejo workflow uses the ubuntu:22.04 container pattern from
release.yml. The GitHub mirror uses native runners (ubuntu-latest)
since the GitHub mirror exists for portability and uses GitHub-native
actions.
Documents the new workflow in CLAUDE.md alongside release.yml so future
contributors know what CI runs before merge.
- 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>
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>
Includes fixes#34, #37, #39: budget prev year actuals, changelog sync via Vite, inline buildPrevYearTotalMap.
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>
- 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>
- 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>
- 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>
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>
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>