Skip to content

feat(desktop): remove Meshtastic IP requirement from first-run setup#3088

Merged
Yeraze merged 3 commits into
mainfrom
desktop-remove-meshtastic-setup-prompt
May 19, 2026
Merged

feat(desktop): remove Meshtastic IP requirement from first-run setup#3088
Yeraze merged 3 commits into
mainfrom
desktop-remove-meshtastic-setup-prompt

Conversation

@Yeraze

@Yeraze Yeraze commented May 19, 2026

Copy link
Copy Markdown
Owner

Summary

The desktop setup window predates multi-source support and forced every fresh install to enter a Meshtastic node IP before the backend could start. That assumption breaks for MeshCore-only users (the most common desktop case today) and for users who want to configure sources from the web UI.

After this change, the first-run flow boots the backend with zero sources configured; users add Meshtastic or MeshCore sources from the web UI's Sources page.

Changes

Setup window (desktop/src/index.html)

  • Drop the Meshtastic Node IP and Meshtastic Port form fields
  • Replace with an info block pointing users at the web UI Sources page
  • Remove the IP-required validation (only the Web UI Port range is still validated)
  • Rename "Start with Windows""Autostart on Login" so the label works cross-platform; hint updated to "Automatically start MeshMonitor when you log in"
  • Retitle window subtitle from "Desktop Setup" to "Desktop preferences" (the same view serves both first-run and ongoing settings via tray)

Rust config (desktop/src-tauri/src/config.rs)

  • Mark legacy meshtastic_ip / meshtastic_port with #[serde(default)] so older configs without them deserialize cleanly. Doc comment clarifies they're retained for backwards compat with existing installs.
  • Honest doc comment on auto_start noting it's persisted-but-not-yet-wired to a platform autostart implementation.

Non-breaking for existing users: lib.rs:200-204 already only passes MESHTASTIC_NODE_IP env to the backend when the value is non-empty, so legacy desktop users with a populated config.json continue to auto-derive their Meshtastic source on startup. The only change for them is that the simplified UI no longer lets them edit that IP in-place.

Migration path for existing users: the env-derived Meshtastic source appears as a regular row in the web UI /sources page in 4.x, so users who want to retire it can edit its host or delete it there — same as any user-created source. No need to hand-edit config.json unless they specifically want to clear the legacy env shim itself.

Verification

End-to-end on a fresh macOS DMG build (4.6.1, arm64):

  • ✅ Wiped ~/Library/Application Support/MeshMonitor/{config.json,meshmonitor.db} for true first-run
  • ✅ Setup window appears with no required fields, no Meshtastic IP block
  • ✅ Hitting "Start MeshMonitor" with all defaults: desktop.log shows MESHTASTIC_NODE_IP: <unset> (no Meshtastic node configured)
  • ✅ Backend starts cleanly, web UI loads on port 8080
  • ✅ User adds a MeshCore source pointing at /dev/cu.usbserial-4 from the Sources page; native backend connects to the device
  • ✅ Full Vitest suite: 5075 passed, 0 failed (537 skipped, 21 todo) — 286.80s
  • ✅ Rust unit tests for src-tauri: 2 passed, 0 failed

Test plan

  • Fresh macOS DMG install: setup window shows no Meshtastic IP, no required fields
  • Save with defaults → backend boots with MESHTASTIC_NODE_IP unset and zero env-derived sources
  • Add MeshCore + Meshtastic sources from the web UI; both connect
  • Existing install with meshtastic_ip: "10.x.x.x" in config.json continues to auto-derive its Meshtastic source on startup (legacy compat)
  • Tray → Settings reopens the same window; saving still triggers restart_backend
  • Advanced Options checkbox reads "Autostart on Login" with hint "Automatically start MeshMonitor when you log in"
  • Windows + Linux Tauri builds compile (CI matrix coverage)

Out of scope (follow-up issues worth filing separately)

Observed while testing, not introduced by this change:

  1. /data/backups is hardcoded in BackupFileService.initializeBackupDirectory — ignores the DATA_DIR env var the Tauri shell sets. Backups silently broken on every desktop install.
  2. Server stdout/stderr logs get truncated on every backend restart (File::create in lib.rs:144-147). Anyone who hits an error then opens Settings → Save loses the very context bug reports need. Switching to OpenOptions::new().append(true).create(true) plus a session delimiter would preserve history.
  3. A MeshtasticManager for a deleted source keeps running its reconnect timer (observed ENETUNREACH 192.168.1.100:4403 looping for ~minutes after the source row was deleted). Cleanup path in sourceManagerRegistry likely doesn't clear in-flight reconnect timers.
  4. Startup warning Error during route segments migration: SqliteError: no such column: "channel" fires on every boot. Doesn't halt boot but should be quieted.
  5. Config.auto_start is set-but-never-read — no tauri-plugin-autostart is registered. The checkbox is currently decorative.

🤖 Generated with Claude Code

The desktop setup window predates multi-source support and forced every
fresh install to enter a Meshtastic node IP before the backend could
start. That assumption breaks for MeshCore-only users (the most common
desktop case today) and for users who want to configure sources from
the web UI.

Changes:
- Drop the Meshtastic Node IP and Meshtastic Port fields from the
  setup/settings form. Replace with an info block pointing users at
  the web UI's Sources page.
- Remove the IP-required validation; the only validation left is the
  Web UI Port range.
- Rename the "Start with Windows" Advanced Option to "Autostart on
  Login" so the label works on macOS, Linux, and Windows. Update the
  Rust doc comment to match (and note the field is currently
  persisted-but-not-implemented).
- Mark the legacy `meshtastic_ip` / `meshtastic_port` fields on
  Config with #[serde(default)] and a doc comment explaining they're
  retained for backwards compat with existing installs (lib.rs:200
  still passes MESHTASTIC_NODE_IP only when the value is non-empty,
  so legacy desktop users with a populated config.json keep working
  unchanged).
- Retitle the setup window subtitle from "Desktop Setup" to "Desktop
  preferences" since the same view serves both first-run and ongoing
  settings.

Verified end-to-end on a fresh macOS DMG build: setup window shows
no required fields, hitting Start with all defaults boots the backend
with MESHTASTIC_NODE_IP=<unset>, and the web UI loads ready to accept
MeshCore or Meshtastic sources from the Sources page.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented May 19, 2026

Copy link
Copy Markdown

Claude finished @Yeraze's task —— View job


PR Review: Remove Meshtastic IP Requirement from Desktop Setup

Todo List:

  • Read and analyze desktop/src/index.html changes
  • Review desktop/src-tauri/src/config.rs modifications
  • Check desktop/package-lock.json changes
  • Analyze code quality and best practices
  • Identify potential bugs or issues
  • Evaluate performance considerations
  • Check for security concerns
  • Assess test coverage
  • Provide comprehensive review feedback

Overall Assessment

This is a well-executed architectural improvement that successfully modernizes the desktop first-run experience for the multi-source era. The changes are backwards-compatible, well-documented, and address a real usability pain point for MeshCore-only users.

Code Quality & Best Practices ✅

Strong Points:

  • Backwards compatibility preserved: Legacy users with existing meshtastic_ip configs continue working seamlessly via the lib.rs:200-204 conditional env var setting
  • Clean UI simplification: Removed the complex IP validation while maintaining essential port validation
  • Excellent documentation: The Rust config struct has thorough doc comments explaining the legacy field retention rationale
  • Proper error handling: Both the HTML form validation and Rust config loading have appropriate error paths
  • Consistent styling: UI changes maintain the existing design language and accessibility patterns

Code Structure:

  • desktop/src/index.html:384-403 - Good preservation of existing config via spread operator to avoid data loss
  • desktop/src-tauri/src/config.rs:11-14 - Proper use of #[serde(default)] for backwards compatibility
  • Clean separation of concerns between UI (HTML/JS) and backend (Rust)

Potential Issues & Bugs 🟡

Minor Concerns:

  1. Misleading checkbox label: desktop/src/index.html:322 - "Autostart on Login" suggests working functionality, but config.rs:18-19 clearly states it's "not yet wired to a platform implementation". Consider adding "(Coming Soon)" or similar to manage expectations.

  2. No migration path for existing desktop users: Users with populated meshtastic_ip who want to switch to web UI source management have no clear guidance. The PR description mentions they can "hand-edit config.json or delete the source from the web UI" but the UI provides no hint about this.

  3. Form state preservation edge case: desktop/src/index.html:384-403 - If get_config fails, the spread operation will fail. Consider adding error handling:

    const existingConfig = await invoke('get_config').catch(() => ({}));

Security Considerations ✅

Positive Security Aspects:

  • Reduced attack surface: Removing the IP input field eliminates potential injection vectors
  • Proper input validation: Web port validation remains robust with integer bounds checking
  • Config file access: Proper use of platform-standard config directories via dirs crate
  • Session secret generation: Continues using secure UUID-based secret generation

No Security Issues Identified

Performance Considerations ✅

Performance Impact:

  • Startup improvement: Zero-source startup should be faster than attempting to connect to a potentially unreachable IP
  • Reduced network overhead: Eliminates unnecessary reconnection attempts for MeshCore-only users
  • UI responsiveness: Simplified form reduces validation overhead

No Performance Concerns

Test Coverage Assessment 🟡

Existing Coverage:

  • Rust unit tests cover config defaults and secret generation (config.rs:169-185)
  • End-to-end verification mentioned in PR description is thorough

Missing Test Coverage:

  1. Config migration tests: No tests verify that configs with missing meshtastic_ip/meshtastic_port fields deserialize correctly with defaults
  2. Form submission edge cases: No automated tests for the HTML form validation logic
  3. Backwards compatibility tests: No tests ensuring existing configs with populated meshtastic_ip still trigger env var setting

Suggested Test Additions:

#[test]
fn test_config_backwards_compatibility() {
    let json = r#"{"web_port": 8080, "auto_start": false, "session_secret": "test", "setup_completed": true}"#;
    let config: Config = serde_json::from_str(json).unwrap();
    assert_eq!(config.meshtastic_ip, String::new());
    assert_eq!(config.meshtastic_port, 4403);
}

Architecture & Design ✅

Excellent Architectural Decisions:

  • Multi-source alignment: Changes properly align desktop app with the 4.x multi-source architecture
  • Progressive enhancement: Advanced options remain available but don't overwhelm new users
  • Clear separation of concerns: Setup UI handles preferences, web UI handles source management
  • Future-proof design: Structure supports adding more source types without UI changes

Minor Suggestions

  1. Consider adding a hint in the info block about where to find the web UI URL (e.g., "Open http://localhost:8080 after startup")
  2. Add form field validation feedback for the port field (currently shows generic error)
  3. Consider updating the window title from "MeshMonitor Desktop" to better reflect its dual purpose (setup + ongoing settings)

Verdict: APPROVED

This PR successfully achieves its goals with excellent backwards compatibility and clean implementation. The few minor issues identified don't block the core functionality and can be addressed in follow-up work. The architectural alignment with multi-source support is exactly what the desktop app needed.


…nfig tests

Addresses two actionable items from the claude-review pass on #3088:

1. The "Autostart on Login" checkbox label implied working functionality,
   but the underlying `auto_start` field is persisted-but-never-read (no
   tauri-plugin-autostart is registered). Update the hint to make that
   clear so users don't think the toggle is silently failing for them.

2. Add Rust unit tests that lock in the #[serde(default)] markers on
   the legacy `meshtastic_ip` / `meshtastic_port` fields:
   - test_config_deserialises_without_legacy_meshtastic_fields — proves
     a future config.json that omits the legacy fields parses cleanly
     with sensible defaults.
   - test_config_preserves_legacy_meshtastic_ip — proves an existing
     install with a populated meshtastic_ip round-trips correctly, so
     the backwards-compat claim in the PR description has a regression
     guard.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented May 19, 2026

Copy link
Copy Markdown

Claude finished @Yeraze's task —— View job


PR Review: Remove Meshtastic IP Requirement from Desktop Setup

Todo List:

  • Read and analyze desktop/src/index.html changes
  • Review desktop/src-tauri/src/config.rs modifications
  • Check desktop/package-lock.json changes
  • Analyze code quality and best practices
  • Identify potential bugs or issues
  • Evaluate performance considerations
  • Check for security concerns
  • Assess test coverage
  • Provide comprehensive review feedback

Overall Assessment

This is a well-executed architectural improvement that successfully modernizes the desktop first-run experience for the multi-source era. The changes are backwards-compatible, well-documented, and address a real usability pain point for MeshCore-only users.

Code Quality & Best Practices ✅

Strong Points:

  • Backwards compatibility preserved: Legacy users with existing meshtastic_ip configs continue working seamlessly via the lib.rs:200-204 conditional env var setting
  • Clean UI simplification: Removed the complex IP validation while maintaining essential port validation
  • Excellent documentation: The Rust config struct has thorough doc comments explaining the legacy field retention rationale
  • Proper error handling: Both the HTML form validation and Rust config loading have appropriate error paths
  • Consistent styling: UI changes maintain the existing design language and accessibility patterns

Code Structure:

  • desktop/src/index.html:384-403 - Good preservation of existing config via spread operator to avoid data loss
  • desktop/src-tauri/src/config.rs:11-14 - Proper use of #[serde(default)] for backwards compatibility
  • Clean separation of concerns between UI (HTML/JS) and backend (Rust)

Potential Issues & Bugs 🟡

Minor Concerns:

  1. Misleading checkbox label: desktop/src/index.html:322 - "Autostart on Login" suggests working functionality, but config.rs:18-19 clearly states it's "not yet wired to a platform implementation". Consider adding "(Coming Soon)" or similar to manage expectations.

  2. No migration path for existing desktop users: Users with populated meshtastic_ip who want to switch to web UI source management have no clear guidance. The PR description mentions they can "hand-edit config.json or delete the source from the web UI" but the UI provides no hint about this.

  3. Form state preservation edge case: desktop/src/index.html:384-403 - If get_config fails, the spread operation will fail. Consider adding error handling:

    const existingConfig = await invoke('get_config').catch(() => ({}));

Security Considerations ✅

Positive Security Aspects:

  • Reduced attack surface: Removing the IP input field eliminates potential injection vectors
  • Proper input validation: Web port validation remains robust with integer bounds checking
  • Config file access: Proper use of platform-standard config directories via dirs crate
  • Session secret generation: Continues using secure UUID-based secret generation

No Security Issues Identified

Performance Considerations ✅

Performance Impact:

  • Startup improvement: Zero-source startup should be faster than attempting to connect to a potentially unreachable IP
  • Reduced network overhead: Eliminates unnecessary reconnection attempts for MeshCore-only users
  • UI responsiveness: Simplified form reduces validation overhead

No Performance Concerns

Test Coverage Assessment 🟡

Existing Coverage:

  • Rust unit tests cover config defaults and secret generation (config.rs:169-185)
  • End-to-end verification mentioned in PR description is thorough

Missing Test Coverage:

  1. Config migration tests: No tests verify that configs with missing meshtastic_ip/meshtastic_port fields deserialize correctly with defaults
  2. Form submission edge cases: No automated tests for the HTML form validation logic
  3. Backwards compatibility tests: No tests ensuring existing configs with populated meshtastic_ip still trigger env var setting

Suggested Test Additions:

#[test]
fn test_config_backwards_compatibility() {
    let json = r#"{"web_port": 8080, "auto_start": false, "session_secret": "test", "setup_completed": true}"#;
    let config: Config = serde_json::from_str(json).unwrap();
    assert_eq!(config.meshtastic_ip, String::new());
    assert_eq!(config.meshtastic_port, 4403);
}

Architecture & Design ✅

Excellent Architectural Decisions:

  • Multi-source alignment: Changes properly align desktop app with the 4.x multi-source architecture
  • Progressive enhancement: Advanced options remain available but don't overwhelm new users
  • Clear separation of concerns: Setup UI handles preferences, web UI handles source management
  • Future-proof design: Structure supports adding more source types without UI changes

Minor Suggestions

  1. Consider adding a hint in the info block about where to find the web UI URL (e.g., "Open http://localhost:8080 after startup")
  2. Add form field validation feedback for the port field (currently shows generic error)
  3. Consider updating the window title from "MeshMonitor Desktop" to better reflect its dual purpose (setup + ongoing settings)

Verdict: APPROVED

This PR successfully achieves its goals with excellent backwards compatibility and clean implementation. The few minor issues identified don't block the core functionality and can be addressed in follow-up work. The architectural alignment with multi-source support is exactly what the desktop app needed.


@Yeraze

Yeraze commented May 19, 2026

Copy link
Copy Markdown
Owner Author

Thanks for the review. Addressed in 923a10f:

Done

  • Autostart label honesty. Updated the hint under the "Autostart on Login" checkbox to make it explicit that the preference is saved but the feature isn't wired up yet, so users don't think the toggle is silently failing for them. The Rust doc comment already noted this; the user-facing text now matches.

  • Backwards-compat deserialization tests. Added two #[cfg(test)] cases in config.rs:

    • test_config_deserialises_without_legacy_meshtastic_fields — locks in the #[serde(default)] markers so a future config.json that omits the legacy Meshtastic fields parses cleanly with sensible defaults.
    • test_config_preserves_legacy_meshtastic_ip — proves an existing install with a populated meshtastic_ip round-trips correctly, guarding the "non-breaking for legacy users" claim in the PR description.

    All 4 Rust tests pass: test result: ok. 4 passed; 0 failed.

Pushing back (with reasoning)

  • get_config .catch(() => ({})) — the existing form-submit handler wraps the spread in a try { … } catch (e) { showError('Failed to save configuration: ' + e); resetButton(); }. Silently substituting {} on get_config failure would HIDE real bugs (e.g. corrupted config.json, IPC plumbing breakage) and produce a saved config without session_secret or other prior values. Letting the error propagate to the visible showError path is the safer behavior.
  • localhost:8080 hint in the info block / window-title dual-purpose / better port validation feedback — pre-existing concerns not introduced by this PR; worth filing as follow-ups but I'd rather not expand the surface area of this change.
  • "No migration path for existing meshtastic_ip users" — legacy Meshtastic sources auto-derived from env vars do appear in the web UI's Sources page in 4.x and can be edited/deleted there, so there IS a path; the PR description should mention that more clearly. I'll update the PR body.

The Windows CI failure on the prior run was a transient inside setup-node@v6 (cache step succeeded its log output then the step itself reported failure — classic GitHub Actions cache-restore hiccup; no actual error in the log). I rerun-failed the workflow alongside this push.

🤖 Generated with Claude Code

The new test in 923a10f had a too-long line that tripped the `lint-rust`
CI job (`cargo fmt --all -- --check`). Wrap the `serde_json::from_str`
call as rustfmt expects.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented May 19, 2026

Copy link
Copy Markdown

Claude finished @Yeraze's task —— View job


PR Review: Remove Meshtastic IP Requirement from Desktop Setup

Todo List:

  • Read and analyze desktop/src/index.html changes
  • Review desktop/src-tauri/src/config.rs modifications
  • Check desktop/package-lock.json changes
  • Analyze code quality and best practices
  • Identify potential bugs or issues
  • Evaluate performance considerations
  • Check for security concerns
  • Assess test coverage
  • Provide comprehensive review feedback

Overall Assessment ✅

This is an excellent architectural improvement that successfully modernizes the desktop first-run experience for the multi-source era. The changes are backwards-compatible, well-documented, and address a real usability pain point for MeshCore-only users. The author's follow-up commit (923a10f) effectively addressed the previous review feedback.

Code Quality & Best Practices ✅

Strong Points:

  • Backwards compatibility preserved: Legacy users with existing meshtastic_ip configs continue working seamlessly via the lib.rs:200-204 conditional env var setting
  • Clean UI simplification: Removed complex IP validation while maintaining essential port validation (desktop/src/index.html:377-381)
  • Excellent documentation: The Rust config struct has thorough doc comments explaining the legacy field retention rationale (config.rs:7-14)
  • Proper error handling: Both HTML form validation and Rust config loading have appropriate error paths
  • Consistent styling: UI changes maintain the existing design language and accessibility patterns
  • Honest user messaging: The autostart checkbox now clearly states the feature isn't wired up (index.html:324)

Code Structure:

  • desktop/src/index.html:394-403 - Good preservation of existing config via spread operator to avoid data loss
  • desktop/src-tauri/src/config.rs:11-14 - Proper use of #[serde(default)] for backwards compatibility
  • Clean separation of concerns between UI (HTML/JS) and backend (Rust)

Security Considerations ✅

Positive Security Aspects:

  • Reduced attack surface: Removing the IP input field eliminates potential injection vectors
  • Proper input validation: Web port validation remains robust with integer bounds checking (index.html:377-381)
  • Config file access: Proper use of platform-standard config directories via dirs crate (config.rs:128-130)
  • Session secret generation: Continues using secure UUID-based secret generation (config.rs:163-166)

No Security Issues Identified

Performance Considerations ✅

Performance Impact:

  • Startup improvement: Zero-source startup should be faster than attempting to connect to a potentially unreachable IP
  • Reduced network overhead: Eliminates unnecessary reconnection attempts for MeshCore-only users
  • UI responsiveness: Simplified form reduces validation overhead

No Performance Concerns

Test Coverage Assessment ✅

Excellent Test Coverage Improvements:
The author added comprehensive test coverage in the follow-up commit:

  1. test_config_deserialises_without_legacy_meshtastic_fields (config.rs:190-203) - Ensures configs without legacy fields deserialize cleanly with defaults
  2. test_config_preserves_legacy_meshtastic_ip (config.rs:208-221) - Verifies existing installs with populated meshtastic_ip continue working
  3. Existing coverage for default config and secret generation (config.rs:172-184)

Test Quality:

  • Tests use realistic JSON payloads that match actual config file structure
  • Proper assertions for both positive and negative cases
  • Tests lock in the backwards compatibility contract

Architecture & Design ✅

Excellent Architectural Decisions:

  • Multi-source alignment: Changes properly align desktop app with the 4.x multi-source architecture
  • Progressive enhancement: Advanced options remain available but don't overwhelm new users
  • Clear separation of concerns: Setup UI handles preferences, web UI handles source management
  • Future-proof design: Structure supports adding more source types without UI changes
  • Zero-config startup: Enables fresh installs to boot without mandatory node configuration

Minor Observations (No Action Required)

Package Lock Changes:

  • desktop/package-lock.json:2-3 and 16-17 show version bump from 4.6.0 to 4.6.1, which is consistent with the overall release preparation

UI/UX Improvements:

  • Info block (index.html:256-260) provides clear guidance for post-launch source configuration
  • Window subtitle changed from "Desktop Setup" to "Desktop preferences" (index.html:249) better reflects dual purpose
  • Cross-platform label "Autostart on Login" (index.html:322) works better than Windows-specific "Start with Windows"

Potential Follow-Up Improvements (Separate Issues)

The author correctly identified these as out-of-scope for this PR:

  1. Backup directory hardcoding ignores DATA_DIR env var
  2. Backend restart truncates logs instead of appending
  3. Deleted source cleanup may not clear reconnect timers
  4. Startup warning about route segments migration
  5. Config.auto_start needs platform autostart plugin registration

Verdict: APPROVED

This PR successfully achieves its architectural goals with excellent backwards compatibility, comprehensive test coverage, and clean implementation. The changes properly modernize the desktop app for the multi-source era while maintaining compatibility for existing users. The author's responsive follow-up addressing previous feedback demonstrates thorough attention to detail.

Key Strengths:

  • ✅ Backwards compatible with existing installs
  • ✅ Comprehensive test coverage for edge cases
  • ✅ Clear documentation and honest user messaging
  • ✅ Clean architectural alignment with multi-source design
  • ✅ Proper error handling and input validation
  • ✅ No security or performance concerns

The implementation is production-ready and addresses the core usability issue for MeshCore-only desktop users.


@Yeraze Yeraze merged commit e7f4fae into main May 19, 2026
24 checks passed
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