Files
GMW/docs/superpowers/plans/2026-07-04-frontend-dependency-upgrade.md
T

17 KiB

Frontend Dependency Upgrade Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Upgrade the Bete frontend to the newest feasible Rust/WASM dependency and build-tool surface, including pre-releases when verified.

Architecture: The frontend is a Leptos CSR WASM app in the services/frontend Cargo workspace. The upgrade is intentionally narrow: update manifests/tooling, refresh Cargo.lock, repair only compiler-required compatibility issues, and verify both local Trunk builds and the production proxy Docker build path.

Tech Stack: Rust, Cargo workspace, Leptos CSR, Trunk, wasm-bindgen/web-sys, Docker proxy image, pnpm root scripts.

Global Constraints

  • Attempt newest visible releases, including pre-releases, for the main frontend stack.
  • Prefer the newest version that passes verification over forcing a broken latest version.
  • Initial target versions: leptos = "0.9.0-alpha", leptos-use = "0.19", lucide-leptos = "3.23", trunk = "0.22.0-beta.1".
  • The current frontend toolchain is nightly-2026-06-01; raise it if needed to satisfy Rust 1.90.0 requirements from Trunk beta.
  • Preserve dashboard behavior; do not redesign UI, change backend APIs, or do unrelated refactors.
  • Keep edits scoped to manifests, lockfile, build tooling, and compatibility changes directly caused by the upgrade.
  • Do not create implementation commits unless the user explicitly grants commit permission for implementation changes in this session.

File Structure

  • Modify: services/frontend/rust-toolchain.toml — pins the Rust toolchain and wasm32-unknown-unknown target for local frontend builds.
  • Modify: services/frontend/frontend/Cargo.toml — direct dependency declarations for the Leptos CSR app.
  • Modify: services/frontend/shared-types/Cargo.toml — direct dependency declarations for frontend-shared serde types.
  • Modify: services/frontend/Cargo.lock — resolved frontend Cargo workspace dependency graph.
  • Modify: infra/docker/Dockerfile.proxy — production build path that compiles the frontend WASM bundle and serves dist from nginx.
  • Inspect only unless needed: .gitlab-ci.yml — CI already builds the proxy Docker image; only modify if Dockerfile changes require CI variables or arguments.
  • Compatibility edits may modify Rust files under services/frontend/frontend/src/**/*.rs only when the upgraded crates require API syntax changes.

Task 1: Establish baseline and choose deterministic build tool pins

Files:

  • Inspect: services/frontend/rust-toolchain.toml
  • Inspect: services/frontend/frontend/Cargo.toml
  • Inspect: infra/docker/Dockerfile.proxy
  • Modify: none in this task

Interfaces:

  • Consumes: Existing frontend workspace and root scripts.

  • Produces: Baseline command results and confirmed target pins for Task 2.

  • Step 1: Record current git state

git status --short

Expected: clean except for this plan file if it has not yet been committed. If there are unrelated user changes, stop and report them before editing dependency files.

  • Step 2: Run current frontend typecheck baseline
pnpm run typecheck:web

Expected: PASS before dependency edits. If this fails before edits, save the output and report that the baseline is already broken.

  • Step 3: Run current frontend release build baseline
pnpm run build:web

Expected: PASS before dependency edits. If this fails before edits, save the output and report that the baseline is already broken.

  • Step 4: Confirm latest target metadata
cargo info leptos
cargo info leptos-use
cargo info lucide-leptos
cargo info trunk

Expected: metadata includes at least these target versions unless newer releases appeared during implementation:

leptos 0.9.0-alpha
leptos-use 0.19.0
lucide-leptos 3.23.0
trunk 0.22.0-beta.1

If newer versions appear, use the same max-feasible policy: attempt the newest visible version, including pre-release, then fall back only if verification fails.


Task 2: Update frontend toolchain and deterministic Docker Trunk install

Files:

  • Modify: services/frontend/rust-toolchain.toml
  • Modify: infra/docker/Dockerfile.proxy
  • Inspect: .gitlab-ci.yml

Interfaces:

  • Consumes: Target Trunk version from Task 1.

  • Produces: A deterministic local/Docker build-tool surface for dependency compilation.

  • Step 1: Replace the frontend toolchain pin

Edit services/frontend/rust-toolchain.toml to this content:

[toolchain]
channel = "nightly-2026-07-04"
components = ["rust-src", "rustc-dev"]
targets = ["wasm32-unknown-unknown"]

Rationale: the frontend currently has no #![feature(...)] gates, but keeping nightly avoids changing compiler channel semantics while moving past the Rust 1.90.0 requirement advertised by Trunk beta.

  • Step 2: Verify the selected toolchain exists
cd services/frontend && rustup show active-toolchain && rustc --version

Expected: active toolchain is nightly-2026-07-04 or rustup installs it and then reports a Rust version at or above 1.90.0-nightly.

If nightly-2026-07-04 is unavailable, use the newest installed or installable nightly at or after 2026-07-04 that satisfies Rust 1.90.0 and update services/frontend/rust-toolchain.toml to that exact date.

  • Step 3: Pin Trunk in the production proxy Dockerfile

In infra/docker/Dockerfile.proxy, replace:

RUN cargo install trunk --locked

with:

RUN cargo install trunk --version 0.22.0-beta.1 --locked
  • Step 4: Inspect CI for required changes
grep -n "build-proxy\|Dockerfile.proxy\|SERVICE_NAME" .gitlab-ci.yml

Expected: CI builds infra/docker/Dockerfile.$SERVICE_NAME with SERVICE_NAME: proxy, so no .gitlab-ci.yml change is required.

If CI does not build Dockerfile.proxy, update the CI job so build-proxy builds infra/docker/Dockerfile.proxy and keep the existing image tags.

  • Step 5: Check formatting of edited non-Rust files
git diff -- services/frontend/rust-toolchain.toml infra/docker/Dockerfile.proxy .gitlab-ci.yml

Expected: diff only changes the toolchain channel and Trunk install version unless CI inspection revealed a real mismatch.


Task 3: Upgrade Cargo manifests and refresh the frontend lockfile

Files:

  • Modify: services/frontend/frontend/Cargo.toml
  • Modify: services/frontend/shared-types/Cargo.toml
  • Modify: services/frontend/Cargo.lock

Interfaces:

  • Consumes: Toolchain and Docker Trunk pin from Task 2.

  • Produces: Updated Cargo dependency declarations and resolved lockfile for Task 4.

  • Step 1: Update direct frontend app dependencies

Edit the [dependencies] section in services/frontend/frontend/Cargo.toml to keep the existing dependency list and set these version requirements:

leptos = { version = "0.9.0-alpha", features = ["csr"] }
leptos-use = "0.19"
lucide-leptos = "3.23"
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
js-sys = "0.3"
web-sys = { version = "0.3", features = [
    "WebSocket",
    "MessageEvent",
    "CloseEvent",
    "ErrorEvent",
    "CanvasRenderingContext2d",
    "AudioContext",
    "AudioBuffer",
    "AudioBufferSourceNode",
    "AudioDestinationNode",
    "AudioNode",
    "AudioProcessingEvent",
    "MediaStreamAudioSourceNode",
    "ScriptProcessorNode",
    "Window",
    "Document",
    "Element",
    "HtmlElement",
    "HtmlSelectElement",
    "KeyboardEvent",
    "Storage",
    "IntersectionObserver",
    "ResizeObserver",
    "Url",
    "Headers",
    "Request",
    "RequestInit",
    "RequestMode",
    "Response",
    "HtmlInputElement",
    "HtmlAudioElement",
    "HtmlCanvasElement",
    "MediaDevices",
    "MediaStream",
    "MediaStreamConstraints",
    "MediaStreamTrack",
    "Navigator",
    "console",
] }
gloo-net = "0.6"
gloo-timers = "0.3"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde-wasm-bindgen = "0.6"
wasm-logger = "0.2"
console_error_panic_hook = "0.1"
regex = "1"

Do not remove shared-types = { path = "../shared-types" }.

  • Step 2: Keep shared-types serde on latest compatible major

Confirm services/frontend/shared-types/Cargo.toml still contains:

[dependencies]
serde = { version = "1", features = ["derive"] }

No change is required unless cargo update reports a resolver issue.

  • Step 3: Refresh the frontend workspace lockfile
cd services/frontend && cargo update

Expected: services/frontend/Cargo.lock updates to resolved versions compatible with the new manifest requirements.

  • Step 4: Check direct resolved versions
cargo tree --manifest-path services/frontend/frontend/Cargo.toml -e normal --depth 1

Expected: direct tree includes the newest feasible resolved versions, ideally:

leptos v0.9.0-alpha
leptos-use v0.19.0
lucide-leptos v3.23.0

If Cargo cannot resolve leptos 0.9.0-alpha with leptos-use 0.19, try the newest mutually compatible pair and record the resolver error and fallback pair in the final report.


Task 4: Run compiler-driven compatibility repairs

Files:

  • Modify as needed: services/frontend/frontend/src/**/*.rs
  • Modify as needed: services/frontend/frontend/Cargo.toml only for documented fallback versions
  • Modify as needed: services/frontend/Cargo.lock after fallback changes

Interfaces:

  • Consumes: Upgraded dependency graph from Task 3.

  • Produces: A compiling Leptos frontend with behavior-preserving source compatibility fixes.

  • Step 1: Run the upgraded typecheck

pnpm run typecheck:web

Expected: either PASS, or FAIL with concrete compiler errors from upgraded Leptos/tooling.

  • Step 2: Apply compatibility fix pattern A for Leptos mount changes if needed

If the compiler reports that leptos::mount::mount_to_body(app::App) no longer matches the expected signature, edit services/frontend/frontend/src/lib.rs from:

    // Mount the Leptos app to the body
    leptos::mount::mount_to_body(app::App);

to:

    // Mount the Leptos app to the body
    leptos::mount::mount_to_body(|| leptos::view! { <app::App /> });

Then rerun:

pnpm run typecheck:web

Expected: the mount signature error disappears.

  • Step 3: Apply compatibility fix pattern B for removed empty-view hacks if needed

If the compiler reports errors around statements like let _: () = view! { <></> }; or converting () into a view, replace the empty branch with an explicit empty view.

For services/frontend/frontend/src/features/live/components/voice_connection_card.rs, replace:

                        } else {
                            let _: () = view! { <></> };
                            ().into_any()
                        }

with:

                        } else {
                            view! { <></> }.into_any()
                        }

Then rerun:

pnpm run typecheck:web

Expected: the empty-view conversion error disappears.

  • Step 4: Apply compatibility fix pattern C for signal constructor changes if needed

If the compiler reports that RwSignal::new(...) is unavailable or deprecated as an error under Leptos alpha, convert local signal creation to the Leptos function form.

Example replacement in services/frontend/frontend/src/app.rs:

let auth = AuthContext {
    authenticated: RwSignal::new(false),
    password: RwSignal::new(String::new()),
};

becomes:

let auth = AuthContext {
    authenticated: RwSignal::new(false),
    password: RwSignal::new(String::new()),
};

Expected: no edit is needed unless the compiler makes this an error. If it is an error and Leptos documents a replacement such as RwSignal::new_with_options or signal, apply the smallest mechanical change consistently to all reported sites and rerun pnpm run typecheck:web.

  • Step 5: Apply compatibility fix pattern D for event and property macro changes if needed

If the compiler reports view! macro errors around event/property syntax, keep the current behavior and update only the reported syntax. Typical sites include:

on:click=move |_| active_tab.set(tab4.clone())
prop:value=selected_guild
class:btn=true
style:background=move || if active_tab.get() == tab2 { "var(--surface-overlay)" } else { "" }

For each compiler-reported macro error, change only the syntax required by the new macro and rerun:

pnpm run typecheck:web

Expected: each macro error is removed without changing UI classes, inline styles, event behavior, or signal reads.

  • Step 6: Decide fallback if alpha migration exceeds scope

If leptos 0.9.0-alpha causes broad API breakage across many components and the typecheck cannot be repaired with behavior-preserving mechanical edits, fall back to newest stable Leptos visible in cargo info leptos or documented by Cargo metadata.

Use these commands to test the fallback:

cd services/frontend
cargo update -p leptos --precise 0.8.14
cargo update
cd ../..
pnpm run typecheck:web

Expected: fallback version typechecks after minimal compatibility repairs. Record the attempted alpha error summary and selected fallback in the final report.

  • Step 7: Finish with a passing typecheck
pnpm run typecheck:web

Expected: PASS.


Task 5: Verify release build, lint/test scope, and production Docker path

Files:

  • Inspect: package.json
  • Inspect: .gitlab-ci.yml
  • Inspect/modify only if required: infra/docker/Dockerfile.proxy

Interfaces:

  • Consumes: Compiling upgraded frontend from Task 4.

  • Produces: Verification evidence for the final response.

  • Step 1: Run the frontend release build

pnpm run build:web

Expected: PASS and Trunk writes release assets to services/frontend/frontend/dist.

  • Step 2: Run root lint if relevant to changed files
pnpm run lint

Expected: PASS. If Biome does not cover the changed Rust/TOML/Docker files and running lint is not useful, report that it was skipped and why.

  • Step 3: Run tests if relevant
pnpm run test

Expected: PASS if tests are runnable in this environment. If tests are unrelated to the frontend Rust workspace or fail for pre-existing service reasons, report the exact result and do not claim all tests pass.

  • Step 4: Verify the production proxy Docker build path if Docker is available
docker build -f infra/docker/Dockerfile.proxy .

Expected: PASS and the build reaches the nginx runner stage after compiling the frontend WASM bundle.

If Docker is unavailable, permission-denied, or impractical in this environment, report that Docker verification was skipped with the exact error and rely on the passing local Trunk release build as the minimum production-path proxy.

  • Step 5: Inspect final dependency and build-tool diff
git diff -- services/frontend/rust-toolchain.toml services/frontend/frontend/Cargo.toml services/frontend/shared-types/Cargo.toml services/frontend/Cargo.lock infra/docker/Dockerfile.proxy .gitlab-ci.yml services/frontend/frontend/src

Expected: diff contains only dependency/toolchain/build pin changes and compatibility edits required by the upgrade.


Task 6: Final review and report

Files:

  • Inspect: all changed files from git status --short
  • Modify: none unless review finds a concrete issue

Interfaces:

  • Consumes: Verification evidence from Task 5.

  • Produces: Final user-facing summary with versions, fallbacks, and verification results.

  • Step 1: Summarize changed files

git status --short

Expected: changed files are limited to the plan, frontend manifests/lockfile/toolchain, Dockerfile/CI if needed, and frontend Rust compatibility edits if needed.

  • Step 2: Check resolved direct frontend versions
cargo tree --manifest-path services/frontend/frontend/Cargo.toml -e normal --depth 1

Expected: output shows the final resolved versions for leptos, leptos-use, lucide-leptos, and support crates.

  • Step 3: Prepare final response

Include this information:

- Dependency targets attempted: leptos, leptos-use, lucide-leptos, trunk.
- Final resolved versions: copied from cargo tree/cargo metadata.
- Toolchain version: copied from services/frontend/rust-toolchain.toml and rustc --version.
- Fallbacks: none, or exact attempted version -> selected version with reason.
- Verification: exact commands run and PASS/FAIL/SKIPPED status.
- Docker: built successfully, or skipped with exact environment limitation.
  • Step 4: Stop before committing implementation changes unless permission was granted
git diff --stat

Expected: final diff is ready for the user to review. Do not run git commit unless the user explicitly asks for a commit.