Skip to content

feat: add REDIS_KEY_PREFIX env var for Redis ACL namespace isolation#365

Merged
KMKoushik merged 4 commits intousesend:mainfrom
tehidea:feat/redis-key-prefix
Mar 1, 2026
Merged

feat: add REDIS_KEY_PREFIX env var for Redis ACL namespace isolation#365
KMKoushik merged 4 commits intousesend:mainfrom
tehidea:feat/redis-key-prefix

Conversation

@designorant
Copy link
Contributor

@designorant designorant commented Feb 28, 2026

Summary

  • Add optional REDIS_KEY_PREFIX env var that namespaces all Redis and BullMQ keys (e.g. REDIS_KEY_PREFIX="usesend" prefixes all keys with usesend:)
  • Useful for shared Redis instances using ACL-based isolation, where each app gets its own key namespace
  • Disable ioredis enableReadyCheck and BullMQ version check to support managed Redis providers (e.g. Dragonfly, KeyDB) that may not expose INFO commands behind ACL

Changes

  • apps/web/src/server/redis.ts: Export getKeyPrefix() helper and prefixedKey() utility; configure ioredis with keyPrefix and disable ready check
  • All BullMQ queue/worker usages: Apply key prefix via BullMQ prefix option and disable version check
  • apps/web/src/env.js: Add REDIS_KEY_PREFIX to env schema
  • Docs/config: Add REDIS_KEY_PREFIX to .env.example, .env.selfhost.example, docker/prod/compose.yml, and self-hosting overview

Test plan

  • Verify existing behavior is unchanged when REDIS_KEY_PREFIX is not set (empty prefix, no colon separator)
  • Set REDIS_KEY_PREFIX="test" and verify all Redis keys are prefixed with test:
  • Verify BullMQ queues work correctly with the prefix (campaign scheduler, email queue, contact queue, webhook, cleanup jobs)
  • Verify ioredis connection works with managed Redis that restricts INFO command

Summary by cubic

Adds optional REDIS_KEY_PREFIX to namespace all Redis and BullMQ keys for ACL isolation. Also adjusts Redis/BullMQ setup to work with managed providers without changing behavior when unset.

  • New Features

    • Prefixes cache, rate-limit, lock, and idempotency keys via redisKey(); BullMQ Queues/Workers use BULL_PREFIX.
    • Defaults to empty; behavior is unchanged when unset.
    • Env schema and configs updated (.env examples, docker compose, self-hosting docs); fixed docker run example.
  • Bug Fixes

    • Disabled ioredis ready check and added skipVersionCheck to all BullMQ Queue/Worker constructors to avoid ACL-blocked INFO command failures.

Written for commit 9439041. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Added optional Redis key prefix support via a new environment variable; queueing and rate-limiting now respect the configured prefix so multiple apps can safely share a Redis instance.
  • Documentation

    • Updated self-hosting and Docker docs with guidance and examples for configuring the Redis key prefix and related env settings.

Adds optional REDIS_KEY_PREFIX env var that prefixes all Redis keys
(BullMQ queues via `prefix` option, cache/lock/rate-limit keys via
`redisKey()` helper). When unset, behavior is unchanged (BullMQ
defaults to "bull:", cache keys are unprefixed).

This enables self-hosters using Redis ACL multi-tenancy to restrict
useSend to its own key namespace (e.g. `~usesend:*`).

16 files changed across env schema, Redis module, 9 BullMQ queue/worker
files, and 5 direct Redis key operation sites.
…mple

Add REDIS_KEY_PREFIX env var to docker/prod/compose.yml, .env.example,
.env.selfhost.example, and self-hosting docs. Fix missing trailing
backslashes in standalone docker run example.
Redis ACL blocks INFO command (in @dangerous category). ioredis uses
INFO for ready check, BullMQ uses it for version detection. Without
these flags, BullMQ workers fail to initialize and silently stop
processing jobs.

- Add enableReadyCheck: false to ioredis connection
- Add skipVersionCheck: true to all 5 Queue + 5 Worker constructors
@vercel
Copy link

vercel bot commented Feb 28, 2026

@designorant is attempting to deploy a commit to the kmkoushik's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 28, 2026

Walkthrough

This PR adds Redis key prefixing: introduces REDIS_KEY_PREFIX env wiring and example docs; exports REDIS_PREFIX, BULL_PREFIX, and redisKey from the Redis module; updates caching to use prefixed keys and sets the Redis client option enableReadyCheck: false; and applies redisKey/BULL_PREFIX across rate limiting, idempotency, team/webhook services, and multiple BullMQ queue/worker initializations. Changes are backward-compatible when the prefix is empty.

Possibly related PRs

  • block sending emails on limits #216: Modifies apps/web/src/server/redis.ts and caching helpers — overlaps with this PR's redis module and withCache updates.
  • idempotency #282: Refactors idempotency-service keys to use a redisKey helper — directly related to this PR's idempotency key changes.

Suggested labels

codex

Suggested reviewers

  • KMKoushik
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes the main change: adding an optional REDIS_KEY_PREFIX environment variable for Redis ACL namespace isolation, which is the core feature across all modified files.

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


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.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/server/jobs/campaign-scheduler-job.ts (1)

17-23: ⚠️ Potential issue | 🟠 Major

Add skipVersionCheck: true to this Queue/Worker pair.

Both the Queue initialization (lines 17-23) and Worker initialization (line 86) are missing skipVersionCheck. Other queue services in the codebase (ses-hook-parser, webhook-service, email-queue-service, contact-queue-service, campaign-service) all include this option to support Redis providers that block the INFO command. This file needs the same fix:

Proposed fix
  private static schedulerQueue = new Queue<SchedulerJob>(
    CAMPAIGN_SCHEDULER_QUEUE,
    {
      connection: getRedis(),
      prefix: BULL_PREFIX,
+     skipVersionCheck: true,
    }
  );
@@
-  { connection: getRedis(), concurrency: 1, prefix: BULL_PREFIX }
+  {
+    connection: getRedis(),
+    concurrency: 1,
+    prefix: BULL_PREFIX,
+    skipVersionCheck: true,
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/server/jobs/campaign-scheduler-job.ts` around lines 17 - 23, The
Queue and Worker here need the skipVersionCheck flag added to their options to
support Redis providers that block INFO: update the static schedulerQueue
initialization (new Queue<SchedulerJob>(CAMPAIGN_SCHEDULER_QUEUE, { connection:
getRedis(), prefix: BULL_PREFIX })) to include skipVersionCheck: true, and
likewise add skipVersionCheck: true to the Worker options used for the
CampaignSchedulerJob worker (the Worker instantiation around the worker setup
at/near the worker initialization). Ensure both Queue and Worker option objects
include skipVersionCheck: true while keeping connection and prefix as they are.
🧹 Nitpick comments (7)
apps/web/src/server/redis.ts (1)

11-13: Normalize REDIS_KEY_PREFIX once to avoid accidental malformed namespaces.

If users set values like "usesend:" or " usesend ", keys become inconsistent (e.g., double separators). Normalize at source before deriving both prefixes.

Proposed refactor
+const NORMALIZED_REDIS_KEY_PREFIX = env.REDIS_KEY_PREFIX
+  .trim()
+  .replace(/:+$/, "");
+
-export const REDIS_PREFIX = env.REDIS_KEY_PREFIX
-  ? `${env.REDIS_KEY_PREFIX}:`
+export const REDIS_PREFIX = NORMALIZED_REDIS_KEY_PREFIX
+  ? `${NORMALIZED_REDIS_KEY_PREFIX}:`
   : "";
 
-export const BULL_PREFIX = env.REDIS_KEY_PREFIX || "bull";
+export const BULL_PREFIX = NORMALIZED_REDIS_KEY_PREFIX || "bull";

Also applies to: 19-19

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/server/redis.ts` around lines 11 - 13, Normalize
env.REDIS_KEY_PREFIX once before deriving REDIS_PREFIX to prevent malformed
namespaces (e.g., trailing/leading spaces or extra colons). Trim whitespace and
strip any leading/trailing ":" from env.REDIS_KEY_PREFIX, then compute
REDIS_PREFIX as `${normalizedPrefix ? normalizedPrefix + ":" : ""}`; update any
other places that derive a prefix (reference REDIS_PREFIX and the raw
env.REDIS_KEY_PREFIX usage) to use this normalized value so all keys share the
same consistent namespace.
apps/web/src/server/service/campaign-service.ts (1)

13-13: Consider using the ~/ alias for consistency.

Similar to ses-hook-parser.ts, this file uses a relative import "../redis" instead of the preferred ~/server/redis alias.

Suggested change
-import { getRedis, BULL_PREFIX } from "../redis";
+import { getRedis, BULL_PREFIX } from "~/server/redis";

As per coding guidelines: "Use the ~/alias for src imports in apps/web"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/server/service/campaign-service.ts` at line 13, The import in
campaign-service.ts uses a relative path ("../redis") which is inconsistent with
the project's ~/ alias; replace the relative import with the alias import (use
~/server/redis) where getRedis and BULL_PREFIX are imported so the file imports
getRedis and BULL_PREFIX from "~/server/redis" instead of "../redis" to match
the coding guideline and other files like ses-hook-parser.ts.
apps/web/src/server/service/ses-hook-parser.ts (1)

24-24: Consider using the ~/ alias for consistency.

The import uses a relative path "../redis" while the coding guidelines specify using the ~/ alias for src imports in apps/web. Other files in this PR use ~/server/redis.

Suggested change
-import { getRedis, BULL_PREFIX } from "../redis";
+import { getRedis, BULL_PREFIX } from "~/server/redis";

As per coding guidelines: "Use the /alias for src imports in apps/web (e.g., import { x } from '/utils/x')"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/server/service/ses-hook-parser.ts` at line 24, The import of
getRedis and BULL_PREFIX currently uses a relative path ("../redis"); update it
to use the apps/web src alias by importing from '~/server/redis' instead so it
matches other files and project guidelines—replace the "../redis" import with an
aliased import that still references the same exported symbols (getRedis,
BULL_PREFIX).
apps/web/src/server/service/webhook-service.ts (1)

13-13: Consider using the ~/ alias for consistency.

The import uses "../redis" instead of the preferred ~/server/redis alias.

Suggested change
-import { getRedis, BULL_PREFIX, redisKey } from "../redis";
+import { getRedis, BULL_PREFIX, redisKey } from "~/server/redis";

As per coding guidelines: "Use the ~/alias for src imports in apps/web"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/server/service/webhook-service.ts` at line 13, Update the import
in webhook-service.ts to use the project alias instead of a relative path:
replace the "../redis" import with the "~/server/redis" alias while keeping the
same named symbols (getRedis, BULL_PREFIX, redisKey) so existing references in
this module continue to work.
apps/web/src/server/service/email-queue-service.ts (1)

8-8: Use alias import for this new redis import.

Line 8 introduces a new relative ../redis import; in this path, use ~/server/redis.

Proposed fix
-import { getRedis, BULL_PREFIX } from "../redis";
+import { getRedis, BULL_PREFIX } from "~/server/redis";

As per coding guidelines, apps/web/src/**/*.{ts,tsx} should use the ~/alias for src imports in apps/web.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/server/service/email-queue-service.ts` at line 8, Replace the
relative import in email-queue-service.ts that currently imports getRedis and
BULL_PREFIX from "../redis" with the project alias path; update the import to
use "~/server/redis" so the symbols getRedis and BULL_PREFIX are imported via
the alias in the import statement for this module.
apps/web/src/server/jobs/campaign-scheduler-job.ts (1)

7-7: Use ~/ alias import for this changed source import.

Line 7 introduces a new relative import from ../redis; in apps/web/src, use the alias form for src imports.

Proposed fix
-import { getRedis, BULL_PREFIX } from "../redis";
+import { getRedis, BULL_PREFIX } from "~/server/redis";

As per coding guidelines, apps/web/src/**/*.{ts,tsx} should use the ~/alias for src imports in apps/web.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/server/jobs/campaign-scheduler-job.ts` at line 7, Replace the
relative import of the Redis helpers with the apps/web src alias: change the
import that currently pulls getRedis and BULL_PREFIX from "../redis" to use the
"~/..." alias form (i.e., import getRedis and BULL_PREFIX via the project's src
alias) so the symbols getRedis and BULL_PREFIX in campaign-scheduler-job.ts use
the approved alias import style.
apps/web/src/server/service/contact-queue-service.ts (1)

2-2: Prefer ~/server/redis over relative import for this new import.

Line 2 adds a new ../redis import in apps/web/src; switch this to alias style.

Proposed fix
-import { getRedis, BULL_PREFIX } from "../redis";
+import { getRedis, BULL_PREFIX } from "~/server/redis";

As per coding guidelines, apps/web/src/**/*.{ts,tsx} should use the ~/alias for src imports in apps/web.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/server/service/contact-queue-service.ts` at line 2, The import
in contact-queue-service.ts currently pulls getRedis and BULL_PREFIX from a
relative path; change the import to use the app alias by importing getRedis and
BULL_PREFIX from "~/server/redis" instead so the module uses the apps/web src
alias (update the import statement that references getRedis and BULL_PREFIX).
🤖 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/web/src/server/jobs/cleanup-email-bodies.ts`:
- Around line 20-23: The Queue/Worker initialization for the cleanup job lacks
the Redis ACL compatibility flag; update the instantiation of the Queue
(cleanupQueue = new Queue(...)) and the Worker (new Worker(...)) to include
skipVersionCheck: true in their options objects so BullMQ won't call INFO
against ACL-restricted Redis instances; locate the new Queue call assigned to
cleanupQueue and the Worker construction later in the file and add
skipVersionCheck: true alongside connection and prefix options.

In `@apps/web/src/server/jobs/usage-job.ts`:
- Around line 12-15: The Queue and Worker created in this module are missing the
BullMQ option skipVersionCheck: true; update the usageQueue instantiation (new
Queue(USAGE_QUEUE_NAME, ...)) to include skipVersionCheck: true in its options
object and likewise add skipVersionCheck: true to the Worker creation call (the
new Worker(...) instance around lines 71-74) so both Queue and Worker pass {
connection: getRedis(), prefix: BULL_PREFIX, skipVersionCheck: true } (or merge
that flag into their existing options).

In `@apps/web/src/server/jobs/webhook-cleanup-job.ts`:
- Around line 10-13: The Queue and corresponding Worker for the webhook cleanup
job are missing the option skipVersionCheck: true, which you must add to the
Queue instantiation (where webhookCleanupQueue is created with
WEBHOOK_CLEANUP_QUEUE, getRedis(), and BULL_PREFIX) and to the Worker creation
for the same queue (the Worker constructed for WEBHOOK_CLEANUP_QUEUE); update
both constructors' options objects to include skipVersionCheck: true to match
usage-job.ts and support managed Redis providers that disallow INFO.

---

Outside diff comments:
In `@apps/web/src/server/jobs/campaign-scheduler-job.ts`:
- Around line 17-23: The Queue and Worker here need the skipVersionCheck flag
added to their options to support Redis providers that block INFO: update the
static schedulerQueue initialization (new
Queue<SchedulerJob>(CAMPAIGN_SCHEDULER_QUEUE, { connection: getRedis(), prefix:
BULL_PREFIX })) to include skipVersionCheck: true, and likewise add
skipVersionCheck: true to the Worker options used for the CampaignSchedulerJob
worker (the Worker instantiation around the worker setup at/near the worker
initialization). Ensure both Queue and Worker option objects include
skipVersionCheck: true while keeping connection and prefix as they are.

---

Nitpick comments:
In `@apps/web/src/server/jobs/campaign-scheduler-job.ts`:
- Line 7: Replace the relative import of the Redis helpers with the apps/web src
alias: change the import that currently pulls getRedis and BULL_PREFIX from
"../redis" to use the "~/..." alias form (i.e., import getRedis and BULL_PREFIX
via the project's src alias) so the symbols getRedis and BULL_PREFIX in
campaign-scheduler-job.ts use the approved alias import style.

In `@apps/web/src/server/redis.ts`:
- Around line 11-13: Normalize env.REDIS_KEY_PREFIX once before deriving
REDIS_PREFIX to prevent malformed namespaces (e.g., trailing/leading spaces or
extra colons). Trim whitespace and strip any leading/trailing ":" from
env.REDIS_KEY_PREFIX, then compute REDIS_PREFIX as `${normalizedPrefix ?
normalizedPrefix + ":" : ""}`; update any other places that derive a prefix
(reference REDIS_PREFIX and the raw env.REDIS_KEY_PREFIX usage) to use this
normalized value so all keys share the same consistent namespace.

In `@apps/web/src/server/service/campaign-service.ts`:
- Line 13: The import in campaign-service.ts uses a relative path ("../redis")
which is inconsistent with the project's ~/ alias; replace the relative import
with the alias import (use ~/server/redis) where getRedis and BULL_PREFIX are
imported so the file imports getRedis and BULL_PREFIX from "~/server/redis"
instead of "../redis" to match the coding guideline and other files like
ses-hook-parser.ts.

In `@apps/web/src/server/service/contact-queue-service.ts`:
- Line 2: The import in contact-queue-service.ts currently pulls getRedis and
BULL_PREFIX from a relative path; change the import to use the app alias by
importing getRedis and BULL_PREFIX from "~/server/redis" instead so the module
uses the apps/web src alias (update the import statement that references
getRedis and BULL_PREFIX).

In `@apps/web/src/server/service/email-queue-service.ts`:
- Line 8: Replace the relative import in email-queue-service.ts that currently
imports getRedis and BULL_PREFIX from "../redis" with the project alias path;
update the import to use "~/server/redis" so the symbols getRedis and
BULL_PREFIX are imported via the alias in the import statement for this module.

In `@apps/web/src/server/service/ses-hook-parser.ts`:
- Line 24: The import of getRedis and BULL_PREFIX currently uses a relative path
("../redis"); update it to use the apps/web src alias by importing from
'~/server/redis' instead so it matches other files and project
guidelines—replace the "../redis" import with an aliased import that still
references the same exported symbols (getRedis, BULL_PREFIX).

In `@apps/web/src/server/service/webhook-service.ts`:
- Line 13: Update the import in webhook-service.ts to use the project alias
instead of a relative path: replace the "../redis" import with the
"~/server/redis" alias while keeping the same named symbols (getRedis,
BULL_PREFIX, redisKey) so existing references in this module continue to work.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between edcd32a and fbf9986.

📒 Files selected for processing (20)
  • .env.example
  • .env.selfhost.example
  • apps/docs/self-hosting/overview.mdx
  • apps/web/src/app/api/auth/[...nextauth]/route.ts
  • apps/web/src/env.js
  • apps/web/src/server/api/routers/waitlist.ts
  • apps/web/src/server/jobs/campaign-scheduler-job.ts
  • apps/web/src/server/jobs/cleanup-email-bodies.ts
  • apps/web/src/server/jobs/usage-job.ts
  • apps/web/src/server/jobs/webhook-cleanup-job.ts
  • apps/web/src/server/public-api/hono.ts
  • apps/web/src/server/redis.ts
  • apps/web/src/server/service/campaign-service.ts
  • apps/web/src/server/service/contact-queue-service.ts
  • apps/web/src/server/service/email-queue-service.ts
  • apps/web/src/server/service/idempotency-service.ts
  • apps/web/src/server/service/ses-hook-parser.ts
  • apps/web/src/server/service/team-service.ts
  • apps/web/src/server/service/webhook-service.ts
  • docker/prod/compose.yml

Add skipVersionCheck: true to Queue and Worker constructors in all 4 job
files (campaign-scheduler, cleanup-email-bodies, usage-job,
webhook-cleanup) to match the pattern already used in service files.
This prevents BullMQ version mismatch errors when using REDIS_KEY_PREFIX
with Redis ACL namespace isolation.
@designorant designorant force-pushed the feat/redis-key-prefix branch from fbf9986 to 9439041 Compare March 1, 2026 03:17
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: 1

🧹 Nitpick comments (2)
apps/web/src/server/service/contact-queue-service.ts (1)

2-2: Use ~/ alias for this src import.

Please switch this import to ~/server/redis to match repository import conventions for apps/web/src.

Proposed fix
-import { getRedis, BULL_PREFIX } from "../redis";
+import { getRedis, BULL_PREFIX } from "~/server/redis";

As per coding guidelines: apps/web/src/**/*.{ts,tsx}: Use the ~/ alias for imports from src in apps/web.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/server/service/contact-queue-service.ts` at line 2, The import
in contact-queue-service.ts currently pulls getRedis and BULL_PREFIX from a
relative path; change it to use the app alias by importing from "~/server/redis"
instead so it follows the apps/web/src import convention and keeps symbols
getRedis and BULL_PREFIX unchanged.
docker/README.md (1)

49-60: Document REDIS_KEY_PREFIX in the standalone docker run example.

This PR introduces REDIS_KEY_PREFIX, but the standalone command omits it. Adding it as optional keeps docs consistent across self-hosting paths.

Proposed doc patch
 docker run -d \
   -p 3000:3000 \
   -e NEXTAUTH_URL="<your-nextauth-url>" \
   -e NEXTAUTH_SECRET="<your-nextauth-secret>" \
   -e DATABASE_URL="<your-database-url>" \
   -e REDIS_URL="<your-redis-url>" \
+  -e REDIS_KEY_PREFIX="<optional-redis-key-prefix>" \
   -e AWS_ACCESS_KEY="<your-aws-access-key-id>" \
   -e AWS_SECRET_KEY="<your-aws-secret-access-key>" \
   -e AWS_DEFAULT_REGION="<your-aws-region>" \
   -e GITHUB_ID="<your-github-client-id>" \
   -e GITHUB_SECRET="<your-github-client-secret>" \
   usesend/usesend
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker/README.md` around lines 49 - 60, The docker run example is missing the
new environment variable REDIS_KEY_PREFIX; update the standalone docker run
command shown (the multi-line snippet that sets NEXTAUTH_URL, NEXTAUTH_SECRET,
DATABASE_URL, REDIS_URL, AWS_*, GITHUB_*) to include an optional -e
REDIS_KEY_PREFIX="<your-redis-key-prefix>" entry so the docs match the PR and
other self-hosting instructions; reference the existing env block in the README
snippet and add the REDIS_KEY_PREFIX line in the same style.
🤖 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/web/src/server/redis.ts`:
- Around line 11-13: Normalize env.REDIS_KEY_PREFIX by trimming any trailing
colon before composing REDIS_PREFIX (and the other prefix at the other
occurrence) to avoid double separators; update the logic that defines
REDIS_PREFIX (and the similar constant around the second occurrence) to first
remove a trailing ':' from env.REDIS_KEY_PREFIX (if present) and then append a
single ':' when building the final prefix so keys like "usesend::..." cannot
occur.

---

Nitpick comments:
In `@apps/web/src/server/service/contact-queue-service.ts`:
- Line 2: The import in contact-queue-service.ts currently pulls getRedis and
BULL_PREFIX from a relative path; change it to use the app alias by importing
from "~/server/redis" instead so it follows the apps/web/src import convention
and keeps symbols getRedis and BULL_PREFIX unchanged.

In `@docker/README.md`:
- Around line 49-60: The docker run example is missing the new environment
variable REDIS_KEY_PREFIX; update the standalone docker run command shown (the
multi-line snippet that sets NEXTAUTH_URL, NEXTAUTH_SECRET, DATABASE_URL,
REDIS_URL, AWS_*, GITHUB_*) to include an optional -e
REDIS_KEY_PREFIX="<your-redis-key-prefix>" entry so the docs match the PR and
other self-hosting instructions; reference the existing env block in the README
snippet and add the REDIS_KEY_PREFIX line in the same style.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fbf9986 and 9439041.

📒 Files selected for processing (15)
  • .env.example
  • .env.selfhost.example
  • apps/docs/self-hosting/overview.mdx
  • apps/web/src/server/jobs/campaign-scheduler-job.ts
  • apps/web/src/server/jobs/cleanup-email-bodies.ts
  • apps/web/src/server/jobs/usage-job.ts
  • apps/web/src/server/jobs/webhook-cleanup-job.ts
  • apps/web/src/server/redis.ts
  • apps/web/src/server/service/campaign-service.ts
  • apps/web/src/server/service/contact-queue-service.ts
  • apps/web/src/server/service/email-queue-service.ts
  • apps/web/src/server/service/ses-hook-parser.ts
  • apps/web/src/server/service/webhook-service.ts
  • docker/README.md
  • docker/prod/compose.yml
✅ Files skipped from review due to trivial changes (1)
  • .env.example
🚧 Files skipped from review as they are similar to previous changes (9)
  • docker/prod/compose.yml
  • apps/web/src/server/service/email-queue-service.ts
  • apps/web/src/server/jobs/webhook-cleanup-job.ts
  • apps/web/src/server/service/campaign-service.ts
  • apps/web/src/server/jobs/campaign-scheduler-job.ts
  • apps/web/src/server/service/webhook-service.ts
  • apps/web/src/server/service/ses-hook-parser.ts
  • .env.selfhost.example
  • apps/web/src/server/jobs/cleanup-email-bodies.ts

Comment on lines +11 to +13
export const REDIS_PREFIX = env.REDIS_KEY_PREFIX
? `${env.REDIS_KEY_PREFIX}:`
: "";
Copy link
Contributor

@coderabbitai coderabbitai bot Mar 1, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Normalize REDIS_KEY_PREFIX to prevent accidental double separators.

If REDIS_KEY_PREFIX is configured as usesend:, current composition yields keys like usesend::.... Trim trailing : once before building both prefixes.

Proposed fix
+const NORMALIZED_REDIS_KEY_PREFIX = env.REDIS_KEY_PREFIX.replace(/:+$/, "");
+
-export const REDIS_PREFIX = env.REDIS_KEY_PREFIX
-  ? `${env.REDIS_KEY_PREFIX}:`
+export const REDIS_PREFIX = NORMALIZED_REDIS_KEY_PREFIX
+  ? `${NORMALIZED_REDIS_KEY_PREFIX}:`
   : "";
@@
-export const BULL_PREFIX = env.REDIS_KEY_PREFIX || "bull";
+export const BULL_PREFIX = NORMALIZED_REDIS_KEY_PREFIX || "bull";

Also applies to: 19-19

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/server/redis.ts` around lines 11 - 13, Normalize
env.REDIS_KEY_PREFIX by trimming any trailing colon before composing
REDIS_PREFIX (and the other prefix at the other occurrence) to avoid double
separators; update the logic that defines REDIS_PREFIX (and the similar constant
around the second occurrence) to first remove a trailing ':' from
env.REDIS_KEY_PREFIX (if present) and then append a single ':' when building the
final prefix so keys like "usesend::..." cannot occur.

Copy link
Contributor Author

@designorant designorant Mar 1, 2026

Choose a reason for hiding this comment

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

Acknowledged — this is a reasonable defensive measure, but out of scope for this PR. The REDIS_KEY_PREFIX env var is documented without a trailing colon, and the Zod schema in env.js could enforce format constraints if needed.

Back to you to resolve.

Copy link
Contributor

Choose a reason for hiding this comment

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

@designorant Understood! That makes sense—documentation and schema validation are good safeguards. I'll mark this as resolved. If you'd like, I can open a follow-up issue to track the normalization enhancement for future consideration.


🧠 Learnings used
Learnt from: KalebJG
Repo: usesend/useSend PR: 362
File: apps/web/src/app/api/inbound_callback/route.ts:114-120
Timestamp: 2026-02-27T05:51:42.679Z
Learning: Actionable guideline: enforce PIIdata redaction across the codebase by centralizing with a Pino serializer rather than ad-hoc fixes. Treat logging of full email addresses at info level as a repository-wide concern and audit all ts files that log user identifiers. Implement or configure a Pino serializer to redact PII (e.g., emails) in info logs, document the policy, and apply it consistently in all logging sites (e.g., mailer.ts, inbound_callback routes, and similar modules).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No need for a follow-up issue, this is out of scope.

Copy link
Contributor

Choose a reason for hiding this comment

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

@designorant Got it, no problem! I'll leave it as is.


🧠 Learnings used
Learnt from: KalebJG
Repo: usesend/useSend PR: 362
File: apps/web/src/app/api/inbound_callback/route.ts:114-120
Timestamp: 2026-02-27T05:51:42.679Z
Learning: Actionable guideline: enforce PIIdata redaction across the codebase by centralizing with a Pino serializer rather than ad-hoc fixes. Treat logging of full email addresses at info level as a repository-wide concern and audit all ts files that log user identifiers. Implement or configure a Pino serializer to redact PII (e.g., emails) in info logs, document the policy, and apply it consistently in all logging sites (e.g., mailer.ts, inbound_callback routes, and similar modules).

@designorant
Copy link
Contributor Author

designorant commented Mar 1, 2026

Re: import alias nitpicks (../redis~/server/redis)

The ../redis relative imports in campaign-scheduler-job.ts, campaign-service.ts, ses-hook-parser.ts, webhook-service.ts, email-queue-service.ts, and contact-queue-service.ts are all pre-existing patterns — this PR only added BULL_PREFIX to existing import lines, it didn't introduce the relative path style.

@KMKoushik KMKoushik merged commit 62d7c44 into usesend:main Mar 1, 2026
1 of 2 checks passed
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.

2 participants