feat(m2): public shard widgets + live SSE stream #7

Merged
whitlocktech merged 1 commits from feat/m2-public-shard into main 2026-07-19 23:44:39 +00:00
Member

M2 — Public shard (functional pass)

Implements M2 of docs/android/PLAN.md §6.2: the public shard widgets over /api/v1/public/shard/*, plus the live SSE stream with reconnect/backoff and graceful degradation (§7). Functional Kotlin pass only — placeholder Compose UI; the design pass is M5.

What's in it

  • Shard DTOs (ShardDto.kt) mirroring public/shard.controller.js: status / economy / feed / online / presence / champs / guilds / governors (+ history) / houses. ignoreUnknownKeys keeps additive backend fields safe, and the live *.update frames decode into the same board DTOs.
  • PublicApi: the /public/shard/* GETs.
  • ShardStreamClient: OkHttp SSE over /public/shard/stream. Unlike the browser EventSource it reconnects itself — a cold Flow<ShardStreamEvent> with growing backoff (reset on open), no read timeout for the idle keepalive, and clean teardown on cancel, so a dropped feed degrades to "offline" rather than crashing.
  • ShardRepository: typed ApiResult snapshot reads + the shared live feed and frame decoders.
  • Screens: a Shard hub (status / online count / economy / presence / staff + a live activity feed with a live/offline indicator) linking to live boards for champion spawns, guilds, governors (with on-demand term history) and falling houses (IDOC). Boards seed from a snapshot then merge SSE deltas in place via a reusable LiveBoard, mirroring the website's merge semantics. Wired into the shared navigation drawer (§5); all strings externalized (§2).
  • The app never touches the sidecar//admin — only the public shard reads and the public SSE channel (safe kinds only).

Tests (28, all green)

DTO + live-frame decode, LiveBoard merge, event-text formatting (parity with lib/shardEvents.js), and SSE frame parsing.

Verification

./gradlew lint test assembleDebug passes locally.

Local-build note: on a JDK 21 host, KSP's incremental storage crashes (PersistentMapImpl); building with -Pksp.incremental=false is the workaround. CI runs JDK 17 and is unaffected, so no committed config change.


AI-assisted: authored with Claude Code (Opus). AI-authored commit carries a Co-Authored-By: Claude trailer per org policy.

🤖 Generated with Claude Code

## M2 — Public shard (functional pass) Implements **M2** of `docs/android/PLAN.md` §6.2: the public shard widgets over `/api/v1/public/shard/*`, plus the live **SSE** stream with reconnect/backoff and graceful degradation (§7). Functional Kotlin pass only — placeholder Compose UI; the design pass is M5. ### What's in it - **Shard DTOs** (`ShardDto.kt`) mirroring `public/shard.controller.js`: status / economy / feed / online / presence / champs / guilds / governors (+ history) / houses. `ignoreUnknownKeys` keeps additive backend fields safe, and the live `*.update` frames decode into the same board DTOs. - **`PublicApi`**: the `/public/shard/*` GETs. - **`ShardStreamClient`**: OkHttp SSE over `/public/shard/stream`. Unlike the browser `EventSource` it **reconnects itself** — a cold `Flow<ShardStreamEvent>` with growing backoff (reset on open), no read timeout for the idle keepalive, and clean teardown on cancel, so a dropped feed degrades to "offline" rather than crashing. - **`ShardRepository`**: typed `ApiResult` snapshot reads + the shared live feed and frame decoders. - **Screens**: a **Shard hub** (status / online count / economy / presence / staff + a live activity feed with a live/offline indicator) linking to live boards for **champion spawns**, **guilds**, **governors** (with on-demand term history) and **falling houses** (IDOC). Boards seed from a snapshot then merge SSE deltas in place via a reusable `LiveBoard`, mirroring the website's merge semantics. Wired into the shared navigation drawer (§5); all strings externalized (§2). - The app never touches the sidecar/`/admin` — only the public shard reads and the public SSE channel (safe kinds only). ### Tests (28, all green) DTO + live-frame decode, `LiveBoard` merge, event-text formatting (parity with `lib/shardEvents.js`), and SSE frame parsing. ### Verification `./gradlew lint test assembleDebug` passes locally. > Local-build note: on a JDK 21 host, KSP's incremental storage crashes (`PersistentMapImpl`); building with `-Pksp.incremental=false` is the workaround. CI runs JDK 17 and is unaffected, so no committed config change. --- **AI-assisted:** authored with **Claude Code** (Opus). AI-authored commit carries a `Co-Authored-By: Claude` trailer per org policy. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
wtclaude added 1 commit 2026-07-19 23:35:05 +00:00
feat(m2): public shard widgets + live SSE stream
All checks were successful
PR Checks / android-build (pull_request) Successful in 9m4s
c8f4e76370
Implements M2 of docs/android/PLAN.md §6.2 (functional pass): the public
shard surface over /api/v1/public/shard/*, plus the live SSE feed with
reconnect/backoff and graceful degradation (§7).

- Shard DTOs (status/economy/feed/online/presence/champs/guilds/governors/
  houses) mirroring public/shard.controller.js; ignoreUnknownKeys keeps
  additive backend fields safe, and the live *.update frames decode into the
  same board DTOs.
- PublicApi: the /public/shard/* GETs (status, feed, economy, online,
  presence, champs, guilds, governors + history, houses).
- ShardStreamClient: OkHttp SSE over /public/shard/stream. Unlike the browser
  EventSource it reconnects itself — a cold Flow<ShardStreamEvent> with
  growing backoff (reset on open), no read timeout for the idle keepalive,
  and clean teardown on cancel so a dropped feed degrades to "offline".
- ShardRepository: typed ApiResult snapshot reads + the shared live feed and
  frame decoders.
- Screens: a Shard hub (status/online count/economy/presence/staff + live
  activity feed with a live indicator) linking to live boards for champion
  spawns, guilds, governors (+ on-demand term history) and falling houses
  (IDOC). Boards seed from a snapshot then merge SSE deltas in place via a
  reusable LiveBoard, mirroring the website's merge semantics. Wired into the
  shared navigation drawer (§5); all strings externalized (§2).
- Tests (28): DTO/frame decode, LiveBoard merge, event-text formatting, and
  SSE frame parsing.

Co-Authored-By: Claude <noreply@anthropic.com>
whitlocktech approved these changes 2026-07-19 23:38:10 +00:00
whitlocktech scheduled this pull request to auto merge when all checks succeed 2026-07-19 23:38:17 +00:00
whitlocktech merged commit 199df6cd64 into main 2026-07-19 23:44:39 +00:00
whitlocktech deleted branch feat/m2-public-shard 2026-07-19 23:44:40 +00:00
Sign in to join this conversation.
No description provided.