Skip to main content

Overview

The dashboard is the landing page after login. It gives you a quick snapshot of your workspace: how many contacts you have, import success rates, recent activity, and a 30-day growth chart. Everything loads fast thanks to server-side prefetching with SWR revalidation.

Stats Cards

The top of the dashboard shows four stat cards:
StatWhat it shows
Total ContactsCount of all contacts in the workspace
Total ImportsNumber of CSV imports performed
Success RatePercentage of rows successfully processed across all imports (SUM(processed_rows) / SUM(total_rows))
Contacts This MonthNew contacts added in the current calendar month
Stats are cached in Redis for 5 minutes. The cache is invalidated whenever contacts are created, deleted, or imported.

Growth Chart

A 30-day line chart showing daily contact creation counts. The data comes from a date_trunc('day', created_at) aggregate query on the contacts table, backed by a dedicated contacts_created_at_idx index for performance. The chart uses the same 5-minute cache as the stats cards.

Recent Activity

The dashboard shows three recent activity sections:

Recent Contacts

The 5 most recently created contacts, showing name (or email as fallback), avatar, and relative timestamp. Clicking a contact navigates to the contacts page.

Recent Imports

Recent CSV imports with status badges (pending, processing, completed, failed) and progress information. Completed imports show “X added, Y updated” when updates were detected during upsert processing.

Recent Exports

Recent exports with status badges and row counts.

Onboarding Flow

For new workspaces with no data, the dashboard shows a guided onboarding timeline instead of empty charts:
  1. Upload your first CSV — links to the import page
  2. Create your first contact — opens the create contact drawer
  3. Create your first tag — links to the tags page
Steps are marked as completed based on actual data presence. The onboarding disappears once all three steps are done.

Data Fetching Pattern

The dashboard uses a specific pattern for fast initial loads:
  1. The RSC (React Server Component) page prefetches all data server-side via apiServer
  2. Data is passed as initialData to the client component
  3. The client component wraps children in <SWRConfig value={{ fallback }}> for instant render
  4. SWR revalidates in the background, so the data stays fresh without a loading spinner
This means the dashboard renders immediately with real data on first load, then silently updates if anything changed.