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 14, 2026 at 10:35 am UTC
frontend-inspector 😴 Sleeping (View Logs) Web Oct 14, 2026 at 12:30 am UTC
kitchen-sink 😴 Sleeping (View Logs) Web Oct 14, 2026 at 12:26 am UTC
ladle ✅ Success (View Logs) Web Oct 14, 2026 at 12:22 am UTC
website ❌ Build Failed (View Logs) Web Oct 14, 2026 at 12:20 am 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 and dashboard design mock

This is a large mock-only PR (about 8k lines, nothing wired to a backend). The structure is sensible. The mock routes are gated, the pricing and model logic have unit tests (model.test.ts, scene.test.ts), and there are Ladle stories. I only skimmed the PR and did not run it, so the notes below are what I could confirm from reading the code.

Gating of the mock routes

  • mock.cluster-onboarding.tsx and mock.cluster-map-lab.tsx return notFound() unless import.meta.env.DEV or VITE_DEMO_ROUTE is set. This is fine for a mock.
  • mock.sidebar-lab.tsx should be checked to confirm it has the same guard.
  • __root.tsx redirects / to VITE_DEMO_ROUTE when the variable is set. If the variable leaks into a real build, the login flow is bypassed for everyone. Add a comment or CI guard so it can't be set for production or engine-embedded builds (build:engine).
  • The mock lives outside the authed _context tree, so it renders without a session. That is fine, but it also means the route is publicly reachable on any demo build.

CLAUDE.md conventions

  • Effects: frontend/CLAUDE.md says not to use useEffect for derived state and to ask before adding one. logs-panel.tsx has two effects (lines 59 and 83, one a setInterval) and cluster-map-lab.tsx has two more. Timers and animation may justify them, but derived values should be computed during render. Please confirm each effect is a real external-sync case.
  • Forms: create-cluster-page.tsx and ip-allowlist.tsx import react-hook-form, which matches the convention. I did not review the other useState sites for hand-rolled form state. Runners and settings controls in runners-config.tsx or the dashboard Settings panel should also go through RHF if they are submit-style forms.
  • Em dashes: the repo forbids them in plain-English text. They appear in the user-facing copy in agent-connect.tsx:35, product-page.tsx:90 and create-cluster-page.tsx:312. The "—" placeholder in create-cluster-page.tsx is arguably a UI glyph, but the two copy strings should use periods.
  • Flavors: the mock is flavor-independent, but the PR touches __root.tsx and shared Ladle config (.ladle/ladle.css shrinks by 44 lines). Please confirm the existing Ladle stories and the OSS and cloud shells are unchanged, since the PR description only mentions light and dark mode.
  • Parallel layouts: the new dashboard (settings, billing) duplicates concepts from the existing billing layout and the namespace landing. The duplication is acceptable for a mock. Before this becomes real, follow the OSS/cloud parity rule in frontend/CLAUDE.md.

Quality and maintainability

  • Dead and experimental files are mixed in with the real mock: cluster-map-lab.tsx, sidebar-lab.tsx, mock.sidebar-lab.tsx, mock.cluster-map-lab.tsx, and the ns=select|heading|card|tree search variants. If these are exploration harnesses, consider dropping them before merge or noting that they are temporary. Otherwise they ship in the dev bundle and the generated routeTree.gen.ts.
  • product-content.ts (763 lines) and catalog.ts (990 lines) carry invented pricing, node sizes, and marketing copy. The PR description already says these are placeholders. Mark them clearly in the file headers so the numbers can't be mistaken for real pricing later.
  • Check that frontend/.gitignore and vite.config.ts changes are intentional and don't affect the production build. I couldn't inspect the 13 changed lines in vite.config.ts in detail.

Performance

  • The deployment map (825 lines) and map lab use animation. Make sure the intervals and animation frames are cleaned up on unmount, and that logs-panel bounds its log buffer so a long session doesn't grow without limit.

Tests

  • The pure model and scene logic are covered. There is no component-level coverage, which is acceptable for a mock. The Ladle stories mostly cover the shell. A fixture-driven story for provisioning versus running states on the dashboard would be more useful than prop permutations, per the Ladle guidance.

Overall this looks fine to merge as a design mock once the em dashes are fixed, the effects are justified, and the demo-route guard is confirmed. Consider trimming the lab and exploration files.

This branch had an error being deployed

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