-
Notifications
You must be signed in to change notification settings - Fork 26
feat(dashboard): Add authenticated Junior dashboard #448
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
8e0fe04
feat(dashboard): Add authenticated Junior dashboard
dcramer a02797a
fix(dashboard): Avoid regex slash trimming
dcramer 50a6cb3
fix(dashboard): Share handler initialization
dcramer 7b489e4
fix(dashboard): fix auth coverage, test mocks, and reply parallelism
sentry-junior[bot] 28a0e8a
fix(tests): add GEN_AI_SERVER_PORT to pi/client mocks
sentry-junior[bot] 7d5296f
fix(privacy): treat undefined conversation privacy as non-public
sentry-junior[bot] 378d566
fix(privacy): align advisor tool and add sub-route auth test
sentry-junior[bot] 0123461
fix(dashboard): Align reporting with session records
dcramer 1bae1aa
ref(dashboard): Apply component styling policy
dcramer b9f1fdc
fix(dashboard): Polish transcript surfaces
dcramer 2b37668
ref(dashboard): Tighten conversation list framing
dcramer 1487de3
ref(dashboard): Flatten conversation detail view
dcramer 04b2810
ref(dashboard): Decompose dashboard components
dcramer f9cfb87
fix(dashboard): Address dashboard review feedback
dcramer c042e7b
fix(dashboard): Require verified allowlist emails
dcramer c0fe311
fix(dashboard): Preserve resumable turn projections
dcramer 588625a
fix(dashboard): Preserve private redaction state
dcramer a79cdda
fix(runtime): Capture summary checkpoint failures
dcramer aa79188
fix(dashboard): Index turn summaries by conversation
dcramer d16817f
fix(dashboard): Restart sign-in after API auth expiry
dcramer e94f527
fix(dashboard): Retry handler initialization after failure
dcramer 96db416
style(dashboard): Use Tailwind for forbidden fallback
dcramer e71b5bb
fix(dashboard): Harden private metadata handling
dcramer 24cf7d4
docs(dashboard): Clarify route ownership
dcramer 2d01fdd
fix(dashboard): Sanitize session identity responses
dcramer d07cbf4
fix(example): Gate dashboard auth bypass to local dev
dcramer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| --- | ||
| title: Dashboard | ||
| description: Mount the authenticated Junior dashboard with Google domain auth. | ||
| type: tutorial | ||
| summary: Add the dashboard package to a Nitro deployment and protect diagnostics with Better Auth and Google domain authorization. | ||
| prerequisites: | ||
| - /start-here/existing-app/ | ||
| - /reference/config-and-env/ | ||
| related: | ||
| - /reference/handler-surface/ | ||
| - /operate/security-hardening/ | ||
| - /start-here/verify-and-troubleshoot/ | ||
| --- | ||
|
|
||
| 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 | ||
|
|
||
| Install the dashboard package next to `@sentry/junior`: | ||
|
|
||
| ```bash | ||
| pnpm add @sentry/junior-dashboard | ||
| ``` | ||
|
|
||
| ## Mount the routes | ||
|
|
||
| Add `juniorDashboardNitro()` before the catch-all Junior route. Configure the Google Workspace domain that should be allowed to view the dashboard: | ||
|
|
||
| ```ts title="nitro.config.ts" | ||
| import { defineConfig } from "nitro"; | ||
| import { juniorDashboardNitro } from "@sentry/junior-dashboard/nitro"; | ||
| import { juniorNitro } from "@sentry/junior/nitro"; | ||
|
|
||
| export default defineConfig({ | ||
| preset: "vercel", | ||
| modules: [ | ||
| juniorNitro({ | ||
| plugins: { | ||
| packages: ["@sentry/junior-sentry"], | ||
| }, | ||
| }), | ||
| juniorDashboardNitro({ | ||
| allowedGoogleDomains: ["sentry.io"], | ||
| trustedOrigins: ["https://<your-domain>"], | ||
| }), | ||
| ], | ||
| routes: { | ||
| "/**": { handler: "./server.ts" }, | ||
| }, | ||
| }); | ||
| ``` | ||
|
|
||
| You can also provide the same authorization policy through deployment environment variables when the handler is loaded outside Nitro's virtual module path: | ||
|
|
||
| | Variable | Purpose | | ||
| | ---------------------------------- | ------------------------------------------------------------- | | ||
| | `JUNIOR_DASHBOARD_GOOGLE_DOMAINS` | Comma-separated or JSON array of allowed Google domains. | | ||
| | `JUNIOR_DASHBOARD_ALLOWED_EMAILS` | Comma-separated or JSON array of explicit email allowlist. | | ||
| | `JUNIOR_DASHBOARD_TRUSTED_ORIGINS` | Comma-separated or JSON array of Better Auth trusted origins. | | ||
| | `JUNIOR_DASHBOARD_AUTH_REQUIRED` | Set to `false` only for explicit local dashboard auth bypass. | | ||
|
|
||
| The dashboard package owns these routes: | ||
|
|
||
| | Route | Purpose | | ||
| | ------------------ | --------------------------------------- | | ||
| | `/` | Authenticated command-center UI. | | ||
| | `/conversations` | Authenticated conversation-history 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: | ||
|
|
||
| | Endpoint | Purpose | | ||
| | -------------------------------------------- | -------------------------------------------------------------------------------------- | | ||
| | `/api/dashboard/health` | Health status for the command center pulse. | | ||
| | `/api/dashboard/runtime` | Runtime paths, providers, skills, and packages. | | ||
| | `/api/dashboard/plugins` | Loaded plugin list. | | ||
| | `/api/dashboard/skills` | Discovered skill list. | | ||
| | `/api/dashboard/sessions` | Recent conversation feed from turn-session checkpoints. | | ||
| | `/api/dashboard/conversations/:conversation` | Expiring conversation transcript; private conversations return redacted metadata only. | | ||
| | `/api/dashboard/config` | Safe dashboard config signals and feature readiness. | | ||
| | `/api/dashboard/me` | Signed-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 and recent turn durations; `/conversations` shows conversation history; `/conversations/:conversation` shows the transcript and turn/tool-call detail for one conversation. 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. | ||
| Dashboard dates use `JUNIOR_TIMEZONE`, defaulting to `America/Los_Angeles`. | ||
|
|
||
| ## Configure Google auth | ||
|
|
||
| Create a Google OAuth client for the deployment origin. Add this redirect URI: | ||
|
|
||
| ```text | ||
| https://<your-domain>/api/auth/callback/google | ||
| ``` | ||
|
|
||
| Set the required environment variables: | ||
|
|
||
| | Variable | Purpose | | ||
| | ---------------------- | --------------------------- | | ||
| | `GOOGLE_CLIENT_ID` | Google OAuth client ID. | | ||
| | `GOOGLE_CLIENT_SECRET` | Google 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. | ||
|
|
||
| ## Verify | ||
|
|
||
| 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`. | ||
|
|
||
| ## Next step | ||
|
|
||
| Use [Security Hardening](/operate/security-hardening/) to review production auth boundaries, then use [Verify & Troubleshoot](/start-here/verify-and-troubleshoot/) for deployment smoke checks. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.