diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml
deleted file mode 100644
index e31427464865..000000000000
--- a/.github/workflows/claude.yml
+++ /dev/null
@@ -1,51 +0,0 @@
-name: Claude Code
-
-on:
- issue_comment:
- types: [created]
- pull_request_review_comment:
- types: [created]
- issues:
- types: [opened, assigned]
- pull_request_review:
- types: [submitted]
-
-jobs:
- claude:
- if: |
- (
- (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude') && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) ||
- (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude') && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) ||
- (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude') && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.review.author_association)) ||
- (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')) && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.issue.author_association))
- )
- runs-on: ubuntu-latest
- permissions:
- contents: read
- pull-requests: read
- issues: read
- id-token: write
- actions: read # Required for Claude to read CI results on PRs
- steps:
- - name: Checkout repository
- uses: actions/checkout@v6
- with:
- fetch-depth: 1
-
- - name: Run Claude Code
- id: claude
- uses: anthropics/claude-code-action@v1
- with:
- claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
-
- # This is an optional setting that allows Claude to read CI results on PRs
- additional_permissions: |
- actions: read
-
- # Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
- # prompt: 'Update the pull request description to include a summary of changes.'
-
- # Optional: Add claude_args to customize behavior and configuration
- # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
- # or https://code.claude.com/docs/en/cli-reference for available options
- # claude_args: '--allowed-tools Bash(gh pr:*)'
diff --git a/README.md b/README.md
index 4c6ec06ae274..c475c2576966 100644
--- a/README.md
+++ b/README.md
@@ -1,24 +1,26 @@
[](https://monkeytype.com/)
-[](https://www.chartjs.org/)
-[](https://eslint.org/)
-[](https://expressjs.com/)
-[](https://firebase.google.com/)
-[](https://fontawesome.com/)
-[](https://developer.mozilla.org/en-US/docs/Web/HTML)
-[](https://www.mongodb.com/)
-[](https://oxc.rs/docs/guide/usage/linter.html)
-[](https://pnpm.io/)
-[](https://redis.io/)
-[](https://sass-lang.com/)
-[](https://www.solidjs.com/)
-[](https://tailwindcss.com/)
+[](https://animejs.com/)
+[](https://www.chartjs.org/)
+[](https://eslint.org/)
+[](https://expressjs.com/)
+[](https://firebase.google.com/)
+[](https://fontawesome.com/)
+[](https://developer.mozilla.org/en-US/docs/Web/HTML)
+[](https://www.mongodb.com/)
+[](https://oxc.rs/docs/guide/usage/linter.html)
+[](https://pnpm.io/)
+[](https://redis.io/)
+[](https://sass-lang.com/)
+[](https://www.solidjs.com/)
+[](https://tailwindcss.com/)
+[](https://tanstack.com/)
[](https://ts-rest.com/)
-[](https://turborepo.org/)
-[](https://www.typescriptlang.org/)
-[](https://vitejs.dev/)
-[](https://vitest.dev/)
+[](https://turborepo.org/)
+[](https://www.typescriptlang.org/)
+[](https://vitejs.dev/)
+[](https://vitest.dev/)
[](https://zod.dev/)
# About
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
index d040161513aa..d024a9d8c958 100644
--- a/docs/CONTRIBUTING.md
+++ b/docs/CONTRIBUTING.md
@@ -81,7 +81,7 @@ If you want to contribute languages but don't know how, check [LANGUAGES.md](/do
- Verify the `id` property is incremented correctly
- Please do not add extremely short quotes (less than 60 characters)
- For quotes not in English, please include translations of quotes in the description of your pull request. This assists in the verification process to ensure the integrity of the quotes.
-- Remember to name your pull request properly. For example, if you are adding new quotes for the language `French`, your pull request should be named `impr(quotes): add French quotes`.
+- Remember to name your pull request properly. For example, if you are adding new quotes for the language `French`, your pull request should be named `impr(quotes): add French quotes (@yourusername)`.
If you want to contribute quotes but don't know how, check [QUOTES.md](/docs/QUOTES.md)
diff --git a/docs/SELF_HOSTING.md b/docs/SELF_HOSTING.md
index dea22c83821e..191287299c5c 100644
--- a/docs/SELF_HOSTING.md
+++ b/docs/SELF_HOSTING.md
@@ -11,6 +11,7 @@
- [Prerequisites](#prerequisites)
- [Quickstart](#quickstart)
- [Hosting over the network (HTTPS)](#hosting-over-the-network-https)
+ - [Security](#security)
- [Account System](#account-system)
- [Setup Firebase](#setup-firebase)
- [Update backend configuration](#update-backend-configuration)
@@ -61,6 +62,30 @@ docker compose up -d --force-recreate
> After updating your configuration and recreating the containers, clear your browser cache or perform a hard reload (Ctrl + F5) to make sure your browser isn't running an old cached version of the frontend.
+## Security
+
+Do not expose the Monkeytype backend directly to the internet. Instead, place it behind a reverse proxy and configure the backend to only accept connections from the reverse proxy.
+
+The backend's built-in rate limiting is based on the authenticated user's `uid` or, for unauthenticated requests, the client's IP address.
+
+To determine the client's IP address, the backend checks the following sources in order:
+
+1. `CF-Connecting-IP` (when requests are proxied through Cloudflare)
+2. `X-Forwarded-For`
+3. The source IP address of the HTTP connection
+
+We recommend the following configuration:
+
+- If you are **not** using Cloudflare, remove any incoming `CF-Connecting-IP` header in your reverse proxy before forwarding requests.
+- Configure your reverse proxy to set the `X-Forwarded-For` header to the client's IP address.
+- Configure the backend to only accept connections from the reverse proxy to prevent clients from spoofing trusted headers.
+
+
+Sources:
+- [cloudflare documentation for cf-connecting-ip](https://developers.cloudflare.com/fundamentals/reference/http-headers/#cf-connecting-ip)
+- [handling headers in traefik](https://doc.traefik.io/traefik/reference/routing-configuration/http/middlewares/headers)
+
+
## Account System
By default, user sign-up and login are disabled. To enable this, you'll need to set up a Firebase project.
diff --git a/frontend/src/privacy-policy.html b/frontend/src/privacy-policy.html
index 4505cd492c4a..3ae78fa2e492 100644
--- a/frontend/src/privacy-policy.html
+++ b/frontend/src/privacy-policy.html
@@ -129,7 +129,7 @@
appears at the end of this Privacy Statement.
Table of Contents
- +