Spec: F65 — Recharts (Dashboard Charts & Visualizations)
Status: partial (source-backed; Today/Projects integrations and runtime evidence remain open)
1. Problem & CEO Job
See clearly (job 1) — Lumi needs compact trends and proportions without making the CEO read every list. Recharts wrappers provide the responsive, localized chart states and token-based palette needed by dashboard surfaces.
2. User Stories & Acceptance Criteria
-
As a CEO, when I open the Today dashboard, I want a visual summary of this week’s activity, so that I see trends without reading every item.
- Given the Today page, a mini-chart shows task counts by status (open/in_progress/done) for the last 7 days (TodayPage.tsx: BarChart with taskStatusData, ChartCard wrapper)
- Given the Today page, a mini-chart shows commitment/risk/decision counts (TodayPage.tsx: signalData BarChart in “Signals” ChartCard)
-
As a CEO, when I open the Deals page, I want a pipeline value chart, so that I see total deal value per stage at a glance.
- Given the Deals page, a funnel/bar chart shows total
valueper stage (DealsPage.tsx: PipelineBarChart using analytics.by_stage)
- Given the Deals page, a funnel/bar chart shows total
-
As a CEO, when I open the Projects page, I want a project progress overview, so that I see which projects are on track vs stalled.
- Given the Projects page, a small bar or donut chart shows project status distribution (ProjectsPage.tsx: BarChart with projectStatusData by active/paused/completed/archived, shown only when projects exist)
3. Scope Boundaries
- In: Installation (
recharts),<ChartCard>wrapper component (shadcn Card + Recharts chart), chart components on Today dashboard, Deals pipeline, Projects overview - Out: Interactive drill-down, real-time updating charts, complex multi-axis charts, export to image/PDF, chart builder/customizer
4. Data Model
n/a — charts consume existing API data. No new backend endpoints needed (aggregation is done client-side on already-fetched lists).
5. API Contract
n/a — existing endpoints return enough data.
6. UI / UX
- Components:
<ChartCard>infrontend/src/components/charts/ChartCard.tsx— wraps<Card>with a title, optional period selector, and a Recharts<ResponsiveContainer> - Chart types:
<BarChart>(status counts),<PieChart>/<DonutChart>(proportions),<AreaChart>(trends over time) - Theming: Use CSS variable tokens from
DESIGN.md—var(--color-chart-1)throughvar(--color-chart-5)for series colors. shadcn’s chart components already define these tokens. No hardcoded hex colors. - States:
- Loading:
<ChartSkeleton />— animate-pulse rectangle at chart aspect ratio - Empty:
<ChartEmpty />— centered text “Chưa có dữ liệu” with icon - Error:
<ChartError />— toast + inline message “Không thể tải biểu đồ” - Populated: Responsive chart with hover tooltips
- Loading:
- i18n: New
chartsnamespace —charts.today_tasks,charts.deal_pipeline,charts.project_status,charts.vs_last_week,charts.no_data - Responsive: Charts stack vertically on mobile (<768px), show 2-column grid on desktop
7. Test Plan
| # | Case | Type | Where |
|---|---|---|---|
| 1 | ChartCard renders with data | frontend | frontend/src/test/ChartCard.test.tsx |
| 2 | ChartCard shows empty state | frontend | frontend/src/test/ChartCard.test.tsx |
| 3 | ChartCard shows error state | frontend | frontend/src/test/ChartCard.test.tsx |
| 4 | Today dashboard shows charts | e2e | lumi.spec.ts existing Today block |
| 5 | Charts use design tokens (not hardcoded colors) | frontend | frontend/src/test/ChartCard.test.tsx |
8. Current Behavior
The shared chart source is present: ChartCard exposes loading/empty/error/populated states, reusable bar/line/pie widgets use responsive containers and chart tokens, and current integrations include the Deals pipeline, HQ analytics, Projects status distribution, and Today signal counts. The historical Today task series is not present in the current payload and remains an explicit gap. Browser and frontend runner evidence is also open.
9. Error States
- No data:
<ChartEmpty>with friendly message — not an error - Fetch failure:
<ChartError>inline + toast — retry via TanStack Query refetch - Empty series: Recharts renders nothing gracefully (no crash)
- Zero division (percentage): Check
total > 0before computing percentages
10. Diagrams & Docs Touched
frontend/DIAGRAMS.md§1 route tree — no new routesTASTE.md— add chart rule (no hardcoded colors, use design tokens)DESIGN.md— ensure--color-chart-*tokens are documented
11. Implementation Audit
| # | Claim | Status | Evidence |
|---|---|---|---|
| 1 | ChartCard.tsx — shared wrapper with loading/empty/error states + ResponsiveContainer | ✅ match | frontend/src/components/charts/ChartCard.tsx |
| 2 | BarChartWidget.tsx — reusable bar chart accepting BarChartDataPoint[], --color-chart-* tokens | ✅ match | frontend/src/components/charts/BarChartWidget.tsx |
| 3 | LineChartWidget.tsx — reusable line/trend chart; color via --color-chart-1 | ✅ match | frontend/src/components/charts/LineChartWidget.tsx |
| 4 | PieChartWidget.tsx — reusable pie/donut chart; innerRadius prop enables donut | ✅ match | frontend/src/components/charts/PieChartWidget.tsx |
| 5 | charts i18n namespace (no_data, error_load, task_status, deal_pipeline etc.) in en/ + vi/ | ✅ match | frontend/src/i18n/locales/en/charts.json + vi/charts.json |
| 6 | Current Deals/HQ/Projects/Today-signal chart integrations | ✅ source match | DealsPage.tsx, HqAnalyticsPage.tsx, ProjectsPage.tsx, TodayPage.tsx |
| 7 | Chart unit/source tests | ✅ source match | ChartCard.test.tsx, charts.test.tsx, F65 convention tests; runtime collection remains open |
| 8 | Today task/signal and Projects status chart integration | ⚠️ partial | TodayPage.tsx now renders current signal counts and ProjectsPage.tsx renders status; Today still lacks an honest historical task series |
12. Open Questions / Decisions
- Client-side aggregation vs dedicated analytics endpoint? Decision: Client-side for v1. Recharts works with plain arrays, and Today/Deals pages already fetch all items. If a page fetches >500 items, add a backend aggregation endpoint.
- Chart library alternative (Recharts vs Nivo vs visx)? Decision: Recharts — simplest API, shadcn has first-class support with
--color-*tokens, same team ecosystem.
13. Bug / Change Log
2026-07-16 — Contract Graph audit
Added the Today signal-count chart from the existing list payload. The historical Today task series remains open because the current payload does not provide it.
2026-07-16 — Today chart progressive loading
The current signal-count chart remains available, but now follows the actionable Today queues and loads its Recharts renderer on viewport approach. This preserves the existing visualization without charging every cold Today visit for chart code before the CEO can act.