feat: add holdings management UI for manual investment accounts#196
feat: add holdings management UI for manual investment accounts#196moltboie wants to merge 3 commits intohoiekim:mainfrom
Conversation
moltboie
left a comment
There was a problem hiding this comment.
Self-Review
Implementation verified
HoldingsManager renders for manual investment accounts only — check in AccountProperties/index.tsx:
{isManualAccount && type === AccountType.Investment && (
<HoldingsManager accountId={account_id} />
)}isManualAccount comes from item provider check. AccountType.Investment gates the investment-specific section.
API integration — GET, POST, DELETE all wired to the new endpoints from #195.
Snapshot date follows the issue spec: viewDate.getEndDate().toISOString().split('T')[0] — same pattern as the balance snapshot date behavior.
Holdings sync — POST handler now calls upsertHoldings after saving snapshot. Sync uses holding_id = ${account_id}-${security_id}`` which matches the existing convention in upsertHoldings.
Security info in GET response — searchSecuritiesById batch-fetches all unique security_ids, avoiding N+1 calls.
Not tested in this review
- Live server test with Polygon API key (needed for ticker validation against external API)
- Manual e2e with actual account in dev DB
CI
Build passes (verified locally with bun run build). No TypeScript errors.
Self-ReviewDiscussion thread status:
Checked:
E2E Testing:
Issues found:
Confidence: Medium (logic is correct; the IDOR and type coercion issues should be fixed before merge) |
2af49ea to
0a34093
Compare
0a34093 to
0b72b34
Compare
|
Rebased on main. The #195 (snapshot API) commit was already merged upstream and has been dropped from this branch — now a single commit on top of main. |
0b72b34 to
c49c3b9
Compare
|
Branch already rebased on main (March 26). The #195 holding snapshot commit has been merged upstream and dropped from this branch — now a single commit on top of current main. Ready for re-review. |
89d74de to
9cadfee
Compare
|
Rebased on main. |
1 similar comment
|
Rebased on main. |
32d9ab0 to
6587550
Compare
|
Rebased on main. |
6587550 to
b21937f
Compare
b21937f to
21974a1
Compare
2401faf to
19e9087
Compare
Self-Review (April 1, 2026)Rebased on upstream/main. Two new commits since last self-review (March 14):
Discussion thread status:
Checked:
Coding rules check:
E2E Testing:
Confidence: High |
19e9087 to
9c41cb8
Compare
79fb1b0 to
8af7177
Compare
9c41cb8 to
4464fd2
Compare
Self-Review (April 26, 2026)Rebased on Discussion thread status
Logic
TypesClean. No QualityCSS now uses the existing Security
TestsNo unit tests for the new routes. The route patterns mirror existing snapshot routes which also lack tests — adding coverage is tracked separately under the test-coverage initiative. E2E (local, against real DB)Started
BlockersNone. Confidence: High — feature works end-to-end, rebase clean, CI green, no open feedback. |
4464fd2 to
cb7553e
Compare
Self-Review (April 29, 2026)Re-running review since the branch was rebased on Discussion thread status
Checked
Coding rules check
E2E Testing
Issues found
Confidence: Medium-High(no |
Implements budget/hoiekim#42: - HoldingsManager component: renders in AccountProperties for manual investment accounts only - Fetches all holding snapshots for the account via GET /api/snapshots/holding - Add holding form: ticker input with validation, quantity, cost basis (optional), snapshot date (view date end date) - Remove holding snapshot with confirmation - GET /api/snapshots/holding now returns ticker_symbol and security_name alongside each snapshot (batch security lookup, single round trip) - POST /api/snapshots/holding now syncs to the holdings table so the current portfolio value reflects the latest snapshot (Holdings-to- Current-Holdings Sync from issue spec) Closes hoiekim#42
Replace custom table-layout classes (holdingRow, col.ticker, col.qty, etc.) with the existing div.Properties pattern: - Each holding renders as a .row.keyValue with propertyName label (ticker) and a holdingDetail span (qty/cost/date inline + delete btn) - Remove custom holdingsHeader, holdingsList, col.* CSS entirely - Form rows already used propertyName/.row.keyValue — no change needed - Keep only component-specific styles: tickerField, feedback states, formActions, validateBtn/submitBtn/cancelBtn
cb7553e to
d887241
Compare
Summary
Implements budget/#42 — Holdings management UI for manual investment accounts.
Changes
Client:
HoldingsManagercomponentsrc/client/components/HoldingsManager/componentAccountPropertiesfor manual investment accounts only (hidden for depository, credit, etc.)/api/validate-ticker), quantity, optional cost basis, snapshot date (auto-set to view date end date per issue spec)Server: GET
/api/snapshots/holdingticker_symbolandsecurity_namealongside each snapshot (batch-fetched viasearchSecuritiesById) — single round trip, no extra client callsServer: POST
/api/snapshots/holding— Holdings syncupsertHoldingsso theholdingstable reflects the latest snapshotTesting
Closes #42