Audit and fix Swagger/OpenAPI accuracy; regenerate served spec #40

Merged
whitlocktech merged 1 commits from docs/swagger-audit into main 2026-07-05 04:33:38 +00:00
Member

Summary

Audit of the Swagger/OpenAPI docs. Route-level annotations were already 100% present across all 67 endpoints — the issues were accuracy, not coverage. This aligns the annotations with actual controller behavior and regenerates the committed/served spec.

Stale served spec (was 64/67 operations)

swagger-output.json predated three routes. Regenerating picks them up:

  • POST /api/v1/auth/sso/totp
  • GET /api/v1/admin/discord-bot/config
  • PUT /api/v1/admin/discord-bot/config

Plus a stale /auth/logout summary.

Response-shape corrections (annotation now matches controller)

Mutation endpoints do not return the generic { message } envelope:

  • Deletes echo { id } / { slug }; toggles return { deleted }, { unlinked }, { totp_enabled }, or { ip, removed } — documented as-is via new DeletedId / DeletedSlug / DeletedFlag / UnlinkedFlag / TotpState / UnbanResult components.
  • POST /account/totp/setup: otpauth_urlotpauthUrl (TotpSetup)
  • PUT /admin/site-mode: { mode }{ site_mode, changed_at, changed_by } (SiteModeState)
  • GET /admin/account: full UserAccountStatus
  • GET /account/identities: add linked_at (LinkedIdentity)
  • GET /public/status: add status_message (PublicStatus)
  • POST /auth/sso/totp: user is SafeUser, not full User
  • GET /dashboard: description/shape corrected (posts + users counts, no wiki)

Schema completeness

  • Provider (public discovery): { id, name, icon, loginUrl, priority }, not { id, name, kind }
  • ProviderConfig: add hasSecret, builtin, health (ProviderHealth)
  • Post: add excerpt, author_id, published_at
  • MobileTokenResponse.expiresIn: duration string ("15m"), not integer seconds

Config

  • Declare the Admin · Discord Bot tag (was used by routes but undeclared).

Verified correct — left unchanged

  • Auth model: cookie + bearer are both accepted on session routes (extractToken reads both; mobile access tokens are full sessions), so the dual cookieAuth + bearerAuth annotations are accurate and the schemes stay distinct.
  • Internal boundary: /internal/* (returns the decrypted Discord bot token) runs on a separate listener and is already excluded from the scan — nothing to redact from the public spec.

Note for reviewers

The mutation responses are genuinely inconsistent across the API ({id} vs {slug} vs {deleted} vs {unlinked} vs {totp_enabled}). They're documented as-is here (a pure docs change). Standardizing them to a common envelope would be a separate code change — happy to propose it if wanted.

🤖 Generated with Claude Code

https://claude.ai/code/session_019rao86n5cXpwAyjdBFEshV

## Summary Audit of the Swagger/OpenAPI docs. Route-level annotations were already **100% present** across all 67 endpoints — the issues were *accuracy*, not coverage. This aligns the annotations with actual controller behavior and regenerates the committed/served spec. ## Stale served spec (was 64/67 operations) `swagger-output.json` predated three routes. Regenerating picks them up: - `POST /api/v1/auth/sso/totp` - `GET /api/v1/admin/discord-bot/config` - `PUT /api/v1/admin/discord-bot/config` Plus a stale `/auth/logout` summary. ## Response-shape corrections (annotation now matches controller) Mutation endpoints do **not** return the generic `{ message }` envelope: - Deletes echo `{ id }` / `{ slug }`; toggles return `{ deleted }`, `{ unlinked }`, `{ totp_enabled }`, or `{ ip, removed }` — documented as-is via new `DeletedId` / `DeletedSlug` / `DeletedFlag` / `UnlinkedFlag` / `TotpState` / `UnbanResult` components. - `POST /account/totp/setup`: `otpauth_url` → `otpauthUrl` (`TotpSetup`) - `PUT /admin/site-mode`: `{ mode }` → `{ site_mode, changed_at, changed_by }` (`SiteModeState`) - `GET /admin/account`: full `User` → `AccountStatus` - `GET /account/identities`: add `linked_at` (`LinkedIdentity`) - `GET /public/status`: add `status_message` (`PublicStatus`) - `POST /auth/sso/totp`: `user` is `SafeUser`, not full `User` - `GET /dashboard`: description/shape corrected (posts + users counts, no wiki) ## Schema completeness - `Provider` (public discovery): `{ id, name, icon, loginUrl, priority }`, not `{ id, name, kind }` - `ProviderConfig`: add `hasSecret`, `builtin`, `health` (`ProviderHealth`) - `Post`: add `excerpt`, `author_id`, `published_at` - `MobileTokenResponse.expiresIn`: duration string (`"15m"`), not integer seconds ## Config - Declare the `Admin · Discord Bot` tag (was used by routes but undeclared). ## Verified correct — left unchanged - **Auth model:** cookie + bearer are both accepted on session routes (`extractToken` reads both; mobile access tokens are full sessions), so the dual `cookieAuth` + `bearerAuth` annotations are accurate and the schemes stay distinct. - **Internal boundary:** `/internal/*` (returns the decrypted Discord bot token) runs on a separate listener and is already excluded from the scan — nothing to redact from the public spec. ## Note for reviewers The mutation responses are genuinely inconsistent across the API (`{id}` vs `{slug}` vs `{deleted}` vs `{unlinked}` vs `{totp_enabled}`). They're documented **as-is** here (a pure docs change). Standardizing them to a common envelope would be a separate code change — happy to propose it if wanted. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_019rao86n5cXpwAyjdBFEshV
wtclaude added 1 commit 2026-07-05 04:17:37 +00:00
The route-level annotations were 100% present, but the committed/served
spec (swagger-output.json) was stale and several response schemas had
drifted from the controllers. This aligns the docs with actual behavior
and regenerates the spec.

Served spec was stale (64/67 operations). Regenerating picks up three
routes that were added after the last generation:
  - POST /api/v1/auth/sso/totp
  - GET  /api/v1/admin/discord-bot/config
  - PUT  /api/v1/admin/discord-bot/config
plus a stale /auth/logout summary.

Response-shape corrections (annotation now matches controller output):
  - Mutation endpoints do NOT return the generic { message } envelope.
    Deletes echo { id } / { slug }; toggles return { deleted },
    { unlinked }, { totp_enabled }, or { ip, removed }. Documented as-is
    via new DeletedId/DeletedSlug/DeletedFlag/UnlinkedFlag/TotpState/
    UnbanResult components. (The API is intentionally inconsistent here;
    recorded rather than normalized — see follow-up note.)
  - POST /account/totp/setup: otpauth_url -> otpauthUrl (TotpSetup)
  - PUT  /admin/site-mode: { mode } -> { site_mode, changed_at, changed_by }
  - GET  /account: full User -> AccountStatus (id/username/role/totp_enabled)
  - GET  /account/identities: add linked_at (LinkedIdentity)
  - GET  /public/status: add status_message (PublicStatus)
  - POST /auth/sso/totp: user is SafeUser, not full User
  - GET  /dashboard: description/shape corrected (posts+users, no wiki)

Schema completeness:
  - Provider (public discovery): { id, name, icon, loginUrl, priority },
    not { id, name, kind }
  - ProviderConfig: add hasSecret, builtin, health (ProviderHealth)
  - Post: add excerpt, author_id, published_at
  - MobileTokenResponse.expiresIn: duration string ("15m"), not integer

Config: declare the Admin · Discord Bot tag (was used but undeclared).

Auth model and the internal/external boundary were verified correct and
left unchanged: cookie + bearer are both accepted on session routes (dual
security annotations are accurate), and /internal/* runs on a separate
listener already excluded from the scan.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019rao86n5cXpwAyjdBFEshV
whitlocktech approved these changes 2026-07-05 04:33:27 +00:00
whitlocktech merged commit 20d3fbf594 into main 2026-07-05 04:33:38 +00:00
whitlocktech deleted branch docs/swagger-audit 2026-07-05 04:33:38 +00:00
Sign in to join this conversation.
No description provided.