RKNnoVPN/docs/architecture-reset/CODE_MIGRATION_PLAN.md
loop-uh 2ccfe8ce0a
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
Перенести выпуск RKNnoVPN на Forgejo
2026-08-07 03:08:36 +03:00

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
```