Skip to content

Dashboard

Use @sentry/junior-dashboard when you want browser access to Junior runtime diagnostics without exposing plugin, skill, or filesystem discovery publicly. The dashboard mounts into the same Nitro deployment as Junior, but its Better Auth session only protects dashboard routes.

Install the dashboard package next to @sentry/junior:

Terminal window
pnpm add @sentry/junior-dashboard

Register juniorDashboardPlugin() in the runtime-safe plugin set. Configure the Google Workspace domain that should be allowed to view the dashboard:

plugins.ts
import { defineJuniorPlugins } from "@sentry/junior";
import { juniorDashboardPlugin } from "@sentry/junior-dashboard";
export const plugins = defineJuniorPlugins([
juniorDashboardPlugin({
allowedGoogleDomains: ["sentry.io"],
trustedOrigins: ["https://<your-domain>"],
}),
]);

createApp() reads that plugin set from Nitro’s virtual config:

server.ts
import { createApp } from "@sentry/junior";
export default await createApp();

Point the Junior Nitro module at the same plugin module:

nitro.config.ts
import { defineConfig } from "nitro";
import { juniorNitro } from "@sentry/junior/nitro";
export default defineConfig({
preset: "vercel",
modules: [
juniorNitro({
plugins: "./plugins",
}),
],
routes: {
"/**": { handler: "./server.ts" },
},
});

You can also provide the same authorization policy through deployment environment variables:

VariablePurpose
JUNIOR_DASHBOARD_GOOGLE_DOMAINSComma-separated or JSON array of allowed Google domains.
JUNIOR_DASHBOARD_ALLOWED_EMAILSComma-separated or JSON array of explicit email allowlist.
JUNIOR_DASHBOARD_TRUSTED_ORIGINSComma-separated or JSON array of Better Auth trusted origins.
JUNIOR_DASHBOARD_AUTH_REQUIREDSet to false only for explicit local dashboard auth bypass.

The dashboard package owns these routes:

RoutePurpose
/Authenticated command-center UI.
/conversationsAuthenticated conversation-history UI.
/pluginsAuthenticated plugin reporting UI.
/api/dashboard/*Authenticated dashboard JSON APIs.
/api/auth/*Better Auth Google login and callbacks.

/health remains the public minimal Junior runtime health response.

The current dashboard API slices are:

EndpointPurpose
/api/dashboard/healthHealth status for the command center pulse.
/api/dashboard/runtimeRuntime paths, providers, skills, and packages.
/api/dashboard/pluginsLoaded plugin list.
/api/dashboard/skillsDiscovered skill list.
/api/dashboard/sessionsRecent conversation feed from turn-session checkpoints.
/api/dashboard/conversation-statsAggregate conversation stats, people/place leaderboards, and sampling metadata.
/api/dashboard/plugin-reportsSanitized trusted-plugin operational summaries.
/api/dashboard/conversations/:conversationExpiring conversation transcript; private conversations return redacted metadata only.
/api/dashboard/configSafe dashboard config signals and feature readiness.
/api/dashboard/meSigned-in dashboard identity.

The dashboard UI is a React client using React Router for browser views and TanStack Query to poll dashboard APIs. / shows command-center health, aggregate conversation stats, and recent turn durations; /conversations shows conversation history; /conversations/:conversation shows the transcript and turn/tool-call detail for one conversation; /plugins shows loaded plugin inventory and trusted plugin operational summaries. The dashboard does not wrap Slack webhooks, provider OAuth callbacks, sandbox egress, or /api/internal/*. The conversation feed is a bounded metadata index with the same expiration policy as turn-session checkpoints. Conversation detail reads transcript data from the expiring checkpoint message store, so old transcripts disappear when checkpoint state expires. When SENTRY_DSN initializes the runtime and SENTRY_ORG_SLUG is set, conversation rows include a Sentry conversation link; when the runtime captures a trace ID, conversation detail shows it with the turn metadata. The conversation stats endpoint is separate from the recent feed and includes sampleLimit, sampleSize, and truncated fields so the UI can mark bounded aggregates. Dashboard dates use JUNIOR_TIMEZONE, defaulting to America/Los_Angeles.

For local dashboard visual QA, pass mockConversations: true to juniorDashboardPlugin() or set JUNIOR_DASHBOARD_MOCK_CONVERSATIONS=true for the env-configured path. The sample conversations are read-only reporting fixtures and appear before real session records.

Create a Google OAuth client for the deployment origin. Add this redirect URI:

https://<your-domain>/api/auth/callback/google

Set the required environment variables:

VariablePurpose
GOOGLE_CLIENT_IDGoogle OAuth client ID.
GOOGLE_CLIENT_SECRETGoogle OAuth client secret.

Dashboard cookies are signed with JUNIOR_SECRET by default. Set BETTER_AUTH_SECRET only when you need a separate rotation boundary for browser sessions. Dashboard callbacks use JUNIOR_BASE_URL, Vercel URL envs, or local dev by default. Set BETTER_AUTH_URL only when dashboard auth needs a different public origin.

After deployment:

  1. GET https://<your-domain>/health returns a minimal health JSON response.
  2. GET https://<your-domain>/api/info returns 404.
  3. Opening https://<your-domain>/ starts Google login.
  4. A user from the configured Google Workspace domain reaches the dashboard.
  5. A user outside the configured domain receives 403.

Use Security Hardening to review production auth boundaries, then use Verify & Troubleshoot for deployment smoke checks.