CodingIdeas.ai
← Browse All Ideas

Build Guide

How to Build a Dashboard

There are 12 dashboard patterns used in 90% of SaaS products — knowing which one fits your data before you write a line of code saves weeks of redesign.

Intermediate3–7 days

Dashboards are the core UI of every B2B SaaS. Build one and you'll learn data aggregation, chart libraries, real-time updates, and responsive table design.

Data model

The core tables you'll need before writing any UI.

Eventid, user_id, type, properties (JSON), created_at — generic event log that feeds most metrics
DailyAggregatedate, metric_name, value — precomputed aggregates for fast chart queries

Build order

The sequence that minimises rewrites — build in this order.

1

KPI summary cards

Start with 3–4 KPI cards at the top: total value, change vs previous period (%), and a mini sparkline. Hard-code sample data first. Get the layout right before connecting real data.

2

Date range selector

Add a date range picker (Last 7 days / 30 days / 90 days / custom). All queries must respect the selected range. Store the range in state and pass it down to every chart and table as a prop.

3

Line chart — trend over time

Add a line chart showing your primary metric over time. Use Recharts or Chart.js. Aggregate data by day in SQL using DATE_TRUNC('day', created_at) and GROUP BY. Return an array of {date, value} pairs.

4

Bar chart — breakdown by category

Add a bar chart showing distribution by category (e.g. revenue by product, signups by source). GROUP BY the category field and SUM the metric.

5

Sortable data table

Add a table showing raw records with sortable columns. Implement server-side sorting (ORDER BY) and pagination (LIMIT + OFFSET). Add a CSV export button that downloads the current view.

6

Real-time updates

For live data, poll /api/metrics every 30 seconds using a useInterval hook. Show a "last updated X seconds ago" indicator. For true real-time, subscribe to Supabase Realtime on the events table.

7

Role-based views

Admin users see all data. Regular users see only their own. Enforce this in your API route by checking the user's role from the session and adding a WHERE user_id = ? clause for non-admins.

Done when

Observable behaviors that confirm V1 is complete — verify each one before you ship.

  • All KPI cards and charts load in under 3 seconds with 10k events in the database

  • Date range filter updates all charts and tables simultaneously without a full page reload

  • Admin user sees all data; regular user sees only their own (row-level security verified)

  • CSV export downloads correctly with all rows matching the current view and date range

  • Dashboard opens with 30 days of seeded demo data — all charts populated on first login

First Run Requirement

Seed 30 days of demo event data (signups, pageviews, conversions) on first login so all charts and KPI cards are populated immediately. No data entry required.

Build it with AI — Architect Prompt

Paste this into Claude, Cursor, Windsurf, or any AI coding tool. It includes the full context of this guide — data model, build order, done conditions, and pitfalls — so the AI starts with everything it needs.

ClaudeCursorWindsurfCopilotGemini
architect-prompt.txt
<context>
App: Dashboard
Difficulty: Intermediate
Estimated build time: 3–7 days
Tech stack (intermediate): Next.js + Supabase + Recharts or Chart.js + Clerk auth

Data model:
  Event: id, user_id, type, properties (JSON), created_at — generic event log that feeds most metrics
  DailyAggregate: date, metric_name, value — precomputed aggregates for fast chart queries

FIRST RUN REQUIREMENT:
Seed 30 days of demo event data (signups, pageviews, conversions) on first login so all charts and KPI cards are populated immediately. No data entry required.

DONE WHEN — verify each before marking V1 complete:
  □ All KPI cards and charts load in under 3 seconds with 10k events in the database
  □ Date range filter updates all charts and tables simultaneously without a full page reload
  □ Admin user sees all data; regular user sees only their own (row-level security verified)
  □ CSV export downloads correctly with all rows matching the current view and date range
  □ Dashboard opens with 30 days of seeded demo data — all charts populated on first login

Recommended build order:
  1. Define API contract + schema + seed data (always first)
  2. KPI summary cards — Start with 3–4 KPI cards at the top: total value, change vs previous period (%), and a mini sparkline. Hard-code sample data first. Get the layout right before connecting real data.
  3. Date range selector — Add a date range picker (Last 7 days / 30 days / 90 days / custom). All queries must respect the selected range. Store the range in state and pass it down to every chart and table as a prop.
  4. Line chart — trend over time — Add a line chart showing your primary metric over time. Use Recharts or Chart.js. Aggregate data by day in SQL using DATE_TRUNC('day', created_at) and GROUP BY. Return an array of {date, value} pairs.
  5. Bar chart — breakdown by category — Add a bar chart showing distribution by category (e.g. revenue by product, signups by source). GROUP BY the category field and SUM the metric.
  6. Sortable data table — Add a table showing raw records with sortable columns. Implement server-side sorting (ORDER BY) and pagination (LIMIT + OFFSET). Add a CSV export button that downloads the current view.
  7. Real-time updates — For live data, poll /api/metrics every 30 seconds using a useInterval hook. Show a "last updated X seconds ago" indicator. For true real-time, subscribe to Supabase Realtime on the events table.
  8. Role-based views — Admin users see all data. Regular users see only their own. Enforce this in your API route by checking the user's role from the session and adding a WHERE user_id = ? clause for non-admins.
  9. End-to-end verification — walk every Done When condition above (always last)

Known pitfalls to avoid:
  - Running aggregation queries on every page load — for large datasets, GROUP BY queries are slow. Precompute daily aggregates in a cron job and store them in a daily_aggregates table. Charts read from there instead of raw events.
  - Putting all charts in one giant component — split each chart into its own component with its own data fetching. This way charts load independently and a slow query doesn't block the whole dashboard.
  - No loading skeleton — charts that flash empty then fill in look broken. Add a skeleton placeholder (grey bars/lines) that shows while data loads, then fade it out when data arrives.
</context>

<role>
You are a Senior Full-Stack Engineer and product architect who has shipped production Dashboards before. You know exactly where developers get stuck and how to structure the project to avoid rewrites.
</role>

<task id="step-1-clarify">
Before writing any code or spec, ask me 3–5 clarifying questions that will meaningfully change the architecture. Focus on: scale expectations, auth requirements, platform (web / mobile / both), must-have vs nice-to-have features for the MVP, and any hard constraints (budget, deadline, existing infrastructure).

<example>
BAD: "What tech stack do you want to use?" — too broad, doesn't change architecture decisions.
GOOD: "Do you need real-time sync across devices, or is single-device with periodic refresh acceptable? This decides whether we use WebSockets or simple REST polling and significantly affects infrastructure complexity."
</example>

⚠️ Do NOT start planning or writing code until I answer. Present the questions, then stop and wait.
</task>

<task id="step-2-architect">
After I answer your questions, produce the following in order:

1. TECHNICAL SPECIFICATION
   - System architecture using → to show data and event flow
   - Core data model (refer to data model in <context>)
   - API contract — list ALL routes with request/response shapes BEFORE any implementation
     WHY: agreeing on contracts first prevents rewrites when frontend and backend shapes diverge
   - External APIs and integration points

2. MVP PLAN in three phases:

   SETUP   ✦ Step 1 (always): API contract + schema migration + seed data
     Done when: schema is migrated, seed script runs, app starts with demo data, zero manual setup.

   CORE FEATURES — build in this exact order:
   2. KPI summary cards
   3. Date range selector
   4. Line chart — trend over time
   5. Bar chart — breakdown by category
   6. Sortable data table
   7. Real-time updates
   8. Role-based views

   DONE WHEN — one observable condition per feature:
   □ All KPI cards and charts load in under 3 seconds with 10k events in the database
   □ Date range filter updates all charts and tables simultaneously without a full page reload
   □ Admin user sees all data; regular user sees only their own (row-level security verified)
   □ CSV export downloads correctly with all rows matching the current view and date range
   □ Dashboard opens with 30 days of seeded demo data — all charts populated on first login

   STRETCH GOALS — post-launch additions that are explicitly out of V1 scope.

3. BLOCKER ANALYSIS
   Flag: API rate limits, auth complexity, scope risks, cold-start problems, top 2–3 failure modes.

   FIRST RUN REQUIREMENT: Seed 30 days of demo event data (signups, pageviews, conversions) on first login so all charts and KPI cards are populated immediately. No data entry required.
   ✓ Done when: app launches with seed data and the full user journey works without any manual setup.

<self_check>
Before presenting your output, verify:
□ Every answer I gave to clarifying questions is reflected in the spec
□ Step 1 is ALWAYS: API contract + schema + seed — never UI first
□ Done When criteria are observable user behaviors, not internal states
□ The plan is realistic for one person to ship within 3–7 days
□ All known pitfalls from <context> are addressed in the spec
</self_check>
</task>

<task id="step-2.5-agents-md">
Generate an AGENTS.md file at the project root. This file is read automatically by Claude Code, Cursor, Windsurf, and all major AI coding tools at the start of every session.

Include:
- Project overview (2–3 sentences)
- Tech stack with exact version numbers
- Folder structure with one-line descriptions per directory
- Key architectural decisions and the WHY behind each
- Coding conventions: camelCase components, kebab-case files, max 200 lines per file, one concern per file
- Available commands: dev, build, test, lint, db:migrate, db:seed
- MVP scope boundaries — features explicitly out of V1

Note in the file: "Cursor users: symlink .cursorrules → AGENTS.md. Claude Code users: symlink CLAUDE.md → AGENTS.md."
</task>

<task id="step-3-implement">
Implement the full project in the exact order from step 2. For each step:
- Write complete code (no placeholders or TODOs)
- Confirm the step works before moving to the next

<constraints>
- Step 1 is ALWAYS: define all API routes + TypeScript request/response interfaces + run schema migration
  WHY: agreeing on contracts before writing a single component prevents shape mismatches that require rewrites
- Final step is ALWAYS: start the app and walk every Done When condition from <context> end-to-end
  WHY: a spec that passes unit tests but breaks the core user journey is not done
- Max 200 lines per file. WHY: every file must fit in one AI context window for complete reasoning
- One concern per file. WHY: mixing auth logic into API routes makes it impossible to reuse — extract to lib/auth.ts
- TypeScript strict mode, no `any` types. WHY: catches data shape mismatches at compile time, not in production
- All database queries in server components or API routes only. WHY: keeps credentials server-side
- All environment variables documented in .env.example. WHY: next developer sets up in under 5 minutes
</constraints>
</task>

How to use this prompt

  1. 1.Copy the prompt above
  2. 2.Open Claude, Cursor (Cmd+L), or Windsurf
  3. 3.Paste the prompt and send — the AI will ask 3–5 clarifying questions
  4. 4.Answer the questions, then it generates your full project spec
  5. 5.Continue in the same session to implement step by step

Common mistakes

What trips up most developers building this for the first time.

⚠️

Running aggregation queries on every page load — for large datasets, GROUP BY queries are slow. Precompute daily aggregates in a cron job and store them in a daily_aggregates table. Charts read from there instead of raw events.

⚠️

Putting all charts in one giant component — split each chart into its own component with its own data fetching. This way charts load independently and a slow query doesn't block the whole dashboard.

⚠️

No loading skeleton — charts that flash empty then fill in look broken. Add a skeleton placeholder (grey bars/lines) that shows while data loads, then fade it out when data arrives.

Recommended tech stack

Pick the level that matches your experience.

Beginner

React + Recharts + hardcoded JSON — learn chart patterns before adding a backend

Intermediate

Next.js + Supabase + Recharts or Chart.js + Clerk auth

Advanced

Next.js + Supabase + Tremor UI (dashboard components) + Supabase Realtime

Take it further — related ideas

Each comes with revenue math, a full build guide, and a prompt to paste into Claude or Cursor.