Dashboard & Analytics

/w/[slug]/dashboard is the first screen after someone picks a workspace: KPIs, a short activity chart, feed items, and buttons into the rest of the app.

Dashboard components

The dashboard is composed of four main sections, all loaded server-side in parallel for fast initial render.

KPI cards

Four metric cards showing key workspace stats:

CardMetricSource
Total ProductsCount of active productsproducts table (where deleted_at IS NULL)
Active MembersCount of workspace membersmemberships table
New This WeekProducts created in the last 7 daysproducts table with date filter
Current PlanActive subscription plan namesubscriptions table

Where to customize

Edit src/app/(app)/w/[workspaceSlug]/dashboard/kpi-cards.tsx to:

  • Change which metrics are displayed
  • Add new KPI cards for your own entities
  • Modify the card layout or styling

Example: adding a custom KPI card

To add a "Total Tasks" card for your own entity:

// In kpi-cards.tsx, add to the stats array:
{
  label: "Total Tasks",
  value: taskCount,
  icon: CheckSquare,
  description: "Active tasks in this workspace",
}

Activity chart

A 30-day area chart showing daily workspace activity (audit events per day). Powered by Recharts with the shadcn chart wrapper.

How it works

The chart uses a PostgreSQL function daily_audit_counts(workspace_id, days) that returns a table of (day, count) pairs. Days with no activity return 0.

SELECT * FROM daily_audit_counts('workspace-uuid', 30);
-- Returns: [(2026-04-16, 12), (2026-04-15, 8), ...]

Where to customize

Edit src/app/(app)/w/[workspaceSlug]/dashboard/activity-chart.tsx to:

  • Change the time range (default: 30 days)
  • Change the chart type (area, bar, line)
  • Add multiple data series
  • Change colors and labels

Activity feed

A timeline of the 10 most recent workspace events, showing who did what and when.

Each entry displays:

  • Actor name and email
  • Action description (human-readable)
  • Relative timestamp ("2 hours ago")

Where to customize

  • Activity feed component: src/components/activity-feed/
  • Action labels: src/components/activity-feed/action-labels.ts -- maps action strings (like product.created) to display text (like "created a product")

When you add new features, register their audit actions in action-labels.ts:

// src/components/activity-feed/action-labels.ts
export const ACTION_LABELS: Record<string, string> = {
  "product.created": "created a product",
  "product.updated": "updated a product",
  // Add your own:
  "task.created": "created a task",
  "task.assigned": "assigned a task",
};

Quick actions

Role-gated shortcut buttons for common operations:

ActionVisible toLinks to
Create ProductOWNER, ADMIN, MEMBERProducts page
Invite MemberOWNER, ADMINMembers page
View BillingOWNERBilling page

Where to customize

Edit src/app/(app)/w/[workspaceSlug]/dashboard/quick-actions.tsx to:

  • Add new quick action buttons for your own features
  • Change which roles can see each action
  • Update the links and icons

Adding your own dashboard widgets

To add a custom widget to the dashboard:

  1. Create a new component in src/app/(app)/w/[workspaceSlug]/dashboard/
  2. Fetch data in the server component at src/app/(app)/w/[workspaceSlug]/dashboard/page.tsx
  3. Pass the data to your client component

Example: adding a "Recent Tasks" widget

// 1. Fetch in page.tsx (add to the existing Promise.all):
const recentTasks = await supabase
  .from("tasks")
  .select("id, title, status, created_at")
  .eq("workspace_id", workspace.id)
  .order("created_at", { ascending: false })
  .limit(5);

// 2. Render in the page:
<RecentTasks tasks={recentTasks.data ?? []} />

Audit log page

The audit log at /w/[slug]/audit provides a full, filterable view of all workspace events. Accessible to OWNER and ADMIN roles.

Features

  • Pagination for browsing through events
  • Filter by actor (select which user's actions to view)
  • Filter by action (multi-select: product.created, member.invited, etc.)
  • Filter by date range (from/to date pickers)
  • Event details: actor, action, resource, metadata, timestamp

Where to customize

  • Audit log page: src/app/(app)/w/[workspaceSlug]/audit/page.tsx
  • Audit table component: src/app/(app)/w/[workspaceSlug]/audit/audit-log-table.tsx
  • Audit log insertion: src/lib/audit/insert-log.ts

Adding audit entries for new features

Every server action should call insertAuditLog() after a successful mutation:

import { insertAuditLog } from "@/lib/audit/insert-log";

await insertAuditLog({
  workspaceId,
  actorUserId: user.id,
  action: "task.created",
  resourceType: "task",
  resourceId: task.id,
  metadata: { title: task.title },
});