refactor(api): collapse /admin/account and /player/account onto /auth/me/account
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>
This commit is contained in:
@@ -8,7 +8,7 @@ process.env.DB_PORT = '59999'
|
||||
const { test, beforeEach, after } = require('node:test')
|
||||
const assert = require('node:assert/strict')
|
||||
|
||||
const account = require('../src/router/v1/admin/account.controller')
|
||||
const account = require('../src/router/v1/auth/account.controller')
|
||||
const mobileSessions = require('../src/model/mobileSessions/mobileSessions.model')
|
||||
const activity = require('../src/model/activity/activity.model')
|
||||
const db = require('../src/utils/db')
|
||||
|
||||
@@ -518,8 +518,8 @@ test('ctx exposes exactly the documented surface, and is frozen', () => {
|
||||
// is core's limiter FACTORY, not a limiter: a module states its own
|
||||
// window and cap and takes the plumbing, so there is one express-rate-limit in
|
||||
// the process and one place a breach is logged. is
|
||||
// handed over whole because it is shared policy — core's /auth/me and
|
||||
// /player/account sit behind the same counter.
|
||||
// handed over whole because it is shared policy — core's /auth/me/account/*
|
||||
// and /player/appeals sit behind the same counter.
|
||||
assert.deepEqual(probe.middleware, [
|
||||
'accountChangeLimiter', 'noindex', 'rateLimit', 'requireAuth', 'requireRole', 'siteMode', 'validate',
|
||||
])
|
||||
|
||||
@@ -8,7 +8,7 @@ const assert = require('node:assert/strict')
|
||||
const bcrypt = require('bcryptjs')
|
||||
|
||||
const authCtrl = require('../src/router/v1/auth/auth.controller')
|
||||
const account = require('../src/router/v1/admin/account.controller')
|
||||
const account = require('../src/router/v1/auth/account.controller')
|
||||
const users = require('../src/model/users/users.model')
|
||||
const settings = require('../src/model/settings/settings.model')
|
||||
const botScore = require('../src/middleware/botScore')
|
||||
|
||||
@@ -13,7 +13,7 @@ const assert = require('node:assert/strict')
|
||||
// - trusting the current device is ownership-scoped and honors the cap (409);
|
||||
// - self-revoke is scoped to the caller's own id;
|
||||
// - regenerating recovery codes is a password step-up (wrong password → 400).
|
||||
const ctrl = require('../src/router/v1/admin/account.controller')
|
||||
const ctrl = require('../src/router/v1/auth/account.controller')
|
||||
const users = require('../src/model/users/users.model')
|
||||
const activity = require('../src/model/activity/activity.model')
|
||||
const sessionService = require('../src/auth/session.service')
|
||||
|
||||
Reference in New Issue
Block a user