Skip to content

feat: implement authentication state management and routing logic#340

Merged
webdevcody merged 5 commits intomainfrom
fix-web-mode-auth
Jan 1, 2026
Merged

feat: implement authentication state management and routing logic#340
webdevcody merged 5 commits intomainfrom
fix-web-mode-auth

Conversation

@webdevcody
Copy link
Collaborator

@webdevcody webdevcody commented Jan 1, 2026

  • Added a new auth store using Zustand to manage authentication state, including authChecked and isAuthenticated.
  • Updated LoginView to set authentication state upon successful login and navigate based on setup completion.
  • Enhanced RootLayoutContent to enforce routing rules based on authentication status, redirecting users to login or setup as necessary.
  • Improved error handling and loading states during authentication checks.

Summary by CodeRabbit

  • Bug Fixes

    • More reliable authentication, routing and startup gating; redirects now wait for auth/setup checks and show a "Redirecting to login..." message.
    • Improved Electron vs Web startup sequencing, WebSocket timing, session/logout and health-check behavior.
    • Sandbox gating and warnings behave consistently during init and redirects.
  • New Features

    • Centralized authentication state store.
    • Option to skip future sandbox warnings with persistent setting, dialog checkbox and UI control (Danger Zone).
    • Added backlog-plan event support.
  • Chores

    • Build step added to ensure shared packages are built before launching the web app.

✏️ Tip: You can customize this high-level summary in your review settings.

- Added a new auth store using Zustand to manage authentication state, including `authChecked` and `isAuthenticated`.
- Updated `LoginView` to set authentication state upon successful login and navigate based on setup completion.
- Enhanced `RootLayoutContent` to enforce routing rules based on authentication status, redirecting users to login or setup as necessary.
- Improved error handling and loading states during authentication checks.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 1, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Centralizes UI auth in a new Zustand store, updates login/root to set and gate on auth/setup state, defers WebSocket startup by environment, and adds a persisted skipSandboxWarning setting with UI and dialog controls.

Changes

Cohort / File(s) Summary
Auth store & login
apps/ui/src/store/auth-store.ts, apps/ui/src/components/views/login-view.tsx
New useAuthStore (authChecked, isAuthenticated, setAuthState, resetAuth). Login sets auth state on success and routes to / or /setup; minor error UI class tweak.
Root routing & sandbox init
apps/ui/src/routes/__root.tsx
Swap to useAuthStore, add authCheckRunning guard, in-memory sandbox status flow (remove sessionStorage), guarded redirects to /login or /setup, and conditional layout rendering.
HTTP client & WebSocket init
apps/ui/src/lib/http-api-client.ts
Harden Electron detection, narrow Electron API access, defer WebSocket in Web mode, require/retry API key before WS in Electron, add logout JSON body/Content-Type, add backlog-plan:event, adjust init sequencing.
Sandbox settings & dialogs
apps/ui/src/store/app-store.ts, apps/ui/src/hooks/use-settings-migration.ts, libs/types/src/settings.ts, apps/ui/src/components/dialogs/sandbox-risk-dialog.tsx, apps/ui/src/components/views/settings-view*.tsx, apps/ui/src/components/views/settings-view/danger-zone/danger-zone-section.tsx
Add persisted skipSandboxWarning and setSkipSandboxWarning; sync to server; dialog onConfirm(skipInFuture) with checkbox; settings UI shows/reset skip state and conditional Danger Zone panel.
CLI/bootstrap script
init.mjs
Add runNpmAndWait() helper, run build:packages before dev servers, switch to _dev:* script usage.

Sequence Diagram(s)

sequenceDiagram
  rect rgba(235,245,255,0.35)
  participant Browser as Browser (Renderer)
  participant Root as Root Route
  participant AuthStore as useAuthStore
  participant HttpClient as HttpApiClient
  participant Server as API / WebSocket
  end

  Note over Browser,Root: App startup (Web mode)
  Browser->>Root: mount
  Root->>AuthStore: initAuth() [guarded by authCheckRunning]
  AuthStore->>HttpClient: verifySession / getServerUrlSync
  HttpClient->>Server: GET /api/health
  alt session valid
    Server-->>HttpClient: 200
    HttpClient-->>AuthStore: setAuthState(isAuthenticated: true, authChecked: true)
    Root->>Browser: render app or navigate /setup (based on setupComplete)
  else unauthenticated
    HttpClient-->>AuthStore: setAuthState(isAuthenticated: false, authChecked: true)
    Root->>Browser: redirect to /login
  end

  Note over Browser,HttpClient: Event subscription (deferred)
  Browser->>HttpClient: subscribeToEvents()
  alt Web mode
    HttpClient->>Server: open WebSocket (deferred until subscription)
  else Electron mode
    HttpClient->>AuthStore: await API key
    AuthStore-->>HttpClient: API key available
    HttpClient->>Server: open WebSocket (with API key)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

Enhancement, Ready-To-Merge

Poem

🐰 I hopped through stores and toggled a flag,

Guarded the auth check so it won't lag.
Electron waits while Web softly queues,
Sandbox checkbox remembers your views.
A nimble rabbit claps—"Deployed with no snag!"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately reflects the main objective of the changeset—implementing authentication state management and routing logic.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 90c89ef and 844be65.

📒 Files selected for processing (2)
  • apps/ui/src/hooks/use-settings-migration.ts
  • libs/types/src/settings.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always import from shared packages (@automaker/*), never from old relative paths

Files:

  • libs/types/src/settings.ts
  • apps/ui/src/hooks/use-settings-migration.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use resolveModelString() from @automaker/model-resolver to convert model aliases (haiku, sonnet, opus) to full model names

Files:

  • libs/types/src/settings.ts
  • apps/ui/src/hooks/use-settings-migration.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: AutoMaker-Org/automaker PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-28T05:07:48.147Z
Learning: Frontend UI must use TanStack Router for file-based routing, organize components in components/views/, implement stores with Zustand, and use custom hooks in hooks/ directory
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: e2e
🔇 Additional comments (2)
libs/types/src/settings.ts (1)

356-357: LGTM! Clean addition with secure defaults.

The new skipSandboxWarning flag is well-implemented:

  • Optional property for backward compatibility
  • Clear documentation
  • Default value of false ensures the security warning is shown by default
  • Logically grouped with related sandbox settings

Also applies to: 536-536

apps/ui/src/hooks/use-settings-migration.ts (1)

229-229: LGTM! Consistent implementation.

The skipSandboxWarning flag is correctly added to the sync payload, following the same pattern as other settings. The placement next to enableSandboxMode is logical and maintains readability.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @webdevcody, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly overhauls the application's authentication and routing mechanisms, particularly for web mode. It establishes a centralized authentication state using Zustand, ensuring consistent tracking of user login status and whether an authentication check has been performed. This new system, combined with refined routing logic in the root layout, guarantees that users are seamlessly directed to the appropriate views—login, setup, or the main application—based on their authentication status and setup completion. Additionally, it includes several robustness improvements to the HTTP API client, especially concerning Electron environment detection and WebSocket connection handling.

Highlights

  • Authentication State Management: Introduced a new Zustand store (auth-store.ts) to centrally manage authentication state, including authChecked (whether auth status has been determined) and isAuthenticated.
  • Login and Setup Routing: The LoginView now updates the global authentication state upon successful login and intelligently navigates users to either the main application (/) or the setup page (/setup) based on whether initial setup is complete.
  • Root Layout Routing Enforcement: The RootLayoutContent component has been enhanced to enforce comprehensive routing rules. It redirects unauthenticated users to the login page and authenticated users to the setup page if setup is incomplete, ensuring a guided user experience.
  • Improved Authentication Flow: The authentication initialization logic in RootLayoutContent has been refined to prevent concurrent auth checks, handle Electron vs. web mode authentication distinctly, and provide a loading state during redirects.
  • HTTP Client Enhancements: The http-api-client.ts received updates for more robust Electron API integration, a more reliable isElectronMode check, and conditional WebSocket connection logic to prevent premature connections and 401 errors in web mode.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new useAuthStore (Zustand) to centralize authentication state management, replacing local state in LoginView and __root.tsx. The LoginView now uses this store to determine navigation after successful login, redirecting to /setup if initial setup is incomplete. Significant changes were made to __root.tsx to implement robust routing rules for web mode: unauthenticated users are forced to /login, and authenticated users with incomplete setup are directed to /setup. The http-api-client.ts file was updated to refine Electron mode detection, improve server URL initialization, and make WebSocket connection conditional based on the environment (immediate in Electron, deferred in web). Additionally, the sandbox risk acknowledgment logic was modified to no longer persist user choices via sessionStorage, causing the confirmation dialog to appear on every page refresh, which a reviewer noted could lead to a frustrating user experience. Other minor changes include adding a backlog-plan:event type, ensuring proper headers for logout requests, and updating a CSS utility class.

Comment on lines +45 to +47
// Always start from pending on a fresh page load so the user sees the prompt
// each time the app is launched/refreshed (unless running in a container).
const [sandboxStatus, setSandboxStatus] = useState<SandboxStatus>('pending');
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This change causes the sandbox confirmation dialog to appear on every page refresh, as the user's choice is no longer persisted in sessionStorage. While the comment suggests this is intentional, it may lead to a frustrating user experience. Consider restoring the use of sessionStorage to remember the user's confirmation for the duration of their session.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
apps/ui/src/lib/http-api-client.ts (1)

454-474: Potential reconnect timer leak on rapid calls.

If connectWebSocket() is called multiple times in quick succession while apiKey is unavailable, each call could potentially schedule its own timer before the previous one fires. The guard if (!this.reconnectTimer) mitigates this, but there's a small window where isConnecting is set to false before the timer check.

Consider verifying isConnecting is only cleared after the timer decision:

🔎 Suggested improvement
       if (!apiKey) {
         console.warn(
           '[HttpApiClient] Electron mode: API key not ready, delaying WebSocket connect'
         );
-        this.isConnecting = false;
         if (!this.reconnectTimer) {
           this.reconnectTimer = setTimeout(() => {
             this.reconnectTimer = null;
             this.connectWebSocket();
           }, 250);
         }
+        this.isConnecting = false;
         return;
       }
apps/ui/src/routes/__root.tsx (1)

44-47: Sandbox status resets on every page refresh.

The comment clarifies this is intentional—users see the sandbox confirmation prompt each time. If this becomes a UX friction point, consider persisting the confirmation in sessionStorage for the browser session.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bd432b1 and 59d4792.

📒 Files selected for processing (4)
  • apps/ui/src/components/views/login-view.tsx
  • apps/ui/src/lib/http-api-client.ts
  • apps/ui/src/routes/__root.tsx
  • apps/ui/src/store/auth-store.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always import from shared packages (@automaker/*), never from old relative paths

Files:

  • apps/ui/src/store/auth-store.ts
  • apps/ui/src/components/views/login-view.tsx
  • apps/ui/src/routes/__root.tsx
  • apps/ui/src/lib/http-api-client.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use resolveModelString() from @automaker/model-resolver to convert model aliases (haiku, sonnet, opus) to full model names

Files:

  • apps/ui/src/store/auth-store.ts
  • apps/ui/src/components/views/login-view.tsx
  • apps/ui/src/routes/__root.tsx
  • apps/ui/src/lib/http-api-client.ts
🧠 Learnings (4)
📚 Learning: 2025-12-30T01:02:07.114Z
Learnt from: illia1f
Repo: AutoMaker-Org/automaker PR: 324
File: apps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsx:122-131
Timestamp: 2025-12-30T01:02:07.114Z
Learning: Tailwind CSS v4 uses postfix syntax for the important modifier: append ! at the end of the utility class (e.g., backdrop-blur-[0px]! or hover:bg-red-500!). The older v3 style used a prefix (!) at the start (e.g., !backdrop-blur-[0px]); prefer the postfix form for consistency across TSX files.

Applied to files:

  • apps/ui/src/components/views/login-view.tsx
  • apps/ui/src/routes/__root.tsx
📚 Learning: 2025-12-28T05:07:48.147Z
Learnt from: CR
Repo: AutoMaker-Org/automaker PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-28T05:07:48.147Z
Learning: Frontend UI must use TanStack Router for file-based routing, organize components in components/views/, implement stores with Zustand, and use custom hooks in hooks/ directory

Applied to files:

  • apps/ui/src/routes/__root.tsx
📚 Learning: 2025-12-28T05:07:48.147Z
Learnt from: CR
Repo: AutoMaker-Org/automaker PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-28T05:07:48.147Z
Learning: Store project-specific rules in `.automaker/context/` and load them into agent prompts via `loadContextFiles()` from automaker/utils

Applied to files:

  • apps/ui/src/routes/__root.tsx
📚 Learning: 2025-12-28T05:07:48.147Z
Learnt from: CR
Repo: AutoMaker-Org/automaker PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-28T05:07:48.147Z
Learning: Applies to apps/server/src/**/*.{ts,tsx} : Use `createEventEmitter()` from `lib/events.ts` for all server operations to emit events that stream to frontend via WebSocket

Applied to files:

  • apps/ui/src/lib/http-api-client.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: e2e
🔇 Additional comments (11)
apps/ui/src/lib/http-api-client.ts (4)

43-53: LGTM on the Electron API narrowing.

The as any cast is documented and necessary to access Electron-only helpers not in the shared interface. The null-safe checks (electron?.getServerUrl) protect against non-browser environments.


114-122: Consider simplifying the Electron mode detection.

The check api?.isElectron === true || !!api?.getApiKey has redundancy—if isElectron is the stable marker, getApiKey availability shouldn't be needed as a fallback. However, the comment explains this guards against early-startup timing issues, so the defensive approach is reasonable.


317-322: Empty body on logout is unusual but harmless.

Adding body: '{}' to the fire-and-forget logout request is not strictly necessary for a POST without payload, but it ensures compatibility with servers that expect a body. No functional issue.


391-407: WebSocket initialization strategy looks correct.

Deferring WebSocket in web mode until subscription avoids 401 errors on unauthenticated routes. The .catch() fallback ensures WebSocket attempts proceed even if API key init fails—reasonable resilience.

apps/ui/src/components/views/login-view.tsx (1)

14-20: LGTM on auth store integration.

The selectors correctly pull setAuthState and setupComplete from their respective stores, enabling centralized state management.

apps/ui/src/store/auth-store.ts (1)

1-29: Clean, minimal auth store implementation.

The design correctly separates UI auth state from the server's cookie-based source of truth. The non-persisted approach ensures fresh auth checks on each page load.

apps/ui/src/routes/__root.tsx (5)

36-41: Good use of derived route flags.

Computing isSetupRoute and isLoginRoute from location.pathname keeps the conditional rendering logic readable.


149-195: Auth initialization guard is well-designed.

The authCheckRunning ref correctly prevents concurrent auth checks without causing re-renders. Directly calling useAuthStore.getState().setAuthState() outside React's render cycle is the correct pattern for async operations.


218-242: Routing rules are comprehensive and correctly ordered.

The logic properly:

  1. Waits for hydration
  2. Waits for auth check (web mode)
  3. Forces /login for unauthenticated users
  4. Forces /setup for authenticated but incomplete setup
  5. Redirects away from /setup when complete

252-264: Health check timeout is a good addition.

Using AbortSignal.timeout(2000) prevents the health check from hanging indefinitely in web mode. This improves resilience.


331-348: Loading and redirect states provide good UX.

The intermediate "Loading..." and "Redirecting to login..." states prevent layout flash and provide user feedback during async transitions.

Comment on lines 30 to +37
try {
const result = await login(apiKey.trim());
if (result.success) {
// Redirect to home/board on success
navigate({ to: '/' });
// Mark as authenticated for this session (cookie-based auth)
setAuthState({ isAuthenticated: true, authChecked: true });

// After auth, determine if setup is needed or go to app
navigate({ to: setupComplete ? '/' : '/setup' });
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if useSetupStore has persist middleware and how it's initialized
ast-grep --pattern 'useSetupStore = create($$$)'
echo "---"
rg -n 'persist' apps/ui/src/store/setup-store.ts

Repository: AutoMaker-Org/automaker

Length of output: 133


🏁 Script executed:

#!/bin/bash
# Read setup-store.ts to understand persist configuration
cat -n apps/ui/src/store/setup-store.ts | head -150

echo "---"
# Check login-view.tsx for context around the login logic
cat -n apps/ui/src/components/views/login-view.tsx | sed -n '1,50p'

Repository: AutoMaker-Org/automaker

Length of output: 6985


🏁 Script executed:

#!/bin/bash
# Read more of setup-store.ts to see persist configuration
cat -n apps/ui/src/store/setup-store.ts | sed -n '125,170p'

echo "---"
# Check __root.tsx for hydration handling
fd --type f -name "__root.tsx" apps/ui/src/ -x cat -n {}

Repository: AutoMaker-Org/automaker

Length of output: 1875


🏁 Script executed:

#!/bin/bash
# Find and read __root.tsx
fd --type f -name "__root.tsx" apps/ui/src/ | head -5

echo "---"
# Also try root.tsx or Root.tsx
fd --type f -name "*root.tsx" apps/ui/src/ | head -10

Repository: AutoMaker-Org/automaker

Length of output: 549


🏁 Script executed:

#!/bin/bash
# Find root files correctly
fd --type f "root\.tsx" apps/ui/src/

echo "---"
# Check router or layout structure
fd --type f -name "*.tsx" apps/ui/src/ | grep -E "(root|main|app|layout)" | head -10

echo "---"
# Check full persist config in setup-store.ts
cat apps/ui/src/store/setup-store.ts | tail -50

Repository: AutoMaker-Org/automaker

Length of output: 1768


🏁 Script executed:

#!/bin/bash
# Read __root.tsx to check for hydration handling
wc -l apps/ui/src/routes/__root.tsx

echo "---"
cat apps/ui/src/routes/__root.tsx

Repository: AutoMaker-Org/automaker

Length of output: 13665


Wait for setup store hydration before reading setupComplete in post-login redirect.

The setupComplete value from useSetupStore is read without checking hydration status. If the user logs in before the persisted store hydrates from storage, setupComplete defaults to false, causing an incorrect redirect to /setup even when setup was previously completed. While __root.tsx will eventually correct this redirect after hydration completes, it creates an unnecessary navigation flicker.

Consider checking useSetupStore.persist?.hasHydrated?.() before or alongside reading setupComplete, or deferring the redirect decision to __root.tsx which already has proper hydration guards in place.

🤖 Prompt for AI Agents
In apps/ui/src/components/views/login-view.tsx around lines 30 to 37, the
post-login redirect reads useSetupStore().setupComplete before the persisted
setup store is hydrated which can cause a false negative redirect to /setup;
update the logic to either (a) check the store hydration status via
useSetupStore.persist?.hasHydrated?.() and only decide/navigate based on
setupComplete after hydration, or (b) skip immediate redirect here and let
__root.tsx (which already guards on hydration) perform the final routing
decision after hydration completes; implement the chosen approach so the
redirect does not happen prematurely.

Shironex and others added 3 commits January 1, 2026 22:39
- Introduced a new function, runNpmAndWait, to execute npm commands and wait for their completion, enhancing error handling.
- Updated the main function to build shared packages before starting the backend server, ensuring necessary dependencies are ready.
- Adjusted server and web process commands to use a consistent naming convention.
- Updated the SandboxRiskDialog to include a checkbox for users to opt-out of future warnings, passing the state to the onConfirm callback.
- Modified SettingsView to manage the skipSandboxWarning state, allowing users to reset the warning preference.
- Enhanced DangerZoneSection to display a message when the sandbox warning is disabled and provide an option to reset this setting.
- Updated RootLayoutContent to respect the user's choice regarding the sandbox warning, auto-confirming if the user opts to skip it.
- Added skipSandboxWarning state management to the app store for persistent user preferences.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 81bd57c and 90c89ef.

📒 Files selected for processing (5)
  • apps/ui/src/components/dialogs/sandbox-risk-dialog.tsx
  • apps/ui/src/components/views/settings-view.tsx
  • apps/ui/src/components/views/settings-view/danger-zone/danger-zone-section.tsx
  • apps/ui/src/routes/__root.tsx
  • apps/ui/src/store/app-store.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always import from shared packages (@automaker/*), never from old relative paths

Files:

  • apps/ui/src/components/dialogs/sandbox-risk-dialog.tsx
  • apps/ui/src/components/views/settings-view.tsx
  • apps/ui/src/store/app-store.ts
  • apps/ui/src/routes/__root.tsx
  • apps/ui/src/components/views/settings-view/danger-zone/danger-zone-section.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use resolveModelString() from @automaker/model-resolver to convert model aliases (haiku, sonnet, opus) to full model names

Files:

  • apps/ui/src/components/dialogs/sandbox-risk-dialog.tsx
  • apps/ui/src/components/views/settings-view.tsx
  • apps/ui/src/store/app-store.ts
  • apps/ui/src/routes/__root.tsx
  • apps/ui/src/components/views/settings-view/danger-zone/danger-zone-section.tsx
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: AutoMaker-Org/automaker PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-28T05:07:48.147Z
Learning: Frontend UI must use TanStack Router for file-based routing, organize components in components/views/, implement stores with Zustand, and use custom hooks in hooks/ directory
📚 Learning: 2025-12-30T01:02:07.114Z
Learnt from: illia1f
Repo: AutoMaker-Org/automaker PR: 324
File: apps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsx:122-131
Timestamp: 2025-12-30T01:02:07.114Z
Learning: Tailwind CSS v4 uses postfix syntax for the important modifier: append ! at the end of the utility class (e.g., backdrop-blur-[0px]! or hover:bg-red-500!). The older v3 style used a prefix (!) at the start (e.g., !backdrop-blur-[0px]); prefer the postfix form for consistency across TSX files.

Applied to files:

  • apps/ui/src/components/dialogs/sandbox-risk-dialog.tsx
  • apps/ui/src/components/views/settings-view.tsx
  • apps/ui/src/routes/__root.tsx
  • apps/ui/src/components/views/settings-view/danger-zone/danger-zone-section.tsx
📚 Learning: 2025-12-28T05:07:48.147Z
Learnt from: CR
Repo: AutoMaker-Org/automaker PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-28T05:07:48.147Z
Learning: Frontend UI must use TanStack Router for file-based routing, organize components in components/views/, implement stores with Zustand, and use custom hooks in hooks/ directory

Applied to files:

  • apps/ui/src/routes/__root.tsx
🧬 Code graph analysis (4)
apps/ui/src/components/dialogs/sandbox-risk-dialog.tsx (2)
apps/ui/src/components/dialogs/index.ts (1)
  • SandboxRiskDialog (7-7)
apps/ui/src/components/ui/button.tsx (1)
  • Button (108-108)
apps/ui/src/store/app-store.ts (1)
apps/ui/src/hooks/use-settings-migration.ts (1)
  • syncSettingsToServer (198-248)
apps/ui/src/routes/__root.tsx (5)
apps/ui/src/store/setup-store.ts (1)
  • useSetupStore (125-184)
apps/ui/src/store/auth-store.ts (1)
  • useAuthStore (25-29)
apps/ui/src/lib/http-api-client.ts (2)
  • initApiKey (130-165)
  • isElectronMode (114-122)
apps/ui/tests/utils/project/setup.ts (1)
  • setupComplete (756-771)
apps/ui/src/lib/electron.ts (2)
  • isElectron (676-686)
  • getElectronAPI (728-737)
apps/ui/src/components/views/settings-view/danger-zone/danger-zone-section.tsx (2)
apps/ui/src/components/ui/button.tsx (1)
  • Button (108-108)
apps/ui/src/lib/utils.ts (1)
  • cn (5-7)
🔇 Additional comments (15)
apps/ui/src/components/views/settings-view.tsx (1)

58-59: LGTM!

Clean integration of the skipSandboxWarning state from the app store and proper wiring to DangerZoneSection. The pattern follows the existing conventions in this file for passing store state to child components.

Also applies to: 189-191

apps/ui/src/components/dialogs/sandbox-risk-dialog.tsx (3)

34-38: Good practice: resetting checkbox state after confirmation.

Resetting skipInFuture to false after confirmation ensures the dialog starts fresh if reopened, preventing stale state from persisting.


105-132: Well-structured footer layout with accessibility considerations.

Good use of htmlFor linking the label to the checkbox, data-testid attributes for testing, and proper semantic structure. The flex layout handles responsive behavior appropriately with sm: breakpoint variants.


22-26: All callers of SandboxRiskDialog have been properly updated to handle the new onConfirm signature. The handleSandboxConfirm callback in apps/ui/src/routes/__root.tsx correctly accepts the (skipInFuture: boolean) parameter and uses it to set the skip warning state. No breaking changes remain.

apps/ui/src/store/app-store.ts (1)

490-491: LGTM - State, initial value, and persistence are properly configured.

The skipSandboxWarning flag is correctly:

  • Typed as boolean in AppState
  • Initialized to false (safe default - shows warning)
  • Included in partialize for local persistence across sessions

Also applies to: 981-981, 2933-2933

apps/ui/src/components/views/settings-view/danger-zone/danger-zone-section.tsx (3)

6-18: LGTM - Props interface and function signature properly updated.

The new props skipSandboxWarning and onResetSandboxWarning are correctly typed and destructured. The interface extension maintains consistency with the existing component pattern.


39-68: Well-designed sandbox warning reset UI.

Good implementation details:

  • Conditional rendering only shows the panel when skipSandboxWarning is true
  • Uses Shield icon to visually differentiate from the destructive delete action
  • outline variant for Reset button is appropriate since this is a non-destructive action
  • Includes data-testid for test automation

99-104: Good UX: Empty state prevents confusion.

The empty state message provides helpful feedback when neither the sandbox warning reset nor project delete options are available.

apps/ui/src/routes/__root.tsx (7)

168-214: Good use of ref guard to prevent concurrent auth checks.

The authCheckRunning ref prevents multiple simultaneous auth initialization calls, which could otherwise cause race conditions during React's strict mode double-invocation or rapid remounts.


102-134: Sandbox check effect may re-run unexpectedly when skipSandboxWarning changes.

The effect depends on skipSandboxWarning, but the early return only checks sandboxStatus !== 'pending'. If a user resets the sandbox warning (setting skipSandboxWarning to false) while sandboxStatus is 'confirmed', the effect won't re-trigger the warning because the status is no longer 'pending'.

This is likely acceptable behavior (the warning only shows on fresh page loads), but consider documenting this explicitly or resetting sandboxStatus to 'pending' when skipSandboxWarning changes from true to false if the intention is to show the warning again immediately.


234-261: Routing logic is well-structured with proper guards.

The routing effect correctly:

  1. Waits for store hydration before acting
  2. Waits for auth check completion in web mode
  3. Prioritizes login redirect over setup redirect
  4. Handles the setup → app transition when setup completes

The dependency array includes all relevant state values.


271-283: Web mode health check is a reasonable fallback for IPC connectivity.

Using /api/health endpoint with a 2-second timeout provides a lightweight way to check backend availability in web mode without instantiating the full HTTP client.


51-53: Intentional: Sandbox warning shows on every page refresh unless skipped.

This design ensures users are reminded of the risks each time they launch the app outside a container. The skipSandboxWarning preference provides an opt-out for users who have acknowledged and accepted the risk.

Note: This addresses the past review comment about sessionStorage removal - the behavior is intentional per the code comments.

Also applies to: 115-129


137-145: Callback correctly persists user's "skip" preference.

When the user confirms with the checkbox checked, setSkipSandboxWarning(true) is called to persist the preference. This integrates properly with the app store's async action which handles both local persistence and server sync.


359-367: Good UX: Loading state during redirect prevents flash of content.

Showing "Redirecting to login..." while the navigation is in progress provides a better user experience than briefly showing protected content before the redirect completes.

- Introduced skipSandboxWarning property in GlobalSettings interface to manage user preference for sandbox risk warnings.
- Updated syncSettingsToServer function to include skipSandboxWarning in the settings synchronization process.
- Set default value for skipSandboxWarning to false in DEFAULT_GLOBAL_SETTINGS.
@webdevcody webdevcody merged commit ab9ef0d into main Jan 1, 2026
6 checks passed
@webdevcody webdevcody deleted the fix-web-mode-auth branch January 1, 2026 22:13
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.

2 participants