From cfcb86cbe4261283ecde94079f950a38701fa2f0 Mon Sep 17 00:00:00 2001 From: Robert Patch Date: Sun, 22 Mar 2026 15:07:08 -0700 Subject: [PATCH] feat(008): Family Office UI redesign - nav restructure, entity tabs, dashboard management --- .github/agents/copilot-instructions.md | 6 +- apps/api/src/app/admin/dev-seed.service.ts | 62 +++ .../cell-mapping-legacy.controller.ts | 32 ++ apps/client/src/app/app.routes.ts | 2 +- .../components/header/header.component.html | 387 +++++++----------- .../app/components/header/header.component.ts | 52 +++ .../entity-detail/entity-detail-page.html | 137 ++++--- .../dashboard-page.component.ts | 285 ++++++++++++- .../analysis/analysis-page.component.ts | 90 ++++ .../portfolio/analysis/analysis-page.html | 203 +++++++++ libs/ui/src/lib/k1-income-summary/index.ts | 1 + .../k1-income-summary.component.ts | 160 ++++++++ libs/ui/src/lib/nav-menu-group/index.ts | 1 + .../nav-menu-group.component.ts | 66 +++ .../checklists/requirements.md | 36 ++ .../contracts/analysis-page.md | 82 ++++ .../contracts/navigation.md | 76 ++++ specs/008-fo-ui-redesign/data-model.md | 143 +++++++ specs/008-fo-ui-redesign/plan.md | 102 +++++ specs/008-fo-ui-redesign/quickstart.md | 97 +++++ specs/008-fo-ui-redesign/research.md | 147 +++++++ specs/008-fo-ui-redesign/spec.md | 147 +++++++ specs/008-fo-ui-redesign/tasks.md | 220 ++++++++++ 23 files changed, 2233 insertions(+), 301 deletions(-) create mode 100644 apps/api/src/app/k1-box-definition/cell-mapping-legacy.controller.ts create mode 100644 libs/ui/src/lib/k1-income-summary/index.ts create mode 100644 libs/ui/src/lib/k1-income-summary/k1-income-summary.component.ts create mode 100644 libs/ui/src/lib/nav-menu-group/index.ts create mode 100644 libs/ui/src/lib/nav-menu-group/nav-menu-group.component.ts create mode 100644 specs/008-fo-ui-redesign/checklists/requirements.md create mode 100644 specs/008-fo-ui-redesign/contracts/analysis-page.md create mode 100644 specs/008-fo-ui-redesign/contracts/navigation.md create mode 100644 specs/008-fo-ui-redesign/data-model.md create mode 100644 specs/008-fo-ui-redesign/plan.md create mode 100644 specs/008-fo-ui-redesign/quickstart.md create mode 100644 specs/008-fo-ui-redesign/research.md create mode 100644 specs/008-fo-ui-redesign/spec.md create mode 100644 specs/008-fo-ui-redesign/tasks.md diff --git a/.github/agents/copilot-instructions.md b/.github/agents/copilot-instructions.md index e73a46729..428eb6ebf 100644 --- a/.github/agents/copilot-instructions.md +++ b/.github/agents/copilot-instructions.md @@ -1,6 +1,6 @@ # portfolio-management Development Guidelines -Auto-generated from all feature plans. Last updated: 2026-03-21 +Auto-generated from all feature plans. Last updated: 2026-03-22 ## Active Technologies - TypeScript 5.9.2, Node.js >= 22.18.0 + Angular 21.1.1, NestJS 11.1.14, Angular Material 21.1.1, Prisma 6.19.0, big.js, date-fns 4.1.0 (003-portfolio-performance-views) @@ -11,6 +11,8 @@ Auto-generated from all feature plans. Last updated: 2026-03-21 - PostgreSQL via Prisma ORM (existing K1ImportSession, Document tables) (005-k1-parser-fix) - TypeScript 5.x (strict mode, `noUnusedLocals`, `noUnusedParameters`) + NestJS 11+ (module-based DI), Prisma ORM 6.x, PostgreSQL 16, Redis (caching), pdfjs-dist (extraction — unaffected by this feature) (006-k1-model-review) - PostgreSQL via Prisma (Docker dev: port 5434). All schema changes via `prisma migrate dev`. (006-k1-model-review) +- TypeScript 5.9.2, Node.js ≥22.18.0 + NestJS 11.1.14 (API), Angular 21.1.1 + Angular Material 21.1.1 (client), Prisma 6.19.0 (ORM), Nx 22.5.3 (monorepo), chart.js 4.5.1, date-fns 4.1.0, Bull 4.16.5 (queues), Redis (caching), Ionic 8.8.1 (008-fo-ui-redesign) +- PostgreSQL via Prisma ORM, Redis for caching (008-fo-ui-redesign) - TypeScript 5.9.2, Node.js ≥22.18.0 + NestJS 11.1.14 (API), Angular 21.1.1 + Angular Material 21.1.1 (client), Prisma 6.19.0 (ORM), Nx 22.5.3 (monorepo), big.js (decimal math), date-fns 4.1.0, chart.js 4.5.1, Bull 4.16.5 (job queues), Redis (caching), yahoo-finance2 3.13.2 (001-family-office-transform) @@ -31,9 +33,9 @@ npm test; npm run lint TypeScript 5.9.2, Node.js ≥22.18.0: Follow standard conventions ## Recent Changes +- 008-fo-ui-redesign: Added TypeScript 5.9.2, Node.js ≥22.18.0 + NestJS 11.1.14 (API), Angular 21.1.1 + Angular Material 21.1.1 (client), Prisma 6.19.0 (ORM), Nx 22.5.3 (monorepo), chart.js 4.5.1, date-fns 4.1.0, Bull 4.16.5 (queues), Redis (caching), Ionic 8.8.1 - 006-k1-model-review: Added TypeScript 5.x (strict mode, `noUnusedLocals`, `noUnusedParameters`) + NestJS 11+ (module-based DI), Prisma ORM 6.x, PostgreSQL 16, Redis (caching), pdfjs-dist (extraction — unaffected by this feature) - 005-k1-parser-fix: Added TypeScript 5.x (Node.js runtime) + NestJS 11.x, pdfjs-dist 5.4.x (already installed via pdf-parse), pdf-parse 2.4.x (kept for `isDigitalK1` detection) -- 004-k1-scan-import: Added TypeScript 5.9.2, Node.js ≥ 22.18.0 + NestJS 11.x (backend), Angular 21.x (frontend), Prisma 6.x (ORM), pdf-parse (PDF text), @azure/ai-form-recognizer (cloud OCR), tesseract.js (local OCR fallback) diff --git a/apps/api/src/app/admin/dev-seed.service.ts b/apps/api/src/app/admin/dev-seed.service.ts index ec7b4576c..5be797940 100644 --- a/apps/api/src/app/admin/dev-seed.service.ts +++ b/apps/api/src/app/admin/dev-seed.service.ts @@ -916,6 +916,68 @@ export class DevSeedService { counts.kDocuments++; } + // ── B9. Ownerships (Entity → Account links) ───────────────────── + // Realistic mapping: Trust owns the IRA & 401(k), LLC owns + // the brokerage & margin accounts, Individual owns Coinbase. + const [trustEntity, llcEntity, jamesEntity] = foEntities; + const ownershipDefs = [ + { + accountId: accountRecords[1].id, // Schwab Traditional IRA + accountUserId: userId, + costBasis: 150000, + effectiveDate: new Date('2020-01-15'), + entityId: trustEntity.id, + ownershipPercent: 100 + }, + { + accountId: accountRecords[3].id, // Fidelity 401(k) + accountUserId: userId, + costBasis: 250000, + effectiveDate: new Date('2019-06-01'), + entityId: trustEntity.id, + ownershipPercent: 100 + }, + { + accountId: accountRecords[0].id, // Schwab Individual Brokerage + accountUserId: userId, + costBasis: 35000, + effectiveDate: new Date('2021-03-10'), + entityId: llcEntity.id, + ownershipPercent: 100 + }, + { + accountId: accountRecords[5].id, // Interactive Brokers Margin + accountUserId: userId, + costBasis: 50000, + effectiveDate: new Date('2022-01-15'), + entityId: llcEntity.id, + ownershipPercent: 100 + }, + { + accountId: accountRecords[2].id, // Vanguard Roth IRA + accountUserId: userId, + costBasis: 20000, + effectiveDate: new Date('2020-09-01'), + entityId: jamesEntity.id, + ownershipPercent: 100 + }, + { + accountId: accountRecords[4].id, // Coinbase + accountUserId: userId, + costBasis: 5000, + effectiveDate: new Date('2023-02-14'), + entityId: jamesEntity.id, + ownershipPercent: 100 + } + ]; + + counts.ownerships = 0; + + for (const def of ownershipDefs) { + await this.prismaService.ownership.create({ data: def }); + counts.ownerships++; + } + this.logger.log(`Dummy data populated: ${JSON.stringify(counts)}`); return { created: counts }; diff --git a/apps/api/src/app/k1-box-definition/cell-mapping-legacy.controller.ts b/apps/api/src/app/k1-box-definition/cell-mapping-legacy.controller.ts new file mode 100644 index 000000000..c3d879328 --- /dev/null +++ b/apps/api/src/app/k1-box-definition/cell-mapping-legacy.controller.ts @@ -0,0 +1,32 @@ +/** + * Legacy redirect controller for /api/v1/cell-mapping/* routes. + * + * The old CellMapping module was replaced by K1BoxDefinition in spec 006. + * This controller ensures any stale PWA bundles or cached clients hitting + * the old /cell-mapping/* paths still get a response (301 redirect to the + * new /k1/box-definitions/* routes). + */ +import { Controller, Get, Query, Redirect } from '@nestjs/common'; + +@Controller('cell-mapping') +export class CellMappingLegacyController { + @Get() + @Redirect('/api/v1/k1/box-definitions', 301) + public getAll(@Query('section') section?: string) { + if (section) { + return { url: `/api/v1/k1/box-definitions?section=${section}` }; + } + } + + @Get('aggregation-rules') + @Redirect('/api/v1/k1/box-definitions/aggregation-rules', 301) + public getAggregationRules() { + // Default redirect target already set by decorator + } + + @Get('aggregation-rules/compute') + @Redirect('/api/v1/k1/box-definitions/aggregation-rules', 301) + public computeAggregationRules() { + // Legacy compute endpoint → redirect to rules list + } +} diff --git a/apps/client/src/app/app.routes.ts b/apps/client/src/app/app.routes.ts index 7f780ccbf..ec5e9b285 100644 --- a/apps/client/src/app/app.routes.ts +++ b/apps/client/src/app/app.routes.ts @@ -220,7 +220,7 @@ export const routes: Routes = [ // wildcard, if requested url doesn't match any paths for routes defined // earlier path: '**', - redirectTo: 'home', + redirectTo: 'family-office', pathMatch: 'full' } ]; diff --git a/apps/client/src/app/components/header/header.component.html b/apps/client/src/app/components/header/header.component.html index 2bf4d1196..0e0ec4db1 100644 --- a/apps/client/src/app/components/header/header.component.html +++ b/apps/client/src/app/components/header/header.component.html @@ -13,129 +13,29 @@