Some checks failed
RKNnoVPN Linux and Android CI / policy-and-go (push) Successful in 14s
RKNnoVPN Linux and Android CI / android-debug (push) Successful in 2m5s
Full build and Forgejo release / Privacy Lint (push) Successful in 3s
Full build and Forgejo release / Local-first Runtime Guardrail (push) Successful in 2s
Full build and Forgejo release / Go Tests (push) Successful in 13s
Full build and Forgejo release / Resolve sing-box release (push) Successful in 1s
Full build and Forgejo release / Resolve Xray-core release (push) Successful in 1s
Full build and Forgejo release / Android Guardrails & Tests (push) Failing after 16s
Full build and Forgejo release / Build APK (push) Has been skipped
Full build and Forgejo release / Build Runtime CLI (arm64) (push) Successful in 11s
Full build and Forgejo release / Build Runtime CLI (armv7) (push) Successful in 11s
Full build and Forgejo release / Build sing-box (arm64) (push) Failing after 2s
Full build and Forgejo release / Build sing-box (armv7) (push) Failing after 2s
Full build and Forgejo release / Build Xray-core (arm64) (push) Failing after 3s
Full build and Forgejo release / Build Xray-core (armv7) (push) Failing after 2s
Full build and Forgejo release / Build Magisk Module (push) Has been skipped
Full build and Forgejo release / Create Release (push) Has been skipped
188 lines
6.2 KiB
Markdown
188 lines
6.2 KiB
Markdown
# RKNnoVPN Local-First Code Migration Plan
|
|
|
|
This plan is the guardrail for the daemon-to-local-first migration. The goal is
|
|
to keep the existing UI and user-visible features while changing ownership and
|
|
execution boundaries:
|
|
|
|
- APK owns profile, settings, subscriptions, and update cache.
|
|
- APK performs subscription and release network requests directly.
|
|
- Root/module runtime is only an executor for apply/start/stop/restart/reset,
|
|
logs, and module staging.
|
|
- Old daemon IPC compatibility is not part of the active APK or runtime path.
|
|
|
|
## Non-Breaking Feature Contract
|
|
|
|
The migration must preserve:
|
|
|
|
- direct link import;
|
|
- QR/import sheet;
|
|
- subscriptions;
|
|
- app list and package picker;
|
|
- routing modes;
|
|
- bypassRussia;
|
|
- DNS settings;
|
|
- always-direct apps;
|
|
- sharing/tethering settings;
|
|
- update check and download;
|
|
- start, stop, restart, reset;
|
|
- logs;
|
|
- node tests.
|
|
|
|
Backend ownership changes are expected:
|
|
|
|
- daemon profile get/apply/import calls become APK-local profile operations:
|
|
`AppProfileStore` is dumb persistence, while `ProfileRepository` is the only
|
|
owner/publisher of observable profile state;
|
|
- daemon subscription preview/refresh becomes APK-side subscription fetching and
|
|
parsing through `ApkSubscriptionClient`;
|
|
- daemon update check/download becomes APK-side Forgejo release fetching through
|
|
`ApkReleaseUpdater`;
|
|
- daemon backend controls become explicit root CLI commands through
|
|
`RuntimeController`;
|
|
- daemon logs become `RuntimeController.logs`.
|
|
|
|
## Phase 1: APK Boot Without Runtime
|
|
|
|
Required code:
|
|
|
|
- `app/app/src/main/AndroidManifest.xml`
|
|
- `app/app/src/main/kotlin/com/rknnovpn/panel/profile/AppProfile.kt`
|
|
- `app/app/src/main/kotlin/com/rknnovpn/panel/storage/AppProfileStore.kt`
|
|
- `app/app/src/main/kotlin/com/rknnovpn/panel/storage/FileAppProfileStore.kt`
|
|
- `app/app/src/main/kotlin/com/rknnovpn/panel/repository/ProfileRepository.kt`
|
|
|
|
Acceptance:
|
|
|
|
- APK opens with no module installed.
|
|
- APK profile is created and stored under app-private storage.
|
|
- Profile editing and imports do not require root or runtime compatibility.
|
|
- `AppProfileStore` remains a persistence-only contract: no `StateFlow`, no
|
|
long-lived `profile`, `warning`, or `error` properties, and no UI/runtime
|
|
state ownership.
|
|
- `ProfileRepository` is the single owner of profile-related observable state:
|
|
profile, freshness/loading, error, and notice flows are published from the
|
|
repository, not from storage.
|
|
|
|
## Phase 2: Remove Active IPC Compatibility
|
|
|
|
Forbidden in active code paths:
|
|
|
|
- `compat.check`
|
|
- `ipc.contract`
|
|
- `GeneratedDaemonContract`
|
|
- `requireCompatible`
|
|
- `compatibilityCache`
|
|
- repair cooldowns
|
|
- stable invalid response recovery
|
|
- automatic module repair after parse errors
|
|
- daemon-owned profile as APK startup dependency
|
|
|
|
Acceptance:
|
|
|
|
- Forbidden strings are absent from `app`, `runtime`, `module`, `tools`, and
|
|
CI scripts except for the local-first checker that defines the forbidden
|
|
patterns.
|
|
|
|
## Phase 3: APK-Side Subscriptions
|
|
|
|
Required code:
|
|
|
|
- `app/app/src/main/kotlin/com/rknnovpn/panel/subscription/ApkSubscriptionClient.kt`
|
|
- `app/app/src/main/kotlin/com/rknnovpn/panel/subscription/SubscriptionRepository.kt`
|
|
|
|
Acceptance:
|
|
|
|
- APK downloads subscription URLs itself.
|
|
- APK parses payloads with `LinkParser`.
|
|
- APK saves imported nodes into `AppProfileStore`.
|
|
- Runtime/module absence does not block preview, commit, refresh, or refresh all.
|
|
|
|
## Phase 4: APK-Side Updates
|
|
|
|
Required code:
|
|
|
|
- `app/app/src/main/kotlin/com/rknnovpn/panel/update/ApkReleaseUpdater.kt`
|
|
- `app/app/src/main/kotlin/com/rknnovpn/panel/update/UpdateRepository.kt`
|
|
- settings update flow.
|
|
|
|
Acceptance:
|
|
|
|
- APK checks the latest release in the project Forgejo itself.
|
|
- APK downloads `module.zip`, `panel.apk`, and `SHA256SUMS`.
|
|
- APK verifies SHA256 before exposing downloaded update paths.
|
|
- Runtime is only needed to stage/install the root/module part.
|
|
|
|
## Phase 5: Root CLI Runtime
|
|
|
|
Required code:
|
|
|
|
- `app/app/src/main/kotlin/com/rknnovpn/panel/runtime/RuntimeController.kt`
|
|
- `app/app/src/main/kotlin/com/rknnovpn/panel/root/RootCommandExecutor.kt`
|
|
- `runtime/cmd/rknnovpn-runtime/main.go`
|
|
|
|
Required commands:
|
|
|
|
- `rknnovpn-runtime version`
|
|
- `rknnovpn-runtime status`
|
|
- `rknnovpn-runtime apply <profile.json>`
|
|
- `rknnovpn-runtime start`
|
|
- `rknnovpn-runtime stop`
|
|
- `rknnovpn-runtime restart`
|
|
- `rknnovpn-runtime reset`
|
|
- `rknnovpn-runtime logs`
|
|
- `rknnovpn-runtime stage-module <module.zip>`
|
|
|
|
Runtime actions are enabled only when:
|
|
|
|
- runtime release version equals APK `BuildConfig.VERSION_NAME`;
|
|
- runtime version code equals APK `BuildConfig.VERSION_CODE`;
|
|
- runtime `wireEpoch` equals `1`.
|
|
|
|
If runtime is missing, old, root-denied, or returns malformed JSON, APK local
|
|
features remain usable and runtime controls fail as disabled/unavailable actions.
|
|
|
|
## Phase 6: Runtime Profile Renderer
|
|
|
|
Required code:
|
|
|
|
- `app/app/src/main/kotlin/com/rknnovpn/panel/runtime/RuntimeProfileRenderer.kt`
|
|
|
|
Acceptance:
|
|
|
|
- APK profile is converted into runtime config only during apply/start.
|
|
- APK boot does not depend on runtime config schema.
|
|
- Routing, DNS, sharing, always-direct apps, app groups, bypassRussia, and active
|
|
node selection are carried into the runtime projection.
|
|
- Runtime projection does not carry APK-only subscription registry, share-link
|
|
fallback data, or stale node metadata.
|
|
|
|
## Phase 7: Tests And Validation
|
|
|
|
Expected coverage areas:
|
|
|
|
- APK profile file store behavior.
|
|
- Profile repository local-first behavior.
|
|
- Profile store/repository boundary: store returns operation results only,
|
|
repository publishes profile/error/notice state.
|
|
- Subscription payload parsing and repository behavior.
|
|
- Release metadata/checksum parsing and update repository behavior.
|
|
- Runtime availability/protocol handling for missing, mismatched, and malformed
|
|
runtime responses.
|
|
- Runtime profile rendering for routing, DNS, sharing, always-direct, app groups,
|
|
and stale-node filtering.
|
|
|
|
Required validation commands:
|
|
|
|
```bash
|
|
./gradlew :app:assembleDebug
|
|
./gradlew :app:testDebugUnitTest
|
|
scripts/ci/check_local_first_runtime.sh
|
|
scripts/ci/check_apk_privacy.sh
|
|
rg "compat\\.check|ipc\\.contract|GeneratedDaemonContract|requireCompatible|compatibilityCache|Repair cooldown|stableInvalidResponse" app runtime module .forgejo
|
|
```
|
|
|
|
Release APK privacy validation requires a built APK:
|
|
|
|
```bash
|
|
scripts/ci/check_release_apk_privacy.sh path/to/app.apk
|
|
```
|