docs(android): add design-pass workflow to app PLAN #7
@@ -82,6 +82,17 @@ runs `openapi-generator` against the committed spec. Endpoints that return
|
|||||||
service (Retrofit) → DTO`. Repositories expose `Result`-like sealed types so the UI degrades
|
service (Retrofit) → DTO`. Repositories expose `Result`-like sealed types so the UI degrades
|
||||||
gracefully (see §7).
|
gracefully (see §7).
|
||||||
|
|
||||||
|
### 2.1 Build workflow: Kotlin first, then design-led UI
|
||||||
|
The app is built in two passes. **First**, the functional Kotlin is written — the layering above with
|
||||||
|
placeholder/functional Compose screens: navigation, ViewModels, repositories, the generated API
|
||||||
|
client, auth/token handling, and every screen wired to its endpoints and working end-to-end. **Then**,
|
||||||
|
once that Kotlin code is done, **Claude Design produces the front-end design** for the app, and
|
||||||
|
**Claude Code implements the final UI (Compose screens, theming, components) according to that
|
||||||
|
design.** The design pass restyles and refines the already-working screens; it does not change the
|
||||||
|
architecture, data flow, or endpoint contracts established in the first pass. Keeping strings
|
||||||
|
externalized and branding data-driven (§2, §3) from the start is what lets the design pass reskin
|
||||||
|
freely without touching logic.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Base URL: first-run + settings
|
## 3. Base URL: first-run + settings
|
||||||
@@ -294,7 +305,7 @@ maintenance cost. Reserve v2 for a real breaking re-shape if one ever arises.
|
|||||||
stay website-handled and the app hands off to them (§4.2). This is a deliberate scope reduction.
|
stay website-handled and the app hands off to them (§4.2). This is a deliberate scope reduction.
|
||||||
3. **Push notifications** — see §11. Additive v1 endpoints under `/auth/me/devices*` and
|
3. **Push notifications** — see §11. Additive v1 endpoints under `/auth/me/devices*` and
|
||||||
`/auth/me/notifications*`, plus a **self-hosted `ntfy` service added to `website/docker-compose.yml`**
|
`/auth/me/notifications*`, plus a **self-hosted `ntfy` service added to `website/docker-compose.yml`**
|
||||||
with fully declarative, zero-interaction config. Not required for the first release (M6, not M1–M5).
|
with fully declarative, zero-interaction config. Not required for the first release (M7, not M1–M6).
|
||||||
4. **Version/health surfacing** — ensure `/public/status` (or a light `/public/version`) exposes
|
4. **Version/health surfacing** — ensure `/public/status` (or a light `/public/version`) exposes
|
||||||
enough for the app's first-run probe and version-mismatch guard.
|
enough for the app's first-run probe and version-mismatch guard.
|
||||||
5. **Docs** — update `docs/website/BACKEND_DESIGN.md` for any new/changed endpoint; keep this file and
|
5. **Docs** — update `docs/website/BACKEND_DESIGN.md` for any new/changed endpoint; keep this file and
|
||||||
@@ -309,25 +320,41 @@ No `link/` or `servuo-plugins/` changes are expected — the app is downstream o
|
|||||||
|
|
||||||
## 9. Milestones
|
## 9. Milestones
|
||||||
|
|
||||||
|
**Two passes (§2.1).** M0–M4 are the **functional Kotlin pass** — every screen wired to its endpoints
|
||||||
|
and working end-to-end with placeholder/functional Compose UI, no design investment yet. **M5 is the
|
||||||
|
design pass**: once the functional Kotlin is done, Claude Design produces the front-end design and
|
||||||
|
Claude Code implements the final UI to it. Polish/release, push, and Play (M6–M8) follow the designed
|
||||||
|
app.
|
||||||
|
|
||||||
1. **M0 — Repo scaffold**: Gradle + Compose + Hilt skeleton, CI (build + lint + unit test), license
|
1. **M0 — Repo scaffold**: Gradle + Compose + Hilt skeleton, CI (build + lint + unit test), license
|
||||||
headers (GPL-3.0-or-later), CONTRIBUTING/AI-disclosure parity with the other repos.
|
headers (GPL-3.0-or-later), CONTRIBUTING/AI-disclosure parity with the other repos.
|
||||||
2. **M1 — Connect & browse**: first-run base-URL flow, `/public/status`+`/public/settings` theming,
|
2. **M1 — Connect & browse** *(functional pass)*: first-run base-URL flow,
|
||||||
generated API client, public content (news/wiki/pages) + contact. No auth yet.
|
`/public/status`+`/public/settings` theming, generated API client, public content
|
||||||
3. **M2 — Public shard**: shard widgets + SSE live stream with reconnect/degradation.
|
(news/wiki/pages) + contact. No auth yet.
|
||||||
4. **M3 — Auth (§4)**: native password+TOTP login (429 handling), token storage, refresh interceptor,
|
3. **M2 — Public shard** *(functional pass)*: shard widgets + SSE live stream with
|
||||||
logout, `/auth/me` role re-validation, the access-level menu. Custom-Tab **hand-offs** to the website
|
reconnect/degradation.
|
||||||
for register / invite / password-reset / SSO (no native screens for those). Optional biometric
|
4. **M3 — Auth (§4)** *(functional pass)*: native password+TOTP login (429 handling), token storage,
|
||||||
app-lock. *Prerequisite:* the website password-reset flow (§8) is already built.
|
refresh interceptor, logout, `/auth/me` role re-validation, the access-level menu. Custom-Tab
|
||||||
5. **M4 — Player self-service & game data**: account management (via `/auth/me/*`), game-account
|
**hand-offs** to the website for register / invite / password-reset / SSO (no native screens for
|
||||||
linking, own roster/characters/vendors/houses/sales — **text-only** presentation (§6.3).
|
those). Optional biometric app-lock. *Prerequisite:* the website password-reset flow (§8) is
|
||||||
6. **M5 — Polish & first release**: settings (server switch = hard reset), version-mismatch guard,
|
already built.
|
||||||
|
5. **M4 — Player self-service & game data** *(functional pass)*: account management (via
|
||||||
|
`/auth/me/*`), game-account linking, own roster/characters/vendors/houses/sales — **text-only**
|
||||||
|
presentation (§6.3).
|
||||||
|
6. **M5 — Design pass & final UI (§2.1)**: with the functional Kotlin from M1–M4 working end-to-end,
|
||||||
|
**Claude Design produces the front-end design** for the app, then **Claude Code implements the final
|
||||||
|
UI to it** — Compose screens, Material 3 theming from the per-shard branding (§3), reusable
|
||||||
|
components, loading/error/empty states, the designed access-level menu. Restyles the existing
|
||||||
|
screens only; no changes to architecture, data flow, or endpoint contracts. Text-only game data
|
||||||
|
(§6.3) still holds — this is visual design of the data screens, not paperdoll art.
|
||||||
|
7. **M6 — Polish & first release**: settings (server switch = hard reset), version-mismatch guard,
|
||||||
release build hardening (HTTPS-only, no token logging). No offline cache in v1 (§7). **Ship v1 as a
|
release build hardening (HTTPS-only, no token logging). No offline cache in v1 (§7). **Ship v1 as a
|
||||||
signed APK attached to a Gitea release** (see §10).
|
signed APK attached to a Gitea release** (see §10).
|
||||||
7. **M6 — Push notifications** (post-v1): add the self-hosted `ntfy` service to
|
8. **M7 — Push notifications** (post-v1): add the self-hosted `ntfy` service to
|
||||||
`website/docker-compose.yml` (declarative, zero-interaction config), UnifiedPush integration in the
|
`website/docker-compose.yml` (declarative, zero-interaction config), UnifiedPush integration in the
|
||||||
app, device registration, the subscriptions UI, and the content-free-tickle backend fan-out (see
|
app, device registration, the subscriptions UI, and the content-free-tickle backend fan-out (see
|
||||||
§11). The app is built with room for this from M0 but it does not gate the first release.
|
§11). The app is built with room for this from M0 but it does not gate the first release.
|
||||||
8. **M7 — Google Play**: Play Console listing, signing/upload key, and (optionally) an FCM build flavor
|
9. **M8 — Google Play**: Play Console listing, signing/upload key, and (optionally) an FCM build flavor
|
||||||
— after the direct-APK release is stable.
|
— after the direct-APK release is stable.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -344,7 +371,7 @@ No `link/` or `servuo-plugins/` changes are expected — the app is downstream o
|
|||||||
|
|
||||||
## 11. Push notifications (built-for, shipped post-v1)
|
## 11. Push notifications (built-for, shipped post-v1)
|
||||||
|
|
||||||
The app is architected from M0 to accommodate push, but push itself ships in M6 — it does not block the
|
The app is architected from M0 to accommodate push, but push itself ships in M7 — it does not block the
|
||||||
first release. Users **opt in per stream**: nothing is pushed unless subscribed.
|
first release. Users **opt in per stream**: nothing is pushed unless subscribed.
|
||||||
|
|
||||||
### Transport — UnifiedPush via self-hosted ntfy (decided)
|
### Transport — UnifiedPush via self-hosted ntfy (decided)
|
||||||
@@ -422,7 +449,7 @@ repos use), on a bare `ubuntu:latest` container.
|
|||||||
frequent: run the job under a prebuilt Android-SDK `container:` image so nothing installs per-run.)
|
frequent: run the job under a prebuilt Android-SDK `container:` image so nothing installs per-run.)
|
||||||
- **PR gate** (`.gitea/workflows/pr-checks.yml`, on PR → `main`): `./gradlew lint test assembleDebug`.
|
- **PR gate** (`.gitea/workflows/pr-checks.yml`, on PR → `main`): `./gradlew lint test assembleDebug`.
|
||||||
Debug builds are auto-signed, so the gate needs no secrets. Mirrors `website/`'s pre-merge gate.
|
Debug builds are auto-signed, so the gate needs no secrets. Mirrors `website/`'s pre-merge gate.
|
||||||
- **Release** (`.gitea/workflows/release.yml`, M5+): build a **signed release APK** and attach it to a
|
- **Release** (`.gitea/workflows/release.yml`, M6+): build a **signed release APK** and attach it to a
|
||||||
Gitea release (mirrors `link/`'s release job). The **keystore is a base64 Gitea Actions secret**
|
Gitea release (mirrors `link/`'s release job). The **keystore is a base64 Gitea Actions secret**
|
||||||
decoded in CI; store/key passwords are secrets. The keystore never lives in the repo. Keep the
|
decoded in CI; store/key passwords are secrets. The keystore never lives in the repo. Keep the
|
||||||
signing identity stable from the first release (Play later requires consistency).
|
signing identity stable from the first release (Play later requires consistency).
|
||||||
@@ -445,7 +472,7 @@ ntfy / UnifiedPush (§11).
|
|||||||
own verified app links — confirm whether any deep-link-back is wanted at all for v1.
|
own verified app links — confirm whether any deep-link-back is wanted at all for v1.
|
||||||
- ntfy: exact upstream image + pinned tag, its reverse-proxy hostname/path, and whether to add a
|
- ntfy: exact upstream image + pinned tag, its reverse-proxy hostname/path, and whether to add a
|
||||||
backend publish token (optional hardening — the content-free-tickle design does not require one).
|
backend publish token (optional hardening — the content-free-tickle design does not require one).
|
||||||
- FCM flavor: build it for the Play release or ship Play on UnifiedPush too? Decide at M7.
|
- FCM flavor: build it for the Play release or ship Play on UnifiedPush too? Decide at M8.
|
||||||
- Deep-link / share targets for wiki pages, posts, and notification taps.
|
- Deep-link / share targets for wiki pages, posts, and notification taps.
|
||||||
- iOS: none planned (this is the Android-only choice); revisit only if cross-platform is later
|
- iOS: none planned (this is the Android-only choice); revisit only if cross-platform is later
|
||||||
required (would change §2 — and push, which would then favor a cross-platform transport).
|
required (would change §2 — and push, which would then favor a cross-platform transport).
|
||||||
|
|||||||
Reference in New Issue
Block a user