Skip to content

Dashboard Architecture

How the Next.js Dashboard communicates with the Go backend

Last Updated: January 25, 2026


Overview

The Fulcrum Dashboard is a Next.js 14 application that provides the admin UI for managing AI agent governance. It communicates with the Go backend via API routes that proxy requests to gRPC services or the MCP server.

Architecture Diagram

Browser                       Next.js Server                 Go Backend
┌────────────────┐           ┌─────────────────┐           ┌──────────────────┐
│                │           │                 │           │                  │
│  React UI      │──HTTP────▶│  /api/* routes  │──gRPC────▶│  fulcrum-server  │
│                │  JSON     │                 │  Proto    │  :50051          │
│  - Pages       │           │  - agents       │           │                  │
│  - Components  │           │  - traces       │           │  - AgentService  │
│  - Hooks       │           │  - events       │           │  - BrainService  │
│                │           │                 │           │                  │
│  Demo Mode     │           │  /api/* routes  │──MCP─────▶│  MCP Server      │
│  Context       │           │                 │  JSON-RPC │  :8080           │
│  (Client)      │           │  - policies     │           │                  │
│                │           │  - budgets      │           │  - policies      │
│                │           │  - keys         │           │  - budgets       │
│                │           │  - approvals    │           │  - keys          │
└────────────────┘           └─────────────────┘           └──────────────────┘
        │                            │
        │                            │
        │  localStorage              ├── isClerkEnabled()?
        │  fulcrum_demo_mode         │   ├── Yes → Call backend (gRPC/MCP)
        │                            │   └── No  → Return mock data (some routes)
        └────────────────────────────┘

Authentication Modes

The dashboard supports multiple authentication modes for different environments:

Mode Clerk Config MOCK_AUTH Demo Mode API Behavior
Production ✅ Keys set false false gRPC/MCP calls, real data
Mock Auth ❌ No keys true false Mock user context, backend calls
Demo Mode Any Any true (client) Client shows demo data
No Backend ❌ No keys false false API returns mock data*

*Note: Only routes that check isClerkEnabled() at the start return mock data.

Auth Configuration Files

File Purpose
lib/auth-config.ts isClerkEnabled(), isMockAuthEnabled(), MOCK_USER
lib/grpc-client.ts gRPC client factory with connection handling
lib/mcp-client.ts MCP client for policy/budget operations

isClerkEnabled() Logic

// lib/auth-config.ts
export const isClerkEnabled = (): boolean => {
  // Mock auth mode bypasses Clerk entirely
  if (isMockAuthEnabled()) {
    return false;
  }
  // Use publishable key as source of truth
  return !!process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY;
};

API Routes Reference

Routes with Mock Support

These routes check isClerkEnabled() and can return mock/demo data when Clerk is not configured:

Route Backend Mock Behavior
/api/agents gRPC (AgentService) Returns demo agents from data/demo/agents.ts
/api/policies MCP Uses mock tenant, calls MCP (needs backend)
/api/budgets MCP Uses mock tenant, calls MCP (needs backend)
/api/approvals MCP Uses mock tenant, calls MCP (needs backend)
/api/keys MCP Uses mock tenant, calls MCP (needs backend)

Routes Without Mock Support

These routes require a running backend:

Route Backend Notes
/api/traces Direct PostgreSQL Queries DB directly, no auth check
/api/events Direct PostgreSQL Queries DB directly
/api/audit-logs Direct PostgreSQL Queries DB directly

Demo Mode (Client-Side)

Demo mode is a client-side only feature that shows sample data without any backend calls.

How It Works

  1. User toggles demo mode via DemoToggle component
  2. State stored in localStorage key: fulcrum_demo_mode
  3. useDemoMode() hook provides context to all components
  4. When enabled, data hooks return demo data instead of fetching

Key Files

File Purpose
lib/hooks/useDemoMode.tsx Demo mode context provider and hook
data/demo/index.ts Demo data exports
data/demo/agents.ts Demo agent data
data/demo/policies.ts Demo policy data
data/demo/helpers.ts Time helpers for realistic timestamps

Demo Mode vs Mock Auth

Aspect Demo Mode Mock Auth
Location Client-side (browser) Server-side (API routes)
Data Source Static demo data Backend with mock tenant
Backend Required No Yes
Use Case Demos, screenshots E2E tests, local dev

Data Flow Patterns

Pattern 1: gRPC Routes (Agents)

Browser → /api/agents → getAgentServiceClient() → gRPC → fulcrum-server
              isClerkEnabled()?
              No → Return demo data

Pattern 2: MCP Routes (Policies, Budgets)

Browser → /api/policies → getMCPClient() → HTTP → MCP Server
              isClerkEnabled()?
              No → Use MOCK_USER tenant, still call MCP

Pattern 3: Direct DB Routes (Traces)

Browser → /api/traces → query() → PostgreSQL
              No auth check - queries directly

Key Implementation Details

gRPC Client Setup

// lib/grpc-client.ts
export function getAgentServiceClient(): AgentServiceClient {
  const channel = new ChannelCredentials.createInsecure();
  return new AgentServiceClient(
    process.env.GRPC_ENDPOINT || 'localhost:50051',
    channel
  );
}

MCP Client Setup

// lib/mcp-client.ts
export function getMCPClient(): MCPClient {
  return new MCPClient({
    endpoint: process.env.MCP_ENDPOINT || 'http://localhost:8080',
  });
}

Mock Tenant Pattern

All routes that need tenant isolation use this pattern:

async function getTenantId(): Promise<{
  tenantId: string;
  userId: string | null;
  error?: NextResponse;
}> {
  // When Clerk is disabled, use mock user
  if (!isClerkEnabled()) {
    return { tenantId: MOCK_USER.tenantId, userId: MOCK_USER.userId };
  }

  const { userId, orgId } = await auth();
  // ... Clerk auth logic
}

Environment Variables

Variable Purpose Required
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY Clerk public key For production
CLERK_SECRET_KEY Clerk secret key For production
MOCK_AUTH Enable mock auth mode For E2E tests
GRPC_ENDPOINT gRPC server address Yes
MCP_ENDPOINT MCP server address Yes
DATABASE_URL PostgreSQL connection Yes

Troubleshooting

"Failed to connect to gRPC" in E2E Tests

Cause: Route doesn't check isClerkEnabled() before calling gRPC.

Fix: Add mock data fallback at the start of the route handler.

Demo mode shows real data

Cause: Demo mode is client-side only. The page might be server-rendered.

Fix: Ensure the component uses useDemoMode() hook and conditionally renders.

Auth works locally but fails in CI

Cause: MOCK_AUTH=true not set in CI environment.

Fix: Add MOCK_AUTH=true to CI environment variables.



Back to Documentation Index