## Summary
Migrate the Edu Joe Charts dashboard (8 tabs, ~50 components, 22 data hooks) from Klair's React SPA at /edu-joe-charts to Aerie's Next.js 15 app at /dashboards?tab=edu-joe-charts. Every component is rewritten to follow Aerie patterns (Tailwind v4 classes, useMemo derivation pipelines, URL-backed state via search params, Clerk auth) while calling the same Klair REST API endpoints. No new API endpoints, no Convex migration, no feature additions.
Implements Phases 1-5 of the [migration plan](../thoughts/shared/plans/2026-04-07-move-edu-joe-charts.md). Phase 6 (Klair deprecation/removal) is deferred pending stakeholder sign-off.
### Changes
Infrastructure (Phase 1)
- chat/package.json / pnpm-lock.yaml — Add recharts dependency
- chat/app/globals.css — Chart series color tokens (--color-chart-1 through --color-chart-8, grid, axis), --color-sage-soft, light-mode overrides, @media print styles
- chat/lib/edu-joe/use-section-fetch.ts *(new)* — Clerk-authenticated fetch hook with abort/race-condition protection, replacing Klair's localStorage.token approach
- chat/lib/use-dashboard-tabs.tsx — Extended with edu-joe-charts tab, 8 sub-tabs (EduJoeSubTab type), and filter params (school, period, comparison, capexPeriod)
- chat/components/shell/dashboards-context-panel.tsx — "Edu Joe Charts" tab + 8 sub-tab entries in sidebar
- chat/components/dashboards/dashboards-layout.tsx — Tab label, breadcrumb, and conditional render for <EduJoeChartsView />
Data Layer (Phase 2)
- edu-joe/types.ts *(new)* — 544 lines of TypeScript interfaces for all API response shapes and BU config
- edu-joe/config/business-units.ts *(new)* — 6 BU configs + getBUConfig() lookup
- edu-joe/config/school-to-bu.ts *(new)* — School-to-BU static mapping
- edu-joe/hooks/use-v3-data.ts *(new)* — 13 exec-dashboard data hooks wrapping useSectionFetch
- edu-joe/hooks/use-bu-data.ts *(new)* — 8 joe-charts BU data hooks with conditional URL patterns
- edu-joe/hooks/use-marketing-spend.ts *(new)* — Marketing spend hook (hardcoded to tsa-strata)
- edu-joe/hooks/use-school-list.ts *(new)* — School list fetch
- edu-joe/hooks/use-paginated-search.ts *(new)* — Local pagination + search state hook
- edu-joe/utils/format.ts *(new)* — fmtCurrency, fmtFullCurrency, CHART_TOOLTIP_STYLE
- edu-joe/utils/csv-export.ts *(new)* — downloadCSV for client-side CSV generation
Shared Components (Phase 3) — 13 reusable components under edu-joe/shared/:
- section-wrapper.tsx — Loading/error/content wrapper
- kpi-tiles-row.tsx — Responsive stat tile grid with semantic tone colors
- pagination-controls.tsx — Prev/next pagination
- last-updated-footer.tsx — Data source badges + print button
- status-indicator.tsx — RYG dot with tooltip popover
- investment-card.tsx — KPI with collapsible yearly breakdown
- key-lever-card.tsx — KPI vs target with percentage badge
- budget-vs-actual-table.tsx — Searchable, paginated table with CSV export
- breakeven-section.tsx — Interactive sliders + metrics grid (267 lines)
- tier-insight-cards.tsx — Breakeven table per tuition tier
- margin-vs-student-chart.tsx — Recharts AreaChart with reference lines
- quarterly-pl-chart.tsx — Recharts ComposedChart (bars + line)
- revenue-expense-chart.tsx — Recharts ComposedChart with budget toggle
Tab Components (Phase 4) — 8 tabs under edu-joe/tabs/:
- Financial (5 files) — KPIs, trend charts, expense breakdown, model-vs-actuals, model-vs-budget
- Enrollment (8 files) — Snapshot, forecast chart, pipeline funnel (HTML/CSS, no @nivo), churn analysis, campus table, YoY growth
- Investment (3 files) — Metrics panel, cashflow chart with conditional bar coloring
- CAPEX & AP (3 files) — CAPEX table, accounts payable table (568 lines, vendor merge, aging KPIs, expandable rows)
- Academic (4 files) — MAP growth panel, subject panel with dual render modes, trend chart
- Marketing Spend (1 file) — Spend breakdown with period selector
- Strategy (6 files) — Breakeven, unit economics, segment cards, CFO insights, churn decomposition, scenario analysis
- Alerts (2 files) — Alert panels + domain-specific alerts gated by BU config
Root View (Phase 1) — edu-joe-charts-view.tsx — Filter bar with conditional controls per sub-tab, sub-tab router, footer
Theme Polish (Phase 5)
- Fixed 4 Recharts <Legend /> components that rendered with hardcoded #666 text (unreadable in dark mode) by adding wrapperStyle={{ color: "var(--color-stone)" }}
- Added @media print block: hides chrome, forces white backgrounds, print-safe chart colors, landscape layout
### Design Decisions
- Rewrite, not copy-paste: Every component was rewritten to Aerie patterns rather than adapted from Klair. This means Tailwind v4 classes instead of inline styles, useMemo derivation pipelines for data transforms, and CSS variable tokens instead of Klair's --klair-* tokens.
- No @nivo/funnel: The PipelineFunnel component (the only Nivo consumer) was reimplemented as stacked horizontal <div> bars with Tailwind, avoiding the entire Nivo dependency tree.
- No Convex: Data continues to flow from Klair's FastAPI REST endpoints via useSectionFetch. Same endpoints, same response shapes.
- Chart tokens: Added 10 new CSS variables (--color-chart-1 through --color-chart-8, --color-chart-grid, --color-chart-axis) with both dark and light mode values, keeping chart colors consistent across themes.
- Print-via-CSS: Print styles use @media print overrides on :root CSS variables so Recharts SVGs automatically pick up print-safe colors without component changes.
## Test Plan
- [x] npm run build compiles cleanly with no TypeScript errors
- [x] Recharts bundled correctly (dashboards page: 203 kB first load)
- [x] Code audit: all components use CSS variable tokens, no hardcoded colors
- [x] Navigate to /dashboards?tab=edu-joe-charts — root view shell renders, "Edu Joe Charts" appears in context panel
- [x] School dropdown populates from API (confirms Clerk auth pipeline works)
- [x] Side-by-side data parity check: each of the 8 tabs matches Klair's /edu-joe-charts with same filter settings
- [x] All 8 tabs in Dark + Alpha palette — no visual issues
- [x] All 8 tabs in Light + Slate palette — no visual issues
- [x] Spot-check 4 additional palette/accent combos — no contrast failures
- [x] Charts are readable and legend text visible in both modes
- [x] Print preview (Cmd+P) shows clean output without nav/sidebar
- [x] CSV export works on Financial (BudgetVsActual), CAPEX, and AP tabs
- [x] Filter bar: school dropdown, period pills, comparison toggle, CAPEX period all work
- [x] Pipeline funnel renders correctly (HTML/CSS replacement for Nivo)
- [x] Accounts Payable table: expandable vendor rows, aging filters, entity filters, search
## Screenshots
<img width="1368" height="875" alt="JoeCharts1" src="https://github.com/user-attachments/assets/86b6e13f-7245-4c11-9e8b-970705a7f10d" />
<img width="1612" height="874" alt="JoeCharts2" src="https://github.com/user-attachments/assets/51582dc0-e93e-4c7a-88cf-58e0b6e79870" />
<img width="1620" height="872" alt="JoeCharts3" src="https://github.com/user-attachments/assets/49a76514-21ee-4939-9915-4309e5d8dcfa" />