Building a Real-Time Analytics Dashboard: From Static Placeholders to Data-Rich Insights
How we transformed a static placeholder dashboard into a comprehensive analytics command center using Recharts, tRPC, and TypeScript - complete with the challenges we faced along the way.
Building a Real-Time Analytics Dashboard: From Static Placeholders to Data-Rich Insights
Every developer knows the feeling: you've built a beautiful dashboard layout with perfectly aligned placeholder cards, but behind those sleek mockups lies the real challenge—making them actually do something useful. Today, I'm sharing the journey of transforming our static dashboard into a data-rich analytics command center that provides real insights into user workflows, AI provider costs, and system performance.
The Vision: Beyond Pretty Placeholders
Our goal was ambitious but clear: replace static dashboard widgets with a comprehensive analytics system that could answer questions like:
- How much are we spending across different AI providers?
- Which workflows are performing well, and which need attention?
- What's our overall system health and user engagement?
- How is our knowledge base growing over time?
The result? A feature-complete analytics dashboard that batches multiple database queries, visualizes complex data relationships, and provides actionable insights—all while maintaining excellent performance.
The Architecture: Building for Scale and Maintainability
Type Safety First
One of the first decisions was establishing a robust type system. We created a comprehensive AnalyticsDashboardData interface that covers every aspect of our analytics:
// src/types/analytics.ts
interface AnalyticsDashboardData {
hero: HeroMetrics;
timeline: TimelineData[];
providers: ProviderIntelligence[];
insights: InsightPulse;
projects: ProjectPortfolio[];
workflows: WorkflowPerformance;
knowledge: KnowledgeBaseStats;
}
This upfront investment in types paid dividends later—no more guessing what data structure a component expects or debugging undefined property access.
Smart Data Fetching with tRPC
Rather than making multiple round trips to the database, we implemented a single getAnalytics tRPC procedure that batches approximately 12 Prisma queries using Promise.all():
// Simplified version of our batched query approach
const [workflows, discussions, insights, projects] = await Promise.all([
ctx.db.workflow.findMany({ /* complex query */ }),
ctx.db.discussion.findMany({ /* with aggregations */ }),
ctx.db.insight.findMany({ /* and computed metrics */ }),
ctx.db.project.findMany({ /* all executed in parallel */ })
]);
This approach dramatically reduced our time-to-first-render while keeping the database load manageable.
Visualization with Recharts
For the charts, we chose Recharts for its React-native approach and extensive customization options. We created a centralized theme system that maps to our CSS custom properties:
// src/lib/chart-theme.ts
export const CHART_COLORS = {
primary: 'hsl(var(--nyx-primary))',
secondary: 'hsl(var(--nyx-secondary))',
accent: 'hsl(var(--nyx-accent))'
};
export const PROVIDER_COLORS = {
anthropic: '#FF6B35',
openai: '#00A86B',
google: '#4285F4',
ollama: '#8B5CF6'
};
This ensures our charts stay consistent with our design system while remaining flexible for future theme changes.
Component Architecture: Modular and Focused
We broke down the dashboard into nine focused components, each handling a specific aspect of the analytics:
Hero Metrics
The dashboard opens with six key performance indicators: total spend, token usage, energy consumption, time saved, workflow count, and success rate. These provide an immediate health check of the system.
Activity Timeline
A 30-day stacked area chart showing workflows, discussions, and insights over time. This helps identify usage patterns and system adoption trends.
Provider Intelligence
Perhaps the most complex visualization—a composed chart showing token usage as bars and costs as a line chart, broken down by AI provider. This directly answers "where is our AI budget going?"
// Example of our ComposedChart setup
<ComposedChart data={providerData}>
<Bar dataKey="tokens" fill={PROVIDER_COLORS[provider.name]} />
<Line dataKey="cost" stroke={CHART_COLORS.accent} />
</ComposedChart>
Performance Insights
Components for workflow performance, insight pulse monitoring, knowledge base growth, and project portfolio views round out the comprehensive analytics suite.
Lessons Learned: The Challenges We Faced
The ESLint Configuration Trap
Our biggest stumbling block wasn't in our new code—it was a pre-existing ESLint configuration issue. The @typescript-eslint/no-unused-vars rule definition was missing, causing build failures across the entire project.
The Learning: Always verify your build pipeline before starting feature work. We ended up using next build --no-lint as a workaround, but the proper fix requires updating the project-wide ESLint configuration.
Suspense Boundaries and SSG
We discovered that one of our existing routes (/dashboard/consolidation/new) was failing static site generation due to useSearchParams() being called without a proper Suspense boundary.
The Learning: When working with Next.js App Router, always wrap components that use search params or other dynamic hooks in Suspense boundaries if you want them to work with SSG.
Performance vs. Completeness Trade-offs
We computed discussion statistics in our backend but decided not to render them in the initial UI to keep the dashboard focused. Sometimes the hardest decisions are about what not to show.
The Result: A Dashboard That Actually Helps
The final implementation provides:
- Real-time insights into system performance and costs
- Visual trends that help identify patterns and issues
- Actionable metrics for optimization decisions
- Scalable architecture that can grow with new analytics needs
Most importantly, it transforms our dashboard from a pretty but useless placeholder into a tool that genuinely helps users understand their AI workflow performance.
What's Next?
With the core analytics dashboard complete, we're looking at:
- Adding more granular filtering and date range controls
- Implementing alert thresholds for key metrics
- Adding export functionality for reports
- Exploring real-time updates via WebSocket connections
The foundation is solid, the data is flowing, and the insights are actionable. Sometimes the best dashboards are the ones that make you go "oh, that's what's happening" rather than just looking impressive.
Want to see more posts about building data-driven applications? Follow along as we continue improving our analytics platform and share the lessons learned along the way.