Files
website/server/routes.guards.json
wtclaude b13ffd584f
All checks were successful
PR Checks / client-build (pull_request) Successful in 27s
PR Checks / bot-tests (pull_request) Successful in 25s
PR Checks / server-tests (pull_request) Successful in 10m29s
feat(notifications): per-channel preferences and the delivery-channel registry (engagement Phase 3)
`notification_subscriptions` answers one question — which streams a user wants
PUSHED — because that is the only question the shipped Android client can ask.
This adds the general one: which subscribable ids, on which channel, in which
mode. The old table becomes the push projection of the new one and keeps its
exact wire shape, so the shipped APK needs no update and no delivery path is
touched.

What lands:

- `engagement/channels.js` — `registerDeliveryChannel` (ENGAGEMENT.md §3.1), the
  declarative half only: id, label, `carriesContent`, `defaultMode`,
  `supportsDigest`. `addressFor`/`render`/`deliver` wait for Phases 6 and 7, for
  the reason `transports/index.js` deferred this file at all. `coreChannels.js`
  declares push / email / inapp through the subsystem's one door.
- `notification_channel_prefs` + a replay-safe `INSERT IGNORE … SELECT` backfill,
  copying the `announce_jobs → announce_job_legs` precedent.
- `GET · PUT /auth/me/notifications/channels`. The PUT is SPARSE — only the
  `(id, channel)` pairs named are written — deliberately unlike the two whole-set
  PUTs beside it. `off` is a mode rather than an omission, so this endpoint has
  no empty-array case and the kotlinx DTO gotcha cannot arise here.

Three decisions the org lead settled before any code, and one corrects the
phase's own acceptance criterion: push's `defaultMode` is `off`, not `instant`.
The plan borrowed "push is opt-OUT" from `team_notification_prefs`, where no row
does mean notified — but stream subscriptions have never worked that way, so
`instant` would have projected the whole catalog into the legacy GET for every
existing user and switched every toggle on in the shipped app after an upgrade
nobody asked for. A test pins the legacy GET at `{streams:[]}` for a fresh user.

One thing not named by the phase, and it is a G24 consequence rather than scope
creep: a trigger ceilinged at `staff` can never reach a non-staff user, so
offering the toggle would be offering a dead control AND disclosing the event
exists — `uo.cheat.detected` would otherwise appear in every player's screen the
moment Phase 11 declared it. Filtered from the catalog and gated on write. That
gave the `staff` label its first consumer, now written down as
`ceilings.STAFF_CEILING_ROLES` (the admin tier's three, deliberately not
`teamGrants.STAFF_ROLES`, which answers a different question).

15 new tests; swagger, route manifest and guards regenerated. No web or app
surface — those are Phases 7 and 8, where a preference governs something visible.

Refs: docs/website/ENGAGEMENT.md Phase 3, §3.1, §4.5

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-29 07:08:17 -05:00

2083 lines
40 KiB
JSON

{
"$comment": "Generated review aid, NOT a gated contract - per route, the middleware handler count and the *named* middleware collected along the mount chain. Anonymous handlers (e.g. the arrow returned by requireRole(...)) cannot be named, so this is a hint for reviewers, never a security check. Regenerate with `npm run routes:manifest`.",
"public": [
{
"method": "GET",
"path": "/.well-known/assetlinks.json",
"handlers": 1,
"gates": []
},
{
"method": "POST",
"path": "/api/csp-report",
"handlers": 6,
"gates": [
"jsonParser"
]
},
{
"method": "GET",
"path": "/api/docs.json",
"handlers": 1,
"gates": []
},
{
"method": "GET",
"path": "/api/health",
"handlers": 1,
"gates": []
},
{
"method": "GET",
"path": "/api/v1/admin/activity",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/admin/auth/providers",
"handlers": 2,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/admin/auth/providers",
"handlers": 14,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/admin/auth/providers/:id",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "PUT",
"path": "/api/v1/admin/auth/providers/:id",
"handlers": 13,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/bot-activity",
"handlers": 2,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/admin/bot-activity/unban",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/dashboard",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/admin/discord-bot/config",
"handlers": 2,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "PUT",
"path": "/api/v1/admin/discord-bot/config",
"handlers": 6,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/email/config",
"handlers": 2,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "PUT",
"path": "/api/v1/admin/email/config",
"handlers": 9,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/email/disconnect",
"handlers": 2,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/admin/email/test",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/engagement/audiences",
"handlers": 2,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/admin/engagement/triggers",
"handlers": 2,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/admin/invites",
"handlers": 2,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/admin/invites",
"handlers": 5,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/admin/invites/:id",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/moderation/appeals",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/admin/moderation/appeals/:id",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/moderation/appeals/:id/claim",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/moderation/appeals/:id/resolve",
"handlers": 5,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/moderation/filter-hits",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/admin/moderation/members",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/admin/moderation/recent",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/admin/moderation/reports",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/admin/moderation/reports/:id/handle",
"handlers": 5,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/moderation/search",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/admin/moderation/spam-hits",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/admin/moderation/stats/summary",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/admin/moderation/user/:discordId",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/moderation/user/:discordId/actions",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/moderation/user/:discordId/appeals",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/moderation/user/:discordId/notes",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/moderation/user/:discordId/notes",
"handlers": 5,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/modules",
"handlers": 2,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/admin/modules",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/admin/modules/:id",
"handlers": 5,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/modules/:id/disable",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/modules/:id/enable",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/modules/:id/purge",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/modules/restart",
"handlers": 2,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "PUT",
"path": "/api/v1/admin/modules/sources",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/pages",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/admin/pages",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/admin/pages/:id",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/pages/:id",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "PATCH",
"path": "/api/v1/admin/pages/:id",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/pages/:id/preview",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/pages/:id/unprotect",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/posts",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/admin/posts",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/admin/posts/:id",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/posts/:id",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "PUT",
"path": "/api/v1/admin/posts/:id",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/posts/:id/announce",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/posts/:id/announce/retry",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "PATCH",
"path": "/api/v1/admin/posts/:id/publish",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/posts/upload",
"handlers": 2,
"gates": [
"noindex",
"requireAuth",
"multerMiddleware"
]
},
{
"method": "GET",
"path": "/api/v1/admin/settings",
"handlers": 2,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "PUT",
"path": "/api/v1/admin/settings",
"handlers": 2,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "DELETE",
"path": "/api/v1/admin/settings/:key",
"handlers": 2,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/admin/settings/brand-asset/:slot",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"multerMiddleware"
]
},
{
"method": "PUT",
"path": "/api/v1/admin/site-mode",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/teams",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/teams/:id",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/teams/:id/archive",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/teams/:id/display-name",
"handlers": 5,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/teams/:id/forum/moderation",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/teams/:id/grants",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/teams/:id/hide",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/teams/:id/leader-override",
"handlers": 6,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/admin/teams/:id/leader-override/:memberKey",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/teams/:id/unhide",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/teams/forum/settings",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/admin/teams/forum/uploads",
"handlers": 5,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/teams/integrations",
"handlers": 2,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "PUT",
"path": "/api/v1/admin/teams/integrations",
"handlers": 8,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/admin/teams/integrations/:teamId",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/teams/requests",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/teams/requests/:id/decide",
"handlers": 5,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/teams/resync",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/admin/teams/review",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/admin/teams/voice",
"handlers": 2,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "PUT",
"path": "/api/v1/admin/teams/voice",
"handlers": 7,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/admin/teams/voice/:teamId",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/teams/voice/sync",
"handlers": 2,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/admin/uploads",
"handlers": 2,
"gates": [
"noindex",
"requireAuth",
"multerMiddleware"
]
},
{
"method": "GET",
"path": "/api/v1/admin/users",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/admin/users",
"handlers": 7,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/admin/users/:id",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/users/:id",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "PUT",
"path": "/api/v1/admin/users/:id",
"handlers": 8,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/users/:id/mfa/reset",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/admin/users/:id/trusted-devices",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/users/:id/trusted-devices",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/admin/users/:id/trusted-devices/:deviceId",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/users/email-dedupe-report",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/admin/users/email-dedupe-report/acknowledge",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/admin/wiki",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/admin/wiki",
"handlers": 8,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/admin/wiki/:slug",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/admin/wiki/:slug",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "PUT",
"path": "/api/v1/admin/wiki/:slug",
"handlers": 8,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "PATCH",
"path": "/api/v1/admin/wiki/:slug/publish",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/wiki/:slug/revisions",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/admin/wiki/:slug/revisions/:id",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/admin/wiki/:slug/revisions/:id/restore",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/wiki/categories",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/admin/wiki/categories",
"handlers": 6,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/admin/wiki/categories/:id",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "PUT",
"path": "/api/v1/admin/wiki/categories/:id",
"handlers": 7,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/admin/wiki/tags",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/auth/email/verify/:token",
"handlers": 3,
"gates": [
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/auth/email/verify/:token",
"handlers": 4,
"gates": [
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/auth/invite/:token",
"handlers": 3,
"gates": [
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/auth/invite/:token/accept",
"handlers": 10,
"gates": [
"backoffGuard",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/auth/login",
"handlers": 8,
"gates": [
"backoffGuard",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/auth/login/totp",
"handlers": 10,
"gates": [
"backoffGuard",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/auth/logout",
"handlers": 2,
"gates": [
"attachSession"
]
},
{
"method": "GET",
"path": "/api/v1/auth/me",
"handlers": 2,
"gates": [
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/auth/me/account",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "PATCH",
"path": "/api/v1/auth/me/account/email",
"handlers": 5,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/auth/me/account/email/pending",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/auth/me/account/email/resend",
"handlers": 2,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/auth/me/account/identities",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "DELETE",
"path": "/api/v1/auth/me/account/identities/:provider",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "PATCH",
"path": "/api/v1/auth/me/account/password",
"handlers": 5,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/auth/me/account/recovery-codes/generate",
"handlers": 6,
"gates": [
"noindex",
"requireAuth",
"backoffGuard",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/auth/me/account/recovery-codes/status",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/auth/me/account/totp/disable",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/auth/me/account/totp/enable",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/auth/me/account/totp/setup",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "PATCH",
"path": "/api/v1/auth/me/account/username",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/auth/me/devices",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/auth/me/devices",
"handlers": 5,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/auth/me/devices/:id",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/auth/me/notifications/channels",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "PUT",
"path": "/api/v1/auth/me/notifications/channels",
"handlers": 6,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/auth/me/notifications/streams",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/auth/me/notifications/subscriptions",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "PUT",
"path": "/api/v1/auth/me/notifications/subscriptions",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/auth/me/notifications/teams",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "PUT",
"path": "/api/v1/auth/me/notifications/teams",
"handlers": 6,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/auth/me/sessions",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "DELETE",
"path": "/api/v1/auth/me/sessions/:id",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/auth/me/trusted-devices",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/auth/me/trusted-devices",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/auth/me/trusted-devices",
"handlers": 4,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/auth/me/trusted-devices/:id",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/auth/mobile/login",
"handlers": 11,
"gates": [
"backoffGuard",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/auth/mobile/logout",
"handlers": 5,
"gates": [
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/auth/mobile/refresh",
"handlers": 4,
"gates": [
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/auth/mobile/sso/exchange",
"handlers": 6,
"gates": [
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/auth/mobile/sso/start",
"handlers": 7,
"gates": [
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/auth/password/forgot",
"handlers": 4,
"gates": [
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/auth/password/reset/:token",
"handlers": 3,
"gates": [
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/auth/password/reset/:token",
"handlers": 5,
"gates": [
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/auth/providers",
"handlers": 1,
"gates": []
},
{
"method": "POST",
"path": "/api/v1/auth/register",
"handlers": 10,
"gates": [
"backoffGuard",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/auth/sso/:provider/callback",
"handlers": 1,
"gates": []
},
{
"method": "GET",
"path": "/api/v1/auth/sso/:provider/link",
"handlers": 2,
"gates": [
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/auth/sso/:provider/start",
"handlers": 2,
"gates": []
},
{
"method": "POST",
"path": "/api/v1/auth/sso/totp",
"handlers": 8,
"gates": [
"backoffGuard",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/player/appeals",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/player/appeals",
"handlers": 5,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/player/appeals/:id/withdraw",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/player/appeals/eligible",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/player/teams",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/player/teams/:slug/access",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "PATCH",
"path": "/api/v1/player/teams/:slug/forum/posts/:id",
"handlers": 5,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/player/teams/:slug/forum/posts/:id/moderate",
"handlers": 5,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/player/teams/:slug/forum/report",
"handlers": 7,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/player/teams/:slug/forum/threads",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/player/teams/:slug/forum/threads",
"handlers": 7,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/player/teams/:slug/forum/threads/:id",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/player/teams/:slug/forum/threads/:id/moderate",
"handlers": 5,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/player/teams/:slug/forum/threads/:id/posts",
"handlers": 5,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/player/teams/:slug/forum/uploads",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"multerMiddleware"
]
},
{
"method": "DELETE",
"path": "/api/v1/player/teams/:slug/forum/uploads/:id",
"handlers": 3,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/player/teams/:slug/grants",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "POST",
"path": "/api/v1/player/teams/:slug/grants",
"handlers": 6,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "DELETE",
"path": "/api/v1/player/teams/:slug/grants/:userId",
"handlers": 5,
"gates": [
"noindex",
"requireAuth",
"middleware",
"validate"
]
},
{
"method": "POST",
"path": "/api/v1/public/contact",
"handlers": 6,
"gates": [
"middleware",
"validate"
]
},
{
"method": "GET",
"path": "/api/v1/public/modules",
"handlers": 1,
"gates": []
},
{
"method": "GET",
"path": "/api/v1/public/pages/:id/preview/:token",
"handlers": 1,
"gates": []
},
{
"method": "GET",
"path": "/api/v1/public/pages/:slug",
"handlers": 2,
"gates": [
"siteMode"
]
},
{
"method": "GET",
"path": "/api/v1/public/posts/:category",
"handlers": 2,
"gates": [
"siteMode"
]
},
{
"method": "GET",
"path": "/api/v1/public/posts/:category/:idOrSlug",
"handlers": 2,
"gates": [
"siteMode"
]
},
{
"method": "GET",
"path": "/api/v1/public/settings",
"handlers": 1,
"gates": []
},
{
"method": "GET",
"path": "/api/v1/public/status",
"handlers": 1,
"gates": []
},
{
"method": "GET",
"path": "/api/v1/public/teams",
"handlers": 2,
"gates": [
"siteMode"
]
},
{
"method": "GET",
"path": "/api/v1/public/teams/:slug",
"handlers": 2,
"gates": [
"siteMode"
]
},
{
"method": "GET",
"path": "/api/v1/public/teams/:slug/activity",
"handlers": 3,
"gates": [
"siteMode",
"optionalAuth"
]
},
{
"method": "GET",
"path": "/api/v1/public/teams/:slug/members",
"handlers": 3,
"gates": [
"siteMode",
"optionalAuth"
]
},
{
"method": "GET",
"path": "/api/v1/public/teams/by-external/:moduleId/:externalId",
"handlers": 2,
"gates": [
"siteMode"
]
},
{
"method": "GET",
"path": "/api/v1/public/teams/unsubscribe/:token",
"handlers": 1,
"gates": []
},
{
"method": "POST",
"path": "/api/v1/public/teams/unsubscribe/:token",
"handlers": 1,
"gates": []
},
{
"method": "GET",
"path": "/api/v1/public/version",
"handlers": 1,
"gates": []
},
{
"method": "GET",
"path": "/api/v1/public/wiki",
"handlers": 2,
"gates": [
"siteMode"
]
},
{
"method": "GET",
"path": "/api/v1/public/wiki/:slug",
"handlers": 2,
"gates": [
"siteMode"
]
},
{
"method": "GET",
"path": "/api/v1/public/wiki/categories",
"handlers": 2,
"gates": [
"siteMode"
]
},
{
"method": "GET",
"path": "/api/v1/public/wiki/tags",
"handlers": 2,
"gates": [
"siteMode"
]
},
{
"method": "GET",
"path": "/api/v1/settings/nav",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
},
{
"method": "GET",
"path": "/api/v1/settings/theme/options",
"handlers": 1,
"gates": [
"noindex",
"requireAuth"
]
}
],
"internal": [
{
"method": "GET",
"path": "/health",
"handlers": 1,
"gates": []
},
{
"method": "GET",
"path": "/internal/bot-config",
"handlers": 1,
"gates": [
"requireInternalKey"
]
},
{
"method": "GET",
"path": "/internal/commands",
"handlers": 1,
"gates": [
"requireInternalKey"
]
},
{
"method": "POST",
"path": "/internal/commands/dispatch",
"handlers": 1,
"gates": [
"requireInternalKey"
]
}
]
}