📄 Frontend Pages
Status: Implemented (Feb 2026)
📖 Overview
Application pages and routing structure. All authenticated routes are under (app)/. The build is
a static SPA: SSR is off in the root +layout.ts (FastAPI serves the static files), and only the
login page is prerendered.
🗺️ Page Structure
frontend/src/routes/
├── +layout.svelte # Root layout (i18n init, splash removal, <html lang>)
├── +layout.ts # ssr = false
├── +page.svelte # Login page (public)
├── +page.ts # prerender = true
├── +error.svelte # Error page
├── (app)/ # Authenticated routes
│ ├── +layout.svelte # App shell: auth check, bootstrap/onboarding gate, sidebar, header, guide host
│ ├── +layout.ts # ssr = false, prerender = false
│ ├── welcome/
│ │ └── +page.svelte # Welcome setup (onboarding), shown without the app shell
│ ├── dashboard/
│ │ └── +page.svelte # Main dashboard
│ ├── brokers/
│ │ ├── +page.svelte # Broker list
│ │ └── [id]/
│ │ ├── +page.svelte # Broker detail
│ │ └── +page.ts # Load function (brokerId)
│ ├── transactions/
│ │ ├── +page.svelte # Transactions list and management
│ │ └── filterState.ts # URL ⇄ filter state
│ ├── assets/
│ │ ├── +page.svelte # Assets list and management
│ │ └── [id]/
│ │ ├── +page.svelte # Asset detail
│ │ └── +page.ts # Load function (assetId; invalid id → /assets)
│ ├── fx/
│ │ ├── +page.svelte # FX pairs list and management
│ │ └── [pair]/
│ │ ├── +page.svelte # FX pair detail
│ │ └── +page.ts # Load function (pair slug; invalid slug → /fx)
│ ├── tools/
│ │ ├── +page.svelte # Tools hub (ToolsHub)
│ │ └── [tool_code]/
│ │ └── +page.svelte # One tool (ToolHost)
│ ├── files/
│ │ └── +page.svelte # Files management (static + BRIM tabs)
│ └── settings/
│ └── +page.svelte # Settings (4 tabs)
📋 Pages
🔐 Login Page (/)
- Public access
- LoginCard / RegisterCard / ForgotPasswordCard (card-style, not modals)
- Animated background with waves and chart lines
- Redirect to dashboard after login
- User preferences (language, theme) applied on login
👋 Welcome (/welcome)
- First-run setup of the onboarding: language, base currency and avatar
- Rendered by the
(app)layout without the app shell (no sidebar or header) - The layout's gate sends the user here (
/welcome?returnTo=<requested path>) while the Welcome flow is due or a Welcome replay is armed (appBootstrap.resolveDestination); afterwards the page continues toreturnTo, or to/dashboardwhen the intro tour starts - Architecture: Onboarding Guides
📊 Dashboard (/dashboard)
- Portfolio view in four tabs: Overview (
KpiSection,GrowthChart,AllocationPanel), Positions (PositionsPanel, with the FIFOLotsAnalysisPanel), Risk (RiskLevelsPanel) and Transactions (TransactionsTable) - Toolbar with the date range (
DateRangePicker) and the display currency (CurrencySearchSelect) - DataQualityBanner above the tabs; its actions can open
FxPairAddModalto add a missing FX pair - KPI row —
KpiSection, also mounted on the broker detail Overview:- it reads
PortfolioSummary:period_pnland its rowsperiod_unrealized_gain_loss_delta(tooltip rowsperiod_unrealized_breakdown, in backend order),period_realized_gain_loss,period_incomeandperiod_fees_taxes(a positive magnitude, shown negated; the tooltip splitsperiod_fees/period_taxes);simple_roi_percent,twrr_percent,mwrr_cumulative_percent,mwrr_annualized_percent;net_worth,total_gain_losswithtotal_gain_loss_percent(since inception),market_value,open_cost_basis,cash_totalandnet_deposited_capital(total_deposited/total_withdrawn, period only) - the start-of-period carets come from
period_market_value_start,period_book_value_startand the first history point'scash_value; the Cash tooltip from the last history point'scash_from_contributed_capital/cash_from_generated_returns - the day-change lines are computed in the browser from the last two history points: Δ of
total_pnl, divided by the previous|total_pnl|(Card 1) or|nav_value|(Card 2); a zero base drops the percentage, and fewer than two points drops the line - the timing effect is
mwrr_cumulative_percent − twrr_percentin pp, labelled neutral below 0.05 pp; its colour intensity saturates at 3 pp - each card's help icon is a
DocsLinktouser/dashboard/kpi-cards/#card-1-period-pl,#card-2-returnsand#card-3-net-worth: keep these explicit anchors in every language
- it reads
- Positions tab —
PositionsPanel, also mounted on the broker detail Positions tab:- Portfolio / Period (modes
holdings/performance) × Table / Map:ExposureTable,ExposureTreemap,ContributionTablewithOtherPeriodEffectsTable,PerformanceChart; both toggles persist per user inlocalStorage(dashboard-positions-semantic,dashboard-positions-visual) - the table layouts (
dashboard-holdings-v5,dashboard-performance-v2) are shared with the broker detail page; the Period view's Status filter is a hidden-by-default enum column ofContributionTable, not a panel toggle, andPerformanceChartshows an Open / Closed badge positions_contributionis fetched apart, on demand:PositionsPanelasks for it the first time the Period view is shown; a cached copy shows at once and is refreshed when stale- the lots panel opens from the Analyze Lots row action (⋮) or the right-click menu of
every view — there is no plain-click trigger — and is mirrored in
?asset=<id>;LotsAnalysisPanelrenders inline below, with a slide transition, and scrolls itself into view. Itsbroker_idsare the broker filter, or every owned broker with a share above 0% - architecture: Lots Analysis and the Lots Analysis Service
- Portfolio / Period (modes
🏦 Brokers (/brokers)
- Grid of broker cards with icons (fallback chain)
- Add/Edit broker via BrokerModal (extends ModalBase); the icon is picked in the form
(
ImagePickerWrapper→ AssetPickerModal) - Sharing via BrokerSharingModal; brokers the user has no access to are listed apart as
BrokerDiscoveryCards, whose sharing view is read-only - Delete via DeleteBrokerDialog, with a force option when the broker still has transactions
🔍 Broker Detail (/brokers/[id])
- Header with back button, icon and name; toolbar actions: edit (BrokerModal, owners and editors), share (opens the Info tab), refresh, and AI export
- Tabs: Overview (KPIs, cash balances, growth chart, allocation), Positions (Analyze Lots, from
the ⋮ menu or the right-click menu, opens the FIFO lots panel, mirrored in
?asset=<id>), Risk, Transactions and Info - Transactions tab: the broker's transactions, its report files (Uploaded Reports → BrokerImportFilesModal), a link to the Transactions page, and — for owners and editors — import and new transaction through the bulk workspace, with this broker pre-selected
- Info tab: broker details and the embedded sharing panel (BrokerSharingPanel)
📝 Transactions (/transactions)
- Master ledger of all user transactions
- Advanced filtering and pagination; filters are mirrored in the URL (
filterState.ts) - A row opens read-only in the Form modal; adding, editing, cloning, deleting and importing go
through the bulk workspace (
TransactionBulkModal). After every saved operation the page clears its selection (Selection on the Transactions page)
💼 Assets (/assets)
- Full list of tracked financial instruments
- Interactive data tables with sorting and filtering
🔍 Asset Detail (/assets/[id])
- Live prices and historical charts (ECharts)
- Technical signals and related events
- Detailed performance metrics and history
💱 FX Rates (/fx)
- List of configured currency pairs and conversion rates
- Direct route and chain management
- Live data sync and technical signals
🔍 FX Pair Detail (/fx/[pair])
[pair]is a slug such asEUR-USD: its order sets the display direction, while stores and API calls use the alphabetical (canonical) pair; an invalid slug redirects to/fx(+page.ts)- Rate summary (
FxPriceSummary), full chart with signals and measurements (PriceChartFull,ChartSignalsSection,MeasurePanel), and the rate editor (FxDataEditorSection)
🧰 Tools (/tools, /tools/[tool_code])
/toolsmountsToolsHub: the catalogue of computation tools read fromGET /api/v1/tools/catalog, one card per tool with its compatibility label/tools/[tool_code]mountsToolHost, which resolves the tool's compiled renderer inlib/features/tools/registry.tsand mounts it; a tool without a compatible renderer is shown as unavailable. Today the registry holds one tool, the PAC allocator- Contract and frontend binding: Tool plugins
📁 Files (/files)
- Two tabs: Static Resources / Broker Reports (BRIM)
- DataTable with sorting, filtering, pagination, URL-synced filters
- Grid view toggle with image previews and search
- Upload interface with:
- Image files → ImageEditModal (crop, rotate, flip)
- Non-image files → FileEditModal (rename)
- Copy link, download, delete actions
- File thumbnails via
?img_preview=API
⚙️ Settings (/settings)
- 4 tabs: Profile, Preferences, About, Admin (global settings);
?tab=selects one - ProfileTab: Avatar editing via AssetPickerModal, username display
- PreferencesTab: Language, currency, theme, and the Onboarding category (guide replays — see Settings Components)
- GlobalSettingsTab: visible to every user, editable only by a superuser, behind an edit lock
- AboutTab: Version info (from Git tag), system info
- PasswordChangeModal from profile
- Mobile responsive with dropdown category selector