[WIP] Restructure repository into workspace with separated backend and frontend#4
Closed
JanZachmann wants to merge 69 commits intomainfrom
Closed
[WIP] Restructure repository into workspace with separated backend and frontend#4JanZachmann wants to merge 69 commits intomainfrom
JanZachmann wants to merge 69 commits intomainfrom
Conversation
Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
* chore: multiple improvements Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
* init vue * base layout * centrifugo v6 envs * Add biomejs * build vue * build base path * implement centrifugo * Show data * remove old static content * optimize rust build by caching deps * implement session * simplify auth middleware * feat: add data folder Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com> * readme Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com> * set correct api key env * fix Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com> * fix Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com> * begin modularisation of frontend and initial styling (omnect#14) * begin refactoring structure * improve styling * remove placeholder data --------- Co-authored-by: Alexander Horn <alexander.horn@conplement.de> * add logout and session purge * smaller fixes * update docu images * fix output * fix reconnect detection * set version to 0.5.0 --------- Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com> Co-authored-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com> Co-authored-by: Alexander Horn <alexomanie@users.noreply.github.com> Co-authored-by: Alexander Horn <alexander.horn@conplement.de>
* fix: resolve clippy warnings * resolve findings
In the course of implementing the automatic generation of server certificates using edgeCA, we had to discontinue support for injecting the app via omnect-cli. As a result, all artifacts related to systemd handling were removed from the repo. For local development use the build-and-run.sh file and read the precondition based on this script. Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
* init vue * base layout * centrifugo v6 envs * Add biomejs * build vue * build base path * implement centrifugo * Show data * remove old static content * optimize rust build by caching deps * implement session * simplify auth middleware * set correct api key env * begin modularisation of frontend and initial styling (omnect#14) * begin refactoring structure * improve styling * remove placeholder data --------- Co-authored-by: Alexander Horn <alexander.horn@conplement.de> * add logout and session purge * smaller fixes * update docu images * fix output * fix reconnect detection * add menu * add file upload for update file * update page * global overlay spinner * load update info and run update * restructure rust code * add update status to device overview * add more infos about the update * bump to version 0.5.1 * show unexpected error on login * set upload limit * env for upload path * set file permission * os update path as env * set correct url to run update * show spinner on run update * optimize code * fix exceeded token issues * show correct app version * chore: renamed omnect_device_socket to omnect_device_service_client (omnect#17) * chore: renamed omnect_device_socket to omnect_device_service_client Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com> * fix service file Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com> --------- Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com> * fix factory reset * update show current version * change online to omnect cloud connection * upload progress * bump packages * show update status * return errors * option to enforce cloud connection after update * close spinner on update succeeded * fix: fixed data folder creation (omnect#18) Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com> * better update status detection * show update state dialog * fix responsive on upload * resolve findings * bump vue packages * bump cargo.lock * properly remove file item on clear * check for env on startup and provide config in server context * check for index file * resolve findings --------- Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com> Co-authored-by: Alexander Horn <alexomanie@users.noreply.github.com> Co-authored-by: Alexander Horn <alexander.horn@conplement.de> Co-authored-by: Buell <50990105+JanZachmann@users.noreply.github.com>
feature: log git short rev version
* feat: generate secrets on startup * use username for local builds * make CENTRIFUGO_HTTP_SERVER_PORT optional * add local build script for vue * bump version * resolve finding * mock IOTEDGE_MODULEGENERATIONID * use cargo package name as id
* feat: check if device is up again properly * disable cache for reconnect request * re-initiate centrifugo
refactor code from previous password handling refactoring
) * feat: call API delete publish endpoint in termination process Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com> * add sigterm handling Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com> * qa Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com> * qa Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com> --------- Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@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>
…initial password (omnect#36) * check login required through vue-router * update dependencies * auth against portal to set initial password * restructure code * check if user has permissions on fleet * style callback page * restructure code * get fleet_id from system info * resolve findings * bump version * set keycloak auth url * resolve findings * only allow env for vue frontend * do not panic * proper way to inject env * introduce healthcheck endpoint and use for wait reconnect * rename reload-network to restart-network
* fix: create config folder if not yet present * bump version
…ct#50) The API had a hard dependency on the ODS and Keycloak. We tried to loosen these bounds by introducing dyn types, so that these dependencies could be tested more easily. However, there is no need to introduce this degree of flexibility. Instead, "normal" traits are sufficient (as the type of ODS provider/SSO provider won't change during the lifetime of the omnect-ui). This simplifies the code and avoids some of the cruft necessary to get mockall to work with the dyn traits. Additionally, this extracts the ODS and SSO provider creation, so that the creation of the API follows more closely dependency injection principles, thus simplifying testing even further. * build: remove dependency to async-trait * build: make mockall a dev-dependency * style: fix code formatting * fix: ensure single instances of Api members * fix: disable unused code/imports warnings for test builds * build: disable default features for mockall --------- Co-authored-by: ronny-standtke <ronny.standtke@conplement.de>
* chore: standardize "omnect UI" terminology * bump version
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>
omnect#56) 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>
* refactor: improve code quality, performance, and consistency
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>
) ## Summary This PR consolidates HTTP client creation logic and improves error handling: - **Centralized Unix socket client creation**: New `http_client` module with `unix_socket_client()` function that handles both raw paths and `unix://` URIs - **Socket path validation**: Added existence check using `try_exists()` to catch I/O errors before client creation - **Simplified KeycloakProvider**: Replaced global `OnceLock` singleton with instance field for HTTPS client - **Improved shutdown sequence**: improve shutdown sequence consistency and error handling - **Comprehensive test coverage**: Added integration tests for Unix socket client functionality (3 integration tests + 2 unit tests) ## Key Changes ### HTTP Client Consolidation - Created `src/http_client.rs` with standalone `unix_socket_client()` function - Handles both raw paths (`/socket/api.sock`) and URIs (`unix:///socket/api.sock`) - Validates socket existence before creating client to provide early error feedback ### Improve shutdown sequence. 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 ### KeycloakProvider Refactoring - Moved HTTPS client from global singleton to instance field - `KeycloakProvider` now owns its `reqwest::Client` - Eliminates global state and improves testability Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
## Summary This PR centralizes authentication infrastructure and improves testing coverage with a simplified `TokenManager` API and comprehensive integration tests. ## Key Changes ### 🔐 Authentication Refactoring #### New: `src/auth/token.rs` (109 lines) - **Simplified API**: Single `token_manager()` function returns global singleton - **Minimal surface**: One constructor `TokenManager::new(secret)` with 1 parameter - **Private internals**: Constants (`TOKEN_SUBJECT`, `TOKEN_EXPIRE_HOURS`) and struct encapsulated - **Global singleton**: Uses `OnceLock` pattern for thread-safe initialization - **Methods**: - `create_token()` - Generate new JWT with 24h expiration - `verify_token(token)` - Validate JWT and return subject - **Comprehensive tests**: 3 unit tests covering token lifecycle #### Updated: `src/auth/mod.rs` - Exports only `token_manager()` function - `TokenManager` struct kept private ### 🧹 Removed Duplication #### `src/middleware.rs` - ❌ Removed local `token_manager()` duplicate - ❌ Removed unnecessary `verify_token()` wrapper - ✅ Uses `auth::token_manager()` directly - ✅ Tests updated to call `token_manager().verify_token()` directly - ✅ Improved error handling and logging #### `src/api.rs` - ❌ Removed local `token_manager()` duplicate - ✅ Uses `auth::token_manager()` directly - ✅ Consistent token creation and validation ### 🧪 Testing Improvements #### New: `tests/validate_portal_token.rs` (98 lines) Integration tests for Keycloak token validation covering: - ✅ Fleet Administrator with valid tenant - ✅ Fleet Administrator with invalid tenant - ✅ Fleet Operator with valid fleet - ✅ Fleet Operator with invalid fleet - ✅ Fleet Observer (insufficient permissions) Uses `mockall` for comprehensive test coverage without external dependencies. #### New: `tests/http_client.rs` (178 lines) Integration tests for Unix socket HTTP client: - ✅ Success scenarios with valid socket paths - ✅ POST request handling - ✅ Multiple sequential requests - ✅ Error handling for non-existent paths - ✅ Error handling for invalid URIs ## Benefits ✅ **Minimal API surface** - One function to get TokenManager ✅ **No duplication** - Single global `token_manager()` implementation ✅ **No wrappers** - Direct access to TokenManager methods ✅ **Better encapsulation** - Constants and struct are private ✅ **Simplified constructor** - 1 parameter instead of 3 ✅ **Code reduction** - Net -31 lines while adding features ✅ **Better testing** - Comprehensive integration test coverage ✅ **Type safety** - Trait-based design for better compile-time checks
…h lifecycle management (omnect#65) ## Summary This PR refactors `OmnectDeviceServiceClient` to implement a type-safe builder pattern with lifecycle management, improving encapsulation and maintainability. ### Key Changes - **Builder Pattern**: Implemented as the only way to create `OmnectDeviceServiceClient`, with private struct fields - **Optional Certificate Setup**: Certificate creation is now optional and injectable via `with_certificate_setup()` - **Optional Publish Endpoint**: Publish endpoint registration is now optional via `with_publish_endpoint()` - **Code Organization**: Extracted service client creation into dedicated `build_service_client()` function - **Simplified Certificate Module**: Made `CreateCertPayload` public and removed intermediate `WorkloadCertPayload` - **Version Bump**: Updated to 1.0.6 - **Dockerfile Fix**: Changed to copy entire `src` directory structure ### Benefits - Better encapsulation through private fields and builder pattern - Clearer lifecycle management with explicit shutdown - Looser coupling via dependency injection (closures for setup) - More flexible configuration (both features are optional) - Easier testing with injectable dependencies --------- Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
## Summary Add network configuration management UI and backend with support for static IP and DHCP configuration. ### Backend - Add `network` 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 --------- Signed-off-by: Jan Zachmann <50990105+JanZachmann@users.noreply.github.com>
## Configuration Management - 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 ## Code Organization - 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 ## Module Updates - `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 ## Testing Improvements - Fix test isolation issues with cached AppConfig - Update middleware tests to work with cached config paths - Add test helper function `create_password_file()` Signed-off-by: Buell <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>
## Overview This PR refactors the omnect-ui backend to separate business logic from HTTP concerns by introducing a dedicated services layer, along with standardized error handling patterns throughout the codebase. **Key improvements:** - 🏗️ **Services Layer Architecture** - Clean separation between HTTP handlers and business logic - 🔒 **Enhanced Error Handling** - Consistent use of `ensure!` and `.context()` for better error propagation ## Services Layer Introduces `src/services/` module that encapsulates all business logic, making it reusable and testable independently of HTTP concerns. ### Authentication & Authorization ([services/auth/](src/services/auth/)) - **AuthorizationService** - Token validation and role-based access control - Validates tenant membership in token claims - FleetAdministrator role grants full access - FleetOperator role requires fleet_id validation - **TokenManager** - Session token creation and validation with configurable expiration and HMAC signing - **PasswordService** - Argon2id password hashing and secure storage ### Business Services - **CertificateService** ([services/certificate.rs](src/services/certificate.rs)) - Module certificate creation via IoT Edge workload API with conditional compilation for mock/production environments - **FirmwareService** ([services/firmware.rs](src/services/firmware.rs)) - Firmware update file handling and data folder management - **NetworkConfigService** ([services/network.rs](src/services/network.rs)) - Network configuration with automatic 90-second rollback mechanism and server restart coordination **Architecture benefits:** - Services accept client traits, enabling easy mocking in tests - Stateless service structs with static methods - Pure business logic with no HTTP dependencies - Reusable functions across different contexts ## Enhanced Error Handling Standardized error handling patterns across the entire workspace. ## API Layer Simplification **Refactored [api.rs](src/api.rs):** - HTTP handlers now delegate to services (239 insertions, 328 deletions = net reduction) - Clear separation between public HTTP handlers and private helper methods - Reduced `Api` struct responsibility to HTTP concerns only - Consistent error handling via `handle_service_result()` helper - Session management delegated to auth service ## File Reorganization **Moved files to services layer:** - `src/auth/` → `src/services/auth/` (added new authorization module) - `src/certificate.rs` → `src/services/certificate.rs` - `src/network.rs` → `src/services/network.rs` --------- 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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
src/backend/vue/tosrc/frontend/src/backend/static/todist/biome.json(frontend has its own)Changes
Cargo.tomlwith workspace configurationsrc/backend/with its ownCargo.tomlinheriting from workspacevue/tosrc/frontend/src/backend/static/to workspace rootdist/biome.jsonTesting
cargo test --features mockPurpose
This prepares the codebase for future Crux framework integration by establishing a clean workspace structure with properly separated concerns.