Skip to content

fix: resolve data directory persistence between Electron and Web modes#572

Closed
DhanushSantosh wants to merge 20 commits intoAutoMaker-Org:mainfrom
DhanushSantosh:patchcraft
Closed

fix: resolve data directory persistence between Electron and Web modes#572
DhanushSantosh wants to merge 20 commits intoAutoMaker-Org:mainfrom
DhanushSantosh:patchcraft

Conversation

@DhanushSantosh
Copy link
Collaborator

@DhanushSantosh DhanushSantosh commented Jan 18, 2026

Summary

This PR fixes critical data persistence issues between Electron and Web modes. Projects and settings created in one mode now correctly sync to the other mode, even after stopping and restarting either mode separately.

Key Issue Resolved: Projects opened in Electron didn't appear in Web mode, and vice versa. Settings changes weren't persisting across mode switches or restarts.

Root Causes Identified

1. Path Navigation Bug

  • process.cwd() returned /apps/ui instead of project root
  • Server was configured to use apps/ui/data instead of shared /data
  • Fix: Use __dirname to navigate up 3 levels to project root

2. Electron's Default userData Not Overridden

  • Electron defaulted to ~/.config/Automaker instead of shared /data
  • No explicit app.setPath() call in development mode
  • Fix: Call app.setPath('userData', projectRoot/data) in development

3. Server Environment Variable Not Exported

  • DATA_DIR environment variable not passed to server in web mode
  • Fix: Export DATA_DIR in start-automaker.sh

4. Wipe Protection Logic Too Aggressive

  • Empty projects array was always treated as accidental wipe
  • Legitimate project removals (moved to trash) were blocked
  • Fix: Allow empty projects if trashedProjects has items

Changes Made

apps/ui/src/main.ts

  • Line 675-688: Explicitly set userData path in development

    • Navigate from __dirname to project root
    • Call app.setPath('userData', userDataPath) to override Electron defaults
  • Line 481-483: Fix startServer() dataDir calculation

    • Use __dirname instead of process.cwd() for reliable path

start-automaker.sh

  • Export DATA_DIR=/home/dhanush/Projects/automaker/data for web mode server

apps/server/src/services/settings-service.ts

  • Distinguish legitimate removals (with trashedProjects) from accidental wipes

apps/ui/src/hooks/use-settings-migration.ts

  • Enhanced logging for cache validation
  • Track project counts from both cache and server

Testing

Manual Tests Performed

✅ Electron startup logs: [DEVELOPMENT] userData path explicitly set to: /data
✅ Server startup logs: [SERVER_STARTUP] Resolved DATA_DIR: /data
✅ Added test project in Web → verified persistence after mode restart
✅ Files preserved: Only /data/settings.json modified, not ~/.config/Automaker
✅ No regression: Existing projects still accessible in both modes

Test Plan for Code Review

  1. Test 1 - Add in Web, See in Electron

    • Start web mode → create new project "WebTest"
    • Stop web mode → start Electron
    • Verify "WebTest" appears in Electron
  2. Test 2 - Add in Electron, See in Web

    • Start Electron → create new project "ElectronTest"
    • Stop Electron → start web mode
    • Verify "ElectronTest" appears in Web
  3. Test 3 - Persist Across Restart Cycles

    • Electron: Create project, modify theme
    • Stop Electron → start Web: Verify theme change persisted
    • Web: Remove project, stop
    • Electron: Verify project is gone

Impact

  • Users can now reliably switch between Electron and Web modes without losing data
  • Projects persist across individual restarts of each mode
  • All settings changes sync bidirectionally between modes
  • No more data loss or duplication issues

Commits Included

  • f378122: fix: resolve data directory persistence between Electron and Web modes
  • 2e57553: Merge remote-tracking branch 'upstream/v0.13.0rc' into patchcraft

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Standardized loading indicators across the app using a unified Spinner component
    • Pull request detection now includes merged and closed PRs in addition to open ones
    • Improved PR metadata synchronization to reflect current GitHub state
    • Added web mode session token persistence across page reloads
  • Bug Fixes

    • Non-existent projects automatically moved to trash on initialization
    • Added protection against accidental settings wipes
    • Enhanced local development CORS support for multiple localhost variants
  • Chores

    • Refactored PR-related type definitions for improved code organization
    • Enhanced internal logging and diagnostics
    • Updated data persistence architecture

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

DhanushSantosh and others added 20 commits January 18, 2026 01:37
When running in web mode (npm run dev:web), the frontend on localhost:3007
was making cross-origin requests to the backend on localhost:3008, causing
CORS errors.

Added Vite proxy configuration to forward /api requests from the dev server
to the backend. This makes all API calls appear same-origin to the browser,
eliminating CORS blocks during development.

Now web mode users can access http://localhost:3007 without CORS errors.

Fixes: CORS "Not allowed by CORS" errors in web mode

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
In web mode, the API client was hardcoding localhost:3008, which bypassed
the Vite proxy and caused CORS errors. Now it uses relative URLs (just /api)
in web mode, allowing the proxy to handle routing and making requests appear
same-origin.

- Web mode: Use relative URLs for proxy routing (no CORS issues)
- Electron mode: Continue using hardcoded localhost:3008

This allows the Vite proxy configuration to actually work in web mode.

Fixes: Persistent CORS errors in web mode development

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
The CORS check was too strict for local development. Changed to:
- Parse origin URL properly to extract hostname
- Allow all localhost origins (any port)
- Allow all 127.0.0.1 origins (loopback IP)
- Allow all private network IPs (192.168.x.x, 10.x.x.x, 172.x.x.x)
- Keep security by rejecting unknown origins

This fixes CORS errors when accessing from http://localhost:3007
or other local addresses during web mode development.

Fixes: "Not allowed by CORS" errors in web mode

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Added detailed logging to see:
- What origin is being sent
- How the hostname is parsed
- Why origins are being accepted/rejected

This will help us understand why CORS is still failing in web mode.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
The web mode launcher was setting CORS_ORIGIN to only include the system
hostname and 127.0.0.1, but users access via http://localhost:3007 which
wasn't in the allowed list.

Now includes:
- http://localhost:3007 (primary dev URL)
- http://$HOSTNAME:3007 (system hostname if needed)
- http://127.0.0.1:3007 (loopback IP)

Also cleaned up debug logging from CORS check since root cause is now clear.

Fixes: Persistent "Not allowed by CORS" errors in web mode

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Enables ws: true for /api proxy to properly forward WebSocket connections through the development server in web mode. This ensures real-time features work correctly when developing in browser mode.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…urvival

Web mode sessions were being lost on page reload because the session token was
stored only in memory (cachedSessionToken). When the page reloaded, the token
was cleared and verifySession() would fail, redirecting users to login.

This commit adds localStorage persistence for the session token, ensuring:
1. Token survives page reloads in web mode
2. verifySession() can use the persisted token from localStorage
3. Token is cleared properly on logout
4. Graceful fallback if localStorage is unavailable (SSR, disabled storage)

The HTTP-only cookie alone isn't sufficient for web mode due to SameSite cookie
restrictions and potential proxy issues with credentials forwarding.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
When a project fails to initialize because the directory no longer exists
(e.g., test artifacts, deleted folders), automatically remove it from the
project list instead of showing the error repeatedly on every reload.

This prevents users from being stuck with broken project references in their
settings after testing or when project directories are moved/deleted.

The user is notified with a toast message explaining the removal.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
In web mode, image loads may not send session cookies due to proxy/CORS
restrictions. This adds the session token as a query parameter to ensure
images load correctly with proper authentication in web mode.

Fixes custom project icons and images not loading in web mode.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Projects are critical data that must persist across mode switches (Electron/web).
Previously, project changes were debounced by 1 second, which could cause data
loss if:
1. User switched from Electron to web mode quickly
2. App closed before debounce timer fired
3. Network temporarily unavailable during debounce window

This change makes project array changes sync immediately (syncNow) instead of
using the 1-second debounce, ensuring projects are always persisted to the
server right away and visible in both Electron and web modes.

Fixes issue where projects opened in Electron didn't appear in web mode.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
When switching between Electron and web modes or when the server temporarily
stops, web mode was falling back to stale localStorage data instead of fresh
server data.

This fix:
1. Updates localStorage cache whenever fresh server settings are fetched
2. Updates localStorage cache whenever settings are synced to server
3. Prioritizes fresh settings cache over old Zustand persisted storage

This ensures that:
- Web mode always sees the latest projects even after mode switches
- Switching from Electron to web mode immediately shows new projects
- Server restarts don't cause web mode to use stale cached data

Fixes issue where projects opened in Electron didn't appear in web mode
after stopping and restarting the server.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
CRITICAL FIX: Electron and web mode were using DIFFERENT data directories:
- Electron: Docker volume 'automaker-data' (isolated from host)
- Web: Local ./data directory (host filesystem)

This caused projects opened in Electron to never appear in web mode because
they were synced to a completely separate Docker volume.

Solution: Mount the host's ./data directory into both containers
This ensures Electron and web mode always share the same data directory
and all projects are immediately visible across modes.

Now when you:
1. Open projects in Electron → synced to ./data
2. Switch to web mode → loads from same ./data
3. Restart server → both see the same projects

Fixes issue where projects opened in Electron don't appear in web mode.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This update standardizes the loading indicators by replacing all instances of Loader2 with the new Spinner component. The Spinner component provides a consistent look and feel for loading states throughout the UI, enhancing the user experience.

Changes include:
- Updated loading indicators in various components such as popovers, modals, and views.
- Ensured that the Spinner component is used with appropriate sizes for different contexts.

No functional changes were made; this is purely a visual and structural improvement.
Updated the PR state handling to use a consistent uppercase format ('OPEN', 'MERGED', 'CLOSED') throughout the codebase. This includes changes to the worktree metadata interface, PR creation logic, and related tests to ensure uniformity and prevent potential mismatches in state representation.

Additionally, modified the GitHub PR fetching logic to retrieve all PR states, allowing for better detection of state changes.

This refactor enhances clarity and consistency in how PR states are managed and displayed.
….0rc-1768688900786-5ea1

refactor: standardize PR state representation across the application
CRITICAL: Electron was using ~/.config/@automaker/app/data/ while web mode
used ./data/, causing projects to never sync between modes.

In development mode, both now use the shared project root ./data directory.
In production, Electron uses its isolated userData directory for app portability.

This ensures:
- Electron projects sync to the same server data directory as web mode
- Projects opened in Electron immediately appear in web mode
- Server restart doesn't lose projects from either mode

The issue was on line 487 where DATA_DIR was set to app.getPath('userData')
instead of the shared project ./data directory.

Fixes the fundamental problem where projects never appeared in web mode
even though they were in the server's settings file.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit fixes bidirectional data synchronization between Electron and Web
modes by addressing multiple interconnected issues:

**Core Fixes:**

1. **Electron userData Path (main.ts)**
   - Explicitly set userData path in development using app.setPath()
   - Navigate from __dirname to project root instead of relying on process.cwd()
   - Ensures Electron reads from /data instead of ~/.config/Automaker

2. **Server DataDir Path (main.ts, start-automaker.sh)**
   - Fixed startServer() to use __dirname for reliable path calculation
   - Export DATA_DIR environment variable in start-automaker.sh
   - Server now consistently uses shared /data directory

3. **Settings Sync Protection (settings-service.ts)**
   - Modified wipe protection to distinguish legitimate removals from accidents
   - Allow empty projects array if trashedProjects has items
   - Prevent false-positive wipe detection when removing projects

4. **Diagnostics & Logging**
   - Enhanced cache loading logging in use-settings-migration.ts
   - Detailed migration decision logs for troubleshooting
   - Track project counts from both cache and server

**Impact:**
- Projects created in Electron now appear in Web mode after restart
- Projects removed in Web mode stay removed in Electron after restart
- Settings changes sync bidirectionally across mode switches
- No more data loss or project duplication issues

**Testing:**
- Verified Electron uses /home/dhanush/Projects/automaker/data
- Confirmed server startup logs show correct DATA_DIR
- Tested project persistence across mode restarts
- Validated no writes to ~/.config/Automaker in dev mode

Fixes: Data persistence between Electron and Web modes

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Jan 18, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

This PR introduces a centralized Spinner UI component, refactors PR state management with validation utilities, expands CORS origin handling, adds settings cache and session token persistence, improves logging across multiple modules, implements wipe protection for global settings, enhances PR list fetching to detect state changes, and unifies data directory handling across Electron and web modes.

Changes

Cohort / File(s) Summary
Spinner Component
apps/ui/src/components/ui/spinner.tsx
New reusable Spinner component with size variants, replaces manual Loader2/RefreshCw animations
Spinner UI Replacements
apps/ui/src/components/*, apps/ui/src/views/* (70+ files)
Systematically replaces Loader2 and RefreshCw spinner icons with new Spinner component across popovers, dialogs, modals, and view components
PR State Type Centralization
libs/types/src/worktree.ts, libs/types/src/index.ts
Adds new PRState type (OPEN|MERGED|CLOSED), PR_STATES constant, validatePRState function, and WorktreePRInfo interface; exports from shared types module
PR State Import & Re-export
apps/server/src/lib/worktree-metadata.ts, apps/ui/.../worktree-panel/types.ts
Removes local PRState/WorktreePRInfo definitions; imports and re-exports from @automaker/types for consistency
Server PR Handling
apps/server/src/routes/worktree/routes/create-pr.ts, apps/server/src/routes/worktree/routes/list.ts
Adds validatePRState usage, fetches all PR states (not just open), detects merged/closed state changes, triggers async metadata sync when states differ
CORS Origin Expansion
apps/server/src/index.ts
Expands origin acceptance to include localhost/loopback (127.0.0.1, ::1, 0.0.0.0) and private networks (192.168., 10., 172.*); replaces string checks with URL parsing
Settings Protection & Logging
apps/server/src/services/settings-service.ts, apps/server/src/routes/settings/routes/update-global.ts
Adds wipe protection logic preventing accidental project deletion; expands logging with project/trash counts and step indicators
Settings Cache & Migration
apps/ui/src/hooks/use-settings-migration.ts, apps/ui/src/hooks/use-settings-sync.ts
Implements localStorage cache (automaker-settings-cache) for settings, adds detailed sync/migration logging, enhances detection of project array changes for immediate sync
Session Token Persistence
apps/ui/src/lib/http-api-client.ts
Adds localStorage-based session token persistence for web mode; initializes token on module load, persists on set, clears on logout
Data Directory Unification
apps/ui/src/main.ts, start-automaker.sh
Implements shared data directory concept (production: Electron userData/Automaker; development: projectRoot/data); propagates DATA_DIR to server; adds related logging
Development Configuration
apps/ui/vite.config.mts, docker-compose.dev.yml, docker-compose.dev-server.yml
Adds Vite proxy for /api to localhost:3008; switches Docker data mount from named volume to host bind mount ./data:/data
Image URL Authentication
apps/ui/src/lib/api-fetch.ts
Includes session token as query parameter in authenticated image URLs for fallback credential handling
Logging Enhancements
apps/ui/src/store/app-store.ts
Adds guard and debug logs when moving projects to trash; logs project counts and state changes
Test Updates
apps/server/tests/unit/lib/worktree-metadata.test.ts
Updates test expectations to use uppercase PR state values (OPEN, CLOSED, MERGED)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested labels

enhancement, refactor, UI, type-safety

Poem

🐰 Spinners spin with grace so bright,
PR states now unified in sight,
Settings cached and tokens saved,
Wipes protected, data paved,
CORS opened, logging blessed—
Automaker, truly test-passed! 🚀

✨ Finishing touches
  • 📝 Generate docstrings

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 @DhanushSantosh, 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 delivers significant improvements to data consistency and user experience by addressing core data persistence challenges between Electron and Web application modes. It ensures that user data, such as projects and settings, remains synchronized regardless of the mode used. The changes also enhance the reliability of project management features, streamline PR information updates, and standardize the visual feedback for loading states across the UI.

Highlights

  • Cross-Mode Data Persistence: Resolved critical data persistence issues, ensuring projects and settings created in either Electron or Web mode now correctly sync and persist across mode switches and restarts.
  • Unified Data Directory: Implemented a shared data directory strategy for both Electron and Web modes. In development, this defaults to the project root's 'data' directory, and in production, it uses Electron's standard 'userData' path, ensuring consistent data storage.
  • Robust Project Management: Refined the project 'wipe protection' logic to accurately distinguish between accidental project deletions and legitimate removals (e.g., moving projects to trash), preventing unintended data loss.
  • Enhanced PR State Handling: Improved the handling and synchronization of GitHub Pull Request (PR) states. The system now fetches all PR states (open, merged, closed) and validates them, ensuring accurate representation and updating cached metadata accordingly.
  • Standardized Loading Indicators: Introduced a new, centralized Spinner UI component and refactored numerous existing loading indicators across the application to use this component, improving visual consistency and maintainability.
  • Web Mode API & Auth Improvements: Configured Vite to proxy API requests in web mode to prevent CORS issues and implemented localStorage persistence for session tokens, allowing web mode authentication to survive page reloads.

🧠 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 is an excellent and comprehensive pull request that addresses a critical data persistence issue between Electron and Web modes. The root causes are well-identified, and the fixes are robust, particularly the changes to unify the data directory using __dirname for reliable pathing and explicitly setting app.setPath('userData') in development. The improved wipe protection logic is also a great enhancement.

I'm very impressed with the extensive refactoring to introduce a consistent <Spinner /> component across the entire UI, which greatly improves code quality and maintainability. The centralization of PR state types into libs/types is another fantastic improvement.

I've found two potential issues related to pathing and security that I've detailed in my comments. Once those are addressed, this PR will be in great shape. Fantastic work!

Comment on lines +186 to +194
if (
hostname === 'localhost' ||
hostname === '127.0.0.1' ||
hostname === '::1' ||
hostname === '0.0.0.0' ||
hostname.startsWith('192.168.') ||
hostname.startsWith('10.') ||
hostname.startsWith('172.')
) {
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The check hostname.startsWith('172.') for allowing local development origins is too broad. It will match any IP starting with 172., including public IP addresses, not just the private range 172.16.0.0 - 172.31.255.255. This could be a security risk by unintentionally allowing connections from outside the local network.

Using a more specific check, like a regular expression for the 172.16.0.0/12 range, would be safer.

Suggested change
if (
hostname === 'localhost' ||
hostname === '127.0.0.1' ||
hostname === '::1' ||
hostname === '0.0.0.0' ||
hostname.startsWith('192.168.') ||
hostname.startsWith('10.') ||
hostname.startsWith('172.')
) {
if (
hostname === 'localhost' ||
hostname === '127.0.0.1' ||
hostname === '::1' ||
hostname === '0.0.0.0' ||
hostname.startsWith('192.168.') ||
hostname.startsWith('10.') ||
/^172\.(1[6-9]|2[0-9]|3[0-1])\./.test(hostname)
) {

Comment on lines +715 to +717
const mainProcessDataDir = app.isPackaged
? app.getPath('userData')
: path.join(process.cwd(), 'data');
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The calculation for mainProcessDataDir uses path.join(process.cwd(), 'data'). Your PR description correctly identifies that process.cwd() can be unreliable and was a source of bugs. To ensure consistency and avoid reintroducing pathing issues, it would be safer to reuse the userDataPathToUse variable, which is reliably calculated based on __dirname in development mode and correctly points to the shared data directory.

  const mainProcessDataDir = userDataPathToUse;

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.

3 participants