Conversation
WalkthroughThis PR implements API rate limiting (100 req/min) in Fastify, introduces comprehensive API reference documentation including authentication and deployment endpoints, restructures documentation site configuration, reorganizes feature documentation from Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ❌ 3❌ Failed checks (1 warning, 2 inconclusive)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
📝 Coding Plan
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. Comment Tip CodeRabbit can use OpenGrep to find security vulnerabilities and bugs across 17+ programming languages.OpenGrep is compatible with Semgrep configurations. Add an |
There was a problem hiding this comment.
5 issues found across 41 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/api/src/fastify.ts">
<violation number="1" location="apps/api/src/fastify.ts:56">
P1: Using the unvalidated `Authorization` header as the rate-limit key lets callers bypass the new limit by rotating fake tokens.</violation>
</file>
<file name="apps/docs/platform/deployments.mdx">
<violation number="1" location="apps/docs/platform/deployments.mdx:12">
P2: This image path does not exist in the repository, so the Demo section will render a broken image.</violation>
</file>
<file name="apps/docs/automations/incident-detection.mdx">
<violation number="1" location="apps/docs/automations/incident-detection.mdx:40">
P2: The branch regex example is incorrect: `hotfix/*` will not match branches like `hotfix/foo`. Use a pattern such as `^hotfix/.*` so the documented rule actually detects hotfix branches.</violation>
</file>
<file name="apps/docs/metrics-and-insights/dora.mdx">
<violation number="1" location="apps/docs/metrics-and-insights/dora.mdx:12">
P2: The demo image points to `/images/dora.png`, but that asset is not present in the repository, so this page will show a broken image.</violation>
</file>
<file name="apps/docs/platform/environments.mdx">
<violation number="1" location="apps/docs/platform/environments.mdx:29">
P2: These example names will not be treated as production environments, so deployments to `production-us`/`production-eu` are excluded from default DORA metrics.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| await scope.register(rateLimit, { | ||
| max: 100, | ||
| timeWindow: "1 minute", | ||
| keyGenerator: (request) => request.headers.authorization || request.ip, |
There was a problem hiding this comment.
P1: Using the unvalidated Authorization header as the rate-limit key lets callers bypass the new limit by rotating fake tokens.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/fastify.ts, line 56:
<comment>Using the unvalidated `Authorization` header as the rate-limit key lets callers bypass the new limit by rotating fake tokens.</comment>
<file context>
@@ -37,17 +38,28 @@ export async function buildApp(opts: FastifyServerOptions = {}) {
+ await scope.register(rateLimit, {
+ max: 100,
+ timeWindow: "1 minute",
+ keyGenerator: (request) => request.headers.authorization || request.ip,
+ });
+
</file context>
| keyGenerator: (request) => request.headers.authorization || request.ip, | |
| keyGenerator: (request) => request.ip, |
| ## Demo | ||
|
|
||
| <Frame> | ||
| <img src="/images/deployments.png" /> |
There was a problem hiding this comment.
P2: This image path does not exist in the repository, so the Demo section will render a broken image.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/docs/platform/deployments.mdx, line 12:
<comment>This image path does not exist in the repository, so the Demo section will render a broken image.</comment>
<file context>
@@ -0,0 +1,105 @@
+## Demo
+
+<Frame>
+ <img src="/images/deployments.png" />
+</Frame>
+
</file context>
| | Pattern | Description | | ||
| | ------------------ | -------------------------------------------------------- | | ||
| | **PR title regex** | Match pull request titles (e.g., `hotfix`, `emergency`). | | ||
| | **Branch regex** | Match branch names (e.g., `hotfix/*`). | |
There was a problem hiding this comment.
P2: The branch regex example is incorrect: hotfix/* will not match branches like hotfix/foo. Use a pattern such as ^hotfix/.* so the documented rule actually detects hotfix branches.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/docs/automations/incident-detection.mdx, line 40:
<comment>The branch regex example is incorrect: `hotfix/*` will not match branches like `hotfix/foo`. Use a pattern such as `^hotfix/.*` so the documented rule actually detects hotfix branches.</comment>
<file context>
@@ -0,0 +1,78 @@
+| Pattern | Description |
+| ------------------ | -------------------------------------------------------- |
+| **PR title regex** | Match pull request titles (e.g., `hotfix`, `emergency`). |
+| **Branch regex** | Match branch names (e.g., `hotfix/*`). |
+| **PR label regex** | Match pull request labels. |
+
</file context>
| | **Branch regex** | Match branch names (e.g., `hotfix/*`). | | |
| | **Branch regex** | Match branch names (e.g., `^hotfix/.*`). | |
| ## Demo | ||
|
|
||
| <Frame> | ||
| <img src="/images/dora.png" /> |
There was a problem hiding this comment.
P2: The demo image points to /images/dora.png, but that asset is not present in the repository, so this page will show a broken image.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/docs/metrics-and-insights/dora.mdx, line 12:
<comment>The demo image points to `/images/dora.png`, but that asset is not present in the repository, so this page will show a broken image.</comment>
<file context>
@@ -0,0 +1,89 @@
+## Demo
+
+<Frame>
+ <img src="/images/dora.png" />
+</Frame>
+
</file context>
| For most teams, the default `production` environment is all you need. Multiple environments are useful when: | ||
|
|
||
| - **You want to measure metrics for non-production environments** — for example, tracking deployment frequency to staging. | ||
| - **You have multiple production environments** — for example, regional deployments (`production-us`, `production-eu`). |
There was a problem hiding this comment.
P2: These example names will not be treated as production environments, so deployments to production-us/production-eu are excluded from default DORA metrics.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/docs/platform/environments.mdx, line 29:
<comment>These example names will not be treated as production environments, so deployments to `production-us`/`production-eu` are excluded from default DORA metrics.</comment>
<file context>
@@ -0,0 +1,47 @@
+For most teams, the default `production` environment is all you need. Multiple environments are useful when:
+
+- **You want to measure metrics for non-production environments** — for example, tracking deployment frequency to staging.
+- **You have multiple production environments** — for example, regional deployments (`production-us`, `production-eu`).
+
+## Archiving
</file context>
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
apps/docs/metrics-and-insights/team/code-review-distribution.mdx (1)
48-48: Consider a small wording polish for readability.“Assert your team members have…” reads a bit stiff here; “ensure communication stays healthy” is clearer.
✍️ Suggested copy tweak
-- Make sure your team feels safe giving feedback. Go through your team's <a href="/metrics-and-insights/pull-requests">Pull Requests</a> to assert your team members have a healthy communication style. +- Make sure your team feels safe giving feedback. Go through your team's <a href="/metrics-and-insights/pull-requests">Pull Requests</a> to ensure communication stays respectful and healthy.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/metrics-and-insights/team/code-review-distribution.mdx` at line 48, Replace the stiff phrase "assert your team members have a healthy communication style" with clearer wording like "ensure communication stays healthy" in the sentence that links to /metrics-and-insights/pull-requests (the line containing "Make sure your team feels safe giving feedback. Go through your team's <a href=\"/metrics-and-insights/pull-requests\">Pull Requests</a>..."); update the copy so the full sentence reads smoothly (for example: "Make sure your team feels safe giving feedback. Go through your team's Pull Requests to ensure communication stays healthy.") and keep the existing link target unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/api/src/fastify.ts`:
- Around line 53-56: The rate-limiting keyGenerator currently uses the raw
request.headers.authorization which fragments buckets; update the keyGenerator
in the rateLimit registration to normalize the authorization value: read
request.headers.authorization, trim whitespace, remove a case-insensitive
"Bearer" prefix if present, then use that normalized token (or fallback to
request.ip) as the key; optionally hash the normalized token before returning to
avoid storing raw credentials in memory. This change should be made inside the
existing keyGenerator function used when registering rateLimit.
In `@apps/docs/api-reference/deployments/create-deployment.mdx`:
- Around line 56-58: Update the curl examples in create-deployment.mdx so the
Authorization header sends the raw API key string (e.g., "Authorization:
YOUR_API_KEY") instead of using the "Bearer " prefix; locate the curl request
block that currently has -H "Authorization: Bearer YOUR_API_KEY" (the example
used for the /v1/deployments POST) and replace the header value to remove
"Bearer " in both occurrences (the example near the first curl block and the
repeated example later) so the server-side findApiKeyOrThrow receives the raw
key to hash and validate.
In `@apps/docs/automations/incident-detection.mdx`:
- Around line 35-40: Replace the glob example in the "Branch regex" table row
(the **Branch regex** entry) with a proper regular expression: use an anchored
pattern that begins with "hotfix/" and matches one or more characters after the
slash (escape the "/" if your renderer requires it) so branch names like
"hotfix/fix-login" are matched instead of the glob "hotfix/*".
In `@apps/docs/metrics-and-insights/team/time-to-merge.mdx`:
- Line 24: Fix the singular/plural mismatch in the sentence "Ideally, most small
Pull Requests should be merged within an hour of it being approved." by
replacing "it being approved" with a plural form such as "their approval" or
rephrasing to "they are approved" so the pronoun agrees with "Pull Requests".
In `@apps/docs/platform/environments.mdx`:
- Around line 26-29: Update the paragraph that lists "production-us" and
"production-eu" to explicitly state that only exact names "production" or "prod"
are auto-detected for default DORA metrics; for regional production environments
like "production-us" or "production-eu" you must explicitly set the production
flag so they will be counted. Reference the existing wording about
auto-detection (the sentence that currently says only exact `production`/`prod`
names are auto-detected) and add a short caveat after the bullet about multiple
production environments clarifying the need to set the production flag for
regional names.
---
Nitpick comments:
In `@apps/docs/metrics-and-insights/team/code-review-distribution.mdx`:
- Line 48: Replace the stiff phrase "assert your team members have a healthy
communication style" with clearer wording like "ensure communication stays
healthy" in the sentence that links to /metrics-and-insights/pull-requests (the
line containing "Make sure your team feels safe giving feedback. Go through your
team's <a href=\"/metrics-and-insights/pull-requests\">Pull Requests</a>...");
update the copy so the full sentence reads smoothly (for example: "Make sure
your team feels safe giving feedback. Go through your team's Pull Requests to
ensure communication stays healthy.") and keep the existing link target
unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c445e0ae-972b-44b9-b4a5-1e611d6b2baa
📒 Files selected for processing (41)
apps/api/src/fastify.tsapps/docs/about/data-privacy-and-security.mdxapps/docs/about/open-source.mdxapps/docs/about/principles.mdxapps/docs/api-reference/authentication.mdxapps/docs/api-reference/deployments/create-deployment.mdxapps/docs/api-reference/introduction.mdxapps/docs/api-reference/rate-limit.mdxapps/docs/automations/alerts.mdxapps/docs/automations/digests.mdxapps/docs/automations/incident-detection.mdxapps/docs/automations/pr-size-labeler.mdxapps/docs/automations/pr-title-check.mdxapps/docs/docs.jsonapps/docs/features/automations/intro.mdxapps/docs/features/deployments.mdxapps/docs/features/environments.mdxapps/docs/get-started/get-started.mdxapps/docs/get-started/intro.mdxapps/docs/get-started/self-host.mdxapps/docs/metrics-and-insights/code-reviews.mdxapps/docs/metrics-and-insights/dora.mdxapps/docs/metrics-and-insights/pull-requests.mdxapps/docs/metrics-and-insights/team/code-review-distribution.mdxapps/docs/metrics-and-insights/team/cycle-time.mdxapps/docs/metrics-and-insights/team/intro.mdxapps/docs/metrics-and-insights/team/pr-size-distribution.mdxapps/docs/metrics-and-insights/team/time-to-approve.mdxapps/docs/metrics-and-insights/team/time-to-first-review.mdxapps/docs/metrics-and-insights/team/time-to-merge.mdxapps/docs/metrics-and-insights/wip.mdxapps/docs/metrics-and-insights/work-log.mdxapps/docs/mint.jsonapps/docs/platform/applications.mdxapps/docs/platform/deployments.mdxapps/docs/platform/environments.mdxapps/docs/platform/incidents.mdxapps/docs/platform/integrations.mdxapps/docs/platform/people.mdxapps/docs/platform/teams.mdxapps/docs/snippets/pr-badge.mdx
💤 Files with no reviewable changes (6)
- apps/docs/snippets/pr-badge.mdx
- apps/docs/features/automations/intro.mdx
- apps/docs/mint.json
- apps/docs/features/environments.mdx
- apps/docs/features/deployments.mdx
- apps/docs/get-started/get-started.mdx
| await scope.register(rateLimit, { | ||
| max: 100, | ||
| timeWindow: "1 minute", | ||
| keyGenerator: (request) => request.headers.authorization || request.ip, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, find and read the fastify.ts file
find . -name "fastify.ts" -path "*/apps/api/*" | head -20Repository: sweetr-dev/sweetr.dev
Length of output: 90
🏁 Script executed:
# Get the file and inspect the specific lines
cat -n apps/api/src/fastify.ts | sed -n '40,70p'Repository: sweetr-dev/sweetr.dev
Length of output: 1094
🏁 Script executed:
# Search for rate-limit usage in the file
rg "rateLimit|rate-limit" apps/api/src/fastify.ts -B 5 -A 10Repository: sweetr-dev/sweetr.dev
Length of output: 1121
🌐 Web query:
@fastify/rate-limit keyGenerator documentation behavior
💡 Result:
In @fastify/rate-limit, keyGenerator is the function used to compute the unique “client key” that the limiter tracks counters against.
- Signature/behavior:
keyGenerator(request)can be sync or async and must return an identifier (typically a string) that will be used as the rate-limit key. The same generated key is also passed into other dynamic options likemax,timeWindow, andallowList(as thekeyargument). [1] - Default:
keyGeneratordefaults to(request) => request.ip. [1] - What
request.ipmeans here: Fastify resolves it fromrequest.connection.remoteAddress, or fromrequest.headers['x-forwarded-for']only if Fastify’strustProxyoption is enabled. [1] - Related option: If you set
groupId, it’s added on top of thekeyGeneratorresult to group multiple routes under a separate shared limit bucket. [1]
Sources: [1]
🏁 Script executed:
# Check what deploymentsRouter does and if it uses bearer tokens
find . -name "*deployments*router*" -type fRepository: sweetr-dev/sweetr.dev
Length of output: 116
🏁 Script executed:
# Look for any existing authorization/token handling patterns
rg "Authorization|Bearer" apps/api/src --type ts -B 2 -A 2 | head -40Repository: sweetr-dev/sweetr.dev
Length of output: 3155
🏁 Script executed:
# Check if there are any tests or documentation about rate limiting
rg "rate.*limit|rateLimit" apps/api/src --type ts -lRepository: sweetr-dev/sweetr.dev
Length of output: 963
🏁 Script executed:
# Check the deployments router to understand what API it handles
cat -n apps/api/src/app/deployment/deployments.router.ts | head -50Repository: sweetr-dev/sweetr.dev
Length of output: 1342
🏁 Script executed:
# Check if there's a rate-limiter plugin that might give context
cat -n apps/api/src/lib/rate-limiter.plugin.tsRepository: sweetr-dev/sweetr.dev
Length of output: 662
🏁 Script executed:
# Look for any API documentation or tests for deployments
find . -name "*deployment*" -type f | grep -E "(test|spec|doc|README)" | head -10Repository: sweetr-dev/sweetr.dev
Length of output: 161
🏁 Script executed:
# Check the deployment API documentation
cat -n apps/docs/api-reference/deployments/create-deployment.mdx | head -60Repository: sweetr-dev/sweetr.dev
Length of output: 2482
🏁 Script executed:
# Look at the findApiKeyOrThrow function to understand how it parses the Authorization header
find . -name "*api-key*" -type f | grep serviceRepository: sweetr-dev/sweetr.dev
Length of output: 121
🏁 Script executed:
# Check how findApiKeyOrThrow processes the authorization header
rg "findApiKeyOrThrow" apps/api/src --type ts -A 20 | head -50Repository: sweetr-dev/sweetr.dev
Length of output: 3785
🏁 Script executed:
# Check how `@fastify/rate-limit` treats the rate limit key - is it persisted or in-memory?
# Also check if there's any hashing happening
rg "class|function" --type ts -A 5 apps/api/src/lib/rate-limiter.plugin.tsRepository: sweetr-dev/sweetr.dev
Length of output: 47
🏁 Script executed:
# Look at the full api-keys service to understand the complete flow
cat -n apps/api/src/app/api-keys/services/api-keys.service.tsRepository: sweetr-dev/sweetr.dev
Length of output: 2044
🌐 Web query:
@fastify/rate-limit key storage persistence memory or persistent
💡 Result:
@fastify/rate-limit stores counters/keys in memory by default (per Node.js process), so limits reset on process restart and aren’t shared across multiple instances/PM2/containers. To make rate-limits survive process restarts and/or work across multiple servers, you need an external store—the plugin supports Redis via the redis option (uses ioredis), or you can provide your own persistent backend via the store option (e.g., SQL/Mongo/etc.). [1][2]
🏁 Script executed:
# Verify if there are any tests or usage patterns for the deployments API
rg "deployments" apps/api/src --type ts -l | grep -E "(test|spec)" | head -5Repository: sweetr-dev/sweetr.dev
Length of output: 131
🏁 Script executed:
# Check if there's any existing Bearer token normalization pattern elsewhere
rg "Bearer|bearer" apps/api/src --type ts -B 2 -A 2 | grep -i strip\|replace\|normalize | head -10Repository: sweetr-dev/sweetr.dev
Length of output: 47
🏁 Script executed:
# Look at how the authorization header is typically formatted when passed through
rg "headers\.authorization" apps/api/src --type ts -B 2 -A 2 | head -30Repository: sweetr-dev/sweetr.dev
Length of output: 669
🏁 Script executed:
# Look for integration tests that might show how the deployment API is actually called
cat -n apps/api/src/app/metrics/services/dora-metrics.integration.test.ts | head -80Repository: sweetr-dev/sweetr.dev
Length of output: 3217
🏁 Script executed:
# Check if there's any middleware or guard that normalizes the Authorization header before routing
rg "middleware|guard|pre-handler" apps/api/src/fastify.ts -B 5 -A 5Repository: sweetr-dev/sweetr.dev
Length of output: 47
🏁 Script executed:
# Search for any normalization of authorization header in the codebase
rg "authorization" apps/api/src --type ts -B 3 -A 3 | grep -i "trim\|normalize\|strip\|replace\|Bearer" -A 2 -B 2Repository: sweetr-dev/sweetr.dev
Length of output: 47
🏁 Script executed:
# Check if there's an HTTP client or test that calls the deployment API to understand how Authorization is formatted
rg "POST.*deployments\|/v1/deployments" apps/api/src --type ts -B 5 -A 10Repository: sweetr-dev/sweetr.dev
Length of output: 47
🏁 Script executed:
# Look for any e2e or integration tests that hit the actual HTTP endpoint
find . -name "*.test.ts" -o -name "*.spec.ts" | xargs rg "/v1/deployments" 2>/dev/null | head -20Repository: sweetr-dev/sweetr.dev
Length of output: 47
🏁 Script executed:
# Check if findApiKeyOrThrow is actually expecting just the token or the full Authorization header
rg "findApiKeyOrThrow" apps/api/src --type ts -B 3 -A 10 | head -60Repository: sweetr-dev/sweetr.dev
Length of output: 2920
🏁 Script executed:
# Search for any Bearer prefix handling anywhere in the codebase
rg "Bearer" apps/api/src --type ts -C 3Repository: sweetr-dev/sweetr.dev
Length of output: 2458
🏁 Script executed:
# Look at the full auth plugin to understand how it handles Bearer tokens
cat -n apps/api/src/app/auth/resolvers/plugins/auth.plugin.ts | head -50Repository: sweetr-dev/sweetr.dev
Length of output: 1859
🏁 Script executed:
# Check if deployments router is part of a different auth flow or if it's broken
rg "deploymentsRouter" apps/api/src --type ts -B 2 -A 2Repository: sweetr-dev/sweetr.dev
Length of output: 1183
🏁 Script executed:
# Verify: does API actually use bearerToken somewhere to normalize it?
rg "bearerToken\|authorization" apps/api/src/app/auth/resolvers/plugins/auth.plugin.ts -B 3 -A 3 | head -40Repository: sweetr-dev/sweetr.dev
Length of output: 47
🏁 Script executed:
# Check if there's any middleware or pre-handler that normalizes the Authorization header before routing
rg "preHandler|hook|middleware" apps/api/src/fastify.ts -B 3 -A 3Repository: sweetr-dev/sweetr.dev
Length of output: 47
🏁 Script executed:
# Look for any request normalization or auth header processing
rg "request.headers.authorization" apps/api/src --type ts -B 5 -A 5 | head -50Repository: sweetr-dev/sweetr.dev
Length of output: 1643
Normalize the Authorization header key for rate-limiting to prevent bucketing fragmentation.
The current keyGenerator uses the raw Authorization header, which fragments the 100 req/min limit across variants: Bearer abc, abc, Bearer abc (extra space), and different casings all create separate rate-limit buckets. This allows clients to bypass the rate limit by varying header formatting. Additionally, the raw credential is retained as the rate-limit key in the in-memory store.
Extract and normalize the token before using it as the rate-limit key. Whitespace should be trimmed, and the Bearer prefix stripped if present. Hashing is optional for rate-limiting, but normalization is essential to enforce the limit per API key.
🔧 Suggested baseline fix
await scope.register(rateLimit, {
max: 100,
timeWindow: "1 minute",
- keyGenerator: (request) => request.headers.authorization || request.ip,
+ keyGenerator: (request) => {
+ const authorization = request.headers.authorization?.trim();
+ if (!authorization) {
+ return request.ip;
+ }
+
+ return authorization.replace(/^Bearer\s+/i, "");
+ },
});🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/api/src/fastify.ts` around lines 53 - 56, The rate-limiting keyGenerator
currently uses the raw request.headers.authorization which fragments buckets;
update the keyGenerator in the rateLimit registration to normalize the
authorization value: read request.headers.authorization, trim whitespace, remove
a case-insensitive "Bearer" prefix if present, then use that normalized token
(or fallback to request.ip) as the key; optionally hash the normalized token
before returning to avoid storing raw credentials in memory. This change should
be made inside the existing keyGenerator function used when registering
rateLimit.
| curl -X POST https://api.sweetr.dev/v1/deployments \ | ||
| -H "Authorization: Bearer YOUR_API_KEY" \ | ||
| -H "Content-Type: application/json" \ |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Verify whether /v1/deployments normalizes the Authorization header
# before calling findApiKeyOrThrow.
rg -n -C3 --type=ts 'findApiKeyOrThrow|authorization|Bearer|addHook|onRequest|preHandler' apps/api/srcRepository: sweetr-dev/sweetr.dev
Length of output: 31844
🏁 Script executed:
head -60 apps/api/src/app/api-keys/services/api-keys.service.tsRepository: sweetr-dev/sweetr.dev
Length of output: 1524
Fix Authorization header format in curl examples.
The /v1/deployments endpoint passes request.headers.authorization directly to findApiKeyOrThrow without stripping the Bearer prefix. findApiKeyOrThrow hashes the value as-is and compares against the stored key hash, which is the hash of the raw API key alone. Requests with Authorization: Bearer YOUR_API_KEY will fail with 401 because the hashed value won't match.
Change the examples to send the raw API key without the Bearer prefix:
Correct format for lines 56-58 and 73-75
curl -X POST https://api.sweetr.dev/v1/deployments \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs/api-reference/deployments/create-deployment.mdx` around lines 56 -
58, Update the curl examples in create-deployment.mdx so the Authorization
header sends the raw API key string (e.g., "Authorization: YOUR_API_KEY")
instead of using the "Bearer " prefix; locate the curl request block that
currently has -H "Authorization: Bearer YOUR_API_KEY" (the example used for the
/v1/deployments POST) and replace the header value to remove "Bearer " in both
occurrences (the example near the first curl block and the repeated example
later) so the server-side findApiKeyOrThrow receives the raw key to hash and
validate.
| Detects incidents based on patterns in pull request titles, branch names, or labels. Configure regular expressions to match your team's conventions. | ||
|
|
||
| | Pattern | Description | | ||
| | ------------------ | -------------------------------------------------------- | | ||
| | **PR title regex** | Match pull request titles (e.g., `hotfix`, `emergency`). | | ||
| | **Branch regex** | Match branch names (e.g., `hotfix/*`). | |
There was a problem hiding this comment.
Replace the branch example with an actual regex.
hotfix/* is a glob, not a regex. As written, it repeats /, so it will not match branch names like hotfix/fix-login.
✏️ Suggested doc tweak
-| **Branch regex** | Match branch names (e.g., `hotfix/*`). |
+| **Branch regex** | Match branch names (e.g., `^hotfix/.*`). |📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Detects incidents based on patterns in pull request titles, branch names, or labels. Configure regular expressions to match your team's conventions. | |
| | Pattern | Description | | |
| | ------------------ | -------------------------------------------------------- | | |
| | **PR title regex** | Match pull request titles (e.g., `hotfix`, `emergency`). | | |
| | **Branch regex** | Match branch names (e.g., `hotfix/*`). | | |
| Detects incidents based on patterns in pull request titles, branch names, or labels. Configure regular expressions to match your team's conventions. | |
| | Pattern | Description | | |
| | ------------------ | -------------------------------------------------------- | | |
| | **PR title regex** | Match pull request titles (e.g., `hotfix`, `emergency`). | | |
| | **Branch regex** | Match branch names (e.g., `^hotfix/.*`). | |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs/automations/incident-detection.mdx` around lines 35 - 40, Replace
the glob example in the "Branch regex" table row (the **Branch regex** entry)
with a proper regular expression: use an anchored pattern that begins with
"hotfix/" and matches one or more characters after the slash (escape the "/" if
your renderer requires it) so branch names like "hotfix/fix-login" are matched
instead of the glob "hotfix/*".
| ## What good looks like | ||
|
|
||
| Ideally, most small Pull Requests should be merged within a hour of it being approved. Teams should prioritize finishing work over starting new things. | ||
| Ideally, most small Pull Requests should be merged within an hour of it being approved. Teams should prioritize finishing work over starting new things. |
There was a problem hiding this comment.
Fix singular/plural agreement in this sentence.
The sentence starts plural (“Pull Requests”) but later uses singular pronoun (“it”).
✍️ Proposed fix
-Ideally, most small Pull Requests should be merged within an hour of it being approved. Teams should prioritize finishing work over starting new things.
+Ideally, most small Pull Requests should be merged within an hour of being approved. Teams should prioritize finishing work over starting new things.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Ideally, most small Pull Requests should be merged within an hour of it being approved. Teams should prioritize finishing work over starting new things. | |
| Ideally, most small Pull Requests should be merged within an hour of being approved. Teams should prioritize finishing work over starting new things. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs/metrics-and-insights/team/time-to-merge.mdx` at line 24, Fix the
singular/plural mismatch in the sentence "Ideally, most small Pull Requests
should be merged within an hour of it being approved." by replacing "it being
approved" with a plural form such as "their approval" or rephrasing to "they are
approved" so the pronoun agrees with "Pull Requests".
| For most teams, the default `production` environment is all you need. Multiple environments are useful when: | ||
|
|
||
| - **You want to measure metrics for non-production environments** — for example, tracking deployment frequency to staging. | ||
| - **You have multiple production environments** — for example, regional deployments (`production-us`, `production-eu`). |
There was a problem hiding this comment.
Mention that regional prod environments need the production flag set explicitly.
Lines 15-18 say only exact production/prod names are auto-detected. Without that caveat here, users can read production-us and production-eu as names that will count toward default DORA metrics automatically.
✏️ Suggested doc tweak
-- **You have multiple production environments** — for example, regional deployments (`production-us`, `production-eu`).
+- **You have multiple production environments** — for example, regional deployments (`production-us`, `production-eu`). Mark these as production manually, since only `production` and `prod` are auto-detected.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| For most teams, the default `production` environment is all you need. Multiple environments are useful when: | |
| - **You want to measure metrics for non-production environments** — for example, tracking deployment frequency to staging. | |
| - **You have multiple production environments** — for example, regional deployments (`production-us`, `production-eu`). | |
| For most teams, the default `production` environment is all you need. Multiple environments are useful when: | |
| - **You want to measure metrics for non-production environments** — for example, tracking deployment frequency to staging. | |
| - **You have multiple production environments** — for example, regional deployments (`production-us`, `production-eu`). Mark these as production manually, since only `production` and `prod` are auto-detected. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs/platform/environments.mdx` around lines 26 - 29, Update the
paragraph that lists "production-us" and "production-eu" to explicitly state
that only exact names "production" or "prod" are auto-detected for default DORA
metrics; for regional production environments like "production-us" or
"production-eu" you must explicitly set the production flag so they will be
counted. Reference the existing wording about auto-detection (the sentence that
currently says only exact `production`/`prod` names are auto-detected) and add a
short caveat after the bullet about multiple production environments clarifying
the need to set the production flag for regional names.
Greptile Summary
This PR introduces rate limiting to the public deployments REST API and performs a comprehensive documentation overhaul migrating from Mintlify v1 (
mint.json) to v2 (docs.json), restructuring the navigation and adding new content for the API Reference, Platform, and Metrics sections.Key changes:
POST /v1/deploymentsusing@fastify/rate-limit(100 req/min), keyed by theAuthorizationheader with IP fallback. The@fastify/rate-limitdependency is correctly present inpackage.json.fastify.ts:slackRouterandbullBoardRouterare grouped under "Integration APIs" before the Stripe conditional;deploymentsRouteris now wrapped in a rate-limited scope.mint.jsonreplaced bydocs.jsonwith an updated icon library (tabler), new "API Reference" tab, and restructured navigation (features split into Metrics & Insights, Automations, and Platform groups).POST /v1/deploymentsreference, DORA metrics, deployments/environments/incidents/applications platform pages, and incident detection automation docs.self-host.mdx, and removal of a spurious trailing;insnippets/pr-badge.mdx.Confidence Score: 5/5
@fastify/rate-limitto the deployments endpoint, which is a straightforward and self-contained addition. The dependency is already declared inpackage.json, the rate limit parameters match the documentation, thekeyGeneratorlogic is correct (falls back from auth header to IP), and the scoped registration approach correctly avoids rate-limiting unrelated routes like GraphQL (which already has@envelop/rate-limiter). The documentation changes are purely additive and don't affect runtime behavior.Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Client: POST /v1/deployments] --> B{Rate Limiter\n100 req/min\nper auth header or IP} B -->|Limit exceeded| C[429 Too Many Requests] B -->|Within limit| D{Auth Validation\nfindApiKeyOrThrow} D -->|Invalid| E[401 Unauthorized] D -->|Valid| F{Body Validation\nzod schema} F -->|Invalid| G[422 Unprocessable Entity] F -->|Valid| H[Enqueue Job:\nDEPLOYMENT_TRIGGERED_BY_API] H --> I[202 Accepted]Last reviewed commit: 0c32f97