Merge pull request 'docs(android): record M1 (connect & browse) landed' (#13) from docs/android-m1-progress into main

Reviewed-on: #13
Reviewed-by: Colby Whitlock <whitlocktech@gmail.com>
This commit is contained in:
2026-07-19 22:12:43 +00:00

View File

@@ -1,6 +1,6 @@
# Android App — Plan # Android App — Plan
Status: **M0 repo scaffold landed; M1 (functional Kotlin pass) next.** This document is the Status: **M0 + M1 landed; M2 (public shard + SSE) next.** This document is the
design contract for the `RunicGateway/Android-app` repo. It was written before implementation so the design contract for the `RunicGateway/Android-app` repo. It was written before implementation so the
API changes it depends on could be landed in `website/` and `docs/` first. The authoritative API API changes it depends on could be landed in `website/` and `docs/` first. The authoritative API
reference is the committed OpenAPI spec at `website/server/swagger/swagger-output.json` (regenerated reference is the committed OpenAPI spec at `website/server/swagger/swagger-output.json` (regenerated
@@ -10,7 +10,30 @@ via `npm run swagger`).
Gradle 8.7 wrapper + AGP 8.6.1 / Kotlin 2.0.20, JDK 17, minSdk 29 / compile-target 35, Gradle 8.7 wrapper + AGP 8.6.1 / Kotlin 2.0.20, JDK 17, minSdk 29 / compile-target 35,
`applicationId com.runicgateway.app`; a version catalog pinning the full §2 stack; a Compose + Hilt `applicationId com.runicgateway.app`; a version catalog pinning the full §2 stack; a Compose + Hilt
single-activity skeleton (externalized strings, adaptive icon); and CI (`pr-checks.yml` single-activity skeleton (externalized strings, adaptive icon); and CI (`pr-checks.yml`
`./gradlew lint test assembleDebug`). **M1M4 (functional pass) and M5 (design pass) remain.** `./gradlew lint test assembleDebug`).
**M1 — connect & browse** (2026-07-19, `RunicGateway/Android-app#6`, functional Kotlin pass): the
first-run base-URL connect flow (probe `GET /public/status`, verify the backend's version identity,
persist to DataStore; HTTPS-only in release, HTTP allowed in debug; Settings → Server hard reset);
a runtime-selected base URL via a sentinel-host Retrofit + `HostSelectionInterceptor` (the host is
**not** compiled in) plus a `UserAgentInterceptor` past the scanner guard (§8); the layered
`screen → ViewModel → repository → PublicApi → DTO` stack returning a typed `ApiResult`
(`Ok`/`HttpError`/`NetworkError`) for graceful degradation (§7); brand-seeded Material 3 theming from
`/public/settings`; and functional Compose screens for Home/Status, News (+ post detail), Wiki
(+ detail), CMS pages (block renderer: `heading/rich_text/image/quote/cta/divider/two_column`), and
the contact form, under one declarative navigation drawer (§5). JVM unit tests cover URL
normalization, host rewriting, `ApiResult`/`UiState` mapping, and brand-color parsing.
> **API-client deviation from §2 (recorded):** DTOs + the Retrofit interface are **hand-written and
> spec-aligned**, not `openapi-generator` output. The committed `swagger-output.json` is produced by
> **swagger-autogen**, whose component schemas are meta-descriptive (nested `{type, example}`
> wrappers) rather than codegen-clean OpenAPI models, so a generator would emit unusable DTOs. The
> hand-authored client is the "checked-in generated module" §2 already allows; shapes were matched
> against the website controllers/models and every DTO ignores unknown keys (additive fields are
> safe). True codegen would first require authoring the spec's component schemas as real OpenAPI
> models.
**M2M4 (functional pass) and M5 (design pass) remain.**
**Prerequisite progress (§8):** all v1 prerequisites are **done** (2026-07-19) — ✅ password reset **Prerequisite progress (§8):** all v1 prerequisites are **done** (2026-07-19) — ✅ password reset
(item 2; website#75 + docs#8), ✅ role-agnostic `/auth/me/*` self surface (item 1; website#76 + docs#10), (item 2; website#75 + docs#8), ✅ role-agnostic `/auth/me/*` self surface (item 1; website#76 + docs#10),