Skip to content

Frontend

This document covers the frontend web distribution model, Compose dependency versioning rules, and frontend-app repository and ViewModel conventions.

For the broader system map, see architecture-overview.md.

frontend-app Web Distribution

frontend-app no longer builds or deploys its own container image. Its JS browser distribution is published as the consumable webDistElements directory artifact backed by jsBrowserDevelopmentExecutableDistribution.

backend-web-app resolves that artifact, stages it into build/caddy/dist, and packages it into the production Caddy image. backend-web-app:assemble pulls the frontend distribution transitively.

Frontend Compose Dependency Versioning

Frontend Compose modules currently include frontend-app and frontend-charts.

  • Prefer version-catalog aliases such as libs.compose.runtime, libs.compose.foundation, libs.compose.ui, and libs.compose.html.core in dependency blocks. Do not use the deprecated compose.* dependency accessors there; keep compose.desktop.currentOs only for the desktop target artifact.
  • Keep org.jetbrains.compose.* modules on the shared compose version in gradle/libs.versions.toml.
  • Keep org.jetbrains.compose.material3:material3 on the separate compose-material3 version because it does not track the rest of the JetBrains Compose modules.
  • Keep AndroidX Compose-adjacent families on their own version refs: org.jetbrains.androidx.lifecycle, org.jetbrains.androidx.navigation, androidx.savedstate, and androidx.activity:activity-compose.
  • Add compose.foundation explicitly when frontend code uses layout, focus, scrolling, pointer-input, or other foundation APIs; do not rely on those APIs arriving transitively.
  • Any module that uses Kotest artifacts should import platform(libs.kotest.bom) in the relevant configuration/source set instead of versioning individual Kotest modules directly.

frontend-app Repository And ViewModel Conventions

  • FeedsRepository and StrategiesRepository are internal interfaces with private in-file implementations. Construct them via companion object { operator fun invoke(...) } and keep DI wiring in AppComponent pointing at those factories.
  • Prefer mocking those repository interfaces directly in commonTest rather than introducing extra port types just for ViewModel tests.
  • Shared instrument-search UI state should stay generic over a feature-owned mode type. Keep instrumentsearch.ViewMode as the shared interface with displayValue, define per-screen enums such as FeedsViewMode and StrategiesViewMode in the owning feature package, and thread them through InstrumentSearchViewState<TViewMode>/SearchView<TViewMode> so each ViewModel keeps exhaustive mode handling without meaningless cross-screen values.
  • For ViewModel search/filter logic, keep helper functions private and verify behavior through exposed flows such as searchViewState instead of widening visibility for tests.
  • Prefer private top-level helpers over nested local functions when extracting non-trivial ViewModel logic.

frontend-app Test Conventions

frontend-app is a Kotlin Multiplatform UI module, so its verification is target-specific rather than a single JVM test task:

  • Shared ViewModel tests live in src/commonTest and use Kotest FunSpec, Mokkery mocks, Turbine flow assertions, and androidx.lifecycle.viewmodel.testing.viewModelScenario.
  • CoroutineTestExtension in src/commonTest sets Dispatchers.Main before each test and resets it afterward. Specs that use it should enable Kotest's coroutine test scope (coroutineTestScope = true) so the test body runs under virtual time.
  • viewModelScenario { ... }.use { ... } is the preferred harness for ViewModel lifecycle tests in common code.
  • Android host unit tests for frontend-app run through testDebugUnitTest; keep android.testOptions.unitTests.isReturnDefaultValues = true because viewModelScenario reaches Android Bundle APIs that otherwise throw "not mocked" errors under local unit tests.
  • Verify frontend-app changes with ./gradlew :frontend-app:testDebugUnitTest :frontend-app:desktopTest :frontend-app:jsTest when the change touches shared ViewModel tests or other code exercised by Android host tests. In CI, the root unit-test step runs ./gradlew test allTests, which covers backend JVM tests plus KMP allTests tasks such as :frontend-app:allTests.