# MCMS Mobile — GUI scaffold notes

The SwiftUI layer sits on top of the networking core from the kickoff brief. It's
a working skeleton you run against a live MCMS box, then refine.

## Layout

```
App/         MCMSMobileApp (@main), RootView routing, AppEnvironment
UI/          Shared components (badges, count tiles, load/error states, LoadPhase)
Features/
  Settings/  Connection config + test (direct or proxy; system TLS trust only)
  Login/     Email/password, Keychain prefill
  Dashboard/ Device + alarm counts (VM + View)
  ONUList/   Searchable ONU list (VM + View)
  ONUDetail/ Stats / Config / Alarms / Logs tabs + Reset op (VM + View)
```

Flow: `RootView` shows **Settings** until a connection is configured, then
**Login**, then the main **TabView**. `AppEnvironment` owns the `MCMSConnection`,
persists the (non-secret) `APIConfiguration` to `UserDefaults`, and keeps
credentials in the Keychain.

## Putting it in Xcode

1. New iOS App (SwiftUI lifecycle), **deployment target iOS 17.0+**, built with
   **Xcode 26 (iOS 26 SDK)**. The 26 SDK is required for App Store / TestFlight
   submission and makes standard components adopt the Liquid Glass look on iOS 26
   devices automatically — no code and no opt-out flag needed; the UI here is stock.
2. Delete the template `ContentView.swift` and the generated `App` struct — this
   scaffold provides its own `@main` in `App/MCMSMobileApp.swift`.
3. Add the whole `MCMSMobile/` tree (networking core + this GUI). One module,
   no external dependencies.

The view models use the `@Observable` macro and views use `@State`/`@Environment`
(iOS 17+). If you ever need to drop below iOS 17, revert those to
`ObservableObject`/`@Published` + `@StateObject`/`@EnvironmentObject` and
reinstate a `ContentUnavailableView` shim.

## App Transport Security (the gotcha)

TLS uses **system trust only** — there is no self-signed bypass. (Historical note:
an earlier build had a `ServerTrustEvaluator` self-signed toggle; it was removed for
parity with Android.) ATS is separate and can still block the connection:

- **HTTPS to a self-signed host:** the connection FAILS unless the host's CA is
  installed on the device (MDM/configuration profile). Keep TLS 1.2+.
- **Plain HTTP** (no TLS) or weak TLS: ATS blocks it by default. Add a *scoped*
  exception for your host in Info.plist rather than a blanket allow:

```xml
<key>NSAppTransportSecurity</key>
<dict>
  <key>NSExceptionDomains</key>
  <dict>
    <key>10.2.10.29</key>
    <dict>
      <key>NSExceptionAllowsInsecureHTTPLoads</key><true/>
      <key>NSIncludesSubdomains</key><false/>
    </dict>
  </dict>
</dict>
```

Avoid `NSAllowsArbitraryLoads`. Behind a proxy with a real cert, you need none of
this and should set the trust policy to `.system`.

## Known TODOs carried from the core

- Confirm `/api/v1` vs `/v1` and the `databases/selection` body key.
- The Mongo-document field accessors (ONU state/parent OLT, alarm severity/time,
  stat counter keys) are best-effort guesses marked `// TODO` — pin them to the
  real `openapi.json` and a live response. The Config tab's `JSONTreeView` shows
  the full raw document, which helps you discover the true field paths quickly.
- Stats tab lists the latest sample's numeric counters; wire a chosen counter
  into Swift Charts once the keys are known.
