Always use the Gradle wrapper (./gradlew). The daemon JVM is provisioned automatically
(gradle/gradle-daemon-jvm.properties); the Android SDK location comes from local.properties
(sdk.dir) or ANDROID_HOME.
| Task | Command |
|---|---|
| Debug build | ./gradlew :app:assembleDebug (or :app:installDebug to a device) |
| Unit tests (local JVM, no device) | ./gradlew :app:testDebugUnitTest |
| One test class | ./gradlew :app:testDebugUnitTest --tests "ru.kryu.ferryfile.server.routes.FileRoutesTest" |
| Compile / lint | ./gradlew :app:compileDebugKotlin :app:lintDebug |
| Instrumented smoke test | ./gradlew :app:connectedDebugAndroidTest (needs a device or emulator) |
| Signed release bundle | ./gradlew :app:bundleRelease — see docs/RELEASE_SIGNING.md |
There is no ktlint or detekt; compiling and lintDebug are the checks.
Single Gradle module :app, package ru.kryu.ferryfile.
domain/— pure Kotlin: noandroid.*,androidx.*,io.ktor.*ordagger.*imports. Repository interfaces live here; their implementations live indata/(Hilt DI).server/— the embedded Ktor server and its routes.ui/— Jetpack Compose screens.app/src/main/assets/webui/— the browser UI (login.html,files.html,app.js,style.css,i18n.js). It is hand-written static HTML/JS/CSS served byserver/routes/FileRoutes.kt, not generated: an API change means editing these assets together with the routes.
- The server runs on Ktor Netty. Do not reintroduce
ktor-server-cio(upstreamExpect: 100-continueframing bug, see docs/KNOWN_ISSUES.md). - Upload limits in
FileRoutes.kt(formFieldLimitbounded by the declaredContent-Length, 8 MiB fallback, 256 MiB hard ceiling) are deliberate. Read the KDoc there before touching them. - The upload route must keep
catch (CancellationException) { throw }semantics and drain the raw request channel on failure; regressions there caused silent upload stalls. - Home screen state refreshes both via
LifecycleEventEffect(ON_RESUME)and via the service-drivenServerRepository.refresh()after a notification Stop. Both are required. - Never commit signing material:
keystore.properties,*.jksand/app/release/are git-ignored.
Every user-visible string must be added in all three places:
- Android UI:
app/src/main/res/values/strings.xmlandapp/src/main/res/values-ru/strings.xml - Web UI:
app/src/main/assets/webui/i18n.js(parallelenandruobjects)
android.util.Logis not stubbed in JVM tests; calling it from code under test throwsMethod ... not mocked. Give such code alogError: (String, Throwable) -> Unitparameter that defaults toLog.e(seeconfigureFileRoutes,stopServerForTimeLimit) and assert on it in tests. Do not re-enableisReturnDefaultValues.- The debug build has
applicationIdSuffix = ".debug", so its package isru.kryu.ferryfile.debug.adb/logcatcommands written forru.kryu.ferryfilehit the release install instead. - Git worktrees have no
local.properties; run Gradle there withANDROID_HOMEset.
- Every change lives on a
feature/<name>branch cut fromdevelop. Nothing is committed todevelopormaindirectly. - A finished feature is merged into
developand its branch is deleted. - When a batch of changes has accumulated,
developis merged intomainwith a version bump and a new tag. - A commit message is one short line (up to 80 characters), in the imperative — for example
Add Stopping server state. No body, no trailers.
The exact procedure is in docs/RELEASING.md; version numbering is in docs/VERSIONING.md.