Configuration, Reports & UI
How tenant settings shape the experience, how PDFs get generated, and what users actually see when they log in.
The Settings System
Portfolio is highly configurable per tenant. Settings are stored in the database using Spatie Laravel Settings — a package that persists typed setting classes to a settings table. There are four setting groups, each controlling a different aspect of the platform.
hideDatePicker is true, all views are locked to this quarter.reportingQuarter — removes the date picker from the UI entirely. Prevents users from viewing non-finalized data.Each tenant has its own copy of all settings. Client A might show IRR while Client B hides it. Client C might have the combined view enabled while Client D only has funds. This is what makes Portfolio work for diverse client types — the same codebase adapts via configuration.
Report Generation
Portfolio generates three types of PDF reports. All use the same pipeline: calculate metrics via the Go gRPC service, render HTML templates with the data, then convert to PDF using Chromium (headless browser).
The flagship report. Per-asset, includes all dashboard metrics (committed, called, paid-in, distributions, NAV, DPI, TVPI, XIRR), allocation charts, valuation bridge, and timeline data. Branded with client logo and colours from ReportSettings. Can include glossary and disclaimer.
Per-investor breakdown of a capital call. Shows the investor's commitment, call percentage, amount due, and payment instructions. Generated when a capital call transaction is created.
Per-investor breakdown of a distribution. Shows the investor's share, distribution type (return of capital, income, etc.), and net amount after any tax withholding. Generated when a distribution transaction is created.
Generated PDFs are stored on S3 and linked to assets or investors via ReportFiles, UserAttachments, and AssetAttachments records in the database. Users can download them from the Documents tab in the frontend.
The Frontend
For annotated mockups of the Dashboard, Investors Table, Data Import page, and Investor "My View," see the UI Visual Reference page. It shows exactly what each screen looks like with the data from our sample exercises.
The Portfolio UI is part of the Delio Frontend — a React + TypeScript application using Ant Design components. Here's the page map:
Overview with StructureSwitcher (Fund / Direct / Combined) and ViewModeToggle (Group vs My View). Widget cards, charts, and summary tables.
List of all investors with key metrics. Click through to investor detail.
Per-investor dashboard, investments breakdown, documents, and transaction history.
All assets (funds and directs) with valuations, structure type, and status.
Investor transactions and fee tabs. Create, view, and reverse transactions.
Full journal-style ledger of all cash flows across the portfolio.
9 import categories (investors, subscriptions, capital calls, etc.) plus import history with reversal support.
Self-service "My View" for investors (LPs). Read-only view of their own positions, documents, and returns.
Dashboard Widgets
The dashboard cards are powered by three dedicated widget endpoints. Each endpoint returns pre-computed data from the Go calculation service (via cache):
| Endpoint | What It Powers |
|---|---|
/widgets/capital-overview | Fund metrics cards: Committed, Called, Uncalled, Paid-In, Distributions, NAV, DPI, TVPI, RVPI, Capital Gains, XIRR |
/widgets/direct-overview | Direct metrics cards: Investment, Valuation, Income, Yield, Return on Capital, Multiple, Profit |
/widgets/aggregates-overview | Combined view: merged fund + direct totals for the unified dashboard |
StructureSwitcher and ViewModeToggle
Two key UI controls sit at the top of the dashboard:
StructureSwitcher
Toggles between three portfolio views:
- Fund — shows only fund-type assets (capital calls, distributions, NAV)
- Direct — shows only direct investments (investment, valuation, income)
- Combined — merged view (only visible if
showCombinedViewis enabled)
ViewModeToggle
Switches the data scope:
- Group — all investors aggregated (the GP/admin view)
- My View — filtered to the logged-in investor's own positions (the LP self-service view)
Feature Flags
Two organisation-level feature flags gate access to Portfolio features:
| Flag | Purpose |
|---|---|
organisation.portfolio_enabled |
Legacy flag. When true, the organisation has access to the Portfolio module. Used during initial rollout. |
organisation.enable_new_portfolio_reporting |
Enables the newer reporting pipeline (QPR generation). Organisations without this flag use an older report format or have reporting disabled entirely. |
Feature flags are organisation-level toggles that gate entire capabilities (can they use Portfolio at all?). ConfigSettings are tenant-level preferences that shape the experience (what do they see once they're in?). They live in different systems — flags in Delio Core, settings in Portfolio's own database.
Whitelabel
Portfolio supports semantic branding — clients can rename key entities to match their own terminology. For example, "Investor" can display as "Client" or "Partner" throughout the UI. This is configured through a branding context that maps semantic labels to display labels.
Combined with ReportSettings (logo, colours, footer, disclaimer), this means two tenants on the same Portfolio instance can have completely different-looking reports and UI labels while running the same underlying code.
The frontend checks the branding context for label overrides. If "Investor" is mapped to "Client", then:
- The "Investors Overview" page title becomes "Clients Overview"
- Table column headers change from "Investor" to "Client"
- Report headers and notices use "Client" throughout
The underlying data model, API endpoints, and code all still use "investor" internally. The label swap is purely cosmetic at the UI and report layer.
Knowledge Check
A client wants to hide IRR from their quarterly reports and lock all views to Q4 2025. Which settings need to be configured?
showIRR = false hides IRR everywhere, hideDatePicker = true prevents users from changing the date range, and reportingQuarter = "Q4 2025" sets the locked quarter. Just setting the reporting quarter without hiding the date picker would still let users browse other periods.reportingQuarter alone doesn't lock the view — users can still pick other dates. You also need hideDatePicker = true to actually remove the date selector from the UI. And hiding IRR requires showIRR = false in ConfigSettings, not disabling reporting entirely. The correct answer is B.Where does the Quarterly Performance Report (QPR) get its financial data from?
What's Next
You now understand how Portfolio is configured, how reports are generated, and what the frontend looks like. Next, we'll take an honest look at strengths, weaknesses, and gotchas — what Portfolio does well, where it falls short, and the landmines to watch out for.