You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

6.2 KiB

Data Model: Family Office UI Redesign

Feature: 008-fo-ui-redesign Date: 2026-03-22

Overview

This feature requires no new database models or schema changes. All data entities already exist in the Prisma schema from the 001-family-office-transform feature. The "data model" for this feature is the UI state model — the shapes of data flowing from existing API endpoints to new/modified Angular components.

Existing Entities (No Changes)

These Prisma models already exist and power the family office API endpoints:

Entity Prisma Model Key Fields Used By
Entity Entity id, name, type (INDIVIDUAL/TRUST/LLC/LP/CORPORATION), taxId Dashboard allocations, Portfolio Summary
Partnership Partnership id, name, ein, entityId, currentValuation Dashboard AUM, Performance metrics
Distribution Distribution id, partnershipId, entityId, amount, date, type Dashboard recent distributions
K1 Document KDocument id, partnershipId, taxYear, filingStatus, normalizedData K1 filing status, Activity ledger
K1 Box Definition K1BoxDefinition id, formType, boxNumber, description, dataType K1 parsing, Cell Mapping page
Valuation Valuation id, partnershipId, value, quarter, year AUM calculation
Partner Performance PartnerPerformance id, partnershipId, irr, tvpi, dpi, rvpi Performance metrics

UI State Models (Data Flow)

These are the TypeScript interfaces already defined in @ghostfolio/common that flow from API to UI. No new interfaces are needed.

Dashboard State

IFamilyOfficeDashboard (existing, from GET /family-office/dashboard)
├── totalAum: number
├── currency: string
├── entitiesCount: number
├── partnershipsCount: number
├── allocationByEntity[]: { entityId, entityName, value, percentage }
├── allocationByAssetClass[]: { assetClass, value, percentage }
├── allocationByStructure[]: { structureType, value, percentage }
├── recentDistributions[]: { id, partnershipName, amount, date, type }
└── kDocumentStatus: { taxYear, total, draft, estimated, final }

Portfolio Summary State (currently unused by any component)

IPortfolioSummary (existing, from GET /family-office/portfolio-summary)
├── entities[]: IEntityPerformanceRow
│   ├── entityId, entityName
│   ├── originalCommitment, percentCalled, unfundedCommitment
│   ├── paidIn, distributions, residualUsed
│   └── dpi, rvpi, tvpi, irr
├── totals: IPerformanceRow (same fields without entity identifiers)
├── valuationYear: number
└── quarter?: number

Asset Class Summary State (currently unused by any component)

IAssetClassSummary (existing, from GET /family-office/asset-class-summary)
├── assetClasses[]: IAssetClassPerformanceRow
│   ├── assetClass, assetClassLabel
│   ├── originalCommitment, percentCalled, unfundedCommitment
│   ├── paidIn, distributions, residualUsed
│   └── dpi, rvpi, tvpi, irr
├── totals: IPerformanceRow
├── valuationYear: number
└── quarter?: number

Activity Ledger State (currently unused by any component)

IActivityDetail (existing, from GET /family-office/activity)
├── rows[]: IActivityRow
│   ├── year, entityId, entityName, partnershipId, partnershipName
│   ├── beginningBasis, contributions
│   ├── interest, dividends, capitalGains, remainingK1IncomeDed
│   ├── totalIncome, distributions
│   ├── otherAdjustments, endingTaxBasis
│   ├── endingGLBalance, bookToTaxAdj
│   ├── endingK1CapitalAccount, k1CapitalVsTaxBasisDiff
│   ├── excessDistribution, negativeBasis, deltaEndingBasis
│   └── notes
├── totalCount: number
└── filters: { entities[], partnerships[], years[] }

Report State (currently unused by any component)

IFamilyOfficeReport (existing, from GET /family-office/report)
├── reportTitle: string
├── period: { start, end }
├── entity?: { id, name }
├── summary: { totalValueStart, totalValueEnd, periodChange, periodChangePercent, ytdChangePercent }
├── assetAllocation: Record<string, { value, percentage }>
├── partnershipPerformance[]: { partnershipId, partnershipName, periodReturn, irr, tvpi, dpi }
├── distributionSummary: { periodTotal, byType: Record<string, number> }
└── benchmarkComparisons?[]: { id, name, periodReturn, excessReturn?, ytdReturn? }

State Transitions

Navigation State

Current: 11+ flat nav items → Target: 5 grouped items
┌─────────────────────────────────────────────┐
│  Dashboard │ Partnerships ▼ │ K-1 Center ▼ │ Analysis │ Admin ▼ │
│            │  Entities      │  K-1 Import   │          │  Admin Ctrl │
│            │  Partnerships  │  K-1 Documents│          │  Accounts   │
│            │  Distributions │  Cell Mapping │          │  Resources  │
│            │  Portf. Views  │               │          │  Pricing    │
│            │                │               │          │  Legacy ▸   │
└─────────────────────────────────────────────┘

Default Route State

Current: /** → /home → GfHomeOverviewComponent (stock portfolio overview)
Target:  /** → /family-office → Dashboard (FO dashboard with AUM + allocations)

Portfolio Analysis Page State

Current data flow:
  DataService.fetchPortfolioPerformance() → performance cards
  DataService.fetchPortfolioHoldings() → top/bottom 3
  DataService.fetchDividends() → dividend chart
  DataService.fetchInvestments() → investment chart

Target data flow (additions):
  FamilyOfficeDataService.fetchPortfolioSummary() → entity performance table + totals
  FamilyOfficeDataService.fetchAssetClassSummary() → asset class breakdown
  FamilyOfficeDataService.fetchActivity() → K1 income summary card

Validation Rules

No new validation rules for this feature. All validation is already handled by the existing API endpoints and DTOs.