Skip to content

feat(frontend): add cluster onboarding and dashboard design mock - #5849

Open
NicholasKissel wants to merge 1 commit into
mainfrom
feat/cluster-onboarding-mock
Open

NicholasKissel wants to merge 1 commit into
mainfrom
feat/cluster-onboarding-mock

Conversation

@NicholasKissel

@NicholasKissel NicholasKissel commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Interactive design mock (not wired to a backend) of the v3 cluster onboarding and cluster dashboard, rendered inside the real frontend shell so it picks up the dashboard theme in light and dark mode.

Try it: /mock/cluster-onboarding on the dev server (create page) or ?view=dashboard for a provisioned cluster. Ladle stories under cluster-onboarding/*.

Create page

  • Cloud first (AWS, GCP, Azure, Hetzner, BYOC), then region, plan, runners, name, allowed IPs; Aiven-style summary rail on the right with the monthly total.
  • Plan = control plane preconfigured by level (Free 1×R-5, Hobby 1×R-10, Team 3×R-20, Enterprise 3×R-40). Runners are sized manually: node size + node count, priced per node for the chosen cloud (Hetzner cheaper, BYOC billed by your cloud).

Dashboard

  • Overview: provisioning/running badge, "Connect your agent to Rivet" pill that copies a single setup prompt, connection information (external + internal endpoint, one admin token, S3-compatible object storage), deployment map, builds with which one is deployed.
  • Deployment map: public internet → control plane (object storage attached) → runners; every node shows provisioning/ready. New nodes added in Settings show up provisioning.
  • Logs: basic merged log stream.
  • Billing: control plane (fixed), runner compute, actor storage, object storage, egress; plan dialog and usage rows reuse the existing billing layout.
  • Settings: control plane (read-only), runner scaling, IP allowlist.

Pricing, node sizes, and provisioning timings are invented placeholders.

@railway-app

railway-app Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

🚅 Deployed to the rivet-pr-5849 environment in rivet-frontend

Service Status Web Updated
frontend-cloud 😴 Sleeping (View Logs) Web Oct 11, 2026 at 1:37 pm UTC
kitchen-sink 😴 Sleeping (View Logs) Web Oct 11, 2026 at 4:53 am UTC
frontend-inspector 😴 Sleeping (View Logs) Web Oct 11, 2026 at 3:42 am UTC
ladle ✅ Success (View Logs) Web Oct 10, 2026 at 5:22 pm UTC
website ❌ Build Failed (View Logs) Web Oct 10, 2026 at 5:20 pm UTC
mcp-hub ✅ Success (View Logs) Web Oct 7, 2026 at 4:01 pm UTC

@the-company-company the-company-company Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 4 medium-severity findings

Reviewed commit c82ae4f.

Comment on lines +285 to +293
export const SETUP_PROMPT_URL = "https://rivet.dev/agent-setup/prompt.md";

/**
* The one line the user pastes into their agent. Everything else (skills,
* MCP server, CLI) lives in the file at SETUP_PROMPT_URL, like Cloudflare's
* agent-setup/prompt.md, so the dashboard never has to explain per-client
* install steps.
*/
export const SETUP_PROMPT = `Fetch and execute the appropriate instructions to set me up for Rivet from ${SETUP_PROMPT_URL}`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Medium · The copied setup prompt points to a 404

The dashboard's primary “Connect your agent” action copies this string, but https://rivet.dev/agent-setup/prompt.md currently returns HTTP 404 and this PR does not add anything that publishes the setupPrompt() content below. An agent following the copied instruction therefore cannot perform any setup. Publish the prompt at this URL as part of the change, or have the button copy the generated instructions directly until that endpoint exists.

);
const [logs, setLogs] = useState<NamespaceLog[]>(() =>
actors
.flatMap((actor) =>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Medium · Namespace changes keep showing the previous namespace's logs

This state is initialized once from useCase and region; the namespace prop is used only in the export filename. Selecting another namespace therefore leaves the same actor history and live stream visible—even a newly created namespace whose table row says it has zero actors immediately shows production logs. Key or regenerate the mock log state by namespace (with empty data for a new namespace), so switching namespaces actually changes the isolated dataset.

Comment on lines +97 to +98
} = useLogScroll({
logs: visible,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Medium · Filtering can leave stale rows visible

useLogScroll intentionally freezes its input while follow is false and only accepts a replacement when the first entry changes. After scrolling up, a filter whose matches retain the same first row—or a filter with zero matches—therefore keeps rendering the old unfiltered displayedLogs, while the counter and export use the filtered visible array. Reset following/frozen state when the filter changes, or filter displayedLogs after the scroll hook so the rows, count, and export stay consistent.

Comment on lines +375 to +379
title="Cluster name"
description="Used in your endpoint hostname and in the dashboard."
>
<Input
{...form.register("name", { required: true })}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Medium · Cluster names can generate invalid endpoints

required accepts whitespace and arbitrary punctuation, but clusterEndpoints() later turns this value directly into a DNS label and S3 bucket. For example, !!! provisions successfully and displays https://---.us-east-1.rivet.run with bucket ---, while a whitespace-only name becomes an empty/invalid label. Validate the submitted name against the actual cluster/DNS naming rules (including nonempty normalized output and length) and show the validation error before provisioning.

@claude

claude Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Review: cluster onboarding design mock

Well-scoped, self-contained mock. It sits outside the authed route tree, the pricing model has unit tests, and the production gating is sensible.

Should fix

  • frontend/.amp/portals/.proxies is a sandbox artifact (local proxy port and service name). Remove it and gitignore frontend/.amp/.
  • VITE_DEMO_ROUTE is build-time only. If it is set in a real production build, / redirects every visitor to the mock. Nothing enforces the "gitignored .env.local" comment, so consider a build warning.
  • mock.cluster-onboarding.tsx unhides the route for any truthy VITE_DEMO_ROUTE, even one pointing elsewhere. Compare against the mock path or use an explicit boolean.

Conventions (CLAUDE.md)

  • An em dash appears in the copied agent prompt in agent-connect.tsx. Use periods. (The placeholder dash in the summary is UI text and probably fine.)
  • A whole new panel set not available in every flavor is the case where CLAUDE.md asks for a features.* flag. Confirm with the user whether one is wanted. Verification was only done on a staging build, not OSS.
  • Forms (create flow, New namespace dialog, allowlist editor) should use react-hook-form. I found only 4 useForm references in the diff, so please check none hand-roll useState inputs.

Minor

  • Sharing allowedHosts between dev and vite preview is a good refactor.
  • Ladle now uses the real src/index.css. Please confirm existing stories still render in both themes.
  • Make sure nothing in catalog.ts looks like a real credential (admin tokens shown are fake).

Tests
model.test.ts covers the pricing and quote model. UI is untested, which is acceptable for a mock.

@claude

claude Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Review: v3 cluster onboarding design mock

Overall this is a self-contained mock. It sits under /mock/*, outside the authed tree, and has unit tests for the pricing model (model.test.ts). I read the shared and infra changes (__root.tsx, vite.config.ts, .gitignore, .ladle/*, mock routes) closely. I only skimmed the component bodies, and I did not run the app or the tests.

Issues worth addressing

  1. Demo redirect in __root.tsx. VITE_DEMO_ROUTE redirects / for every flavor, and it is a build-time flag. Nothing enforces that it is unset in production builds. Consider also requiring !features.auth. Also check the OSS /ui/ base, where the pathname may not be exactly /.
  2. Feature flag. Per CLAUDE.md, a whole new panel should be behind a features.* flag, or the PR should say the mock is deliberately exempt. Confirm the mock is lazy-loaded and not in the main bundle for the OSS and cloud flavors.
  3. Form state. CLAUDE.md requires react-hook-form for user-submitted form state. The create page uses it. ip-allowlist.tsx, runners-config.tsx and the settings editors use plain useState. If they accept input, move them to RHF.
  4. Unrelated changes bundled in. The .amp/ gitignore entry and the allowedHosts refactor (plus preview.allowedHosts) in vite.config.ts are sandbox tooling and belong in a separate change.
  5. .ladle/ladle.css rewrite. It drops the forced dark theme and theme import, which affects every existing Ladle story. Please verify the other stories still render.
  6. mock.cluster-map-lab is a dev harness but ships in demo builds. Gate it on DEV only.

Style

  • Avoid em dashes in prose and UI copy (CLAUDE.md), for example "Copied. Paste it into your agent — it sets up Rivet…" in agent-connect.tsx.
  • Make sure timers and animation frames in cluster-map-lab.tsx and deployment-map.tsx are cleaned up on unmount.

Tests
model.test.ts is good. There is no coverage of the beforeLoad guards (demo redirect and notFound), and a small test would protect the production 404 behavior.

Security
This is frontend only. Make sure the admin token and S3 credentials shown in the connection panel are obviously fake strings.

Nothing blocking. Items 1, 2 and 5 are the ones I would resolve before merging.

🤖 Generated with Claude Code

@NicholasKissel
NicholasKissel force-pushed the feat/cluster-onboarding-mock branch from 7bb99e8 to 092bb7f Compare October 9, 2026 20:49
@NicholasKissel
NicholasKissel force-pushed the feat/cluster-onboarding-mock branch from 092bb7f to 52a1175 Compare October 9, 2026 21:10
@NicholasKissel
NicholasKissel force-pushed the feat/cluster-onboarding-mock branch from 52a1175 to 38390df Compare October 9, 2026 21:24
@NicholasKissel
NicholasKissel force-pushed the feat/cluster-onboarding-mock branch from 38390df to 145f9fa Compare October 9, 2026 22:26
@NicholasKissel
NicholasKissel force-pushed the feat/cluster-onboarding-mock branch from 145f9fa to 3427ef3 Compare October 9, 2026 22:34
@NicholasKissel
NicholasKissel force-pushed the feat/cluster-onboarding-mock branch from 3427ef3 to 6ab0d69 Compare October 9, 2026 22:56
@NicholasKissel
NicholasKissel force-pushed the feat/cluster-onboarding-mock branch from 6ab0d69 to 46da0e0 Compare October 9, 2026 23:17
@NicholasKissel
NicholasKissel force-pushed the feat/cluster-onboarding-mock branch from 46da0e0 to fe70ac3 Compare October 9, 2026 23:30
@NicholasKissel
NicholasKissel force-pushed the feat/cluster-onboarding-mock branch from fe70ac3 to 2e5fc42 Compare October 9, 2026 23:38
@claude

claude Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Review: cluster onboarding and dashboard design mock

This is a non-wired design mock, so my feedback is mostly about keeping it contained. I reviewed the PR metadata and a grep of the added lines. I couldn't read the full diff, so the points below are from that grep and not a line-by-line read.

Things to check

  • Production exposure: Confirm /mock/cluster-onboarding and /mock/cluster-map-lab are not reachable in production or cloud builds. Gate them on import.meta.env.DEV, or put them behind a flag in frontend/src/lib/features.ts as CLAUDE.md describes. The invented pricing and provisioning copy shouldn't ship to real users.
  • Root and Vite changes: I couldn't read the __root.tsx and vite.config.ts changes. Check that the mock shell and Ladle setup don't alter normal routing or build output. routeTree.gen.ts is generated, so regenerate it and don't edit it by hand.
  • Flavor testing: CLAUDE.md asks for visual changes to be checked in OSS and cloud flavors. Say in the PR whether you did that.

Conventions

  • Forms: create-cluster-page.tsx and ip-allowlist.tsx use react-hook-form, which matches the convention. runners-config.tsx and the settings panels hold values in useState (runnerCount, selection, filter). If any of those are user-submitted form inputs, they should go through RHF too. The log filter is probably fine as plain state.
  • Dashes: The comment rule bans em dashes in prose. The user-facing copy has some (for example Paste it into your agent — it sets up Rivet). In UI strings it's a minor point, but check code comments for the same.
  • Tests: model.test.ts and scene.test.ts cover the pricing model and scene logic, which is good. If any vi.waitFor calls were added, they need the adjacent justification comment.

Code quality

  • cluster-dashboard-page.tsx holds many independent useState hooks (view, deployed build, rollouts, engine version, pending). Consider a useReducer or extracting sub-components if the mock grows.
  • scene.ts and cluster-map-lab.tsx use timers and a useSyncExternalStore scene. Verify that intervals, animation frames and subscriptions are cleaned up on unmount.

Security and performance: No concerns. This is mock data with no backend calls. The admin token and endpoints shown must be hard-coded fake values, so make sure none of them look like real credentials.

Overall this is reasonable for a mock. The main ask is to gate the routes out of production builds.

@claude

claude Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Review: cluster onboarding and dashboard design mock

I reviewed this from the PR diff and metadata. I didn't run the app, tests or Ladle, and I only skimmed vite.config.ts and the per-component logic. Treat the points below as things to check, not confirmed bugs.

Looks good

  • The code is isolated under components/cluster-onboarding/ and the mock.* routes. It doesn't touch real data providers.
  • model.test.ts and scene.test.ts cover the pricing and scene logic.
  • The create-cluster and IP-allowlist forms use react-hook-form, as CLAUDE.md requires.

Suggestions

  1. useEffect use. frontend/CLAUDE.md says to derive state during render and to ask before adding an effect. logs-panel.tsx, cluster-map-lab.tsx and the scene hook use useEffect, probably for timers and log streaming. If they are real subscriptions or timers, add a short comment saying why. Otherwise derive the values during render.
  2. Hand-rolled keyboard handling. Use useHotkey instead of window.addEventListener("keydown") if any of the mock code adds one. I didn't spot one.
  3. Em dashes in user-facing copy. The copied-confirmation text in agent-connect.tsx is "Copied. Paste it into your agent — it sets up…". CLAUDE.md bans em dashes in plain-English text, so split it into sentences.
  4. Mock routes in production builds.
    • /mock/cluster-onboarding and /mock/cluster-map-lab are registered unconditionally in routeTree.gen.ts. Real production bundles will therefore ship the mock and its invented pricing.
    • Consider gating them with import.meta.env.DEV or a feature flag. CLAUDE.md asks for a flag on a whole new page or subsystem that isn't available in every flavor.
    • The VITE_DEMO_ROUTE redirect in __root.tsx is env-gated, which is fine. A short comment noting that it must stay unset for engine and cloud builds would help.
  5. Flavor check. Please confirm the shell renders correctly in both OSS and cloud, as the Frontend Visual Changes section requires. The PR description only mentions the default theme in light and dark.
  6. Ladle stories. The .ladle CSS and config changes touch shared setup. The ladle.css diff is 7 additions and 44 deletions, so confirm the existing stories still look right.
  7. Component size. catalog.ts (990 lines), deployment-map.tsx (825) and billing-panel.tsx (555) are large for a mock. That's acceptable, but the invented pricing in catalog.ts should be clearly labelled as placeholder so nobody wires it to real billing.

I found no security concerns. The PR only changes frontend code and nothing sends data to a backend.

This branch had an error being deployed

1 failed deployment
rivet-frontend / rivet-pr-5849 — 9cd9fabd Deployed Oct 10, 2026 by railway-app[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant