diff --git a/android/PLAN.md b/android/PLAN.md index 8535a85..425a3ed 100644 --- a/android/PLAN.md +++ b/android/PLAN.md @@ -419,21 +419,29 @@ console. It is a **read + self-service** app, not an operator tool. - **Access-level menu**: one shared navigation that reveals items based on the signed-in user's role. - **Opt-in push notifications** (post-v1; architected for from the start): per-stream subscriptions the user chooses — nothing is pushed unless subscribed. See §11. +- **Staff operations subset** (post-v1, **M10** — decided 2026-07-21): a *defined* slice of the admin + surface, native, for `admin`/`moderator` staff. In scope: **moderation actions** (kick / ban / unban / + broadcast), the **support (help-page) queue** (reply / close / resolve), the **dashboard summary + + site-mode** toggle, and **content management** (news posts — list / create / edit / publish / delete — + plus wiki category & tag management). These consume the existing `/api/v1/admin/**` routes (which + already accept bearer auth and re-check role every request); no backend routes are added. See §6.4 + §10. ### Explicitly OUT of scope (never in the app, for any role) -- The **hero editor** and any CMS authoring/block editing. -- The **admin / auth-management console** — user management, invites issuance, SSO provider config, - moderation console, email config, bot-activity/ban console. (Players still *log in*; what's - excluded is the management surface, not authentication itself.) -- The **Discord bot** management (and anything under the unpublished `/internal/**` port — it - returns the decrypted bot token and must never be reachable from a client). -- **Shard / uo-link administration** — sidecar base-URL/token config (`uoLinkConfig`), shard ops, - the staff shard-user console. (The app shows *public* shard widgets and a player's *own* game - data; it does not manage the sidecar.) +The exclusions are now a *narrow* list (M10 brought the operational admin subset in-scope, above). The +app still never ships: +- The **hero editor** and CMS **block/page authoring** (the visual page builder). *(News-post and + wiki category/tag management ARE in scope; the excluded piece is the CMS block editor / hero builder.)* +- **Discord bot** configuration (and anything under the unpublished `/internal/**` port — it returns the + decrypted bot token and must never be reachable from a client). +- **uo-link / sidecar administration** — the shard sidecar base-URL/token config (`uoLinkConfig`). (The + app performs *shard operations* like kick/ban/broadcast against the live shard, but never configures + the sidecar connection itself.) +- **OAuth / SSO provider setup** — creating/editing identity providers and their client secrets. -> The excluded surfaces all live under `/api/v1/admin/**` and `/api/v1/internal/**`. The app only -> ever calls `/api/v1/public/**`, `/api/v1/auth/**` (incl. the new role-agnostic self surface -> `/auth/me/*`, §6.4), and `/api/v1/player/**` — it never references `/admin`. +> The app calls `/api/v1/public/**`, `/api/v1/auth/**` (incl. the role-agnostic self surface +> `/auth/me/*`, §6.4), `/api/v1/player/**`, and — for staff, M10 — the **defined `/api/v1/admin/**` +> operations listed above. It never touches `/api/v1/internal/**`, nor the four excluded admin surfaces +> (hero/CMS block editor, Discord-bot config, uo-link config, OAuth-provider setup). --- @@ -635,11 +643,18 @@ Guidelines: Player self-service is under `/player/account/*` (gated to `role='player'`) and staff use the *same* handlers under `/admin/account/*`. Rather than have the app branch by role (and touch `/admin`), we **add a role-agnostic self surface under `/auth/**`** — the canonical "me" endpoints for every role. -The app calls these regardless of role, and never references `/admin`. This is an **additive v1** +The app calls these regardless of role. This is an **additive v1** change (see §8): the existing `/player/account/*` and `/admin/account/*` routes stay for web back-compat; `/auth/me/*` reuses the same `account.controller` handlers behind `requireAuth` (any authenticated role), so there's no logic duplication. +> **M10 update (2026-07-21):** *self-service* stays role-agnostic under `/auth/me/*` as above. Separately, +> the **operational** admin subset (§1, §10 — moderation, support queue, dashboard/site-mode, content) +> *does* call `/api/v1/admin/**` directly, gated to staff by a new `STAFF`/`ADMIN` menu access level. +> The earlier "the app never references `/admin`" rule is superseded for these defined staff operations +> only; `validateSession` accepts the mobile bearer on those routes and `requireRole` re-checks every +> request, so a demoted user loses the surface immediately (the app treats any `403` as authoritative). + --- ## 7. Degradation & offline @@ -808,6 +823,25 @@ push, and Play (M6–M8) follow the designed app. generic build stays custom-scheme; white-label/first-party builds bake one host). The custom scheme remains the permanent fallback on every build. Full spec + rollout in [`APP_LINKS.md`](./APP_LINKS.md). +11. **M10 — Native SSO fixes + staff operations** (post-v1; decided 2026-07-21). Two threads found + during on-device QA: + - **SSO discovery + reachability fixes (app-only, done):** the native login screen only rendered + provider buttons when `GET /auth/providers` was non-empty and otherwise fell back to the desktop + website login (which can't deep-link a mobile session back → it hung). `AuthRepository.ssoProviders()` + now returns `Available` / `None` / `Unavailable` (retry once); the login screen shows native + buttons / a loading hint / a retry, and the website-login fallback is removed. The pending PKCE + `{state,verifier}` is persisted (encrypted `PendingSsoStore`) so the exchange survives Custom-Tab + process death. The nav drawer is now `verticalScroll`-wrapped so a signed-in session's longer menu + (which includes **Notifications**) can't clip on short screens. Dev testing uses a **stub OAuth IdP** + (`website/scripts/dev/`), since dev configures no real provider. Verified end-to-end on an emulator. + - **Staff operations (§1, §6.4):** a new `STAFF`/`ADMIN` menu access level reveals a staff section + for `admin`/`moderator`, with native screens over the existing `/api/v1/admin/**`: **moderation** + (`POST /admin/shard/{kick,ban,unban,broadcast}`), **support queue** (`GET /admin/shard/pages`, + `POST /admin/shard/pages/:id/{respond,close}`), **dashboard + site-mode** (`GET /admin/dashboard`, + `PUT /admin/site-mode`), and **content** (news posts under `/admin/posts*`, wiki categories/tags + under `/admin/wiki/*`). No backend routes added (they already accept bearer + re-check role); + shard-write actions degrade gracefully when the sidecar is offline. Excluded: hero/CMS block + editor, Discord-bot config, uo-link config, OAuth-provider setup. ---