diff --git a/Cargo.lock b/Cargo.lock index 1421ed1..023e1fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,21 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - [[package]] name = "ahash" version = "0.8.12" @@ -115,21 +100,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - [[package]] name = "base64" version = "0.22.1" @@ -665,12 +635,6 @@ dependencies = [ "wasi 0.14.2+wasi-0.2.4", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "gl_generator" version = "0.14.0" @@ -1504,15 +1468,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - [[package]] name = "naga" version = "25.0.1" @@ -1576,15 +1531,6 @@ dependencies = [ "malloc_buf", ] -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - [[package]] name = "oco_ref" version = "0.1.1" @@ -1741,7 +1687,6 @@ dependencies = [ name = "price-chart-wasm" version = "0.1.0" dependencies = [ - "backtrace", "bytemuck", "console_error_panic_hook", "derive_more", @@ -2038,12 +1983,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - [[package]] name = "rustc-hash" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 936aa64..aeebd31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,6 @@ bytemuck = { version = "1.14.0", features = ["derive"] } # Utilities & macros console_error_panic_hook = "0.1.7" # Better panic messages -backtrace = "0.3" # Explicit stack traces gloo = { version = "0.11", features = ["console", "timers", "events", "net", "utils"] } gloo-net = { version = "0.5", features = ["websocket"] } gloo-timers = { version = "0.3", features = ["futures"] } @@ -50,3 +49,6 @@ panic = "unwind" # Preserves stack traces [profile.release] debug = 1 # Keep debug symbols even in release mode panic = "unwind" # Preserve stack traces + +[package.metadata.cargo-machete] +ignored = ["wasm-bindgen-futures"] diff --git a/DOCS/REFACTORING_ROADMAP.md b/DOCS/REFACTORING_ROADMAP.md new file mode 100644 index 0000000..8ae9bce --- /dev/null +++ b/DOCS/REFACTORING_ROADMAP.md @@ -0,0 +1,71 @@ +# ARCHITECTURE REFACTORING ROADMAP + +## OBJECTIVES +- Stabilize domain logic so it can compile without Leptos, WebGPU, or WASM-only dependencies. +- Introduce clear seams between user interface, rendering, data access, and core computations. +- Prepare the repository for a multi-crate workspace without circular dependencies. +- Reduce reliance on ad-hoc global state in favor of explicit application services and state containers. +- Maintain current functionality (real-time stream, indicators, rendering) while refactoring incrementally with tests. + +## CURRENT COUPLING HOTSPOTS +- `src/global_state.rs` stitches together Leptos UI types (`TooltipData`), renderer configuration (`LineVisibility`), and ECS accessors, so any change in UI or rendering cascades through the entire app. +- ECS components (`src/ecs/components.rs`) embed `RwSignal`, preventing the ECS layer from being reused without Leptos. +- Rendering queue helpers (`src/app.rs` and `src/infrastructure/rendering`) pull values directly from global signals, hiding side effects and making it difficult to test rendering decisions. +- Binance clients under `src/infrastructure` push updates straight into Leptos signals rather than exposing a domain-friendly API. +- `DomainState` mixes historical candle storage with Leptos-driven refresh cadence, but lacks a dedicated repository service that other layers can depend on. + +## TARGET WORKSPACE LAYOUT +| Crate | Responsibilities | Depends On | +| --- | --- | --- | +| `core` | Entities, value objects, indicators, pure services, deterministic tests. | — | +| `data` | Binance REST/WebSocket clients, DTO translation, retry/backoff policies, mocked providers for tests. | `core` | +| `rendering` | GPU primitives, buffer packing, line/tooltip layout independent from Leptos. | `core` | +| `app-services` | Application state container, ECS orchestration, traits for streaming/backfill, adapter from Leptos signals to core models. | `core`, `rendering`, optionally `data` via traits | +| `wasm-app` | Leptos components, hydration entry points, wiring between UI, `app-services`, and platform APIs. | `app-services` | + +The first four crates compile natively; only `wasm-app` requires the `wasm32` target. + +## ITERATIVE PLAN +### ITERATION 0 – BASELINE AND SAFETY NETS +- Document the current refactoring roadmap (this file) and list required invariants. +- Add integration tests for indicator calculations and chart viewport math to guard key behaviors. +- Introduce feature flags or conditional compilation hooks to run the app without WebGPU during tests. + +### ITERATION 1 – HARDEN DOMAIN AND ECS BOUNDARIES +- Move `TooltipData`, `LineVisibility`, and similar UI concepts into a dedicated `app::ui_state` module so `global_state` depends only on that module instead of the entire `app.rs`. +- Replace `RwSignal` in ECS components with a small handle (`ChartHandle`) that hides Leptos behind trait bounds; provide a synchronous implementation for tests. +- Extract `DomainState` and `ViewState` constructors into functions that do not require Leptos, and ensure no domain module imports anything from `app` or `infrastructure`. + +### ITERATION 2 – INTRODUCE APPLICATION SERVICES +- Create an `AppContext` struct that owns all signals and exposes typed methods for updates (e.g., `set_streaming`, `update_tooltip`). +- Move Binance websocket/rest callbacks to call through the new context instead of touching globals directly. +- Define traits (`MarketStream`, `HistoryProvider`) that describe the data services. Provide adapters for current Binance implementations. +- Cover the service layer with unit tests using fake implementations of the traits. + +### ITERATION 3 – ISOLATE RENDERING +- Wrap the render queue helpers behind a `RenderScheduler` trait implemented by the WebGPU renderer. +- Migrate `LineVisibility` and GPU configuration types into `rendering` so the UI layer only depends on traits. +- Provide a dummy renderer used in tests to verify scheduling without invoking WebGPU. +- Ensure rendering-specific state is no longer stored in `global_state`, but owned by the scheduler or renderer crate. + +### ITERATION 4 – PREPARE CRATE EXTRACTION +- Split the repository into a Cargo workspace with `core`, `app-services`, and `wasm-app` crates; move source files accordingly while keeping `rendering` and `data` inside `app-services` temporarily via modules. +- Fix imports, adjust `Cargo.toml` dependencies, and ensure `cargo check` succeeds for the new workspace. +- Update documentation (`ARCHITECTURE.md`, `README.md`) to reflect the new structure. + +### ITERATION 5 – FINALIZE MULTI-CRATE STRUCTURE +- Extract `data` and `rendering` as standalone crates consumed by `app-services`. +- Provide integration tests that run the full pipeline using mock data streams to validate crate boundaries. +- Audit for any remaining `OnceCell` globals; replace them with context-owned instances passed through dependency injection. +- Conduct final cleanup: remove dead code, ensure all binaries and WASM entry points build, update CI workflows. + +## RISKS AND MITIGATIONS +- **Risk:** Increased compilation times due to workspace split. **Mitigation:** Share features and enable incremental builds; start by creating crates without additional dependencies. +- **Risk:** Hard-to-test asynchronous flows. **Mitigation:** Introduce trait-based abstractions and synchronous mocks in early iterations. +- **Risk:** UI regressions caused by refactored state handling. **Mitigation:** Add snapshot tests for tooltip rendering and viewport calculations before moving logic. + +## DONE CRITERIA PER ITERATION +- ✅ All commands `cargo fmt --all`, `cargo check --tests --benches`, `cargo clippy --tests --benches`, `cargo test`, and `cargo machete` (if available) succeed. +- ✅ Documentation updated to mirror the new module ownership. +- ✅ Tests cover new seams introduced in each iteration. +- ✅ No module (or crate, once extracted) depends on layers above it.