Skip to content

Conversation

@JanZachmann
Copy link
Contributor

@JanZachmann JanZachmann commented Nov 28, 2025

Summary

Comprehensive refactor migrating the Vue.js frontend to the Crux Core architecture, establishing clear separation between platform-agnostic business logic (Rust Core) and UI rendering (Vue Shell).

Key Changes

Crux Core Architecture

  • Migrated state management and business logic from Vue composables to Rust Core
  • Components now bind to reactive viewModel from Core
  • Shell handles effects (HTTP, WebSocket, rendering) emitted by Core

Bearer Token Authentication

  • Replaced cookie-based auth with explicit Bearer tokens for Core API calls
  • Enables platform-agnostic Core that works across different shells
  • Improves testability and simplifies local debugging

Network Configuration

  • Added automatic rollback for IP and DHCP changes with countdown overlay
  • Improved handling of network transitions and reconnection logic
  • Extended rollback timeout configuration

Password Management

  • Implemented atomic password file writes with verification
  • Resolved race conditions in password update flow
  • Enhanced robustness of password change operations

Local Development

  • Fixed local debugging setup for full-stack development
  • Improved build scripts and Docker configuration

Bug Fixes

  • Fixed Centrifugo WebSocket race condition on authentication
  • Resolved firmware manifest display issue
  • Corrected network settings serialization (snake_case/camelCase)

Signed-off-by: Jan Zachmann 50990105+JanZachmann@users.noreply.github.com

Replace hyper-util with reqwest for all HTTP/Unix socket communication,
remove Arc wrappers, and eliminate the socket_client module to simplify
the codebase.

Changes:
- Remove Arc wrappers from Api struct fields (OmnectDeviceServiceClient
  and SingleSignOnProvider are already cheap to clone via internal pools)
- Replace hyper-util Client with reqwest for Unix socket communication
  using reqwest 0.12.23's native unix_socket() support
- Remove socket_client.rs module entirely (~109 lines removed)
- Inline HTTP request logic directly in OmnectDeviceServiceClient with
  cleaner helper methods: get(), post(), post_json()
- Convert keycloak_client from blocking to async reqwest
- Update certificate.rs to use reqwest::Client directly

Dependencies:
- Remove: http-body-util, hyper, hyperlocal, hyper-util
- Update: reqwest from 0.12 to 0.12.23 (minimum for Unix socket support)
- Remove: blocking feature from reqwest (no longer needed)

Benefits:
- Single HTTP client library throughout codebase
- Simpler, more maintainable code with direct reqwest usage
- Better error messages and logging
- Removed unnecessary abstraction layers
- Zero runtime overhead (no Arc, reqwest uses internal Arc)

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
This commit implements comprehensive refactorings across the codebase:

Performance Optimizations:
- Cache Keycloak HTTP client using OnceLock to avoid repeated instantiation
- Consolidate HTTP client usage patterns

Code Quality Improvements:
- Add HTTP response handling helper to reduce duplication
- Consolidate path macros for consistency
- Add API error handling helper with standardized logging
- Use endpoint constants instead of string literals
- Remove unnecessary .map(|_| ()) patterns
- Standardize error logging format to {e:#}
- Standardize all error messages to use "failed to..." format

Maintainability:
- Replace magic string "omnect-ui" with env!("CARGO_PKG_NAME")
- Improve string interpolation to use direct variable references
- Optimize imports (remove wildcard imports, use explicit imports)
- Fix inconsistent crate imports in main.rs

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Problems addressed:
- Inconsistent cleanup across different shutdown paths (ctrl-c, SIGTERM, server crash, centrifugo crash)
- Race conditions between service client shutdown and centrifugo termination
- Mixed error handling (panics vs logging)
- No guaranteed cleanup order

Solution:
- Unified shutdown sequence that runs regardless of exit reason
- Consistent cleanup order: service client → server → centrifugo
- Graceful error handling throughout (no panics)
- Clear debug logging at each step

Benefits:
- Predictable shutdown behavior in all scenarios
- Proper resource cleanup guaranteed
- Better observability with consistent logging
- Safer error handling

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
This commit introduces new infrastructure modules without changing existing
code, preparing for gradual migration in future PRs.

New Modules:
- config.rs: Centralized configuration management with validation
  - AppConfig struct with all environment variable configuration
  - Explicit validation at startup instead of lazy initialization
  - IoT Edge configuration detection
  - Path configuration helpers

- errors.rs: Structured error types with HTTP status mapping
  - OmnectUiError enum with specific error categories
  - Automatic HTTP status code mapping via ResponseError trait
  - ErrorContext trait for adding typed error context
  - Better error diagnostics for API responses

Benefits:
- Foundation for removing global OnceLock state in future PRs
- Type-safe configuration with clear documentation
- Structured error handling improves debugging and API responses
- No breaking changes to existing code

Future Work:
- PR #2: Consolidate HTTP clients using config
- PR #3: Migrate authentication and testing to use new infrastructure
This commit introduces HttpClientFactory to centralize HTTP client creation,
eliminating code duplication and ensuring consistent configuration.

New Module: http_client.rs
- HttpClientFactory with three client types:
  - https_client(): Cached HTTPS client for external APIs
  - unix_socket_client(): For local Unix socket communication
  - workload_client(): For IoT Edge workload API

Testing:
- Unit tests: 8 tests covering all three client factory methods
  - test_https_client_is_cached
  - test_https_client_returns_valid_client
  - test_https_client_multiple_calls_same_instance
  - test_workload_client_parses_uri
  - test_workload_client_rejects_invalid_scheme
  - test_unix_socket_client_creates_client
  - test_unix_socket_client_with_relative_path
  - test_unix_socket_client_with_empty_path

- Integration tests: 14 tests in tests/http_client.rs
  - 6 tests for https_client (using httpbin.org and example.com)
  - 4 tests for unix_socket_client (using mock Unix socket servers)
  - 4 tests for workload_client (using mock IoT Edge workload API)

- Test configuration: Added .cargo/config.toml
  - Set RUST_TEST_THREADS=1 to prevent rate-limiting issues
  - Ensures reliable test execution for external API tests

- Fixed dead_code warning for workload_client when using mock feature
  by adding #[cfg_attr(feature = "mock", allow(dead_code))]

Benefits:
- Eliminates 3 separate OnceLock instances across modules
- Single source of truth for HTTP client configuration
- Shared connection pools improve performance
- Easier to add timeout/retry configuration in future
- Better testability with centralized mocking point
- Comprehensive test coverage for all client types

Changes by Module:
- keycloak_client.rs: Use HttpClientFactory::https_client()
  - Removed local OnceLock<Client>
  - 4 lines removed, cleaner code

- omnect_device_service_client.rs: Use HttpClientFactory::unix_socket_client()
  - Simplified client creation
  - 3 lines removed

- certificate.rs: Use HttpClientFactory::workload_client()
  - Removed manual URI parsing
  - 8 lines removed, moved to factory

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
This commit introduces a centralized TokenManager for handling JWT token
creation and verification, eliminating scattered token logic.

New Module: auth/token.rs
- TokenManager: Centralized token management
  - create_token(): Generate JWT tokens with configured expiration
  - verify_token(): Validate tokens with proper verification options
  - Configurable expiration, subject, and secret

Benefits:
- Single source of truth for token handling
- Eliminates duplicate token creation/verification logic
- Consistent verification options (expiration, subject, tolerance)
- Better testability with 4 comprehensive tests
- Easier to change token strategy in future

Changes by Module:
- middleware.rs: Use TokenManager for verify_token()
  - Removed inline HS256Key creation
  - Removed manual VerificationOptions setup
  - 15 lines simplified to 1-line call

- api.rs: Use TokenManager for session_token()
  - Removed inline HS256Key and Claims creation
  - Cleaner error handling
  - 8 lines simplified to 6 lines

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Add network configuration management UI and backend:

Backend:
- Add network_config module with support for static IP and DHCP configuration
- Implement network rollback mechanism with 90-second timeout
- Add API endpoint for setting network configuration with validation
- Refactor certificate management to use DeviceServiceClient reference
- Move certificate creation to server startup after service client initialization
- Remove certificate regeneration from network rollback flow
- Add server restart channel for handling network changes
- Cancel pending rollback on successful authentication

Frontend:
- Add Network page with network settings UI
- Add NetworkSettings component for editing network configuration
- Add NetworkActions component for network-related actions
- Add useWaitForNewIp composable for handling IP changes
- Update DeviceNetworks component to show network details
- Refactor DeviceActions to use composable pattern
- Update Vuetify and Biome configurations
- Add route for /network page

Dependencies:
- Add rust-ini for network config file management
- Add serde_valid for request validation
- Add trait-variant for async trait support
- Add actix-cors for CORS support
- Bump version to 1.1.0

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
…e common.rs

- Introduce AppConfig with OnceLock for thread-safe singleton configuration
- Replace all direct environment variable access with AppConfig::get()
- All config fields now used (centrifugo, iot_edge, paths)
- Add test-mode support with conditional validation and defaults

- Remove common.rs by moving functions to appropriate modules:
  - validate_password → auth/mod.rs
  - create_frontend_config_file → keycloak_client.rs
  - handle_http_response → http_client.rs
- Consolidate HTTP response handling across all clients
- Remove unnecessary wrapper functions (cert_path, key_path, keycloak_url macro)
- Remove duplicate CentrifugoConfig from common.rs

- main.rs: Use AppConfig for UI_PORT, config paths
- api.rs: Use AppConfig for tenant, paths
- keycloak_client.rs: Remove keycloak_url! macro, use AppConfig directly
- omnect_device_service_client.rs: Use AppConfig for socket_path, centrifugo config
- certificate.rs: Use AppConfig for cert/key paths, iot_edge config
- middleware.rs: Use AppConfig for centrifugo client_token in tests

- Fix test isolation issues with cached AppConfig
- Update middleware tests to work with cached config paths
- Add test helper function create_password_file()
- All 69 tests passing with zero warnings

- Make iot_edge mandatory (no longer Option)
- Add cfg_attr for mock feature dead_code suppression
- Remove unnecessary pub from test modules
- Direct calls to handle_http_response (remove wrapper methods)
- Conditional bail import for test vs non-test builds

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
This commit refactors the codebase to separate business logic from HTTP
concerns by introducing a dedicated services layer.

Introduces a new `services/` module that encapsulates all business logic:

- **AuthorizationService**: Token validation and role-based access control
  (FleetAdministrator, FleetOperator) with tenant/fleet authorization
- **TokenManager**: Session token creation and validation with configurable
  expiration and HMAC signing
- **CertificateService**: Module certificate creation via IoT Edge workload
  API with conditional compilation for mock/production
- **FirmwareService**: Update file persistence and data folder management
- **NetworkConfigService**: Network configuration with automatic rollback,
  server restart coordination, and certificate renewal
- **PasswordService**: Password hashing (Argon2id) and secure storage

- Clear separation of concerns between HTTP handlers and business logic
- Improved testability through dependency injection
- Services accept client traits, enabling easy mocking
- Stateless service structs with static methods
- Reusable functions across different contexts

- Moves `certificate.rs` to `services/certificate.rs`
- Moves `network.rs` to `services/network.rs` (also introduces NetworkConfigService pattern)
- Moves `auth/` to `services/auth/` with new authorization module
- API handlers (`api.rs`) now delegate to services
- Backward compatibility maintained via re-exports in `lib.rs`

- Separates public HTTP handlers from private helper methods
- Reduces `Api` struct responsibility to HTTP concerns only
- Consistent error handling and logging patterns
- Session management delegated to auth service

This refactoring improves maintainability, testability, and code clarity
while maintaining all existing functionality.

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Fixed network configuration rollback implementation:
- Corrected rollback processing logic to properly handle pending rollbacks
- Fixed rollback file structure and serialization/deserialization
- Improved rollback timing and cancellation handling
- Added proper error context throughout network service

Reverted device service client builder pattern:
- Removed OmnectDeviceServiceClientBuilder in favor of simpler initialization
- Moved certificate creation and endpoint registration to main startup flow
- Made startup sequence more explicit and easier to follow
- Changed has_publish_endpoint to public field for direct access

Optimized application startup:
- Reorganized startup sequence for better clarity
- Service client now created once and reused across restarts
- Certificate and centrifugo setup moved to run_until_shutdown
- Added warning for unexpected pending rollback on startup

Improved error handling in main.rs:
- Replaced all .expect() calls with proper anyhow::Result and .context()
- Added top-level error handler in main() with proper logging
- All functions now return Result with descriptive error context
- Error chains display full context with {e:#} formatting
- Standardized error messages: lowercase, concise, no trailing periods

Additional improvements:
- Added complete function documentation for network service
- Fixed shutdown sequence to only unregister service client on full shutdown
- Removed redundant "backup:" prefixes from log messages
- Fixed typo: "publish} endpoint" -> "publish endpoint"
- Added centrifugo log level configuration support

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
…d and frontend

- Created Cargo workspace structure with backend in src/backend/
- Moved Vue 3 frontend from vue/ to src/frontend/
- Updated build artifacts location from src/backend/static/ to dist/
- Removed redundant root biome.json (frontend has its own)
- Updated all Docker paths and build scripts for new structure
- Updated documentation to reflect new project layout

This prepares the codebase for future Crux framework integration.

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
- Rename src/frontend/ to src/ui/ to reflect its new role as UI shell
- Create src/app/ as Crux Core workspace member with:
  - Model/ViewModel pattern for state management
  - Event-driven architecture with Command API (Crux 0.16)
  - Consolidated shared types (SystemInfo, NetworkStatus, etc.)
  - Custom Centrifugo capability for WebSocket
  - HTTP capability for REST API calls
- Create src/shared_types/ for TypeGen to generate TypeScript types
- Update Dockerfile and .dockerignore for new structure
- Fix formatting issues in backend services
- All 31 tests pass, clippy clean

This lays the foundation for migrating frontend state management from
Vue to Crux Core, enabling type-safe cross-platform logic sharing.

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
- Add WASM FFI bindings using crux_core::bridge::Bridge for serialization
- Create useCore.ts Vue composable for Crux Core integration
- Integrate generated TypeScript types from shared_types for type safety
- Implement event serialization and effect processing pipeline
- Add complete ViewModel deserialization from bincode format
- Support for Render, HTTP, and Centrifugo effects (HTTP/Centrifugo not yet implemented)
- Build WASM module with wasm-pack (586KB optimized)
- Add WASM package output directory to .gitignore

The Vue bridge provides:
- Reactive viewModel state synchronized with Crux Core
- Event constructors for type-safe communication
- Convenience methods for common operations (login, logout, reboot, etc.)
- Automatic WASM module loading with fallback mode

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
- Integrate actix-web-static-files to embed Vue dist at compile time
- Update build.rs to generate embedded static resources
- Serve embedded index.html and static assets from memory
- Implement complete Centrifugo capability in Core (Connect, Subscribe, History, etc.)
- Add shell handler for Centrifugo WebSocket operations
- Fix import mismatch (useCentrifuge vs useCentrifugo)
- Configure workspace to exclude shared_types from default-members
- Add lints.rust config to allow facet_typegen cfg from crux_macros
- Remove deprecated filesystem-based static file serving

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Migrated Centrifugo WebSocket capability from deprecated Capabilities API
to new Command API pattern. The old capability remains in Capabilities struct
for Effect enum generation, while actual usage now goes through the Command-based
API using RequestBuilder pattern.

Also updated README future work items to reflect completed milestones.

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Migrated all HTTP handlers from deprecated Capabilities API to new Command API
pattern. HTTP requests now use HttpCmd type alias with RequestBuilder pattern,
returning Commands with Command::all() to combine render() and HTTP effects.

Updated documentation to clarify that deprecated capabilities are kept only for
Effect enum generation via #[derive(Effect)] macro.

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
- Replace build-arm64-image.sh with build-and-deploy-image.sh
  - Full CLI with --help, --deploy, --push, --arch, --host, --port, --tag
  - Configurable architecture (default: arm64), tag (default: whoami)
  - Pre-flight directory validation on target device
  - Optional push to registry and deploy to device
- Update build-and-run-image.sh to use main build script internally
  - Auto-detect host architecture
  - Consistent image naming
- Restructure Dockerfile for correct build order
  - Build Rust first to generate TypeScript types
  - Vue build uses generated types from Rust build
  - Add dependency caching with dummy source files
  - Skip frontend embedding warning with SKIP_EMBED_FRONTEND
- Move Centrifugo to tools/ directory with setup script
  - tools/setup-centrifugo.sh downloads binary for local development
  - Backend looks in multiple locations (Docker, tools/, legacy)
- Improve README with Development section and script documentation

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
- Extract Model and ViewModel into separate model.rs
- Extract Event enum into events.rs
- Split update logic into domain handlers (auth, device, websocket, ui)
- Mock centrifugo binary path in test/mock mode to fix test failures
- Suppress deprecated warnings in centrifugo capability module

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
- Update key files section with domain-based update modules
- Document new auth, device, websocket, and ui handlers
- Mark completed tasks in Future Work section
- Clarify deprecated capability usage

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
- Remove username field from Event::Login (only password required)
- Remove username field from LoginCredentials type
- Update auth handler and test to use password-only
- Update README example to reflect password-only API

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
- Add deployment prerequisite warning to build-and-deploy-image.sh
- Update README.md to document deployment requirements

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Remove the hack that called reload_network twice with a 5 second delay.
The issue where ods reports same networks after reload has been fixed.

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
- Make --host parameter required for deployment to prevent accidental deployments
- Remove hardcoded default device host IP for safety
- Optimize build.rs to reduce unnecessary rebuilds
- Fix reboot error handling to treat connection drops as success
  (device successfully reboots but HTTP connection drops before response)

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
- Add wasm-build stage to Dockerfile to build Crux core WASM module
- Install wasm-pack and build WASM package before Vue build
- Copy WASM pkg to Vue build stage to resolve import errors
- Remove reboot fetch error workaround in DeviceActions component

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
- Document completed infrastructure (WASM, TypeGen, capabilities)
- List 6 Vue components that need migration to use Core
- Add detailed migration tasks for each component
- Note technical debt items

This provides a clear roadmap for future PRs to complete the
transition from direct API calls to Crux Core architecture.

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
@JanZachmann JanZachmann force-pushed the refactor-frontend-to-use-crux branch from 6684c2f to ccbdbff Compare December 11, 2025 13:50
When network IP changes, show an overlay spinner with:
- Countdown timer (1-second ticks) showing time until automatic rollback
- Redirect button to open new IP address in new tab
- Clear messaging about rollback cancellation requirement

Technical changes:
- Added redirect_url and countdown_seconds fields to OverlaySpinnerState
- Backend sends UI port in SetNetworkConfigResponse
- Core stores ui_port in NetworkChangeState variants
- Healthcheck uses HTTPS with dynamic port from backend
- Overlay button opens new tab to allow certificate acceptance
- Automatic redirect when new IP becomes reachable

User workflow:
1. User changes network IP configuration
2. Overlay appears with countdown and "Open new address in new tab" button
3. User clicks button, new tab opens with certificate warning
4. User accepts certificate, accesses new IP address
5. Rollback is cancelled automatically

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Fixed countdown timer and redirect functionality for network IP changes by
adding the missing rollback_timeout_seconds field to the TypeScript type
definitions and conversion functions.

Root cause: The Rust NetworkChangeState::WaitingForNewIp variant includes
rollback_timeout_seconds, but the TypeScript type definition was missing
this field, causing it to be undefined and leading to NaN calculations.

Changes:
- Added rollback_timeout_seconds to NetworkChangeStateType
- Updated convertNetworkChangeState to extract and convert the field
- Added ui_port field to all network change state variants for consistency
- Removed unsafe type casts in favor of proper TypeScript type narrowing
- Cleaned up debug logging added during troubleshooting
- Removed unused watch import from OverlaySpinner.vue

The countdown now properly displays and decrements, and redirect
functionality works as expected.

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Removed redirect_url from OverlaySpinnerState and moved the URL
construction to the Shell side (App.vue) where it's computed from
network_change_state.

This is cleaner architecture because:
- Core only needs to track the state machine (network_change_state)
- Shell derives the redirect URL when needed
- Avoids duplicating new_ip and ui_port in multiple places
- Shell can access network_change_state fields with proper typing

Changes:
- Removed redirect_url field from OverlaySpinnerState (Rust)
- Removed with_redirect_url() and set_redirect_url() methods
- Added redirectUrl computed property in App.vue that builds URL from
  network_change_state when type is 'waiting_for_new_ip'
- Updated overlay spinner initialization in network.rs

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Add user-configurable automatic rollback protection when changing the
IP address of the currently connected network adapter.

Changes:
- Add SetNetworkConfigRequest wrapper with enable_rollback field
- Add rollback_enabled field to SetNetworkConfigResponse
- Backend conditionally creates rollback based on user choice
- Server always restarts when server IP changes (regardless of rollback)
- Core handles three scenarios: rollback enabled, disabled, or not applicable
- Add modal dialog with checkbox (enabled by default) for user confirmation
- Show overlay with countdown when rollback enabled (90 seconds)
- Show overlay without countdown when rollback disabled (manual navigation)
- Add comprehensive user documentation in README

The feature provides safety for IP changes while giving users control:
- With rollback: 90-second window to confirm at new IP, auto-restore if timeout
- Without rollback: immediate application, manual navigation, no safety net
- Other adapters: simple success message, no modal

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Extend the automatic network configuration rollback feature to also cover
changes where the network adapter is switched to DHCP. This includes:

- Added  field to network config requests and state.
- Updated backend and core logic to correctly handle DHCP changes for rollback.
- Refined UI messaging in the network settings component to distinguish
  between static IP changes and switching to DHCP, providing clearer
  guidance to the user.
- Updated README.md documentation to reflect these changes in rollback
  behavior for both static IP and DHCP scenarios.

This ensures a consistent and safer user experience when making critical
network configuration adjustments.

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Add a notification dialog to the UI that appears when a network rollback has occurred. This dialog informs the user that network settings were reverted due to an unconfirmed configuration change. The user can dismiss the notification, which then clears the rollback occurred flag in the backend.
When switching the current adapter to DHCP, the new IP address is unknown.
Instead of trying to poll an unknown address or redirecting, we now:
1. Stay in WaitingForNewIp state if rollback is enabled, showing the countdown but suppressing the polling logic.
2. Show a clear overlay message instructing the user to check their DHCP server.
3. Skip the automatic polling/redirect behavior since we don't have a target IP.

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
This commit introduces several optimizations and refactorings to improve
the efficiency and readability of network configuration handling within
the Crux Core.

- **Refactor  for efficient dirty checking**:
  The  and
  variants in  now include an
  field. This allows for O(1) dirty checking in
   by directly comparing against the cached
  original data, avoiding repeated O(N) lookups and allocations.

- **Encapsulate  creation using  trait**:
  An  has been added
  in . This streamlines the creation
  of  instances in ,
  improving code clarity and maintainability.

- **Optimize  to reduce allocations**:
  The logic within  in
   has been refactored to use
  in-place mutation of the  counter and minimize unnecessary
  string cloning. This reduces memory allocations and improves the
  efficiency of the new IP polling mechanism.
…tion

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
- backend: implement atomic file write and verification retry strategy for password updates
- core: do not invalidate session on password update success to prevent race condition with auto-relogin
Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
This commit introduces a navigation guard to prevent authenticated users from
accessing the login page directly and fixes a race condition during logout
that caused incorrect redirects.

Changes include:
- Added `guestOnly: true` meta field to the `/login` route definition in
  `src/ui/src/plugins/router.ts`.
- Implemented `router.beforeEach` guard in `src/ui/src/plugins/router.ts` to
  redirect authenticated users from `/login` to `/` (Dashboard).
- Modified `src/ui/src/components/UserMenu.vue` to `await router.push("/login")`
  after `logout()`, ensuring the logout event is fully processed and
  `viewModel.is_authenticated` is updated before navigation, thus allowing
  the `beforeEach` guard to function correctly for logout.
- Updated `GEMINI.md` with new testing guidelines, build/deploy command, and
  learnings about locating dynamic UI elements.
Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Extracted hardcoded omnectweucopsacr.azurecr.io references into a
DOCKER_NAMESPACE variable that can be overridden via environment
variable or --namespace flag. The namespace is now passed as a
build argument to the Dockerfile.

Changes:
- Added DOCKER_NAMESPACE variable with default value
- Added --namespace command-line option
- Updated help text and environment variables documentation
- Replaced hardcoded registry references with ${DOCKER_NAMESPACE}
- Pass DOCKER_NAMESPACE as build-arg to docker buildx build

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Add test-only mutex to serialize password file access across all tests.
This prevents race conditions when tests run in parallel and try to
modify the shared password file simultaneously.

Changes:
- Added PASSWORD_FILE_LOCK mutex in password service (test-only)
- Added lock_for_test() method to acquire the lock
- Updated middleware and password service tests to use the lock
- Suppressed clippy::await_holding_lock warning (intentional behavior)

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Remove comments referencing past architecture decisions and temporal
context. Comments now describe current behavior without historical
references that belong in git history.

Changes:
- model.rs: Simplify auth_token and overlay_spinner comments
- reconnection.rs: Rewrite temporal "previously" reference

Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
@JanZachmann JanZachmann requested review from empwilli and ronny-standtke and removed request for empwilli and ronny-standtke December 17, 2025 18:58
@JanZachmann JanZachmann merged commit 3aefee4 into omnect:main Dec 18, 2025
1 of 3 checks passed
@JanZachmann JanZachmann deleted the refactor-frontend-to-use-crux branch December 18, 2025 08:44
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