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 19, 2026 at 4:31 pm UTC
frontend-inspector 😴 Sleeping (View Logs) Web Oct 17, 2026 at 8:48 am UTC
kitchen-sink 😴 Sleeping (View Logs) Web Oct 16, 2026 at 9:58 pm UTC
ladle ✅ Success (View Logs) Web Oct 16, 2026 at 9:54 pm UTC
website ❌ Build Failed (View Logs) Web Oct 16, 2026 at 9:50 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 design mock

Overall this is a well-scoped mock. It's gated to dev and demo builds, it uses react-hook-form as CLAUDE.md requires, and it has unit tests for model.ts and scene.ts. I only read the routing, config and gating files plus a grep of the diff. I did not read the ~7k lines of component code in detail.

Issues and suggestions

  1. Mock routes stay in the production bundle. The notFound() guard in mock.cluster-onboarding.tsx and mock.cluster-map-lab.tsx is a runtime check, so the mock UI and catalog.ts are still bundled and the generated route tree references them. If production should never carry them, lazy-load the components so they split into a chunk fetched only on those routes. That also keeps invented pricing out of the main bundle.
  2. VITE_DEMO_ROUTE is a build-time footgun. It redirects / in __root.tsx and unlocks both mock routes, which sit outside the authed tree. Nothing stops it leaking into a real build via a stray .env.local or CI env. Consider failing the build when it is set with a production flavor, or document it in .claude/reference/feature-flags.md.
  3. Feature-flag convention. CLAUDE.md says a whole new page or subsystem should ship behind a flag in features.ts. The env gate may be deliberate for a mock; please confirm. If the real v3 cluster UI builds on these components later, it will need a flag.
  4. Redirect only matches an exact /. location.pathname === "/" may miss the /ui/ base used when multitenancy is off. Check the demo redirect in the OSS flavor, or handle the base path.
  5. Unrelated scope. The vite.config.ts allowedHosts refactor (plus preview.allowedHosts) and the .ladle/ladle.css change (-44 lines) are infrastructure changes. Splitting them out would keep the revision self-contained.
  6. routeTree.gen.ts is generated. Confirm it was regenerated by the router plugin and not hand-edited.
  7. Test coverage. The pure logic (model, scene) is covered. actor-logs.ts (341 lines) and the form flows have no tests, which is acceptable for a mock.
  8. Visual verification. CLAUDE.md asks for checks in OSS and cloud flavors and in light and dark mode. The PR description doesn't mention OSS verification, so please confirm it.

Nits

  • The allowedHosts comment mentions "Amp orbs" and sandbox hostnames. Environment-specific comments like that age badly.
  • Placeholder pricing is hard-coded in catalog.ts. A short note that the values are invented would keep them from being mistaken for real prices.

No security or performance blockers for a dev and demo-only mock. Items 1, 2 and 4 are the ones I'd address before merge.

@claude

claude Bot commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

Review

Frontend-only design mock, so risk is low. It uses react-hook-form for the create form and the allowlist input, and the mock routes are gated behind DEV or VITE_DEMO_ROUTE. I only skimmed the diff and ran nothing (no build, tests, or browser check), so the notes below are from reading it.

Worth addressing

  • Demo-build gating (__root.tsx, mock.*.tsx). VITE_DEMO_ROUTE is a build-time flag that both unlocks the mock routes and redirects / away from the login flow. If it leaks into a real deploy's env, production silently loses its entry point. Consider a build-time guard that fails if it's set together with the auth/platform flags. At minimum, document it next to features.ts instead of only in a comment in __root.tsx.
  • Feature flags. CLAUDE.md asks that significant new panels sit behind a flag in frontend/src/lib/features.ts. The routes are env-gated, which is reasonable for a mock. Please confirm that is the intended approach rather than a flag. Also check the OSS and cloud flavors, since the mock sits outside the _context tree.
  • useState for non-form state. Local UI state like copied, plansOpen and rollouts is fine. selection in the flow (useState(initial)) mirrors form data. Since the create page already uses RHF, keep a single source of truth to avoid drift.
  • Unrelated change in vite.config.ts. Hoisting allowedHosts out of server is a refactor that isn't part of this feature. Consider splitting it into its own revision.
  • Wording. The agent-connect copy and a few comments contain em dashes (e.g. "Copied. Paste it into your agent — it sets up Rivet..."). CLAUDE.md says to avoid them in prose and comments.
  • Secrets in the mock. DiscreteInput shows an admin token and S3 secret key. Make sure these are obvious fakes (e.g. mock_...) so secret scanners and readers don't mistake them for real credentials.

Tests

  • model.test.ts and scene.test.ts cover pricing and scene logic with no mocking, which is good. There is no coverage for the create-form flow, which is acceptable for a mock.

Nits

  • routeTree.gen.ts is regenerated. Make sure it matches the router plugin output.
  • The new .ladle/ config adds Ladle tooling. Confirm the dependency is declared in package.json and that CI doesn't try to build it.
  • Hardcoded placeholder pricing should stay clearly labelled as invented. The PR description already says so, and a short comment in catalog.ts would help.

Overall this looks reasonable as a mock. The main ask is a safer story for VITE_DEMO_ROUTE.

@claude

claude Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Review: cluster onboarding and dashboard design mock

This is a frontend-only mock with no backend wiring, so the risk is low. The code is deterministic and well-structured, and it has unit tests for model.ts and scene.ts. A few items are worth addressing.

Should fix

  • Demo redirect in the root route (routes/__root.tsx): VITE_DEMO_ROUTE makes / redirect to a mock in any build where it is set. The mock routes only 404 when the flag is unset, so one env var turns on both the mock and the redirect. That is fine for a demo deploy, but make sure it is never set in production or cloud CI.
  • Feature flag (CLAUDE.md, Frontend Feature Flags): the mock is a whole page subsystem, but it is gated only by import.meta.env.DEV or VITE_DEMO_ROUTE. If the real feature will ship, put it behind a features.* flag. If it stays a throwaway mock, say so in the PR.
  • Form state (CLAUDE.md, Frontend Forms): the create page, IP allowlist and runner config look like user-submitted forms, but there are 34 added useState calls and only a few react-hook-form references. Please check that the form inputs go through RHF (Controller is fine for Select) rather than controlled useState.
  • Em dashes (CLAUDE.md, Comments): the agent-connect hint strings use an em dash in user-facing copy, for example "Copied. Paste it into your agent — it sets up Rivet...". Use periods instead.

Nits

  • Unrelated changes (frontend/.gitignore, vite.config.ts): the .amp/ ignore entry and the allowedHosts refactor for vite preview are unrelated to the mock. They would be easier to review in a separate change.
  • Ladle CSS (.ladle/ladle.css): it now imports the full src/index.css, which fixes theming. Please confirm that existing stories (xyflow edge colors, for example) still look right, since the old dark overrides were removed.
  • Duplicated PRNG code: rng and hash in actor-logs.ts and seededRandom in actor-metrics.tsx are separate implementations of the same idea. One shared helper would do.
  • Visual verification: please confirm the mock was checked in OSS and cloud flavors, in light and dark mode. The description only mentions light and dark.

Security and performance
There are no security concerns: nothing is wired to a backend, the data is static, and the tokens shown are placeholders. Be sure no real-looking tokens or endpoints in catalog.ts or agent-connect.tsx could be mistaken for real credentials. I saw no performance concerns beyond the animated deployment map, which should clean up timers and animation frames on unmount.

Tests
Coverage of the model and scene logic is good. The UI components have only Ladle stories, which is reasonable for a mock.

@claude

claude Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Review: cluster onboarding design mock

Large, self-contained frontend mock (about 9k added lines). It doesn't touch backend or runtime paths. I read the route and root wiring and skimmed the rest. I did not run the dev server or the tests.

Things to fix

  • Demo gating is easy to enable by accident. The /mock/* routes 404 only when both !DEV and !VITE_DEMO_ROUTE hold (three copies of the guard). If VITE_DEMO_ROUTE leaks into a real build (committed or CI .env), the invented pricing UI ships to production. Consider a CI check that fails production builds when it is set, and a shared assertMockEnabled() helper.
  • VITE_DEMO_ROUTE redirect is unvalidated. redirect({ href: demoRoute }) in __root.tsx accepts any string. Restricting it to a /mock/ prefix avoids a misconfiguration becoming an open redirect.
  • Feature flags. Per CLAUDE.md, a whole new page or panel should sit behind a flag in features.ts. The DEV/demo gate stands in for that. If this becomes real, add a flag.
  • routeTree.gen.ts should be router-plugin output, not hand-edited. Please confirm.

Style and convention checks

  • Possibly unrelated changes: .ladle/ladle.css (-44 lines), vite.config.ts, and the four public/images/brand/*.svg logos. Confirm they belong here or split them out.
  • Brand spelling: user-facing strings should use agentOS, not AgentOS (product-content.ts, catalog.ts).
  • No em dashes in comments or copy (CLAUDE.md), especially in the large product-content.ts and catalog.ts.
  • Forms in create-cluster-page.tsx, runners-config.tsx, ip-allowlist.tsx should use react-hook-form. A mock is a reasonable exception, but adopt it now if this seeds the real flow.
  • Use rivet.dev only. Check endpoint snippets and the agent setup prompt for rivet.gg.

Security

  • The admin token and the connect-your-agent prompt are placeholders. Make sure none look like real credential formats or a working endpoint.
  • No network calls or secrets spotted in the mock routes.

Tests

  • model.test.ts and scene.test.ts cover pricing and scene logic with no module mocking. Good.
  • Per CLAUDE.md, verify the visual change in OSS and cloud flavors (and dark mode) with agent-browser.

Overall: no blocking correctness issues in what I read. Main requests: harden the demo gating and confirm the ladle, vite, and svg changes belong in this PR.

This branch had an error being deployed

1 failed deployment
rivet-frontend / rivet-pr-5849 — acf81aca Deployed Oct 16, 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