Skip to content

docs: OpenAPI 3.0 spec with Mintlify documentation site#154

Merged
BillChirico merged 16 commits intomainfrom
docs/openapi-swagger
Mar 1, 2026
Merged

docs: OpenAPI 3.0 spec with Mintlify documentation site#154
BillChirico merged 16 commits intomainfrom
docs/openapi-swagger

Conversation

@BillChirico
Copy link
Collaborator

@BillChirico BillChirico commented Feb 28, 2026

Summary

Adds comprehensive API documentation using OpenAPI 3.0.3 spec generation (via swagger-jsdoc) and a Mintlify documentation site.

What's included

OpenAPI Spec Generation:

  • JSDoc @openapi annotations on all 37+ API endpoints across 10 route files
  • Reusable schemas (Error, ValidationError, PaginatedResponse)
  • Security schemes (ApiKeyAuth + BearerAuth)
  • Rate limit header documentation
  • Public /api/docs.json endpoint serving the live spec

Mintlify Docs Site (docs/):

  • mint.json configuration with navigation, theming, and API reference
  • Introduction and Authentication guide pages
  • Auto-generated API reference from OpenAPI spec
  • pnpm docs:generate script to export static openapi.json

Endpoints Documented:

  • Health, Auth (OAuth2 flow), Config CRUD
  • Guilds (management, analytics, actions)
  • Members (list, detail, XP, cases, export)
  • Moderation (cases, stats, user history)
  • Community (leaderboard, showcases, stats, profiles)
  • Tickets (CRUD, stats)
  • Conversations (list, detail, flags, stats)
  • Webhooks

CI Fixes

  • Fixed OpenAPI version mismatch (3.1.0 → 3.0.3 for nullable compatibility)
  • Fixed auth scheme (CookieAuthBearerAuth to match actual JWT middleware)
  • Fixed analytics endpoint enum values and missing query params
  • ESM import for package.json (replaced createRequire)
  • Pre-existing formatting fixes

Closes #127

Copilot AI review requested due to automatic review settings February 28, 2026 21:45
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 28, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca2f095 and 6037683.

📒 Files selected for processing (1)
  • src/api/middleware/rateLimit.js
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (3)
**/*.js

📄 CodeRabbit inference engine (AGENTS.md)

**/*.js: Use ESM modules only — import/export, never require()
Always use node: protocol for Node.js builtin imports (e.g., import { readFileSync } from 'node:fs')

Files:

  • src/api/middleware/rateLimit.js
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,tsx}: Always use semicolons
Use single quotes — enforced by Biome
Use 2-space indentation — enforced by Biome

Files:

  • src/api/middleware/rateLimit.js
src/**/*.js

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.js: NEVER use console.log, console.warn, console.error, or any console.* method in src/ files — always use Winston logger instead: import { info, warn, error } from '../logger.js'
Pass structured metadata to Winston logger: info('Message processed', { userId, channelId })
Use custom error classes from src/utils/errors.js and always log errors with context before re-throwing
Use getConfig(guildId?) from src/modules/config.js to read config; use setConfigValue(path, value, guildId?) to update at runtime
Use safeSend() utility for outgoing Discord messages to sanitize mentions and enforce allowedMentions
Use splitMessage() utility for messages exceeding Discord's 2000-character limit
Add tests for all new code with mandatory 80% coverage threshold on statements, branches, functions, and lines; run pnpm test before every commit

Files:

  • src/api/middleware/rateLimit.js
🔇 Additional comments (1)
src/api/middleware/rateLimit.js (1)

44-48: LGTM!

The rate-limit headers are correctly implemented:

  • Math.max(0, ...) properly prevents negative remaining counts when the limit is exceeded.
  • Reset timestamp is correctly converted from milliseconds to Unix seconds.
  • Headers are emitted before the 429 check, ensuring clients always have quota visibility regardless of outcome.

📝 Walkthrough

Summary by CodeRabbit

  • Documentation

    • Comprehensive API docs added and published (authentication, endpoints, rate limits, site config and navigation).
  • New Features

    • Public API spec endpoint to fetch the OpenAPI JSON.
    • Rate-limit headers included on responses for client visibility.
  • Behavior

    • Moderation and related paginated endpoints now include an explicit limit field; one listing endpoint switched to offset-based pagination.
  • Tests / Chores

    • Added OpenAPI validation tests and a docs-generation script.

Walkthrough

Adds OpenAPI/Swagger documentation and specimen generation, Mintlify docs, a /api/docs.json endpoint, rate-limit headers, minor pagination/documentation-driven response changes, a helper export for conversations grouping, and tests validating the generated OpenAPI spec. No substantive runtime behavior changes beyond headers/pagination metadata and the docs endpoint.

Changes

Cohort / File(s) Summary
Documentation & Mintlify
docs/authentication.mdx, docs/introduction.mdx, docs/mint.json
New site/docs pages and Mintlify config describing API intro, auth (API key & OAuth2), public endpoints, rate-limit headers, and navigation/site metadata.
OpenAPI Spec Generator
src/api/swagger.js, scripts/generate-openapi.js, package.json
Added swagger-jsdoc-based spec exporter (swaggerSpec), script to write docs/openapi.json, and docs:generate script; dependency added.
Server Exposure
src/api/server.js
Imported swaggerSpec and added public GET /api/docs.json to serve the OpenAPI JSON.
Route Annotations (OpenAPI)
src/api/routes/...
src/api/routes/auth.js, src/api/routes/community.js, src/api/routes/config.js, src/api/routes/conversations.js, src/api/routes/guilds.js, src/api/routes/health.js, src/api/routes/members.js, src/api/routes/moderation.js, src/api/routes/tickets.js, src/api/routes/webhooks.js
Extensive @openapi JSDoc blocks added across route files documenting paths, parameters, request/response schemas, and security. Mostly documentation-only changes.
Conversations helper export
src/api/routes/conversations.js
Added and exported groupMessagesIntoConversations(rows) to group flat message rows into conversations.
Pagination / Response metadata
src/api/routes/moderation.js, src/api/routes/...
Added limit field to moderation paginated responses; flags endpoint pagination made explicit (LIMIT/OFFSET).
Rate-limit headers
src/api/middleware/rateLimit.js
Response now includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset on every response.
Tests
tests/api/swagger.test.js, tests/api/routes/moderation.test.js
New OpenAPI validation tests for swaggerSpec and /api/docs.json; updated moderation tests to assert limit in paginated responses.

Possibly related PRs

  • PR #70 — Adds REST API server foundations and core routes that are now documented and exposed via the generated OpenAPI spec and /api/docs.json.
  • PR #120 — Implements the community endpoints that receive the new OpenAPI documentation in this change.
  • PR #119 — Implements members endpoints which are covered by the OpenAPI annotations and tests added here.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive The PR fulfills most core requirements from issue #127: OpenAPI spec generation via swagger-jsdoc, all endpoints documented with schemas, security schemes defined, rate-limit headers documented, and authentication flow documented. However, Swagger UI access not fully implemented per requirements. Clarify whether the /api/docs.json endpoint and Mintlify site satisfy the Swagger UI requirement from #127, or if auth-gated /api/docs endpoint is still needed.
Out of Scope Changes check ❓ Inconclusive Most changes are in-scope documentation additions, but rate-limit header implementation and moderation endpoint limit field appear to extend beyond pure documentation. Verify whether the X-RateLimit headers in rateLimit.js and limit field additions in moderation.js were required dependencies for the OpenAPI documentation or are separate enhancements.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding OpenAPI 3.0 spec generation and a Mintlify documentation site.
Description check ✅ Passed The description provides relevant details about the changeset, including OpenAPI spec generation, Mintlify site structure, documented endpoints, and CI fixes.
Docstring Coverage ✅ Passed Docstring coverage is 87.50% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch docs/openapi-swagger

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude
Copy link

claude bot commented Feb 28, 2026

Claude finished @BillChirico's task in 3m 40s —— View job


Review Summary

6 issues found: 0 critical, 3 warnings, 3 nitpicks.

Many prior review issues (OpenAPI version 3.1→3.0.3, CookieAuth→BearerAuth, analytics enum values, missing query params, stale openapi.json, fabricated stats schema, missing 429/403/404 responses) have been addressed across commits. Good iteration.

# Severity File Issue
1 🟡 Warning src/api/routes/guilds.js:596-604 Roles color type is string but discord.js returns integer; position documented but not returned by handler
2 🟡 Warning src/api/routes/guilds.js:753-754 Stats description says "messages, active users" but implementation returns guildId, aiConversations, moderationCases, memberCount, uptime
3 🟡 Warning docs/mint.json:102 Placeholder api.yourdomain.com URL, inconsistent with introduction.mdx
4 🔵 Nitpick docs/mint.json:4-8 Logo/favicon SVG assets referenced but not present in repo
5 🔵 Nitpick docs/mint.json:58-61 Members nav incomplete (missing export, cases, xp); Webhooks group missing
6 🔵 Nitpick docs/authentication.mdx:33-37 Path param style inconsistency (:guildId vs {guildId})
Prompt to fix all issues
Fix these issues on branch docs/openapi-swagger:

1. src/api/routes/guilds.js roles endpoint (lines 596-617):
   - Change the OpenAPI schema color property from type: string to type: integer
     (discord.js Role.color is an integer, e.g. 16711680 for red)
   - Either remove `position` from the schema (lines 603-604) since it's not
     returned by the handler, OR add position to the .map() at line 617:
     .map((r) => ({ id: r.id, name: r.name, color: r.color, position: r.position }))

2. src/api/routes/guilds.js stats endpoint (lines 753-754):
   Change the description from "including member count, messages, active users,
   and moderation data" to "member count, AI conversations, moderation cases,
   and uptime" to match the actual response at lines 818-824.

3. docs/mint.json line 102:
   Replace "https://api.yourdomain.com/api/v1" with the same placeholder used
   in introduction.mdx ("https://your-domain.com/api/v1") for consistency,
   or use a relative path if Mintlify supports it.

4. docs/mint.json lines 58-61:
   Add missing member endpoint pages to navigation:
   - "api-reference/members/export-csv"
   - "api-reference/members/member-cases"
   - "api-reference/members/adjust-xp"
   Also add a Webhooks group:
   { "group": "Webhooks", "icon": "webhook", "pages": ["api-reference/webhooks/config-update"] }

5. docs/authentication.mdx lines 33-37:
   Replace Express-style params (:guildId, :userId) with OpenAPI-style ({guildId}, {userId}).

6. After all changes, regenerate docs/openapi.json:
   node scripts/generate-openapi.js

@claude
Copy link

claude bot commented Feb 28, 2026

Review Summary

5 issues found across the OpenAPI documentation PR.

# Severity File Issue
1 🔴 Critical src/api/routes/guilds.js:841-845 Analytics range enum lists [7d, 30d, 90d, 1y] but actual implementation accepts [today, week, month, custom]
2 🟡 Warning src/api/swagger.js:14 Spec declares OpenAPI 3.1.0 but all routes use nullable: true (a 3.0 keyword removed in 3.1); swagger-jsdoc@6 targets 3.0.x
3 🟡 Warning src/api/routes/guilds.js:846-853 Analytics endpoint missing from, to, interval, compare query parameters in docs
4 🟡 Warning src/api/routes/guilds.js:1397-1404 Actions description says "sync roles, purge cache" but implementation only supports sendMessage, sendEmbed, botSay
5 🔵 Nitpick src/api/swagger.js:9-10 createRequire for JSON import; AGENTS.md says "never require()" — Node 22 supports import ... with { type: 'json' }
Prompt to fix all issues
Fix these issues in the volvox-bot repo on branch docs/openapi-swagger:

1. src/api/swagger.js line 14: Change `openapi: '3.1.0'` to `openapi: '3.0.3'`
   because all route annotations use `nullable: true` (an OpenAPI 3.0 keyword
   removed in 3.1) and swagger-jsdoc@6 targets 3.0.x.

2. src/api/swagger.js lines 9-10: Replace the createRequire/require pattern
   with an ESM-native JSON import:
   - Remove: `import { createRequire } from 'node:module';`
   - Remove: `const require = createRequire(import.meta.url);`
   - Remove: `const { version } = require('../../package.json');`
   - Add: `import pkg from '../../package.json' with { type: 'json' };`
   - Add: `const { version } = pkg;`

3. src/api/routes/guilds.js analytics endpoint JSDoc (around line 841-845):
   Change the range enum from `enum: [7d, 30d, 90d, 1y]` and `default: 30d`
   to `enum: [today, week, month, custom]` and `default: week` to match
   the actual parseAnalyticsRange() implementation.

4. src/api/routes/guilds.js analytics endpoint JSDoc (after the channelId
   parameter around line 853): Add the missing query parameters:
   - `from` (string, format: date-time) — Start date, required for custom range
   - `to` (string, format: date-time) — End date, required for custom range
   - `interval` (string, enum: [hour, day]) — Bucket size, auto-derived if omitted
   - `compare` (string) — Enable period-over-period comparison (accepts 1/true/yes/on)

5. src/api/routes/guilds.js actions endpoint JSDoc (around line 1397-1404):
   Change the description from "e.g. sync roles, purge cache" to list the
   actual supported actions: "sendMessage, sendEmbed, botSay". Also note
   that OAuth is not accepted to prevent CSRF.

6. Update tests/api/swagger.test.js line 39: If you changed to 3.0.3,
   update the assertion from `toBe('3.1.0')` to `toBe('3.0.3')`.

Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 issues found: 1 critical (wrong analytics range enum values — docs list [7d,30d,90d,1y] but implementation accepts [today,week,month,custom]), 3 warnings (OpenAPI 3.1 declared but 3.0 patterns used; missing analytics query params; misleading actions description), 1 nitpick (createRequire vs ESM import). See inline comments and summary comment for details and fix prompt.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds OpenAPI 3.1 documentation generation for the Express REST API and exposes it via an auth-gated Swagger UI, with JSDoc @openapi annotations added across the route modules.

Changes:

  • Introduces swagger-jsdoc-based spec generation (swaggerSpec) and mounts Swagger UI at /api/docs plus raw JSON at /api/docs.json.
  • Adds/updates @openapi annotations across route files to document endpoints, parameters, and response shapes.
  • Adds Vitest coverage for spec presence and basic auth-gating behavior of the docs endpoints.

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/api/swagger.test.js Adds smoke tests for spec generation and /api/docs* auth gating
src/api/swagger.js Defines OpenAPI 3.1 base spec + components and generates spec via swagger-jsdoc
src/api/server.js Mounts Swagger UI and raw spec endpoints (auth-gated)
src/api/routes/auth.js Adds OpenAPI annotations for OAuth/login, /me, and logout endpoints
src/api/routes/community.js Adds OpenAPI annotations for public community endpoints
src/api/routes/config.js Adds OpenAPI annotations for global config read/update
src/api/routes/conversations.js Adds OpenAPI annotations for conversation list/detail/stats/flags
src/api/routes/guilds.js Adds OpenAPI annotations for guild endpoints (list/detail/config/stats/analytics/moderation/actions)
src/api/routes/health.js Adds OpenAPI annotation for health endpoint
src/api/routes/members.js Adds OpenAPI annotations for member list/detail/export/cases/xp
src/api/routes/moderation.js Adds OpenAPI annotations for moderation endpoints
src/api/routes/tickets.js Adds OpenAPI annotations for ticket endpoints
src/api/routes/webhooks.js Adds OpenAPI annotation for config-update webhook
package.json Adds swagger-jsdoc and swagger-ui-express dependencies
pnpm-lock.yaml Locks transitive dependencies for the new Swagger packages
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@greptile-apps
Copy link

greptile-apps bot commented Feb 28, 2026

Greptile Summary

This PR adds comprehensive API documentation using OpenAPI 3.0.3 spec generation and a Mintlify documentation site.

What's included:

  • OpenAPI spec generation via swagger-jsdoc with JSDoc @openapi annotations on 37+ endpoints across 10 route files
  • Reusable schemas (Error, ValidationError, PaginatedResponse) and security schemes (ApiKeyAuth, BearerAuth)
  • Public /api/docs.json endpoint serving the live spec
  • Mintlify docs site with introduction, authentication guide, and auto-generated API reference
  • Rate limit headers now emitted on all responses per OpenAPI spec

Issues found:

  • src/api/routes/moderation.js applies rate limiter twice (globally via router.use() on line 30, then again on individual routes at lines 144, 315, 436, 599) - causes double rate limiting

Overall assessment:
The implementation is well-structured and follows project conventions (ESM imports, Winston logging, proper error handling). The OpenAPI annotations are comprehensive and accurate. The duplicate rate limiter in moderation routes should be fixed before merging.

Confidence Score: 3/5

  • Safe to merge after fixing duplicate rate limiter in moderation routes
  • The PR adds valuable documentation infrastructure with proper OpenAPI spec generation and comprehensive annotations. However, the duplicate rate limiter application in src/api/routes/moderation.js is a functional bug that would cause incorrect rate limiting behavior (counting requests twice). Once this is fixed, the PR will be safe to merge.
  • Fix src/api/routes/moderation.js to remove duplicate rate limiter applications on lines 144, 315, 436, and 599

Important Files Changed

Filename Overview
src/api/swagger.js New file - properly configures OpenAPI 3.0.3 spec with security schemes, reusable schemas, and rate limit headers
scripts/generate-openapi.js New file - generates docs/openapi.json from swagger spec, properly uses Winston logger
src/api/server.js Added public /api/docs.json endpoint for Mintlify documentation site
src/api/middleware/rateLimit.js Added X-RateLimit-* headers on all responses per OpenAPI spec requirements
src/api/routes/moderation.js Added OpenAPI annotations - rate limiter incorrectly applied twice (globally + per-route)
src/api/routes/auth.js Added comprehensive OpenAPI annotations for OAuth2 flow endpoints
src/api/routes/guilds.js Added OpenAPI annotations for guild management, analytics, and action endpoints
package.json Added swagger-jsdoc dependency and docs:generate script

Last reviewed commit: 6037683

Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

9 issues found: 1 critical, 5 warnings, 3 nitpicks. See inline comments for details.

# Severity File Issue
1 🔴 Critical src/api/routes/guilds.js:839-841 Analytics range enum lists [7d, 30d, 90d, 1y] but actual implementation accepts [today, week, month, custom]
2 🟡 Warning src/api/swagger.js:14 Spec declares OpenAPI 3.1.0 but all routes use nullable: true (a 3.0 keyword); swagger-jsdoc@6 targets 3.0.x
3 🟡 Warning src/api/swagger.js:30-35 CookieAuth scheme documents cookie auth but middleware only reads Authorization: Bearer header
4 🟡 Warning src/api/routes/guilds.js:843-846 Analytics endpoint missing from, to, interval, compare query params in docs
5 🟡 Warning src/api/routes/guilds.js:1402-1404 Actions description says "sync roles, purge cache" but only sendMessage is implemented
6 🟡 Warning src/api/routes/auth.js:358-361 /auth/me docs say "session cookie" with CookieAuth but requireOAuth() uses Bearer JWT
7 🟡 Warning tests/api/swagger.test.js:39 Version assertion must stay in sync if OpenAPI version is changed
8 🔵 Nitpick src/api/swagger.js:9-10 createRequire for JSON import; AGENTS.md says "never require()"
9 🔵 Nitpick scripts/generate-openapi.js:5 console.log usage (acceptable in scripts/ but noting for awareness)
Prompt to fix all issues
Fix these issues in the volvox-bot repo on branch docs/openapi-swagger:

1. src/api/swagger.js line 14: Change `openapi: '3.1.0'` to `openapi: '3.0.3'`
   because all route annotations use `nullable: true` (an OpenAPI 3.0 keyword
   removed in 3.1) and swagger-jsdoc@6 targets 3.0.x.

2. src/api/swagger.js lines 6-10: Replace the createRequire/require pattern
   with an ESM-native JSON import:
   - Remove: `import { createRequire } from 'node:module';`
   - Remove: `const require = createRequire(import.meta.url);`
   - Remove: `const { version } = require('../../package.json');`
   - Add: `import pkg from '../../package.json' with { type: 'json' };`
   - Add: `const { version } = pkg;`

3. src/api/swagger.js lines 30-35: Replace the CookieAuth security scheme
   with a BearerAuth scheme that matches the actual implementation:
   - Change CookieAuth to:
     BearerAuth: {
       type: 'http',
       scheme: 'bearer',
       bearerFormat: 'JWT',
       description: 'JWT bearer token via Authorization header after Discord OAuth2 login.',
     },
   - Then find-and-replace all `CookieAuth: []` references in route files
     to `BearerAuth: []`.

4. src/api/routes/guilds.js analytics endpoint JSDoc (around line 839-841):
   Change the range enum from `enum: [7d, 30d, 90d, 1y]` and `default: 30d`
   to `enum: [today, week, month, custom]` and `default: week` to match
   the actual parseAnalyticsRange() implementation at line 81-84.

5. src/api/routes/guilds.js analytics endpoint JSDoc (after the channelId
   parameter around line 846): Add the missing query parameters:
   - `from` (string, format: date-time) - Start date, required for custom range
   - `to` (string, format: date-time) - End date, required for custom range
   - `interval` (string, enum: [hour, day]) - Bucket size, auto-derived if omitted
   - `compare` (string) - Enable period-over-period comparison

6. src/api/routes/guilds.js actions endpoint JSDoc (around line 1402-1404):
   Change the description from "e.g. sync roles, purge cache" to note that
   only `sendMessage` is currently supported. Also note OAuth is not accepted
   to prevent CSRF.

7. src/api/routes/auth.js lines 358-361: Change /auth/me description from
   "Requires a valid session cookie" to "Requires a valid Bearer token" and
   change security from CookieAuth to BearerAuth (after the rename in step 3).
   Do the same for /auth/logout.

8. tests/api/swagger.test.js line 39: Update the assertion from
   `toBe('3.1.0')` to `toBe('3.0.3')` (if step 1 is applied).
   Also update line 82 in the same file.

9. After all fixes, regenerate docs/openapi.json by running:
   node scripts/generate-openapi.js

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 28, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 22 changed files in this pull request and generated 7 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (1)

docs/introduction.mdx:33

  • The rate limit header table has an extra leading |, creating an empty column (|| Header | Description |). This likely renders incorrectly in Markdown/MDX; use a standard two-column table format so the docs display as intended.
All endpoints return rate limit headers:

| Header | Description |
|--------|-------------|
| `X-RateLimit-Limit` | Max requests per window |
| `X-RateLimit-Remaining` | Requests remaining |
| `X-RateLimit-Reset` | Unix timestamp when window resets |

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/authentication.mdx`:
- Around line 25-27: Update the incorrect OAuth callback path in the
documentation: replace the referenced route string "/api/v1/auth/callback" with
the implemented route "/api/v1/auth/discord/callback" wherever it appears
(notably the step describing Discord redirect), and verify any related
references (e.g., examples, README or flow steps) match the implemented handler
name to keep docs consistent with the actual route.

In `@docs/mint.json`:
- Around line 65-67: The docs currently hardcode api.baseUrl as
"http://localhost:3001/api/v1"; change this to a deploy-safe value by replacing
the literal with a configurable placeholder or environment-driven value (e.g.,
use a relative path like "/api/v1" or a template token such as
"{{API_BASE_URL}}") so that api.baseUrl can be set at deploy/CI time; update any
build/deploy scripts to replace the placeholder or set the env var used by
mint.json.

In `@scripts/generate-openapi.js`:
- Around line 1-5: The script currently calls writeFileSync to write JSON for
swaggerSpec and will throw if the docs directory is missing; before calling
writeFileSync in generate-openapi.js, ensure the target directory exists (create
it with fs.mkdirSync('docs', { recursive: true }) or equivalent) and wrap the
write in a try/catch to log and exit on errors; update the block that references
swaggerSpec and writeFileSync to first create the directory and handle any
filesystem errors gracefully.

In `@src/api/routes/conversations.js`:
- Around line 844-913: The OpenAPI doc for POST
/guilds/{id}/conversations/{conversationId}/flag is missing 403 and 429
responses even though the route uses requireGuildAdmin and
conversationsRateLimit middleware; update the responses section of that
operation to include "403": $ref: "#/components/responses/Forbidden" and "429":
$ref: "#/components/responses/RateLimited" so the docs reflect authorization and
rate-limit failures.
- Around line 496-591: The OpenAPI doc for the GET
/guilds/{id}/conversations/flags endpoint is missing the 429 rate-limit response
even though the route uses the conversationsRateLimit middleware; update the
endpoint's responses block to include a "429" entry referencing
"#/components/responses/RateLimited" (i.e., add the equivalent of `"429": $ref:
"#/components/responses/RateLimited"` to the responses for the
/guilds/{id}/conversations/flags GET spec so it documents rate limiting).
- Around line 664-736: The OpenAPI responses for the GET
/guilds/{id}/conversations/{conversationId} endpoint are missing 403 and 429
entries even though requireGuildAdmin and conversationsRateLimit middleware are
applied; update the responses object for that operation (the GET block for
conversation detail) to include a "403" entry referencing
"#/components/responses/Forbidden" and a "429" entry referencing
"#/components/responses/RateLimited" so the documentation matches the middleware
behavior.
- Around line 348-408: The OpenAPI block for the
/guilds/{id}/conversations/stats GET endpoint is missing a 429 response
declaration even though it uses the conversationsRateLimit middleware; update
the spec for that endpoint to include a "429" response entry referencing the
shared TooManyRequests response (same style as other endpoints in this file) so
clients can see rate-limit behavior. Ensure you add the "429" key under
responses with the same $ref used elsewhere (e.g.,
"#/components/responses/TooManyRequests") so the documentation is consistent.

In `@src/api/routes/guilds.js`:
- Around line 558-562: The OpenAPI block for the guilds endpoint is missing a
404 response even though the validateGuild middleware (function validateGuild)
can return 404 when a guild isn't found; update the Swagger/OpenAPI doc for that
route to include a "404" response entry referencing the existing
components/responses/NotFound (or add a NotFound response if it doesn't exist)
alongside the existing "401" and "403" entries so the spec accurately reflects
validateGuild's behavior.
- Around line 1361-1372: The OpenAPI response schema lists a "pages" integer but
the actual response returns "limit" (response shape is { page, limit, total,
cases }); update the schema to replace the "pages" property with a "limit"
integer property (and adjust any examples/description to reflect {page, limit,
total, cases}) so the documented response matches the implementation.
- Around line 476-496: The OpenAPI response schema is out of sync with the
handler: the code returns channels: getGuildChannels(guild) (an array) and also
includes channelCount (integer), while the schema currently declares channels
and roles as integers. Update the schema in this response to make channels an
array (type: array, items: object) that describes the channel object shape
returned by getGuildChannels, add channelCount as an integer property, and
change the roles property to match the implementation (e.g., roleCount as
integer or roles as an array) so it matches whatever the route uses (refer to
getGuildChannels(guild) and the guild roles/count code in the same handler to
mirror the actual fields).

In `@src/api/routes/moderation.js`:
- Around line 301-308: The OpenAPI response objects for the rate-limited
moderation routes in src/api/routes/moderation.js currently list 401/403/404/500
but omit a 429 response; update each affected endpoint's responses block (the
same object that contains "401","403","404","500") to include a "429" entry that
references the central Too Many Requests response (e.g. "$ref":
"#/components/responses/TooManyRequests" or the project-equivalent), ensuring
all three rate-limited moderation endpoints (the OpenAPI blocks surrounding the
existing 401/403/404/500 entries) include the new 429 response to prevent
contract drift.

In `@src/api/routes/tickets.js`:
- Around line 62-69: The OpenAPI docs for the ticket routes are missing a 429
response for endpoints that use the ticketRateLimit middleware; update every
operation that applies ticketRateLimit (refer to uses of ticketRateLimit in this
file) to add a "429" response entry pointing to the shared TooManyRequests/429
response (e.g. $ref: "#/components/responses/TooManyRequests" or equivalent)
alongside the existing 401/403/500/503 entries; specifically add the 429
response to the same operation objects around the spots where ticketRateLimit is
applied (the blocks you noted near lines ~73, ~186-196, ~199, ~321-328, and
~330) so the spec exposes rate-limit behavior.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 665b74e and 889699f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (21)
  • docs/authentication.mdx
  • docs/introduction.mdx
  • docs/mint.json
  • docs/openapi.json
  • package.json
  • scripts/generate-openapi.js
  • src/api/routes/auth.js
  • src/api/routes/community.js
  • src/api/routes/config.js
  • src/api/routes/conversations.js
  • src/api/routes/guilds.js
  • src/api/routes/health.js
  • src/api/routes/members.js
  • src/api/routes/moderation.js
  • src/api/routes/tickets.js
  • src/api/routes/webhooks.js
  • src/api/server.js
  • src/api/swagger.js
  • src/api/utils/configValidation.js
  • src/modules/welcomeOnboarding.js
  • tests/api/swagger.test.js
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Greptile Review
  • GitHub Check: Agent
  • GitHub Check: claude-review
🧰 Additional context used
📓 Path-based instructions (4)
**/*.js

📄 CodeRabbit inference engine (AGENTS.md)

**/*.js: Use ESM modules only — import/export, never require()
Always use node: protocol for Node.js builtin imports (e.g., import { readFileSync } from 'node:fs')

Files:

  • src/modules/welcomeOnboarding.js
  • tests/api/swagger.test.js
  • src/api/routes/auth.js
  • src/api/utils/configValidation.js
  • src/api/routes/guilds.js
  • src/api/routes/health.js
  • src/api/routes/members.js
  • src/api/routes/webhooks.js
  • src/api/server.js
  • src/api/swagger.js
  • src/api/routes/moderation.js
  • src/api/routes/community.js
  • src/api/routes/conversations.js
  • scripts/generate-openapi.js
  • src/api/routes/config.js
  • src/api/routes/tickets.js
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,tsx}: Always use semicolons
Use single quotes — enforced by Biome
Use 2-space indentation — enforced by Biome

Files:

  • src/modules/welcomeOnboarding.js
  • tests/api/swagger.test.js
  • src/api/routes/auth.js
  • src/api/utils/configValidation.js
  • src/api/routes/guilds.js
  • src/api/routes/health.js
  • src/api/routes/members.js
  • src/api/routes/webhooks.js
  • src/api/server.js
  • src/api/swagger.js
  • src/api/routes/moderation.js
  • src/api/routes/community.js
  • src/api/routes/conversations.js
  • scripts/generate-openapi.js
  • src/api/routes/config.js
  • src/api/routes/tickets.js
src/**/*.js

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.js: NEVER use console.log, console.warn, console.error, or any console.* method in src/ files — always use Winston logger instead: import { info, warn, error } from '../logger.js'
Pass structured metadata to Winston logger: info('Message processed', { userId, channelId })
Use custom error classes from src/utils/errors.js and always log errors with context before re-throwing
Use getConfig(guildId?) from src/modules/config.js to read config; use setConfigValue(path, value, guildId?) to update at runtime
Use safeSend() utility for outgoing Discord messages to sanitize mentions and enforce allowedMentions
Use splitMessage() utility for messages exceeding Discord's 2000-character limit
Add tests for all new code with mandatory 80% coverage threshold on statements, branches, functions, and lines; run pnpm test before every commit

Files:

  • src/modules/welcomeOnboarding.js
  • src/api/routes/auth.js
  • src/api/utils/configValidation.js
  • src/api/routes/guilds.js
  • src/api/routes/health.js
  • src/api/routes/members.js
  • src/api/routes/webhooks.js
  • src/api/server.js
  • src/api/swagger.js
  • src/api/routes/moderation.js
  • src/api/routes/community.js
  • src/api/routes/conversations.js
  • src/api/routes/config.js
  • src/api/routes/tickets.js
src/modules/*.js

📄 CodeRabbit inference engine (AGENTS.md)

src/modules/*.js: Register event handlers in src/modules/events.js by importing handler functions and calling client.on() with config parameter
Check config.yourModule.enabled before processing in module event handlers
Prefer per-request getConfig() pattern in new modules over reactive onConfigChange() wiring; only add onConfigChange() listeners for stateful resources that cannot re-read config on each use

Files:

  • src/modules/welcomeOnboarding.js
🧠 Learnings (6)
📚 Learning: 2026-02-27T16:24:15.054Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-27T16:24:15.054Z
Learning: Applies to src/**/*.js : Use getConfig(guildId?) from src/modules/config.js to read config; use setConfigValue(path, value, guildId?) to update at runtime

Applied to files:

  • src/api/routes/guilds.js
  • src/api/routes/webhooks.js
📚 Learning: 2026-02-27T16:24:15.054Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-27T16:24:15.054Z
Learning: Applies to src/modules/moderation.js : Case numbering must be per-guild sequential, assigned atomically using COALESCE(MAX(case_number), 0) + 1 in a single INSERT statement

Applied to files:

  • src/api/routes/guilds.js
  • src/api/routes/moderation.js
📚 Learning: 2026-02-27T16:24:15.054Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-27T16:24:15.054Z
Learning: Applies to **/*.js : Use ESM modules only — import/export, never require()

Applied to files:

  • src/api/swagger.js
📚 Learning: 2026-02-27T16:24:15.054Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-27T16:24:15.054Z
Learning: Applies to **/*.js : Always use node: protocol for Node.js builtin imports (e.g., import { readFileSync } from 'node:fs')

Applied to files:

  • src/api/swagger.js
📚 Learning: 2026-02-27T16:24:15.055Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-27T16:24:15.055Z
Learning: Update AGENTS.md, README.md, CONTRIBUTING.md, .env.example, and config.json documentation whenever code changes are made (new commands, modules, env vars, or architecture changes)

Applied to files:

  • docs/introduction.mdx
  • scripts/generate-openapi.js
📚 Learning: 2026-02-27T16:24:15.054Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-27T16:24:15.054Z
Learning: Applies to src/**/*.js : NEVER use console.log, console.warn, console.error, or any console.* method in src/ files — always use Winston logger instead: import { info, warn, error } from '../logger.js'

Applied to files:

  • scripts/generate-openapi.js
🧬 Code graph analysis (2)
tests/api/swagger.test.js (2)
src/api/server.js (3)
  • createApp (28-91)
  • app (29-29)
  • app (108-108)
src/api/swagger.js (2)
  • swaggerSpec (140-140)
  • swaggerSpec (140-140)
src/api/server.js (1)
src/api/swagger.js (2)
  • swaggerSpec (140-140)
  • swaggerSpec (140-140)
🔇 Additional comments (21)
src/modules/welcomeOnboarding.js (1)

46-57: Formatting-only update looks good.

No functional behavior changed here; normalization for rulesChannel, verifiedRole, and introChannel remains intact and readable.

src/api/utils/configValidation.js (1)

196-198: Formatting-only change is safe.

Line 196-Line 198 keeps the same validation behavior and error output; this refactor is clean.

docs/introduction.mdx (1)

1-33: Solid introductory API page.

The structure and coverage (base URL, capabilities, and rate-limit headers) look good for a landing doc.

src/api/routes/webhooks.js (1)

15-69: OpenAPI contract matches the webhook auth model.

The operation-level docs correctly describe API-secret-only authentication and the request/response shape for this endpoint.

src/api/routes/auth.js (1)

112-130: Auth OpenAPI annotations are clear and consistent.

These docs blocks accurately map to route behavior and improve endpoint discoverability without changing runtime paths.

Also applies to: 167-219, 353-392, 423-445

src/api/routes/community.js (1)

58-129: Community endpoint docs are comprehensive and well-scoped.

Good OpenAPI coverage for public parameters, payloads, and error responses across all four routes.

Also applies to: 218-298, 381-436, 531-632

src/api/routes/config.js (1)

103-206: LGTM!

The OpenAPI documentation accurately reflects the endpoint behavior, including the 207 Multi-Status response for partial success scenarios. The security schemes and error responses are properly documented.

src/api/routes/health.js (1)

42-122: LGTM!

The OpenAPI documentation comprehensively covers the health check endpoint, including the conditional extended diagnostics when authenticated. The schema accurately reflects the response structure with proper nullable annotations.

src/api/server.js (1)

68-69: LGTM!

The public /api/docs.json endpoint is appropriately positioned after the rate limiter middleware (Line 66), so it benefits from rate limiting protection. The endpoint correctly serves the OpenAPI spec for Mintlify integration.

src/api/swagger.js (1)

1-140: LGTM!

The OpenAPI configuration is well-structured with:

  • Proper security schemes matching the authentication middleware (ApiKeyAuth for x-api-secret, BearerAuth for JWT)
  • Reusable schemas and responses reducing duplication across route annotations
  • Rate limit headers documented consistently
  • Version extracted from package.json for automatic sync

The with { type: 'json' } import assertion syntax at Line 7 is supported by Node.js 22+, which aligns with the engine requirement in package.json.

package.json (1)

36-36: No action needed. The swagger-jsdoc package is pinned to the latest stable version (6.2.8) with no known security vulnerabilities.

src/api/routes/members.js (5)

49-83: LGTM — OpenAPI documentation for CSV export endpoint.

The documentation accurately reflects the endpoint behavior: streaming CSV response, security schemes, and appropriate error responses including 503 for database unavailability.


183-296: LGTM — Comprehensive OpenAPI documentation for member list endpoint.

The documentation accurately captures:

  • Pagination parameters with proper defaults and bounds
  • Search and sort options matching the implementation (validSorts at line 389)
  • Response schema matching the enriched member object structure

436-560: LGTM — Member detail endpoint documentation is thorough.

The nested schema structure for stats, reputation, and warnings accurately reflects the response object built at lines 624-658.


673-758: LGTM — Moderation case history documentation.

The pagination and response schema accurately match the implementation. Note that returning an empty cases array for users with no moderation history is the correct behavior (no 404 needed).


817-889: LGTM — XP adjustment endpoint documentation.

The request body schema correctly documents the amount constraint (non-zero integer, ±1,000,000 cap) and the optional reason field. The response schema accurately reflects the implementation.

src/api/routes/conversations.js (1)

147-257: LGTM — Conversation list endpoint documentation.

The documentation accurately reflects:

  • Query parameters (page, limit, search, user, channel, from, to)
  • Default 30-day window behavior mentioned in description
  • Response schema matching buildConversationSummary output
tests/api/swagger.test.js (4)

1-19: LGTM — Test setup with appropriate mocks.

The mocks correctly isolate the test from:

  • Logger (preventing console output)
  • Database queries (logQuery)
  • restartTracker (simulating module not found)

The throw new Error('Module not found') pattern for restartTracker mock is appropriate for simulating a missing optional module.


27-34: LGTM — Minimal but sufficient test fixture.

The mock client provides just enough structure for the app to initialize, and passing null for dbPool is intentional since these tests only validate the OpenAPI spec structure, not database-dependent routes.


36-75: Good coverage of OpenAPI spec structure.

The tests validate essential elements: version, paths, security schemes, schemas, and headers. The route group coverage test ensures all documented endpoint categories are present.


77-86: LGTM — Endpoint test confirms public accessibility.

The test correctly verifies that /api/docs.json is publicly accessible without authentication, matching the implementation in src/api/server.js (line 67) where it's served directly without auth middleware.

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 28, 2026
coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 28, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI review requested due to automatic review settings March 1, 2026 00:18
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/generate-openapi.js`:
- Around line 1-7: The script currently imports and calls info from
src/logger.js (see import of info and the call info('OpenAPI spec written to
docs/openapi.json')) which couples a CLI script to application logging; replace
that with a simple console.log for the standalone script: remove the import of
info, keep mkdirSync/writeFileSync and swaggerSpec, and call console.log(...)
after writing the file to report success (e.g., "OpenAPI spec written to
docs/openapi.json").

In `@src/api/routes/health.js`:
- Around line 52-131: The OpenAPI response schema is missing the authenticated
"pool" property that the route adds to body.pool; update the schema for the 200
response to include a "pool" object property (documenting the database pool
statistics added when authenticated) and describe its fields to match the
runtime shape (e.g., connection counts/metrics the route populates) so the
documented response matches the actual response produced by the health handler.

In `@tests/api/swagger.test.js`:
- Around line 14-16: Add an explanatory comment immediately above the
vi.mock('../../src/utils/restartTracker.js', ...) call in
tests/api/swagger.test.js that clarifies this mock intentionally throws to
simulate a missing module during resolution (so tests exercise code paths that
handle module-not-found errors); reference the vi.mock invocation and the target
module '../../src/utils/restartTracker.js' in the comment and briefly state why
this approach is used so future maintainers understand the intent.
- Around line 27-34: The guild mock used in buildApp's client.guilds.cache is an
empty object which can cause runtime errors when code expects properties like
name or memberCount; update the Map entry in buildApp (the client object passed
to createApp) to include minimal guild properties such as id, name, memberCount
(and any other fields your app accesses like ownerID or region) so tests won't
throw when code paths read those values.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 665e290 and ca2f095.

⛔ Files ignored due to path filters (4)
  • docs/favicon.svg is excluded by !**/*.svg
  • docs/logo/dark.svg is excluded by !**/*.svg
  • docs/logo/light.svg is excluded by !**/*.svg
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • docs/authentication.mdx
  • docs/introduction.mdx
  • docs/mint.json
  • docs/openapi.json
  • package.json
  • scripts/generate-openapi.js
  • src/api/routes/auth.js
  • src/api/routes/community.js
  • src/api/routes/config.js
  • src/api/routes/conversations.js
  • src/api/routes/guilds.js
  • src/api/routes/health.js
  • src/api/routes/members.js
  • src/api/routes/moderation.js
  • src/api/routes/tickets.js
  • src/api/routes/webhooks.js
  • src/api/server.js
  • src/api/swagger.js
  • tests/api/routes/moderation.test.js
  • tests/api/swagger.test.js
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (3)
**/*.js

📄 CodeRabbit inference engine (AGENTS.md)

**/*.js: Use ESM modules only — import/export, never require()
Always use node: protocol for Node.js builtin imports (e.g., import { readFileSync } from 'node:fs')

Files:

  • src/api/swagger.js
  • src/api/routes/health.js
  • src/api/routes/guilds.js
  • src/api/routes/tickets.js
  • src/api/routes/moderation.js
  • src/api/server.js
  • scripts/generate-openapi.js
  • src/api/routes/webhooks.js
  • tests/api/swagger.test.js
  • src/api/routes/conversations.js
  • src/api/routes/members.js
  • src/api/routes/auth.js
  • src/api/routes/config.js
  • src/api/routes/community.js
  • tests/api/routes/moderation.test.js
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,tsx}: Always use semicolons
Use single quotes — enforced by Biome
Use 2-space indentation — enforced by Biome

Files:

  • src/api/swagger.js
  • src/api/routes/health.js
  • src/api/routes/guilds.js
  • src/api/routes/tickets.js
  • src/api/routes/moderation.js
  • src/api/server.js
  • scripts/generate-openapi.js
  • src/api/routes/webhooks.js
  • tests/api/swagger.test.js
  • src/api/routes/conversations.js
  • src/api/routes/members.js
  • src/api/routes/auth.js
  • src/api/routes/config.js
  • src/api/routes/community.js
  • tests/api/routes/moderation.test.js
src/**/*.js

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.js: NEVER use console.log, console.warn, console.error, or any console.* method in src/ files — always use Winston logger instead: import { info, warn, error } from '../logger.js'
Pass structured metadata to Winston logger: info('Message processed', { userId, channelId })
Use custom error classes from src/utils/errors.js and always log errors with context before re-throwing
Use getConfig(guildId?) from src/modules/config.js to read config; use setConfigValue(path, value, guildId?) to update at runtime
Use safeSend() utility for outgoing Discord messages to sanitize mentions and enforce allowedMentions
Use splitMessage() utility for messages exceeding Discord's 2000-character limit
Add tests for all new code with mandatory 80% coverage threshold on statements, branches, functions, and lines; run pnpm test before every commit

Files:

  • src/api/swagger.js
  • src/api/routes/health.js
  • src/api/routes/guilds.js
  • src/api/routes/tickets.js
  • src/api/routes/moderation.js
  • src/api/server.js
  • src/api/routes/webhooks.js
  • src/api/routes/conversations.js
  • src/api/routes/members.js
  • src/api/routes/auth.js
  • src/api/routes/config.js
  • src/api/routes/community.js
🧠 Learnings (9)
📚 Learning: 2026-02-27T16:24:15.054Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-27T16:24:15.054Z
Learning: Applies to **/*.js : Use ESM modules only — import/export, never require()

Applied to files:

  • src/api/swagger.js
📚 Learning: 2026-02-27T16:24:15.054Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-27T16:24:15.054Z
Learning: Applies to **/*.js : Always use node: protocol for Node.js builtin imports (e.g., import { readFileSync } from 'node:fs')

Applied to files:

  • src/api/swagger.js
📚 Learning: 2026-02-27T16:24:15.054Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-27T16:24:15.054Z
Learning: Applies to src/**/*.js : Use getConfig(guildId?) from src/modules/config.js to read config; use setConfigValue(path, value, guildId?) to update at runtime

Applied to files:

  • src/api/routes/guilds.js
  • src/api/routes/webhooks.js
📚 Learning: 2026-02-27T16:24:15.054Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-27T16:24:15.054Z
Learning: Applies to src/modules/moderation.js : Case numbering must be per-guild sequential, assigned atomically using COALESCE(MAX(case_number), 0) + 1 in a single INSERT statement

Applied to files:

  • src/api/routes/guilds.js
  • src/api/routes/moderation.js
📚 Learning: 2026-02-27T16:24:15.054Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-27T16:24:15.054Z
Learning: Applies to src/commands/*mod*.js : Moderation commands must follow the shared pattern: deferReply({ ephemeral: true }), validate inputs, sendDmNotification(), execute Discord action, createCase(), sendModLogEmbed(), checkEscalation()

Applied to files:

  • src/api/routes/moderation.js
📚 Learning: 2026-02-27T16:24:15.054Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-27T16:24:15.054Z
Learning: Applies to src/**/*.js : NEVER use console.log, console.warn, console.error, or any console.* method in src/ files — always use Winston logger instead: import { info, warn, error } from '../logger.js'

Applied to files:

  • scripts/generate-openapi.js
📚 Learning: 2026-02-27T16:24:15.055Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-27T16:24:15.055Z
Learning: Update AGENTS.md, README.md, CONTRIBUTING.md, .env.example, and config.json documentation whenever code changes are made (new commands, modules, env vars, or architecture changes)

Applied to files:

  • scripts/generate-openapi.js
  • docs/introduction.mdx
  • package.json
📚 Learning: 2026-02-27T16:24:15.054Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-27T16:24:15.054Z
Learning: Applies to src/**/*.js : Pass structured metadata to Winston logger: info('Message processed', { userId, channelId })

Applied to files:

  • scripts/generate-openapi.js
📚 Learning: 2026-02-27T16:24:15.055Z
Learnt from: CR
Repo: VolvoxLLC/volvox-bot PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-27T16:24:15.055Z
Learning: Applies to src/logger.js : Logging transport must use Winston with daily file rotation; the PostgreSQL logging transport is a stateful long-lived transport requiring reactive onConfigChange() wiring

Applied to files:

  • scripts/generate-openapi.js
🧬 Code graph analysis (2)
src/api/swagger.js (1)
src/api/routes/config.js (1)
  • path (70-70)
src/api/server.js (1)
src/api/swagger.js (2)
  • swaggerSpec (143-143)
  • swaggerSpec (143-143)
🔇 Additional comments (52)
src/api/routes/config.js (2)

104-126: LGTM!

The OpenAPI documentation for GET /config accurately describes the endpoint behavior, including security requirements (ApiKeyAuth and BearerAuth), and appropriate error responses (401, 403). The response schema correctly indicates that sensitive fields are masked.


141-206: LGTM!

The OpenAPI documentation for PUT /config comprehensively covers all response scenarios including 200 (success), 207 (partial success), 400 (validation errors), and 500 (all writes failed). The request body schema and writable sections are clearly documented.

src/api/routes/community.js (4)

58-129: LGTM!

The OpenAPI documentation for the leaderboard endpoint accurately documents pagination parameters (limit with min/max constraints, page), response schema including XP/level progression fields, and appropriate error responses (429, 500, 503).


218-298: LGTM!

The showcases endpoint documentation correctly describes the sort parameter enum (upvotes, recent), pagination, and response schema with project details including nullable URL fields.


381-436: LGTM!

The stats endpoint documentation accurately reflects the aggregate statistics returned, including memberCount, totalMessagesSent, activeProjects, challengesCompleted, and topContributors array.


531-632: LGTM!

The profile endpoint documentation is comprehensive, covering all response fields including user info, XP progression, activity stats, projects array, and recentBadges. The 404 response for non-public profiles is correctly documented.

src/api/routes/auth.js (4)

112-130: LGTM!

The OAuth initiation endpoint documentation correctly describes the 302 redirect to Discord, rate limiting (429), and the 500 error for misconfigured OAuth.


167-219: LGTM!

The callback endpoint documentation comprehensively covers all error scenarios: 400 (missing code), 401 (token exchange failure), 403 (invalid state), 500 (server error), and 502 (invalid Discord response). The parameter documentation for code and state query params is accurate.


353-392: LGTM!

The /auth/me endpoint documentation accurately describes the response schema including userId, username, avatar, and guilds array with proper field types. The 503 response for session store unavailability is correctly documented.


423-445: LGTM!

The logout endpoint documentation correctly describes the POST method, BearerAuth security requirement, and success response.

src/api/routes/webhooks.js (1)

15-69: LGTM!

The OpenAPI documentation accurately describes the webhook endpoint behavior: API secret authentication only (OAuth rejection documented in 403 response), required request body fields (guildId, path, value), and appropriate error responses. The description clearly states OAuth is not accepted, matching the runtime check at line 71.

docs/introduction.mdx (1)

1-35: LGTM!

The introduction page provides a clear overview of the API, with appropriate placeholders for deployment-specific values and accurate rate limit header documentation matching the X-RateLimit-* headers typically returned by rate-limited endpoints.

src/api/routes/moderation.js (6)

39-143: LGTM!

The OpenAPI documentation for listing mod cases is comprehensive: pagination parameters with constraints (limit max: 100), filter parameters (targetId, action with enum), and response schema including the newly added limit field. The 429 RateLimited response is correctly documented.


208-210: LGTM!

Good addition of the limit field to the response, making the pagination contract explicit for API consumers.


220-314: LGTM!

The case detail endpoint documentation accurately describes the response including scheduled actions array with proper field types and nullable annotations. The 429 response is now included.


376-435: LGTM!

The moderation stats endpoint documentation correctly describes the aggregate response structure including byAction as an object with additionalProperties for the dynamic action-to-count mapping. The 429 response is documented.


510-598: LGTM!

The user history endpoint documentation is complete with pagination parameters, response schema including the limit field, and byAction breakdown. The 429 response is correctly documented.


668-670: LGTM!

Consistent addition of the limit field to the user history response, matching the documentation schema.

docs/mint.json (1)

1-137: LGTM!

The Mintlify configuration is well-structured with proper navigation covering all documented API groups. Previous issues (hardcoded localhost URL and missing endpoint navigation) have been addressed - the baseUrl now uses a relative path /api/v1 and navigation includes all endpoint groups including Moderation stats/user-history, Conversations, and Tickets.

src/api/routes/tickets.js (3)

31-72: LGTM!

The OpenAPI documentation for the ticket stats endpoint is comprehensive, including all relevant response codes (401, 403, 429, 500, 503) that match the middleware chain (ticketRateLimit, requireGuildAdmin, validateGuild) and implementation. The 429 response was appropriately added to address the previous review comment.


120-200: LGTM!

The ticket detail endpoint documentation accurately describes the response schema including nullable fields with proper nullable: true annotations, the status enum, and all error responses (400, 401, 403, 404, 429, 500, 503).


237-335: LGTM!

The list tickets endpoint documentation properly documents pagination parameters with defaults and maximums, filter options (status, user), and the paginated response schema. All appropriate error responses are included.

package.json (3)

22-22: LGTM!

The docs:generate script addition aligns with the PR objectives to enable OpenAPI spec generation via node scripts/generate-openapi.js.


36-36: LGTM!

The swagger-jsdoc dependency (^6.2.8) is appropriate for generating OpenAPI specs from JSDoc annotations, which is central to this PR's objectives.


26-26: No action needed—@anthropic-ai/sdk is actively used in the tldr command (src/commands/tldr.js) and is properly tested (tests/commands/tldr.test.js). The addition is intentional and necessary for the application's functionality.

Likely an incorrect or invalid review comment.

src/api/routes/members.js (5)

49-83: LGTM!

The CSV export endpoint documentation correctly describes the text/csv response content type and includes all relevant error responses matching the middleware chain.


183-296: LGTM!

The list members endpoint documentation thoroughly covers pagination parameters (limit with min/max, after cursor), filtering (search), sorting (sort, order with enums), and the enriched response schema including nested objects for roles and nullable fields.


436-560: LGTM!

The member detail endpoint documentation provides a comprehensive schema covering stats, reputation (with level progression), warnings, and roles. The nested object structures accurately reflect the implementation.


673-758: LGTM!

The member cases endpoint documentation properly describes pagination parameters and the case history response schema including all relevant fields (case_number, action, reason, moderator info, timestamps).


817-889: LGTM!

The XP adjustment endpoint documentation correctly specifies the POST method, required request body with the amount field, and response schema. The description accurately reflects the implementation constraints (non-zero integer between ±1,000,000, XP floors at 0).

src/api/routes/conversations.js (5)

147-257: LGTM!

The list conversations endpoint documentation comprehensively covers all query parameters (pagination, search, user, channel, date filters) and the grouped conversation response schema with participant details.


348-410: LGTM!

The conversation stats endpoint documentation now includes the 429 response (addressing the previous review comment) and accurately describes the analytics response schema including topUsers, dailyActivity, and estimatedTokens.


498-595: LGTM!

The flags endpoint documentation now includes the 429 response (addressing the previous review comment) and properly documents the status filter enum and the detailed flagged message response schema.


668-744: LGTM!

The conversation detail endpoint documentation now includes both 403 and 429 responses (addressing the previous review comment) and accurately describes the message array with flag status, duration, and token estimate.


852-925: LGTM!

The flag message endpoint documentation now includes 403 and 429 responses (addressing the previous review comment) and properly documents the request body with messageId, reason, and notes fields including maxLength constraints.

src/api/server.js (2)

11-11: LGTM!

The import of swaggerSpec from ./swagger.js correctly integrates the OpenAPI spec generation module.


68-70: LGTM!

The /api/docs.json endpoint is appropriately placed before the versioned API routes and marked as public for Mintlify integration. The endpoint is still protected by the global rate limiter applied at line 66.

tests/api/routes/moderation.test.js (4)

82-82: LGTM!

The assertion for the default limit value (25) ensures the API response matches the OpenAPI documentation.


144-144: LGTM!

The assertion verifies custom pagination limit values are correctly returned in responses.


159-159: LGTM!

The assertion confirms the limit is capped at 100 as documented in the OpenAPI spec.


375-375: LGTM!

The assertion for user history pagination limit ensures consistency with the moderation cases endpoint behavior.

docs/authentication.mdx (1)

1-37: LGTM!

The authentication documentation is clear and accurate. The OAuth callback path has been corrected to /api/v1/auth/discord/callback (addressing the previous review comment), and the public endpoints list correctly identifies unauthenticated routes.

src/api/routes/guilds.js (5)

317-440: LGTM — OpenAPI documentation for GET /guilds is comprehensive.

The documentation correctly covers the success response schema with all fields (id, name, icon, memberCount, access), the 401/502/503/500 error responses, and both authentication methods. The schema accurately reflects the implementation's return values for OAuth users, bot owners, and API-secret authentication.


466-532: LGTM — GET /guilds/{id} schema aligns with implementation.

The OpenAPI spec correctly documents the response including the channels array with typed properties, channelCount, and all other fields. The 404 response for validateGuild middleware is properly documented.


578-627: LGTM — GET /guilds/{id}/roles documentation is accurate.

The schema correctly defines color as type: integer matching Discord's decimal color representation, and the response structure (id, name, color) aligns with the implementation at line 624.


1354-1447: LGTM — /guilds/{id}/moderation pagination schema is correct.

The response schema properly documents page, limit, total, and cases array, matching the implementation at lines 1437-1442.


1449-1563: LGTM — POST /guilds/{id}/actions documentation matches runtime behavior.

The 201 response with { id, channelId, content } and the 404 response for channel-not-found are correctly documented, aligning with the implementation at lines 1541 and 1555.

src/api/swagger.js (3)

1-12: LGTM — Clean ESM setup with proper Node.js protocol imports.

The file correctly uses node:path and node:url protocols as per coding guidelines, and the JSON import assertion syntax (with { type: 'json' }) is valid for modern Node.js versions.


14-67: LGTM — Well-structured OpenAPI definition with reusable components.

The configuration properly defines:

  • OpenAPI 3.0.3 for nullable compatibility
  • Both security schemes (ApiKeyAuth header and BearerAuth JWT)
  • Reusable schemas (Error, ValidationError, PaginatedResponse) that are referenced throughout route documentation

68-143: LGTM — Rate limit headers and standard responses are well-defined.

The X-RateLimit-* headers and common error responses (Unauthorized, Forbidden, NotFound, RateLimited, ServerError, ServiceUnavailable) provide consistent documentation referenced by route files via $ref.

tests/api/swagger.test.js (2)

36-75: LGTM — Comprehensive OpenAPI spec validation tests.

The tests thoroughly validate:

  • OpenAPI version and basic structure
  • Security schemes presence (ApiKeyAuth, BearerAuth)
  • Reusable schemas (Error, ValidationError, PaginatedResponse)
  • Rate limit headers
  • Coverage of all major route groups

This provides good regression protection for the API documentation.


77-86: LGTM — Public endpoint test validates unauthenticated access.

The test correctly verifies that /api/docs.json is publicly accessible without authentication, which aligns with typical API documentation exposure patterns.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 24 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (1)

tests/api/swagger.test.js:16

  • This test mocks an existing module by throwing an error during import (restartTracker.js). That makes the test less representative (it will still pass even if restartTracker.js has a real import-time/runtime failure) and can hide regressions in the optional-diagnostics path. Consider either letting the real module load (it has no heavy side effects) or mocking it with a minimal stub export instead of throwing.
vi.mock('../../src/utils/restartTracker.js', () => {
  throw new Error('Module not found');
});

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 1, 2026
@BillChirico BillChirico disabled auto-merge March 1, 2026 00:59
@BillChirico BillChirico merged commit 87b4b7a into main Mar 1, 2026
15 checks passed
@BillChirico BillChirico deleted the docs/openapi-swagger branch March 1, 2026 00:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs: OpenAPI/Swagger documentation for REST API

3 participants