Reports & Analytics

Last updated on 2026-09-02

The reports module provides four analytics screens covering sales performance, pipeline health, team metrics, and revenue segmentation. All data comes from aggregate Supabase queries executed via Server Actions in lib/actions/reports.ts. Charts use Recharts wrapped in shadcn/ui ChartContainer for consistent theming.

Sales Overview

Route: /reports

The main reporting dashboard with configurable date range and high-level sales metrics.

  • Date range selector -- pill-style buttons for 7d, 30d, 90d, and All time; the selected range is passed to Supabase queries as date filters
  • KPI cards -- four StatCard components with data from aggregate queries:
    • Revenue -- SUM(deals.value) WHERE stage = 'closed_won' with trend percentage vs previous period
    • Deals Won -- COUNT(deals) WHERE stage = 'closed_won' with trend
    • Average Deal Size -- AVG(deals.value) WHERE stage = 'closed_won'
    • Win Rate -- closed_won / (closed_won + closed_lost) * 100
  • Revenue trend area chart -- Recharts AreaChart with data points aggregated by day/week/month from deals.created_at
  • Deals won vs lost bar chart -- grouped BarChart comparing won and lost deal counts by month
  • Revenue by source pie chart -- PieChart with revenue grouped by deals.source
  • Top performing reps table -- ranked by total revenue from won deals, joined with profiles for avatar and name

Sales Overview Layout

+----------+----------+----------+----------+
| Revenue  | Deals    | Avg Deal | Win      |
|          | Won      | Size     | Rate     |
+----------+----------+----------+----------+
| Revenue Trend       | Won vs Lost         |
| (area chart)        | (bar chart)         |
+---------------------+---------------------+
| Revenue by Source   | Top Performing      |
| (pie chart)         | Reps (table)        |
+---------------------+---------------------+

Example Query

// lib/actions/reports.ts (simplified)
export async function getRevenueBySource(dateRange: DateRange) {
  const supabase = await createServerClient()

  const { data } = await supabase
    .from("deals")
    .select("source, value")
    .eq("stage_id", closedWonStageId)
    .gte("created_at", dateRange.start)
    .lte("created_at", dateRange.end)

  // Group and sum by source
  return groupBy(data, "source").map(([source, deals]) => ({
    source,
    revenue: deals.reduce((sum, d) => sum + d.value, 0),
  }))
}

Pipeline Analytics

Route: /reports/pipeline

Pipeline health metrics and conversion analysis with data from the deals, pipeline_stages, and activities tables.

  • Conversion funnel -- horizontal funnel showing deal count and conversion rate at each stage transition, calculated from deal stage history in activities
  • Deals by stage bar chart -- vertical BarChart with deal count per stage, colored to match pipeline stage colors
  • Average time in stage -- horizontal bar chart showing mean days deals spend in each stage, calculated from activities timestamps
  • Pipeline velocity metrics -- four cards:
    • Average Sales Cycle -- mean days from first stage to Closed Won
    • Pipeline Value -- SUM(deals.value) for all open deals
    • Weighted Pipeline -- SUM(deals.value * deals.probability / 100)
    • Conversion Rate -- closed_won / (closed_won + closed_lost) * 100
  • Stalled deals alert -- deals not changing stage in 14+ days, identified by comparing deals.updated_at to current date

Pipeline Velocity Metrics

Metric Calculation Description
Average Sales Cycle Mean days from Lead to Closed Won How long deals take to close
Pipeline Value Sum of all open deal values Total potential revenue
Weighted Pipeline Sum of (value x probability) for open deals Probability-adjusted revenue
Conversion Rate Closed Won / Total Closed Percentage of deals won

Team Performance

Route: /reports/team

Individual and team performance analytics with data joined from profiles, deals, and activities.

  • Leaderboard table -- ranked by revenue:
    • Rank badges -- gold (1st), silver (2nd), bronze (3rd) medal icons
    • Rep info -- avatar and name from profiles
    • Deals won -- COUNT(deals) WHERE stage = closed_won AND owner_id = profile.id
    • Revenue -- SUM(deals.value) for won deals
    • Win rate -- won / total closed percentage
    • Quota attainment -- SUM(won revenue) / profiles.quota * 100 with progress bar
  • Expandable rep details -- per-rep deal breakdown, monthly trend, and recent activities
  • Team radar chart -- Recharts RadarChart comparing performance across 6 dimensions
  • Activity donut chart -- PieChart showing activity type distribution from activities grouped by type

Leaderboard Layout

+----+--------------+-------+----------+--------+------------------+
| #  | Rep          | Won   | Revenue  | Win %  | Quota Attainment |
+----+--------------+-------+----------+--------+------------------+
| 1  | Sarah Chen   | 12    | $485,000 | 68%    | ############ 112%|
| 2  | Mike Johnson | 10    | $392,000 | 62%    | #########... 89% |
| 3  | Lisa Park    | 9     | $367,000 | 58%    | ########.... 82% |
| 4  | Tom Wilson   | 7     | $284,000 | 54%    | ######...... 64% |
+----+--------------+-------+----------+--------+------------------+

Revenue Breakdown

Route: /reports/revenue

Detailed revenue segmentation with data from deals, companies, and deal_products.

  • Revenue by product -- horizontal BarChart with revenue per product from deal_products joined with deals (closed won), sorted by revenue descending
  • Revenue by industry -- PieChart (donut) breaking down revenue by companies.industry for won deals
  • Deal size distribution -- histogram BarChart showing deal count in value ranges ($0-10K, $10-25K, $25-50K, $50-100K, $100K+)
  • Recurring vs one-time revenue -- stacked AreaChart showing revenue trends over time
  • Customer lifetime value table -- top companies ranked by total deal value, with columns for company name, total revenue, deal count, first deal date, average deal size, and LTV

Revenue Breakdown Layout

+---------------------+---------------------+
| Revenue by Product  | Revenue by Industry |
| (horizontal bar)    | (donut chart)       |
+---------------------+---------------------+
| Deal Size           | Recurring vs        |
| Distribution        | One-Time Revenue    |
| (histogram)         | (stacked area)      |
+---------------------+---------------------+
| Customer Lifetime Value (table)           |
+-------------------------------------------+

Charts Architecture

All report charts follow a consistent pattern using Recharts wrapped in shadcn/ui ChartContainer:

import { ChartContainer, ChartConfig, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart"
import { AreaChart, Area, XAxis, YAxis } from "recharts"

const chartConfig: ChartConfig = {
  revenue: {
    label: "Revenue",
    color: "oklch(0.585 0.233 270)",
  },
}

function RevenueTrendChart({ data }: { data: RevenueDataPoint[] }) {
  return (
    <ChartContainer config={chartConfig}>
      <AreaChart data={data}>
        <XAxis dataKey="month" />
        <YAxis />
        <ChartTooltip content={<ChartTooltipContent />} />
        <Area
          type="monotone"
          dataKey="revenue"
          fill="var(--color-revenue)"
          stroke="var(--color-revenue)"
          fillOpacity={0.2}
        />
      </AreaChart>
    </ChartContainer>
  )
}

Next Steps