feat(onboarding): step cards of the Categories and Reports pages (#432) #445

Merged
maximus merged 2 commits from issue-432-cards-categories-reports into main 2026-10-16 00:38:00 +00:00
Owner

Generated autonomously by /autopilot run of 2026-10-13

Link 8 of 8 (the last) of the milestone planned-2026-10-12-retours-onboarding-v0171 (task T8). Stacked on #444 (issue-425-visit-steps).

What it does

The two visit steps added by #425 get their card. With this link the path no longer stops at step 5.

  • /categories: card "Step 5 of 8 · Browse categories and keywords" (the issue's text). It explains keywords and names "All keywords" by its own label (StepCardText.labels). The outline goes on "All keywords", never on "Reset", which is destructive. "Got it" leads to "Done." and "Next step: Categorize a transaction by hand →".
  • /reports: card "Step 8 of 8" (7 of 7 in Free). It covers the hub and names "Trends" by its label. The locked variant, which mentions the padlock, is used when the page's advancedLocked holds (license read and not entitled). The outline goes on the Trends card. "Got it" leads to "Done." and the end message.
  • D17: while the card shows and the step is not done, the Trends card also gets onNavigate={() => acknowledge("reports")}, called on click before the navigation. Following the ring leaves the page, which releases the card latch, so the click checks the step. The local ACKNOWLEDGE wins over the re-read the route change starts (ADR 0022 §4, unchanged).
  • Opening either page without a click checks nothing (pinned by both page tests).

Changes

  • src/utils/onboardingPath.ts: CARD_PAGES and PAGE_STEPS gain /categories and /reports. New categoriesCardModel(checklist) and reportsCardModel(checklist, advancedLocked), with their target types.
  • src/pages/CategoriesPage.tsx: <OnboardingStepCard> first, and onboardingTargetAttributes(CATEGORIES_ALL_KEYWORDS_TARGET, …) on "All keywords" while the card shows.
  • src/pages/ReportsPage.tsx: the card first. Only the Trends card gets onboardingTarget + onNavigate.
  • src/components/reports/HubReportNavCard.tsx: optional onboardingTarget (highlight attributes on its Link, REPORTS_TRENDS_TARGET) and onNavigate (the Link's onClick).
  • i18n: onboarding.card.categories and onboarding.card.reports.{all,locked}, FR and EN word for word. docs.gettingStarted.subsections[0].steps[2] names the five card pages, "Got it" and the Trends card.
  • Docs: guide §1 item 3 (same text). architecture.md: card pages, the two models, the two targets, onNavigate / D17. QA list (docs/qa-onboarding.html): steps 5 and 8 of the guided walk (guided-categories, guided-reports), v0171-reports-free-padlock and v0171-reports-trends-click. The guided-list case no longer calls Categories a page without a card.
  • CHANGELOG: the #425 Added entry is completed with the plan's clause, in both files.
  • ADR 0022 needs no change: "Got it" and the Trends click both go through acknowledge, and so through the ACKNOWLEDGE that #425 already wrote into §2, §4 and §5.

Tests

  • onboardingPath.test.ts:
    • stepsOfPage, CARD_PAGES (/reports/trends is not a card page);
    • cardStep: /categories 5/8, /reports 8/8 and 7/7 in Free, null before the visit steps' initialization;
    • cardNext: after Categories the next step is manualCategory, after Reports the end;
    • both models: done, all, locked, skipped is not done, targets, FR/EN sentences through the real i18n.
  • HubReportNavCard.render.test.tsx (new): highlight only with onboardingTarget. Called as a function, its Link's onClick calls onNavigate.
  • CategoriesPage.render.test.tsx (new):
    • card first, 5/8, sentence;
    • one ring, on "All keywords" and not "Reset";
    • "Done." then the manual category;
    • no card or ring off card mode, no acknowledgement on open.
  • ReportsPage.render.test.tsx (new):
    • card first, 8/8, all / locked (7/7), and no padlock sentence before the license is read;
    • one ring on Trends, the other cards without props;
    • onNavigate acknowledges reports;
    • "Done." plus the end message, no ring, Trends back to a plain link;
    • nothing off card mode.
  • OnboardingStepCard.test.tsx: the /stand-in-categories mock is removed. "Got it" is tested on the real /categories (5/8) and /reports (8/8) routes.

Decisions (details in the run's decisions log)

  • [MEDIUM] Target keys exported next to their control, following TRANSACTION_CATEGORY_TARGET.
  • [MEDIUM] Page render tests added beyond the plan's file list (the real pages are wired and tested), and the stand-in route is removed.
  • [MEDIUM] Guide wording "la carte se termine par « J'ai compris », qui coche l'étape" instead of the plan's "se ferme": the card stays after "Got it" to say "Done.".
  • [MEDIUM] QA: guided-list moved from Categories to Settings as its "page without a card". Four cases added.
  • [MEDIUM] Existing drift left as is: the /reports row of architecture.md says "4 cartes" (there are 5).
  • [HIGH] Trends props only while showsStepCard holds and the step is not done. CHANGELOG clause word for word.

Proof table (mutations, one at a time, restored by git checkout, on the committed implementation 00be287)

# Mutation Result
M1 /categories removed from CARD_PAGES red (1)
M2 /reports removed from PAGE_STEPS red (10)
M3 categoriesCardModel ignores the done step red (2)
M4 categoriesCardModel checks manualCategory red (2)
M5 reportsCardModel locked variant inverted red (6)
M6 reportsCardModel ignores the done step red (2)
M7 trends label dropped red (6)
M8 Categories ring shown without the card red (1)
M9 ring also put on "Reset" red (1)
M10 no step card on Categories red (4)
M11 Trends targeted without the card red (1)
M12 Trends still targeted once the step is done red (1)
M13 Trends click acknowledges categories red (1)
M14 ReportsPage passes advancedLocked = false red (1)
M15 HubReportNavCard drops onNavigate red (1)
M16 HubReportNavCard always highlighted red (4)
M17 no step card on Reports red (5)

Validation

  • npm run build green (tsc covers the test files).
  • npm test: 130 files, 2222 tests, all green.
  • No Rust change, no migration (v1 to v17 unchanged), no network call, no Journal line.

🤖 Generated with Claude Code

Generated autonomously by /autopilot run of 2026-10-13 Link 8 of 8 (the last) of the milestone `planned-2026-10-12-retours-onboarding-v0171` (task T8). Stacked on #444 (`issue-425-visit-steps`). ## What it does The two visit steps added by #425 get their card. With this link the path no longer stops at step 5. - **`/categories`**: card "Step 5 of 8 · Browse categories and keywords" (the issue's text). It explains keywords and names "All keywords" by its own label (`StepCardText.labels`). The outline goes on "All keywords", never on "Reset", which is destructive. "Got it" leads to "Done." and "Next step: Categorize a transaction by hand →". - **`/reports`**: card "Step 8 of 8" (7 of 7 in Free). It covers the hub and names "Trends" by its label. The `locked` variant, which mentions the padlock, is used when the page's `advancedLocked` holds (license read and not entitled). The outline goes on the Trends card. "Got it" leads to "Done." and the end message. - **D17**: while the card shows and the step is not done, the Trends card also gets `onNavigate={() => acknowledge("reports")}`, called on click before the navigation. Following the ring leaves the page, which releases the card latch, so the click checks the step. The local `ACKNOWLEDGE` wins over the re-read the route change starts (ADR 0022 §4, unchanged). - Opening either page without a click checks nothing (pinned by both page tests). ## Changes - `src/utils/onboardingPath.ts`: `CARD_PAGES` and `PAGE_STEPS` gain `/categories` and `/reports`. New `categoriesCardModel(checklist)` and `reportsCardModel(checklist, advancedLocked)`, with their target types. - `src/pages/CategoriesPage.tsx`: `<OnboardingStepCard>` first, and `onboardingTargetAttributes(CATEGORIES_ALL_KEYWORDS_TARGET, …)` on "All keywords" while the card shows. - `src/pages/ReportsPage.tsx`: the card first. Only the Trends card gets `onboardingTarget` + `onNavigate`. - `src/components/reports/HubReportNavCard.tsx`: optional `onboardingTarget` (highlight attributes on its `Link`, `REPORTS_TRENDS_TARGET`) and `onNavigate` (the `Link`'s `onClick`). - i18n: `onboarding.card.categories` and `onboarding.card.reports.{all,locked}`, FR and EN word for word. `docs.gettingStarted.subsections[0].steps[2]` names the five card pages, "Got it" and the Trends card. - Docs: guide §1 item 3 (same text). `architecture.md`: card pages, the two models, the two targets, `onNavigate` / D17. QA list (`docs/qa-onboarding.html`): steps 5 and 8 of the guided walk (`guided-categories`, `guided-reports`), `v0171-reports-free-padlock` and `v0171-reports-trends-click`. The `guided-list` case no longer calls Categories a page without a card. - CHANGELOG: the #425 Added entry is completed with the plan's clause, in both files. - ADR 0022 needs no change: "Got it" and the Trends click both go through `acknowledge`, and so through the `ACKNOWLEDGE` that #425 already wrote into §2, §4 and §5. ## Tests - `onboardingPath.test.ts`: - `stepsOfPage`, `CARD_PAGES` (`/reports/trends` is not a card page); - `cardStep`: `/categories` 5/8, `/reports` 8/8 and 7/7 in Free, null before the visit steps' initialization; - `cardNext`: after Categories the next step is `manualCategory`, after Reports the end; - both models: done, `all`, `locked`, skipped is not done, targets, FR/EN sentences through the real i18n. - `HubReportNavCard.render.test.tsx` (new): highlight only with `onboardingTarget`. Called as a function, its `Link`'s `onClick` calls `onNavigate`. - `CategoriesPage.render.test.tsx` (new): - card first, 5/8, sentence; - one ring, on "All keywords" and not "Reset"; - "Done." then the manual category; - no card or ring off card mode, no acknowledgement on open. - `ReportsPage.render.test.tsx` (new): - card first, 8/8, `all` / `locked` (7/7), and no padlock sentence before the license is read; - one ring on Trends, the other cards without props; - `onNavigate` acknowledges `reports`; - "Done." plus the end message, no ring, Trends back to a plain link; - nothing off card mode. - `OnboardingStepCard.test.tsx`: the `/stand-in-categories` mock is removed. "Got it" is tested on the real `/categories` (5/8) and `/reports` (8/8) routes. ## Decisions (details in the run's decisions log) - [MEDIUM] Target keys exported next to their control, following `TRANSACTION_CATEGORY_TARGET`. - [MEDIUM] Page render tests added beyond the plan's file list (the real pages are wired and tested), and the stand-in route is removed. - [MEDIUM] Guide wording "la carte se termine par « J'ai compris », qui coche l'étape" instead of the plan's "se ferme": the card stays after "Got it" to say "Done.". - [MEDIUM] QA: `guided-list` moved from Categories to Settings as its "page without a card". Four cases added. - [MEDIUM] Existing drift left as is: the `/reports` row of `architecture.md` says "4 cartes" (there are 5). - [HIGH] Trends props only while `showsStepCard` holds and the step is not done. CHANGELOG clause word for word. ## Proof table (mutations, one at a time, restored by `git checkout`, on the committed implementation `00be287`) | # | Mutation | Result | |---|---|---| | M1 | `/categories` removed from `CARD_PAGES` | red (1) | | M2 | `/reports` removed from `PAGE_STEPS` | red (10) | | M3 | `categoriesCardModel` ignores the done step | red (2) | | M4 | `categoriesCardModel` checks `manualCategory` | red (2) | | M5 | `reportsCardModel` locked variant inverted | red (6) | | M6 | `reportsCardModel` ignores the done step | red (2) | | M7 | `trends` label dropped | red (6) | | M8 | Categories ring shown without the card | red (1) | | M9 | ring also put on "Reset" | red (1) | | M10 | no step card on Categories | red (4) | | M11 | Trends targeted without the card | red (1) | | M12 | Trends still targeted once the step is done | red (1) | | M13 | Trends click acknowledges `categories` | red (1) | | M14 | ReportsPage passes `advancedLocked = false` | red (1) | | M15 | `HubReportNavCard` drops `onNavigate` | red (1) | | M16 | `HubReportNavCard` always highlighted | red (4) | | M17 | no step card on Reports | red (5) | ## Validation - `npm run build` green (tsc covers the test files). - `npm test`: 130 files, 2222 tests, all green. - No Rust change, no migration (v1 to v17 unchanged), no network call, no Journal line. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
maximus added 2 commits 2026-10-14 01:49:32 +00:00
The two visit steps get their card: /categories explains keywords and
points at "All keywords" (never "Reset"), /reports explains the hub and
points at the Trends card, with a padlock variant in the Free edition.
"Got it" acknowledges the step; opening the highlighted Trends card does
too (D17), since following the ring leaves the page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs(onboarding): cards of the Categories and Reports pages
All checks were successful
PR Check — Frontend / frontend (pull_request) Successful in 1m57s
934bcbf9aa
Guide and in-app docs name the five card pages, "Got it" on the two
visit cards and the Trends card that also checks the reports step;
architecture lists the new models and targets; the QA list gets the
steps 5 and 8 of the guided walk, the Free padlock variant and the
Trends click.

Resolves #432

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
maximus added the
autopilot:pending-human
label 2026-10-14 01:49:39 +00:00
Author
Owner

Self-review (autopilot worker, not independent): APPROVE

Generated autonomously by /autopilot run of 2026-10-13. I read the full diff of PR #445 against issue-425-visit-steps, 16 files.

Acceptance criteria of #432

  • After the import, "Next step" leads to /categories. The import card's cardNext gives the categories step (to: "/categories"), and /categories is now in CARD_PAGES, so the card latches there. The card explains keywords, outlines "All keywords" and announces the keyword added at the next step. Pinned by CategoriesPage.render.test.tsx and by M1, M8, M9 and M10.
  • "Got it" checks the step, then the card shows "Done." and "Categorize a transaction by hand". This goes through acknowledge("categories") on the real /categories route (OnboardingStepCard.test.tsx), and cardNext gives manualCategory (path test). Render after acknowledgement: "Done.", the manual-category link, no ring.
  • On /reports, the card outlines the Trends card, the only ring (M11, M12, M16). In Free it mentions the padlock (M5, M14). "Got it" or opening Trends checks the step (M13, M15). When it was the last step, the card shows the end message (render test), and the banner says "Getting started complete" on the page you land on, through the existing bannerMode and the QA case v0171-reports-trends-click.
  • Opening either page without a click checks nothing (both page tests assert that acknowledge and skip are not called).
  • FR and EN complete, with the texts word for word (sentences asserted through the real i18n in both languages). Build green, 130 files and 2222 tests green.

Other checks

  • Security: no new write path. onNavigate calls only the provider's acknowledge, which writes a fixed preference. No Journal line, no network call, no destructive control targeted: "Reset" is never outlined, see M9.
  • Regressions: other report cards get no prop (asserted). HubReportNavCard without the new props renders as before: no onClick, no attributes, lock badge unchanged.
  • Race: on a Trends click, the route-change re-read starts while the write is in flight. ACKNOWLEDGE takes acknowledgedSetAt = loadSeq, so the older snapshot cannot undo it (ADR 0022 §4, unchanged).
  • No SQL migration touched. CHANGELOG updated in both files under [Unreleased]. Docs rule followed: guide plus docs.*, architecture.md, QA list. No new ADR needed: no new pattern, D17 was already noted in architecture.md by #425.

For the reviewer to judge

  • In the Free edition, before the license is read (ready false), the Reports card shows the all sentence, then switches to locked. This follows the page's own advancedLocked and the padlocks, which wait for the license in the same way. The switch is short and the test pins it.
  • The guide says "la carte se termine par « J'ai compris »" rather than the plan's "se ferme par": the card stays open after "Got it".
  • The page render tests and the removal of the stand-in route go beyond the plan's file list.
## Self-review (autopilot worker, not independent): APPROVE Generated autonomously by /autopilot run of 2026-10-13. I read the full diff of PR #445 against `issue-425-visit-steps`, 16 files. **Acceptance criteria of #432** - [x] After the import, "Next step" leads to `/categories`. The import card's `cardNext` gives the categories step (`to: "/categories"`), and `/categories` is now in `CARD_PAGES`, so the card latches there. The card explains keywords, outlines "All keywords" and announces the keyword added at the next step. Pinned by `CategoriesPage.render.test.tsx` and by M1, M8, M9 and M10. - [x] "Got it" checks the step, then the card shows "Done." and "Categorize a transaction by hand". This goes through `acknowledge("categories")` on the real `/categories` route (`OnboardingStepCard.test.tsx`), and `cardNext` gives `manualCategory` (path test). Render after acknowledgement: "Done.", the manual-category link, no ring. - [x] On `/reports`, the card outlines the Trends card, the only ring (M11, M12, M16). In Free it mentions the padlock (M5, M14). "Got it" or opening Trends checks the step (M13, M15). When it was the last step, the card shows the end message (render test), and the banner says "Getting started complete" on the page you land on, through the existing `bannerMode` and the QA case `v0171-reports-trends-click`. - [x] Opening either page without a click checks nothing (both page tests assert that `acknowledge` and `skip` are not called). - [x] FR and EN complete, with the texts word for word (sentences asserted through the real i18n in both languages). Build green, 130 files and 2222 tests green. **Other checks** - Security: no new write path. `onNavigate` calls only the provider's `acknowledge`, which writes a fixed preference. No Journal line, no network call, no destructive control targeted: "Reset" is never outlined, see M9. - Regressions: other report cards get no prop (asserted). `HubReportNavCard` without the new props renders as before: no `onClick`, no attributes, lock badge unchanged. - Race: on a Trends click, the route-change re-read starts while the write is in flight. `ACKNOWLEDGE` takes `acknowledgedSetAt = loadSeq`, so the older snapshot cannot undo it (ADR 0022 §4, unchanged). - No SQL migration touched. CHANGELOG updated in both files under `[Unreleased]`. Docs rule followed: guide plus `docs.*`, `architecture.md`, QA list. No new ADR needed: no new pattern, D17 was already noted in `architecture.md` by #425. **For the reviewer to judge** - In the Free edition, before the license is read (`ready` false), the Reports card shows the `all` sentence, then switches to `locked`. This follows the page's own `advancedLocked` and the padlocks, which wait for the license in the same way. The switch is short and the test pins it. - The guide says "la carte se termine par « J'ai compris »" rather than the plan's "se ferme par": the card stays open after "Got it". - The page render tests and the removal of the stand-in route go beyond the plan's file list.
Author
Owner

CI lue par l'orchestrateur sur la tête 934bcbf : PR Check — Frontend run 551 vert (build OK, vitest 130 fichiers / 2222 tests, comptes égaux à ceux du worker). Pas de job Rust attendu.

Generated autonomously by /autopilot run of 2026-10-13

CI lue par l'orchestrateur sur la tête `934bcbf` : **PR Check — Frontend** run 551 vert (build OK, vitest 130 fichiers / 2222 tests, comptes égaux à ceux du worker). Pas de job Rust attendu. Generated autonomously by /autopilot run of 2026-10-13
Author
Owner

Verdict : APPROVE

Résumé : les cartes d'étape de Catégories et de Rapports sont branchées comme celles d'Import, de Transactions et de Budget. Le contour suit showsStepCard et l'état de l'étape. Le clic sur Tendances (D17) passe par le même acknowledge que « J'ai compris ». Les textes FR/EN correspondent au code : tri ORDER BY priority DESC dans categorizationService, panneau des faits saillants (solde courant, solde cumulatif, plus gros mouvements), Tendances jamais verrouillée.

Preuves rejouées par le relecteur (tête 934bcbf, worktree détaché, npm ci propre)

  • npm run build vert ; vitest run : 130 fichiers, 2222 tests verts.
  • CI de la tête : success (statut agrégé).
  • Huit mutations du relecteur, une à la fois, restaurées par git checkout :
# Mutation Résultat
R1 categoriesCardModel garde la cible une fois l'étape faite rouge (2)
R2 advancedLocked = !advancedAllowed (cadenas avant la lecture de la licence) rouge (1)
R3 onClick={onNavigate} retiré du Link rouge (1)
R4 contour Tendances sans showsStepCard rouge (1)
R5 contour « Tous les mots-clés » sans showsStepCard rouge (1)
R6 libellé trends pointé sur reports.hub.compare rouge (6)
R7 reportsCardModel ignore l'étape faite rouge (2)
R8 libellé allKeywords pointé sur categories.reinitialize rouge (3)

Suggestions (non bloquantes)

  1. Le corps de la PR ne porte pas de mot-clé de fermeture : la timeline de #432 montre ref_action: none. Le seul Resolves #432 est dans le message du commit 934bcbf. Il fermera l'issue avec un merge ff (/merge-stack), qui lit les messages de commit, mais pas avec un merge par commit de merge, qui lit le corps. Ajouter Resolves #432 au corps pour ne pas dépendre du chemin de merge.
  2. onNavigate part aussi sur un clic du milieu ou un Ctrl+clic. Dans le webview Tauri, ces clics n'ouvrent pas d'onglet, donc l'étape cochée sans navigation reste théorique.
  3. La dérive « 4 cartes » de la ligne /reports de docs/architecture.md, signalée dans le corps, reste à corriger dans un suivi.

Actions faites

  • Worktree de revue et scripts de mutation supprimés en fin de revue.
  • #432 : status:review → status:approved.
## Verdict : APPROVE **Résumé** : les cartes d'étape de Catégories et de Rapports sont branchées comme celles d'Import, de Transactions et de Budget. Le contour suit `showsStepCard` et l'état de l'étape. Le clic sur Tendances (D17) passe par le même `acknowledge` que « J'ai compris ». Les textes FR/EN correspondent au code : tri `ORDER BY priority DESC` dans `categorizationService`, panneau des faits saillants (solde courant, solde cumulatif, plus gros mouvements), Tendances jamais verrouillée. ### Preuves rejouées par le relecteur (tête `934bcbf`, worktree détaché, `npm ci` propre) - `npm run build` vert ; `vitest run` : 130 fichiers, 2222 tests verts. - CI de la tête : `success` (statut agrégé). - Huit mutations du relecteur, une à la fois, restaurées par `git checkout` : | # | Mutation | Résultat | |---|---|---| | R1 | `categoriesCardModel` garde la cible une fois l'étape faite | rouge (2) | | R2 | `advancedLocked = !advancedAllowed` (cadenas avant la lecture de la licence) | rouge (1) | | R3 | `onClick={onNavigate}` retiré du `Link` | rouge (1) | | R4 | contour Tendances sans `showsStepCard` | rouge (1) | | R5 | contour « Tous les mots-clés » sans `showsStepCard` | rouge (1) | | R6 | libellé `trends` pointé sur `reports.hub.compare` | rouge (6) | | R7 | `reportsCardModel` ignore l'étape faite | rouge (2) | | R8 | libellé `allKeywords` pointé sur `categories.reinitialize` | rouge (3) | ### Suggestions (non bloquantes) 1. Le corps de la PR ne porte pas de mot-clé de fermeture : la timeline de #432 montre `ref_action: none`. Le seul `Resolves #432` est dans le message du commit `934bcbf`. Il fermera l'issue avec un merge ff (/merge-stack), qui lit les messages de commit, mais pas avec un merge par commit de merge, qui lit le corps. Ajouter `Resolves #432` au corps pour ne pas dépendre du chemin de merge. 2. `onNavigate` part aussi sur un clic du milieu ou un Ctrl+clic. Dans le webview Tauri, ces clics n'ouvrent pas d'onglet, donc l'étape cochée sans navigation reste théorique. 3. La dérive « 4 cartes » de la ligne `/reports` de `docs/architecture.md`, signalée dans le corps, reste à corriger dans un suivi. ### Actions faites - Worktree de revue et scripts de mutation supprimés en fin de revue. - #432 : `status:review` → `status:approved`.
maximus changed target branch from issue-425-visit-steps to main 2026-10-16 00:37:51 +00:00
maximus merged commit 934bcbf9aa into main 2026-10-16 00:38:00 +00:00
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#445
No description provided.