// /api/v1/player โ€” the player self-service surface, assembled from // per-capability routers. // // This file owns exactly two things: the gate every player route shares, and the // mount table. No route is declared here. Each capability router mounts at the // prefix it already owned inside the old monolithic player.routes.js, so the // emitted URL set is byte-identical โ€” proved by a zero-line diff in // server/routes.manifest.json (`npm run routes:manifest`). // // **Staff are a superset of players.** This group is open to any authenticated // account, not just role 'player': every read/write is self-scoped to req.user.id, // and a staff member has every player ability plus their staff tools on top. // Adding a requireRole('player') here would 403 an admin off their own characters // (it happened once โ€” see docs/website/BACKEND_DESIGN.md). Staff also reach the // identical self-scoped handlers under /admin/shard and /auth/me/account; those // are alternative URLs onto the same controllers, not duplicated logic. // // See docs/website/API_V2_PLAN.md ยง Phase 2 for the split. const express = require('express') const { requireAuth } = require('../../../auth/session.middleware') const noindex = require('../../../middleware/noindex') const accountRouter = require('./account.router') const shardRouter = require('./shard.router') const appealsRouter = require('./appeals.router') const playerRouter = express.Router() // Group gate: authenticated only (no role restriction). Keep it out of search // indexes. requireAuth also enforces the account status check (a disabled/banned // account is rejected here with 403 before any handler runs). // // It lives here, ahead of every mount, so a capability router added later cannot // silently ship without it. playerRouter.use(noindex, requireAuth) playerRouter.use('/account', accountRouter) playerRouter.use('/shard', shardRouter) playerRouter.use('/appeals', appealsRouter) module.exports = playerRouter