refactor(api): collapse /admin/account and /player/account onto /auth/me/account #166
Reference in New Issue
Block a user
No description provided.
Delete Branch "refactor/collapse-account-surfaces"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Engagement Phase 1a — design of record:
docs/website/ENGAGEMENT.mdPhase 1a (companion PR). Lands ahead of Phase 1b.Why
Self-service account security had three URL surfaces onto one controller. All three mounted the same
admin/account.controller.jshandlers, and each of the three router files carried a header comment apologising for the arrangement —player/account.router.js:8: "Three URL surfaces, one implementation; this file must not grow a fourth copy of the logic."Phase 1b adds a self-service field (email), Phase 3 adds another (channel preferences). Each would otherwise be written three times.
Which one to keep
/auth/me/accountwas already a strict superset — that settled it:/admin/accountnoindex, isLoggedIn, staffOnly/player/accountnoindex, requireAuth/auth/me/accountnoindex, requireAuthThe split was already leaking. Recovery codes exist only on
/auth/me, soclient.jscalled/auth/me/account/recovery-codes/*for two operations on a screen it otherwise served from/admin/account— in the same file. We are not collapsing three equal surfaces; we are deleting two partial ones.Gating is equivalent where it overlapped:
/playerand/auth/meapply byte-identicalnoindex, requireAuth, andstaffOnlyon/admin/accountwas strictly narrower while buying nothing, since every handler is self-scoped toreq.user.id. There is no CSRF layer to differ.What changed
account.controller.jsmovedrouter/v1/admin/→router/v1/auth/, beside the one router that still reaches it.api.myAccount/api.changeUsername/ … group, matching the/auth/memethods already sitting there.MeApi.ktwas already 100%/auth/me/account/*.Admin · AccountandPlayerwere declared only by the deleted routes and go with them. The orphanedAccountStatusschema goes too;PlayerAccountis re-described as the any-role/auth/me/accountshape (name kept so existing$refs resolve).Breaking change, accepted deliberately
This removes 14 paths from the published OpenAPI surface. Both consumers are in this org. Deprecate-then-delete was considered and rejected: it would leave Phase 1b deciding whether to add its email routes to surfaces already marked for removal.
Verification
routes.manifest.json: exactly 14 deletions, 0 additions.componentsotherwise untouched. Its large textual diff is pure reordering — removing the first-mounted router shifts every later path. Verified by set-comparison against the committed spec, not by reading the diff.check:modules,check:hosts,routes:manifest --checkall pass.Reviewer notes
/admin/accountand/accountas browser paths are untouched — the SPA pages still live there. Only the API paths moved.Admin · Modules,Admin · Teams,Player · Teams,Public · Teams) are used by routes but never declared. Unrelated drift.AI disclosure
Written with Claude Code (Opus 5).
Self-service account security had three URL surfaces onto one controller. All three mounted the same `admin/account.controller.js` handlers; each of the three router files carried a header comment apologising for the arrangement. `/auth/me/account` was already a strict superset, which settles which to keep: /admin/account 6 routes noindex, isLoggedIn, staffOnly /player/account 8 routes noindex, requireAuth /auth/me/account 10 routes noindex, requireAuth Neither of the deleted surfaces carried recovery codes, and /admin/account carried no username or password change at all — so client.js already called /auth/me/account/recovery-codes/* for two operations on a screen it otherwise served from /admin/account. The split was leaking before this change. Gating is equivalent where it overlapped: /player and /auth/me apply identical `noindex, requireAuth`, and `staffOnly` on /admin/account was strictly narrower while buying nothing, since every handler is self-scoped to req.user.id. There is no CSRF layer to differ. - 14 routes deleted, 0 added, no handler changed. - account.controller.js moves router/v1/admin/ -> router/v1/auth/, beside the one router that still reaches it. - Web client: 14 call sites move onto a root-level api.myAccount / api.changeUsername / ... group, matching the /auth/me methods already there. - Android app: no change. MeApi.kt was already 100% /auth/me/account/*. - Two swagger tags, `Admin · Account` and `Player`, were declared only by the deleted routes and go with them. The orphaned `AccountStatus` schema goes too; `PlayerAccount` is re-described as the any-role /auth/me/account shape (the name is kept so existing $refs resolve). Breaking to the published OpenAPI surface, accepted deliberately: both consumers are in this org, and deprecate-then-delete would leave the next phase deciding whether to add routes to surfaces already marked for removal. Verification: routes.manifest.json shows exactly 14 deletions and 0 additions. The OpenAPI spec loses the same 14 paths with zero surviving path definitions changed; its large textual diff is pure reordering, because removing the first-mounted router shifts every later path. 1203 server tests, 288 client tests, 53 bot tests green; check:modules, check:hosts and routes:manifest --check all pass. Design of record: docs/website/ENGAGEMENT.md Phase 1a. This lands ahead of engagement Phase 1b, which adds a self-service email field — written once here rather than three times. Co-Authored-By: Claude <noreply@anthropic.com>