Closes the last big spec gap: a single bundled React+Vite+Tailwind+Recharts
SPA that renders any report's dataset_v2.json under /api/reports/:id/dashboard/.
Spec deviation (intentional): rather than per-brief Vite builds (Netlify-
portable case), one bundle serves every report and fetches its dataset at
runtime. The portable HTML bundle (§10b) still ships per-report for offline
upload to claude.ai.
Dashboard template (v2/templates/dashboard_template):
- React 18 + Vite + TypeScript + Tailwind + Recharts. Same dark theme tokens
as the operator app.
- 9 views: Overview, Categories, Trends explorer (filters + sort + drilldown),
Lenses (4 sub-tabs for Hooks Library / Visual Vernacular / Audio Atlas /
Sentiment Map), Charts (engagement-vs-reach scatter, category treemap,
paid-vs-organic stacked bar), Compare (MoM new/returning/faded + category
momentum), Paid creators appendix, Methodology.
- Tab-based navigation with hash-stable URLs so deep links work.
Server:
- GET /api/reports/:id/dataset returns the on-disk dataset_v2.json (auth-
gated; 404 if Stage 10 hasn't built it yet).
- handleDashboardServe rewrite: serves (1) the explicit dashboard.html bundle,
(2) per-report on-disk static (covers, dataset_v2.json), (3) the bundled
SPA's assets/* and index.html with SPA fallback.
Build:
- v2/package.json workspaces re-includes templates/dashboard_template (was
excluded after earlier cutover-prep).
- Dockerfile.v2 builds the dashboard template alongside operator-app and
copies dist/ into the runtime image.
Local build: 838 modules transformed, 580 kB / 166 kB gzipped.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>