# Handoff — PON Go iOS Context for the next session/developer. Pairs with [`README.md`](README.md) and [`MCMS_API.md`](MCMS_API.md). ## Last session (2026-05-31) Landed on `main`: a multi-agent code-review pass (correctness / concurrency / security / cleanup — see [`CHANGELOG.md`](CHANGELOG.md)), then removal of the self-signed TLS option (system trust only, parity with the Android client). > ⚠️ **Verify on the next Mac build.** The code-review fixes were confirmed > building on the Mac, but the **self-signed-TLS removal was merged to `main` > un-compiled** — the Linux dev box that made the change has no Swift toolchain. > First thing next session: build `main` and confirm it compiles. It's a small > change (removed `ServerTrustPolicy.allowSelfSignedForHost` + the Settings > toggle; the trust `switch` stays exhaustive), so it should be clean. TLS consequence: **system trust only** now — a self-signed appliance (the lab box `mcms.lab.svorka.net`) is unreachable until its CA is installed on the device (MDM/configuration profile), or it gets a CA-trusted cert. `CHANGELOG.md` is written to port these changes to the Android side. Merged branches `code-review-fixes` and `remove-self-signed-tls` can be deleted. ## Status Feature-complete and (per off-device typecheck + the user's Xcode builds) compiling. Screens: Login, Settings, Dashboard (counts, total OLT traffic, Health with tappable drill-downs, ONU-state breakdown, detailed-stats + auto-refresh toggles), ONU list + detail (Overview with status/firmware+update/ optical-FEC/UNI/traffic, CPE DHCP, Config raw-JSON tree, Alarms, Logs; reset + firmware behind hardened confirms), OLT list + detail (status/uptime/traffic/ environment/uplink/registration buckets, reset). ## Architecture - `AppEnvironment` (`@MainActor @Observable`) owns the active `MCMSConnection`, persists the non-secret `APIConfiguration` to UserDefaults, keeps credentials in the Keychain, and routes `RootView` (Settings → Login → main `TabView`). - Networking core: `APIConfiguration` → `SessionStore`/`APIClient` → repositories. Mongo documents are kept as a dynamic `JSONValue` (`APIEnvelope.swift`) and read via typed accessors on `MongoDocument` structs (`DeviceModels.swift`) — type the fields you use, leave the rest raw. - View models are `@MainActor @Observable` classes with a `LoadPhase` + `load()`. ## API gotchas (handled in code — don't regress) - **Single-encode URLs.** `APIClient.makeRequest` builds the path with `URLComponents.path` (encodes once, keeps `:` in MAC ids raw); `MCMSEndpoint` keeps ids RAW. `appendingPathComponent` double-encoded MAC colons → MCMS "invalid id". (Verified empirically.) - **401 bounces to login; 403 does NOT** — `APIError.requiresReauthentication` is 401-only (403 is permission/CSRF; re-login won't help). The `onAuthExpired` hook flows `APIClient → MCMSConnection → AppEnvironment`. - **Writes return `{"status":"success"}` with no `data`** — `decodeEnvelope` returns the type's empty value instead of throwing (so login + all writes work). - **ONU registration is on OLT-STATE buckets** (`OLTRepository.registrationMap`), not ONU-STATE. Parent OLT is `OLT.MAC Address`. Friendly names are `ONU.Name` / `OLT.Name` (NOT `Netconf.Name`/`NETCONF.Name`, which default to the id), fetched via `projection`. - **CPE DHCP** = web helper `GET /api/cpe/onu//` (versionless, bare `[code, cpe…]` array — `APIClient.getRaw`). - **Firmware** = Procedure 7 (`FirmwareUpgrade.apply`, unit-tested against a real config): GET ONU-CFG → write filename/version into the **inactive** bank → full- doc PUT. Inactive-bank only; still test on a spare ONU before production. - **Timestamps** are UTC `yyyy-MM-dd HH:mm:ss[.SSSSSS]` with a literal space (`MongoTimestamp`, not ISO8601). Uptime = state `Time` − `Online Time`. - Everything is `/api/v1` except `/v3/tasks/configs/` (unused). Cookies may be `__Host-`-prefixed (`SessionStore` matches either). `/api` is auto-appended to the base URL in Settings. ## Known real-world notes - One lab box (`mcms.lab.svorka.net`) once sent an illegal `Upgrade: h2` header over HTTP/2 that iOS rejects (`-1005`). Fix is server-side (Apache `Protocols http/1.1`) or an HTTP/1.1 reverse proxy; iOS has no supported "force HTTP/1.1". - The base URL must include `/api`; Settings normalises this. ## Verify loop `swiftc -typecheck` against the macOS SDK for the core + view models (see README). Tricky SwiftUI bits: compile isolated snippets sans iOS-only modifiers. No iOS SDK on the dev machine, so full builds are the user's Xcode step. ## Repo split Recommended: consolidate the flat sources + `Assets.xcassets` into the Xcode project and git-init that as the iOS repo (with `docs/MCMS_API.md` + the PDFs). The included `.gitignore` covers Xcode/Swift build artifacts. The Android app is a separate repo (`../mcms_android`), self-contained. ## Possible next steps OLT bulk firmware (Procedure 8 task); Swift Charts for PM history; live optical on the list rows; richer alarm handling; widen test coverage of the firmware PUT against more ONU-CFG shapes.