Overview
⚠️ Depends on: #42 (GF-09 — Wallet Integration) and #44 (GF-12 — Data Service Layer).
Build the portfolio page — the primary logged-in view showing a user's active positions, accrued yield, lock countdowns, and available actions. This is the page users will return to most often after depositing.
Problem
No portfolio view exists anywhere in the app. After a user deposits, there is no way for them to:
- See their positions
- Track accrued yield
- Know when their lock expires
- Withdraw or early exit
The dashboard (app/src/app/dashboard/page.tsx) only shows static vault tier info, not user-specific position data.
Proposed Solution
Create app/src/app/portfolio/page.tsx
Portfolio summary card (top of page)
- Total USDC deposited across all tiers
- Total accrued yield (live, updating)
- Blended APY across all positions
- Number of active positions
Position cards (one per active tier)
Each position card shows:
- Tier name and share multiplier
- Principal deposited
- Shares held
- Accrued yield (calculated from share value delta since deposit, updating every 30 seconds)
- Lock expiry: either
Unlocked (Flex) or a countdown: Expires in 47 days with the exact date
- Withdraw button — enabled only when
current_ledger >= lock_until (or always for Flex); calls sdk.withdraw({ tier }) from GF-08
- Early Exit button — always shown for locked tiers; shows the fee and net amount in a confirmation modal before submitting; calls
sdk.earlyExit({ tier })
Yield history chart
A simple line chart (use recharts or chart.js) showing cumulative yield earned over time per position, using harvest event history from the data layer (GF-12).
CSV export
A Download CSV button that exports a table of all transactions (deposits, withdrawals, harvests attributed to the user) for tax reporting purposes. Columns: date, type, tier, amount, tx hash.
Empty state
If the wallet has no positions, show an encouraging empty state with a Deposit Now link to /deposit.
Navigation
Add a Portfolio link to the main nav (visible only when wallet is connected).
Acceptance Criteria
Overview
Build the portfolio page — the primary logged-in view showing a user's active positions, accrued yield, lock countdowns, and available actions. This is the page users will return to most often after depositing.
Problem
No portfolio view exists anywhere in the app. After a user deposits, there is no way for them to:
The dashboard (
app/src/app/dashboard/page.tsx) only shows static vault tier info, not user-specific position data.Proposed Solution
Create
app/src/app/portfolio/page.tsxPortfolio summary card (top of page)
Position cards (one per active tier)
Each position card shows:
Unlocked(Flex) or a countdown:Expires in 47 dayswith the exact datecurrent_ledger >= lock_until(or always for Flex); callssdk.withdraw({ tier })from GF-08sdk.earlyExit({ tier })Yield history chart
A simple line chart (use
rechartsorchart.js) showing cumulative yield earned over time per position, using harvest event history from the data layer (GF-12).CSV export
A
Download CSVbutton that exports a table of all transactions (deposits, withdrawals, harvests attributed to the user) for tax reporting purposes. Columns: date, type, tier, amount, tx hash.Empty state
If the wallet has no positions, show an encouraging empty state with a
Deposit Nowlink to/deposit.Navigation
Add a
Portfoliolink to the main nav (visible only when wallet is connected).Acceptance Criteria
/portfoliopage exists and requires wallet connection (redirects to connect flow if not connected)Withdrawbutton is disabled before lock expiry and enabled at maturityEarly Exitbutton shows fee and net amount in a confirmation modal before submitting