92 lines
4.9 KiB
Markdown
92 lines
4.9 KiB
Markdown
# Handoff — PON Go Android
|
||
|
||
Context for the next session/developer. Pairs with [`README.md`](README.md) and
|
||
[`docs/MCMS_API.md`](docs/MCMS_API.md).
|
||
|
||
## Architecture
|
||
|
||
- **`core/`** — pure Kotlin, no Android UI deps. Mirrors the iOS networking core.
|
||
- JSON: MCMS docs are heterogeneous Mongo documents, so we keep raw
|
||
`kotlinx.serialization` `JsonElement` trees and read fields via the accessors
|
||
in `Json.kt` (`el["key"]`, `.string/.int/.double/.array/.obj`) — the analogue
|
||
of the iOS `JSONValue`. Models (`Models.kt`) are thin wrappers over a
|
||
`JsonElement` with computed properties.
|
||
- `ApiClient` (OkHttp): builds versioned requests, injects `Referer` +
|
||
`X-CSRFToken` (writes), unwraps the `{status,data}` envelope, maps status
|
||
codes to `ApiError`, paginates via the `next` cursor. `Call.await()` bridges
|
||
OkHttp to coroutines with cancellation.
|
||
- Repositories return model wrappers; `McmsConnection` wires it all; auth/cookies
|
||
in `Networking.kt` (`SessionCookieJar` + `SessionStore`), TLS policy in
|
||
`ServerTrust`, secrets in `KeychainStore` (EncryptedSharedPreferences).
|
||
- **`ui/`** — Jetpack Compose. Navigation is **state-based** in `MainActivity`
|
||
(a `List<Screen>` back stack + `BackHandler`), not Navigation-Compose — so
|
||
detail screens and the dashboard drill-downs can take in-memory objects
|
||
directly. Each screen has a plain **state-holder class** (`…Model`) exposing
|
||
`mutableStateOf` fields + `suspend load()/refresh()` — the analogue of the iOS
|
||
`@Observable` view models. No androidx `ViewModel`/DI.
|
||
|
||
## Build / verify loop (this matters)
|
||
|
||
The dev machine had **no `kotlinc`/`gradle` on PATH**, but Android Studio provides
|
||
everything. Two loops:
|
||
|
||
- **Full build (authoritative):**
|
||
```
|
||
export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home"
|
||
./gradlew :app:assembleDebug --no-daemon --console=plain
|
||
```
|
||
Needs `local.properties` (`sdk.dir=…`, git-ignored). First run downloads deps
|
||
to `~/.gradle`; afterwards it's ~20–60 s. This is what proves the whole app
|
||
(UI + resources + manifest + icons) compiles.
|
||
- **Quick core-only check (no Gradle), when iterating on `core/`:** the bundled
|
||
compiler at `…/Android Studio.app/Contents/plugins/Kotlin/kotlinc/bin/kotlinc`
|
||
with `-Xplugin=…/kotlinc/lib/kotlinx-serialization-compiler-plugin.jar` and a
|
||
classpath of Maven jars (kotlinx-serialization-json/core, okhttp, okio-jvm,
|
||
kotlinx-coroutines-core-jvm). Compiles every `core/*.kt` except
|
||
`KeychainStore.kt` (androidx). Faster than a Gradle round-trip.
|
||
|
||
## API gotchas (all handled in code — don't regress)
|
||
|
||
- **Single-encode URLs.** Ids stay RAW in `McmsEndpoint`; `ApiClient` encodes the
|
||
path once via `HttpUrl.addPathSegments`. Pre-encoding double-encoded MAC colons
|
||
(`:` → `%3A` → `%253A`) → MCMS "invalid id".
|
||
- **401 bounces to login; 403 does NOT** (permission/CSRF — `requiresReauthentication`
|
||
is 401-only).
|
||
- **Writes return `{"status":"success"}` with no `data`** — the unwrap tolerates it.
|
||
- **ONU registration lives on OLT-STATE buckets** (`OltRepository.registrationMap`),
|
||
not ONU-STATE. Friendly names are `ONU.Name` / `OLT.Name` (NOT `NETCONF.Name`).
|
||
- **CPE DHCP** comes from the web helper `GET /api/cpe/onu/<id>/` — a versionless,
|
||
bare `[code, cpe…]` array (use `ApiClient.getRaw`).
|
||
- **Firmware** = Procedure 7: GET ONU-CFG → write filename/version into the
|
||
**inactive** bank → full-doc PUT (`FirmwareUpgrade.apply`). Inactive-bank only,
|
||
so service stays up until the ONU reboots. Still worth testing on a spare ONU.
|
||
- Field paths were confirmed against live JSON; see `docs/MCMS_API.md` and the
|
||
model accessors.
|
||
|
||
## Trimmed vs iOS (intentional, easy to restore)
|
||
|
||
- ONU detail tabs are **Overview / CPE / Logs / Config** — no separate Alarms tab.
|
||
Current alarms live on ONU-STATE `"Alarm"` buckets if you want to add it.
|
||
- **Config** shows pretty-printed JSON text, not the collapsible tree the iOS app
|
||
has.
|
||
- Dashboard **ONU-state rows aren't tappable** (the Health rows are). The iOS app
|
||
drills ONU-state → filtered ONU list.
|
||
- Toggles use `rememberSaveable` (survive rotation, not process death). Persist in
|
||
prefs if you want parity with iOS `@AppStorage`.
|
||
- Self-signed/cleartext: the TLS trust policy is in `ServerTrust`. Plain-HTTP hosts
|
||
also need a `usesCleartextTraffic`/network-security-config exception (Android's
|
||
ATS analogue) — add when needed.
|
||
|
||
## Repo split
|
||
|
||
This folder is self-contained (has its own `docs/MCMS_API.md`). To make it a git
|
||
repo: `git init` here; the included `.gitignore` already excludes `build/`,
|
||
`.gradle/`, `local.properties`, `.idea/`. Commit the Gradle wrapper
|
||
(`gradlew`, `gradle/wrapper/*`). The full dev-guide PDFs (`323-1961-30x`) live in
|
||
the iOS repo if you ever need the deep source.
|
||
|
||
## Possible next steps
|
||
|
||
Restore the trimmed items above; add OLT firmware (Procedure 8 bulk task);
|
||
per-ONU live-alarms view; charts for PM history; pull-to-refresh on lists;
|
||
dark-theme polish; a proper app theme from the brand colours.
|