From eda817e6f3a9bbbe477137ef175f834b719f6be0 Mon Sep 17 00:00:00 2001 From: wtclaude Date: Sun, 19 Jul 2026 17:11:15 -0500 Subject: [PATCH] docs(android): record M1 (connect & browse) landed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mark M0+M1 done in the build-progress header and next up M2. Summarize the M1 functional pass (first-run connect, runtime base URL + host interceptor, layered ApiResult stack, brand-seeded theming, public content/wiki/pages/contact screens) and record the deliberate hand-written-vs-openapi-generated API-client deviation from §2 and its rationale (swagger-autogen schemas are meta-descriptive, not codegen-clean). Tracks RunicGateway/Android-app#6. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01NgyHnrNa8WwG3doxvxjuCr --- android/PLAN.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/android/PLAN.md b/android/PLAN.md index 12a1a02..b4bca89 100644 --- a/android/PLAN.md +++ b/android/PLAN.md @@ -1,6 +1,6 @@ # 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 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 @@ -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, `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` → -`./gradlew lint test assembleDebug`). **M1–M4 (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. + +**M2–M4 (functional pass) and M5 (design pass) remain.** **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), -- 2.49.1