Skip to content

v2: accounts list + detail pages with inline account linking#1104

Merged
canalesb93 merged 4 commits into
mainfrom
claude/v2-accounts-page-20260515-223740
May 16, 2026
Merged

v2: accounts list + detail pages with inline account linking#1104
canalesb93 merged 4 commits into
mainfrom
claude/v2-accounts-page-20260515-223740

Conversation

@canalesb93
Copy link
Copy Markdown
Owner

@canalesb93 canalesb93 commented May 16, 2026

Summary

Adds the Accounts surface to the v2 SPA: a list page grouped by institution or type, and a per-account detail page that hosts inline rename, exclude, and account linking (which is now scoped to the account it's set up on, since the top-level Account links page was removed in #1098).

What's new

  • /v2/accounts — list grouped by institution (default) or type, with a net-worth/assets/liabilities strip, family-member tab filter, dependent badges, credit utilization bars, and inline connection-status pills for accounts on a degraded connection. Pulls from /api/v1/accounts.
  • /v2/accounts/$id — balance hero (sign-aware: "Balance owed" for credit/loan, "Current balance" otherwise), inline display-name editor, exclude-from-sync toggle, parent-connection link, the most recent 25 transactions, and an Account links card.
  • Account linking inline — the detail page lists every link this account participates in (as primary "covers" or as dependent "attributed to"), with reconcile + unlink dropdown actions. A LinkAccountSheet creates a new primary→dependent link, filtering out ineligible accounts (already-dependent, reverse-link conflicts) the way the backend would. Dependents themselves hide the linking UI to avoid offering an A→B→C chain the backend would reject.
  • Account links nav entry removed from the sidebar (it pointed at a page that no longer exists post-v2: simplify-pass over connections stack (stack 7/7) #1098). Setup now reads as Accounts / Connections.

Backend

Untouched — the page uses the existing /api/v1/accounts, /api/v1/accounts/{id}/detail, /api/v1/account-links (list / create / update / delete / reconcile) endpoints via new TanStack Query hooks in web/src/api/queries/{accounts,account-links}.ts. The Account TS type was widened to mirror the full AccountResponse (was a subset).

Conventions

  • Routes registered via PAGE_OVERRIDES + an explicit detail route in web/src/main.tsx.
  • Reusable atoms (AccountCard, AccountsSummary, account-utils) live under web/src/features/accounts/ — used only by these two routes for now, so feature-scoped per the v2 rules.
  • ShadCN toggle-group primitive installed for the institution/type grouping switch.
  • The list endpoint returns *_account_id as short_ids (cf. the project's compact-ID convention); the singular endpoints return UUIDs. The links section and link-sheet filter on short_id so the current shape works — noted inline.

Evidence

Validated in Chrome DevTools MCP against make dev on port 8082 (Plaid sandbox data). bun run lint and bun run build both pass.

Accounts list (desktop) — net-worth / assets / liabilities strip, institution grouping, credit-card sign flip on the Platinum row:
accounts list — desktop

Accounts list (mobile, 420px) — same content, single column:
accounts list — mobile

Account detail — credit card — "Balance owed $2,571.04" hero, settings card, empty account-links section, recent transactions:
account detail — credit card

Account detail — depository with active link — "Current balance $55,807.95", with an active "Primary · Covers → Essential Savings" link in the Account links section:
account detail — depository, with link

Link account sheet — primary fixed to the current account, dependent picker filters out ineligible accounts, tolerance defaults to 3 days:
link account sheet

Account detail — dependent state — the "Linked dependent" badge appears, the Link CTA is hidden, and the AccountLinksSection is suppressed:
account detail — dependent

I exercised the create + delete link flow end-to-end during validation (verified the dependent badge propagates and the link sheet's eligible-dependent filter updates after creation) and cleaned up the test link after capturing evidence.

Test plan

  • Click into each account from /v2/accounts and confirm the detail page loads with correct balance / utilization / recent transactions
  • Rename an account via the inline editor; confirm the list reflects the new name (cache invalidates on success)
  • Toggle "Exclude from sync" and confirm the badge appears in the hero
  • Link two of your own accounts via the sheet; confirm the dependent shows the "Linked dependent" badge and the link disappears from the eligible-dependent picker for other accounts
  • Unlink via the dropdown menu; confirm the dependent badge clears
  • Switch the grouping toggle on the list between Institution and Type and confirm the URL ?group= updates
  • On a single-user household, confirm no FamilyTabs render

🤖 Generated with Claude Code

canalesb93 and others added 4 commits May 15, 2026 22:55
Adds the Accounts surface to the v2 SPA. The list page groups every
account by institution or type, surfaces a net-worth / assets /
liabilities strip, and exposes a per-card link to the new detail page.
The detail page covers balance hero (sign-aware for liabilities,
utilization bar for credit), inline rename via display_name, exclude
toggle, recent transactions, and parent-connection link.

Account linking moves here from the removed top-level Account links
page: the detail page hosts a section listing every link the account
participates in (primary or dependent), with reconcile + unlink
actions, and a Sheet to create a new link from this account to an
eligible dependent. Dependents themselves hide the linking UI to
prevent A→B→C chains the backend would reject anyway.

Backend untouched — uses /api/v1/accounts, /api/v1/accounts/{id}/detail,
/api/v1/account-links. The Account interface is widened to mirror the
full AccountResponse (previously a subset). Existing connections page
+ connection detail page link through to the new account detail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Card primitive defaults to py-6 and I added py-4 on CardContent —
the two stacked into ~40px of vertical padding inside what's meant to
be a one-liner stat card. Override the Card wrapper to py-4 and drop
the redundant CardContent padding so the strip reads as a dense header
instead of a content panel.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The detail page was fighting the Card primitive's defaults. Two
problems:

  1. Stat cards (Balance, Details) split the label and value across
     CardHeader and CardContent. The Card's flex `gap-6` between
     children pushed the 24px of air between the label and the number
     that read as broken layout. The shadcn dashboard pattern puts
     CardDescription + CardTitle inside one CardHeader (gap-2) instead.
     Rewrote BalanceCard to do this — utilization bar / currency note
     move to CardFooter. Dropped the redundant "Details" header from
     SecondaryCard; the rows are self-labelling.

  2. Section cards (Settings, Account links, Recent transactions)
     used `pb-3` / `pb-2` overrides on CardHeader to tighten the gap.
     That class is a no-op without a border-b — only `[.border-b]:pb-6`
     responds to it — so the gap-6 was applying anyway. Removed the
     overrides and moved right-aligned actions (Link an account, Last
     N) into CardAction, which is the slot the Card grid is built to
     place them in (no flex justify-between hacks).

Result: stat cards now read as a polished label/value pair, sections
breathe with consistent vertical rhythm.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two follow-ups based on review:

- Row padding was py-3 (12px) while the Transactions page's TableCell
  is p-2 (8px), so rows on the account detail read as ~50% taller
  than the same data on the Tx page. Dropped to py-2 to match.

- Cap the recent-transactions list at 15 client-side. The detail
  endpoint returns up to 25; 25 is too many for a "preview" — the
  full list is one click away via the footer link.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@canalesb93 canalesb93 force-pushed the claude/v2-accounts-page-20260515-223740 branch from 984a1aa to 380eaf3 Compare May 16, 2026 05:55
@canalesb93 canalesb93 enabled auto-merge (squash) May 16, 2026 05:55
@canalesb93 canalesb93 merged commit 9ffe326 into main May 16, 2026
7 checks passed
@canalesb93 canalesb93 deleted the claude/v2-accounts-page-20260515-223740 branch May 16, 2026 05:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant