From 2cb6f7a3b987968c24aaf80b3925ad5eba011974 Mon Sep 17 00:00:00 2001 From: wtclaude Date: Wed, 22 Jul 2026 16:54:23 -0500 Subject: [PATCH] docs(website): add /api/v2 skeleton (PR 1 scaffold), link from plan Companion doc to API_V2_PLAN.md describing PR 1: stand up router/v2/ empty but wired next to a frozen /api/v1, with a trivial GET /api/v2/version to make the mount testable and no behavior change. Includes the file tree, the api.router.js / v2.router.js wiring, empty capability-router stubs, and acceptance criteria. Adds a forward link from the plan's PR-1 line to the skeleton doc. Co-Authored-By: Claude --- website/API_V2_PLAN.md | 2 +- website/API_V2_SKELETON.md | 122 +++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 website/API_V2_SKELETON.md diff --git a/website/API_V2_PLAN.md b/website/API_V2_PLAN.md index ed9b11a..dc98b01 100644 --- a/website/API_V2_PLAN.md +++ b/website/API_V2_PLAN.md @@ -168,7 +168,7 @@ Steps: ## Sequencing & PR breakdown 1. **PR 1 — v2 scaffold:** `router/v2/` skeleton, `v2.router.js`, mount `/v2` next to `/v1`. Empty - but wired; no behavior change. + but wired; no behavior change. Detailed in [API_V2_SKELETON.md](./API_V2_SKELETON.md). 2. **PR 2 — auth merge (server):** v2 bearer auth routes + SSO callback code-exchange + SSE-on-Bearer + docs/swagger. 3. **PR 3 — auth merge (client):** `client.js` bearer + silent-refresh; `useShardFeed.js` fetch stream. diff --git a/website/API_V2_SKELETON.md b/website/API_V2_SKELETON.md new file mode 100644 index 0000000..78101a2 --- /dev/null +++ b/website/API_V2_SKELETON.md @@ -0,0 +1,122 @@ +# Website API v2 — `/api/v2` Skeleton (PR 1) + +Companion to [API_V2_PLAN.md](./API_V2_PLAN.md) — this is the concrete scaffold for **PR 1** in that +plan's sequencing. It stands up `/api/v2` **empty but wired**, next to a frozen `/api/v1`, with **no +behavior change**. Endpoints are filled in by the later PRs (auth merge, then the domain split). + +## Scope + +- Create the `router/v2/` tree of empty, domain-named routers. +- Mount `/v2` alongside `/v1` in `api.router.js`. +- Add a single trivial `GET /api/v2/version` so the mount is testable end-to-end. +- **Out of scope:** any real endpoint, any auth change, any controller edit. Those are PR 2+. + +## File tree to create + +``` +website/server/src/router/v2/ + v2.router.js # mounts the domain sub-routers; adds GET /version + admin/ + index.js # mounts the admin capability routers under /admin + dashboard.router.js users.router.js moderation.router.js + content.router.js wiki.router.js shard.router.js + settings.router.js invites.router.js bot-activity.router.js + auth/ + index.js login.router.js sso.router.js totp.router.js session.router.js + public/ + index.js news.router.js wiki.router.js page.router.js shard.router.js + player/ + index.js profile.router.js appeals.router.js shard.router.js +``` + +`internal/` is **not** part of v2's public tree — the internal routes stay on the separate, +unpublished port (`internalApp.js`), exactly as in v1. See `API_V2_PLAN.md` § Phase 2. + +## Wiring + +`api.router.js` gains the v2 mount next to v1: + +```js +const v1Router = require('./v1/v1.router') +const v2Router = require('./v2/v2.router') + +apiRouter.use('/v1', v1Router) +apiRouter.use('/v2', v2Router) // NEW — parallel version, migrate off v1 route-by-route +``` + +`v2.router.js` mounts each domain group and exposes the version ping: + +```js +const express = require('express') +const v2Router = express.Router() + +const adminRouter = require('./admin') +const authRouter = require('./auth') +const publicRouter = require('./public') +const playerRouter = require('./player') + +// Cheap liveness/mount check so the parallel version is testable before any +// real endpoint exists. Returns the API major version, nothing sensitive. +v2Router.get('/version', (req, res) => res.json({ version: 2 })) + +v2Router.use('/auth', authRouter) +v2Router.use('/public', publicRouter) +v2Router.use('/admin', adminRouter) +v2Router.use('/player', playerRouter) +// NOTE: /internal is intentionally NOT mounted here — same reason as v1. + +module.exports = v2Router +``` + +Each capability router is an empty stub at this stage — a router that mounts cleanly and adds no +routes yet, so PR 2+ only has to add handlers, never re-wire: + +```js +// router/v2/admin/dashboard.router.js +const express = require('express') +const router = express.Router() + +// Routes added in the admin domain-split PR (see API_V2_PLAN.md § Phase 2). + +module.exports = router +``` + +Each `index.js` mounts its group's capability routers under the URL that names them, e.g.: + +```js +// router/v2/admin/index.js +const express = require('express') +const admin = express.Router() + +admin.use('/dashboard', require('./dashboard.router')) +admin.use('/users', require('./users.router')) +admin.use('/moderation', require('./moderation.router')) +admin.use('/content', require('./content.router')) +admin.use('/wiki', require('./wiki.router')) +admin.use('/shard', require('./shard.router')) +admin.use('/settings', require('./settings.router')) +admin.use('/invites', require('./invites.router')) +admin.use('/bot-activity', require('./bot-activity.router')) + +module.exports = admin +``` + +## Acceptance criteria + +- Server boots with no error; every sub-router mounts. +- `GET /api/v2/version` → `200 { "version": 2 }`. +- `GET /api/v1/**` behavior is **byte-for-byte unchanged** — v1 is untouched. +- Existing server tests stay green (`cd website/server && npm test`). +- A new test asserts the `/api/v2/version` mount (smallest possible coverage of the wiring). + +## Docs / spec + +- Swagger regeneration is deferred until v2 has real routes (PR 2) — a lone `/version` ping doesn't + need an annotation. When PR 2 lands, add `#swagger.*` to the new routes and run `npm run swagger`. +- No `BACKEND_DESIGN.md` change here beyond noting the parallel `/api/v2` mount exists; the + route-map/security-contract edits land with the PRs that add real endpoints. + +## Next + +PR 2 fills the `auth/` routers with the bearer access + refresh flow and drops the session cookie — +see [API_V2_PLAN.md](./API_V2_PLAN.md) § Phase 1. -- 2.49.1