Skip to content

DJ-92: Account Overview dashboard (/api/account-summary + Angular /dashboard) - #30

Open
devin-ai-integration[bot] wants to merge 7 commits into
mainfrom
devin/1755440000-dj92-account-summary-dashboard
Open

DJ-92: Account Overview dashboard (/api/account-summary + Angular /dashboard)#30
devin-ai-integration[bot] wants to merge 7 commits into
mainfrom
devin/1755440000-dj92-account-summary-dashboard

Conversation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Summary

DJ-92 — first user-facing summary screen: a read-only aggregation endpoint plus an authenticated Angular page at /dashboard showing total balance, per-account balances and the 10 most recent operations. Backend and frontend were built in parallel against the contract frozen in docs/account-summary-contract.md (copied verbatim from DJ-92), which is the single source of truth for both sides.

Backend — GET /api/account-summary

Authenticated-only (anonymous → 401), AccountSummaryResourceAccountSummaryService (@Transactional(readOnly = true)).

Aggregation is 4 fixed queries — no N+1 per account:

bankAccountRepository.sumBalances()                    -- coalesce(sum(balance), 0)
bankAccountRepository.findBalancesWithOperationCount() -- left join + group by, one row per account
operationRepository.findRecentOperations(PageRequest.of(0, 10))
                                                       -- order by date desc, id desc (deterministic tie-break)
operationRepository.count()

The repository methods return nested interface projections (AccountBalanceProjection, RecentOperationProjection) rather than the service DTOs, because the project's ArchUnit rule forbids repositoryservice dependencies; AccountSummaryService maps projections to DTOs.

Contract invariants enforced in the DTOs, not the callers: monetary fields are setScale(2, HALF_UP) in their setters, totalBalance defaults to 0.00, and the arrays default to empty so they are never null on an empty database.

Frontend — /dashboard

Lazy standalone component guarded by UserRouteAccessService (anonymous SPA navigation redirects to login), reached from the navbar and a home-page link, all strings via i18n. DashboardService follows the existing service shape:

resourceUrl = applicationConfigService.getEndpointFor('api/account-summary');
getSummary(): Observable<AccountSummary> // maps recentOperations[].date: string -> dayjs.Dayjs

Signals + inject(); amounts via the currency pipe, dates via the shared FormatMediumDatetimePipe; separate empty states for accounts (#no-accounts) and operations (#no-operations).

The temporary mock used while the endpoint was being built in parallel is gone — getSummary() always hits HTTP; only HttpTestingController and the component-level service stub remain, inside dashboard.spec.ts.

Verification

Gates: ./mvnw verify (168 tests), ./npmw test (404 tests), ./npmw run lint, ./mvnw -Pprod clean verify — all green.

End-to-end against the running app with data seeded through the existing entity screens: total balance $176,885.48 matches the sum of the 12 accounts, operation count and per-account counts match, recent operations are date-desc and capped at 10, negative amounts render as -$54.20. Anonymous curl /api/account-summary401; anonymous /dashboard → redirected to /login. Empty state is covered by AccountSummaryResourceIT and dashboard.spec.ts.

Before

before

After

after

Link to Devin session: https://partner-workshops.devinenterprise.com/sessions/207f4f91b2fc4bfba4446fddf35f5546
Requested by: @neilspalding-hub

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

DJ-92 verified end-to-end

Tested against the running dev stack (Spring Boot :8080 + Angular :9000, H2 dev data). Raw GET /api/account-summary JSON, fetched with an admin JWT, was used as ground truth and compared against the rendered page.

Recording of the full run

Dashboard renders live data from /api/account-summary

Cards matched the API JSON exactly (totalBalance 176885.48, accountCount 12, operationCount 12), 12 account rows in id order with per-account operation counts, and exactly 10 recent operations in date-descending order with formatted datetimes and currency (negative renders as -$54.20).

Dashboard loaded from /api/account-summary

To prove the figures are live and not a fixture, a new bank account (DJ92 Test Account, $1,000) and a new operation (DJ92 Newest Op, -$12.34) were created through the existing entity screens. The dashboard moved by the exact expected delta → $177,885.48 / 13 / 13, the new account row shows $1,000.00 / 1 operation, and the new operation became row 1 of the recent list while the list stayed capped at 10 rows (the previously-oldest row dropped off).

Dashboard after creating an account and operation

Recent operations capped at 10, date-descending

Navigation + auth gating
  • Navbar "Dashboard" link and home-page "View account summary" button both route to /dashboard.
  • Unauthenticated GET /api/account-summaryHTTP 401.
  • After sign out, navigating to /dashboard redirects to /login; the navbar link and home button are hidden for anonymous users.

Signed out: /dashboard redirects to /login

Cosmetic observations (not blockers)
  • The "Account" column is blank for faker-seeded operations because the API returns bankAccountName: null for them (those seed rows have no bank account). UI-created operations show the account name correctly.
  • Amounts use the default currency pipe with no explicit currency code, so they render as $ under the default locale.

Written by Devin

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.

0 participants