Skip to content

Add cold email notifier#1117

Merged
elie222 merged 7 commits intomainfrom
feat/cold-email-notify
Dec 19, 2025
Merged

Add cold email notifier#1117
elie222 merged 7 commits intomainfrom
feat/cold-email-notify

Conversation

@elie222
Copy link
Owner

@elie222 elie222 commented Dec 19, 2025

Add cold email notifier by introducing ActionType.NOTIFY_SENDER across UI, validation, and backend execution to send Resend-based notifications for cold outreach filtering

Introduce a new action type that displays dedicated UI copy, appears only for cold email rules when NEXT_PUBLIC_IS_RESEND_CONFIGURED is true, validates in schemas, and executes via utils/ai/actions.ts::notify_sender using Resend with a new email template and helper. Include enum/migration updates, icon/color mappings, and subject formatting fixes.

📍Where to Start

Start with the notify_sender flow in apps/web/utils/ai/actions.ts, then review the email send helper in apps/web/utils/cold-email/send-notification.ts and the Resend sender in packages/resend/src/send.tsx.


📊 Macroscope summarized 854178c. 19 files reviewed, 4 issues evaluated, 2 issues filtered, 2 comments posted

🗂️ Filtered Issues

apps/web/app/(app)/[emailAccountId]/assistant/constants.ts — 0 comments posted, 1 evaluated, 1 filtered
  • line 63: The getActionTypeColor function does not include a case to match strings containing "notify" or "sender", so any caller passing a string like "notify sender" will receive the fallback "bg-gray-500" instead of the newly added "bg-amber-500" color for ActionType.NOTIFY_SENDER. This is inconsistent with the pattern used for other action types in the function. [ Out of scope ]
apps/web/utils/actions/rule.validation.ts — 0 comments posted, 1 evaluated, 1 filtered
  • line 29: The new ActionType.NOTIFY_SENDER is added to zodActionType but no validation is added in the superRefine block of zodAction. If NOTIFY_SENDER requires specific fields (like content, subject, or recipient configuration similar to other email-related actions like FORWARD or SEND_EMAIL), users could create invalid rules that pass validation but fail at runtime when the action is executed. [ Low confidence ]

Summary by CodeRabbit

  • New Features
    • Added "Notify Sender" action across the UI with icon, label, tooltip, validation, DB enum, and backend delivery using a new notification email template and provider integration.
    • Added a cold-email "Test" tab in the blocker UI.
  • Bug Fixes
    • Reply subject generation improved (handles non-user messages and empty subjects).
  • Chores
    • Version bumped to v2.25.0 and added a runtime flag indicating external mail service configuration.
  • Style/Tools
    • Enhanced error utilities with sampling and robust error-message extraction.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Dec 19, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
inbox-zero Ready Ready Preview Dec 19, 2025 0:20am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 19, 2025

Caution

Review failed

The pull request is closed.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a new NOTIFY_SENDER action end-to-end: database enum and migration, AI action handler, Resend email template and send logic, frontend UI/constants/validation, env flag for Resend, subject formatting guard, error utils update, Cold Email blocker UI tweak, and a version bump.

Changes

Cohort / File(s) Summary
Database & Schema
apps/web/prisma/schema.prisma, apps/web/prisma/migrations/20251219012216_add_notify_sender_action_type/migration.sql
Added NOTIFY_SENDER to ActionType in Prisma schema and applied a Postgres enum migration.
AI Action Handling & Backend
apps/web/utils/ai/actions.ts, apps/web/utils/cold-email/send-notification.ts, packages/resend/src/send.tsx
Added ActionType.NOTIFY_SENDER handler that extracts sender email and calls sendColdEmailNotification; implemented send function using Resend with template rendering, config checks, logging and error handling; exported sendColdEmailNotification.
Email Template
packages/resend/emails/cold-email-notification.tsx
New React Email template ColdEmailNotification and props type used for cold-email notification messages.
Frontend UI / Forms / Components
apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx, apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx, apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx, apps/web/app/(landing)/components/page.tsx, apps/web/components/PlanBadge.tsx, apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
Added rendering, label, tooltip, and conditional availability for NOTIFY_SENDER across action steps, summary card, rule form (gated by cold-email system type and env flag), landing badges, plan badge, and available actions panel.
Constants & Display Utilities
apps/web/app/(app)/[emailAccountId]/assistant/constants.ts, apps/web/utils/action-display.tsx, apps/web/utils/action-item.ts
Mapped NOTIFY_SENDER to BellIcon and amber/purple colors; added actionInputs entry and handling in getActionFields/sanitizeActionFields; extended action display utilities.
Validation & Env
apps/web/utils/actions/rule.validation.ts, apps/web/env.ts
Included NOTIFY_SENDER in zod action-type validation; added NEXT_PUBLIC_IS_RESEND_CONFIGURED client env flag derived from RESEND_API_KEY.
Email Reply Subject
apps/web/components/email-list/EmailMessage.tsx, apps/web/utils/email/subject.ts
Use formatReplySubject for replies and guard empty subjects to return "Re: (no subject)".
UI Behavior / Cold Email Blocker Tabs
apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
Reordered Tabs triggers, added test tab content, and changed default tab to cold-emails.
Error Utilities
apps/web/utils/error.ts
Added sampling support to captureException and new helper getErrorMessage for robust message extraction.
Version
version.txt
Bumped version from v2.24.8 to v2.25.0.

Sequence Diagram(s)

sequenceDiagram
    participant Email as Incoming Email
    participant AI as AI Action Handler
    participant Notify as sendColdEmailNotification
    participant Resend as Resend Service
    participant Sender as Cold Emailer

    Email->>AI: Email ingested (headers, subject, messageId)
    AI->>AI: Rule matches → ActionType.NOTIFY_SENDER
    AI->>Notify: call with senderEmail, recipientEmail, originalSubject, messageId
    activate Notify
    Notify->>Notify: format reply subject, build payload (from,to,replyTo,in-reply-to)
    Notify->>Resend: render ColdEmailNotification & send via Resend API
    activate Resend
    Resend-->>Notify: send response (success / error)
    deactivate Resend
    alt success
        Notify->>Notify: log success (message id)
    else error
        Notify->>Notify: log error and return failure
    end
    Notify-->>AI: { success, error? }
    deactivate Notify
    opt delivered
        Resend->>Sender: deliver notification email
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay attention to:
    • Sender email extraction and edge-case handling in apps/web/utils/ai/actions.ts.
    • Env gating and error paths in apps/web/utils/cold-email/send-notification.ts and packages/resend/src/send.tsx.
    • Prisma migration correctness and ordering for enum addition.
    • RuleForm gating condition and client env exposure (NEXT_PUBLIC_IS_RESEND_CONFIGURED).

Possibly related PRs

Suggested reviewers

  • edulelis

"I hopped through code and chimed a bell,
A tiny nudge where cold senders dwell.
Inbox Zero tapped, polite and merry—
'You were filtered, friend'—a gentle, bright ferry. 🔔🐰"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add cold email notifier' clearly and concisely describes the main feature addition in the PR: implementing a NOTIFY_SENDER action type for cold email notifications.

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 06789e4 and 854178c.

📒 Files selected for processing (2)
  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts (4 hunks)
  • apps/web/utils/cold-email/send-notification.ts (1 hunks)

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
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 16 files

Prompt for AI agents (all 2 issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="apps/web/app/(app)/[emailAccountId]/assistant/constants.ts">

<violation number="1" location="apps/web/app/(app)/[emailAccountId]/assistant/constants.ts:29">
P2: The `getActionTypeColor` helper function is missing a case for the new `NOTIFY_SENDER` action type. Following the established pattern in this file, consider adding a condition to handle strings containing &quot;notify&quot; to return the correct amber color.</violation>
</file>

<file name="apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx">

<violation number="1" location="apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx:343">
P2: Missing `rule.systemType` in the `useMemo` dependency array. The memoized `typeOptions` now depends on `rule.systemType` but this value isn&#39;t included in the dependencies, which could cause stale options when the rule type changes. Add `rule.systemType` to the dependency array.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

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

Caution

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

⚠️ Outside diff range comments (1)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)

282-355: Add rule.systemType to useMemo dependencies.

The typeOptions memoization depends on rule.systemType (checked at line 343), but it's not included in the dependencies array at line 355. While systemType rarely changes after initialization, adding it ensures correctness and prevents potential stale closures.

🔎 Proposed fix
     return options;
-  }, [provider, terminology.label.action]);
+  }, [provider, terminology.label.action, rule.systemType]);
🧹 Nitpick comments (2)
packages/resend/emails/cold-email-notification.tsx (1)

34-36: Consider using baseUrl prop for the image URL.

The image URL is currently hardcoded to "https://www.getinboxzero.com/icon.png", which matches the default baseUrl. For consistency and flexibility, consider using the baseUrl prop:

-                  src={"https://www.getinboxzero.com/icon.png"}
+                  src={`${baseUrl}/icon.png`}

This ensures the image URL adapts when a different baseUrl is provided.

apps/web/utils/ai/actions.ts (1)

328-345: Consider logging the notification result for better observability.

The notify_sender function calls sendColdEmailNotification but doesn't capture or log the result. Since sendColdEmailNotification returns { success: boolean; error?: string }, capturing this would improve observability and debugging.

🔎 Suggested improvement
 const notify_sender: ActionFunction<Record<string, unknown>> = async ({
   email,
   userEmail,
   logger,
 }) => {
   const senderEmail = extractEmailAddress(email.headers.from);
   if (!senderEmail) {
     logger.error("Could not extract sender email for notify_sender action");
     return;
   }

-  await sendColdEmailNotification({
+  const result = await sendColdEmailNotification({
     senderEmail,
     recipientEmail: userEmail,
     originalSubject: email.headers.subject,
     logger,
   });
+
+  if (!result.success) {
+    logger.warn("Notify sender action completed with error", {
+      error: result.error,
+      senderEmail,
+    });
+  }
 };
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 581f33b and 13d8561.

📒 Files selected for processing (16)
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts (4 hunks)
  • apps/web/app/(landing)/components/page.tsx (1 hunks)
  • apps/web/components/PlanBadge.tsx (2 hunks)
  • apps/web/prisma/migrations/20251219012216_add_notify_sender_action_type/migration.sql (1 hunks)
  • apps/web/prisma/schema.prisma (1 hunks)
  • apps/web/utils/action-display.tsx (3 hunks)
  • apps/web/utils/action-item.ts (2 hunks)
  • apps/web/utils/actions/rule.validation.ts (1 hunks)
  • apps/web/utils/ai/actions.ts (3 hunks)
  • apps/web/utils/cold-email/send-notification.ts (1 hunks)
  • packages/resend/emails/cold-email-notification.tsx (1 hunks)
  • packages/resend/src/send.tsx (3 hunks)
  • version.txt (1 hunks)
🧰 Additional context used
📓 Path-based instructions (32)
**/prisma/schema.prisma

📄 CodeRabbit inference engine (.cursor/rules/prisma.mdc)

Use PostgreSQL as the database system with Prisma

Files:

  • apps/web/prisma/schema.prisma
!(pages/_document).{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

Don't use the next/head module in pages/_document.js on Next.js projects

Files:

  • apps/web/prisma/schema.prisma
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/prisma/migrations/20251219012216_add_notify_sender_action_type/migration.sql
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/cold-email/send-notification.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/action-display.tsx
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • version.txt
  • packages/resend/emails/cold-email-notification.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/components/PlanBadge.tsx
  • apps/web/utils/ai/actions.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)

**/*.{ts,tsx}: For API GET requests to server, use the swr package
Use result?.serverError with toastError from @/components/Toast for error handling in async operations

**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls

**/*.{ts,tsx}: For early access feature flags, create hooks using the naming convention use[FeatureName]Enabled that return a boolean from useFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming convention use[FeatureName]Variant that define variant types, use useFeatureFlagVariantKey() with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g., inbox-cleaner, pricing-options-2)
Always define types for A/B test variant flags (e.g., type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting

**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the ! postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Use as const instead of literal types and type annotations
Use either T[] or Array<T> consistently
Initialize each enum member value explicitly
Use export type for types
Use `impo...

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/cold-email/send-notification.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/action-display.tsx
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • packages/resend/emails/cold-email-notification.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/components/PlanBadge.tsx
  • apps/web/utils/ai/actions.ts
apps/web/app/(app)/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)

apps/web/app/(app)/**/*.{ts,tsx}: Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
If we're in a deeply nested component we will use swr to fetch via API
If you need to use onClick in a component, that component is a client component and file must start with use client

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)

Always import Prisma enums from @/generated/prisma/enums instead of @/generated/prisma/client to avoid Next.js bundling errors in client components

Import Prisma using the project's centralized utility: import prisma from '@/utils/prisma'

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/cold-email/send-notification.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/action-display.tsx
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • packages/resend/emails/cold-email-notification.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/components/PlanBadge.tsx
  • apps/web/utils/ai/actions.ts
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Import specific lodash functions rather than entire lodash library to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Use @/ path aliases for imports from project root
Follow tailwindcss patterns with prettier-plugin-tailwindcss class organization
Prefix client-side environment variables with NEXT_PUBLIC_
Leverage TypeScript inference for better developer experience with type exports from API routes

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/cold-email/send-notification.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/action-display.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/components/PlanBadge.tsx
  • apps/web/utils/ai/actions.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Use next/image package for images
For API GET requests to server, use the swr package with hooks like useSWR to fetch data
For text inputs, use the Input component with registerProps for form integration and error handling

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/cold-email/send-notification.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/action-display.tsx
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • packages/resend/emails/cold-email-notification.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/components/PlanBadge.tsx
  • apps/web/utils/ai/actions.ts
**/*.{tsx,ts,css}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

Implement responsive design with Tailwind CSS using a mobile-first approach

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/cold-email/send-notification.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/action-display.tsx
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • packages/resend/emails/cold-email-notification.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/components/PlanBadge.tsx
  • apps/web/utils/ai/actions.ts
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.tsx: Use the LoadingContent component to handle loading states instead of manual loading state management
For text areas, use the Input component with type='text', autosizeTextarea prop set to true, and registerProps for form integration

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/utils/action-display.tsx
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • packages/resend/emails/cold-email-notification.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/components/PlanBadge.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use accessKey attribute on any HTML element
Don't set aria-hidden="true" on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like <marquee> or <blink>
Only use the scope prop on <th> elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assign tabIndex to non-interactive HTML elements
Don't use positive integers for tabIndex property
Don't include "image", "picture", or "photo" in img alt prop
Don't use explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Always include a title element for SVG elements
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
Assign tabIndex to non-interactive HTML elements with aria-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include a type attribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden)
Always include a lang attribute on the html element
Always include a title attribute for iframe elements
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress
Accompany onMouseOver/onMouseOut with onFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid AR...

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/cold-email/send-notification.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/action-display.tsx
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • packages/resend/emails/cold-email-notification.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/components/PlanBadge.tsx
  • apps/web/utils/ai/actions.ts
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{jsx,tsx}: Don't use unnecessary fragments
Don't pass children as props
Don't use the return value of React.render
Make sure all dependencies are correctly specified in React hooks
Make sure all React hooks are called from the top level of component functions
Don't forget key props in iterators and collection literals
Don't define React components inside other components
Don't use event handlers on non-interactive elements
Don't assign to React component props
Don't use both children and dangerouslySetInnerHTML props on the same element
Don't use dangerous JSX props
Don't use Array index in keys
Don't insert comments as text nodes
Don't assign JSX properties multiple times
Don't add extra closing tags for components without children
Use <>...</> instead of <Fragment>...</Fragment>
Watch out for possible "wrong" semicolons inside JSX elements
Make sure void (self-closing) elements don't have children
Don't use target="_blank" without rel="noopener"
Don't use <img> elements in Next.js projects
Don't use <head> elements in Next.js projects

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/utils/action-display.tsx
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • packages/resend/emails/cold-email-notification.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/components/PlanBadge.tsx
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)

**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/cold-email/send-notification.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/action-display.tsx
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • packages/resend/emails/cold-email-notification.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/components/PlanBadge.tsx
  • apps/web/utils/ai/actions.ts
apps/web/**/app/**

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Follow NextJS app router structure with (app) directory

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/app/(landing)/components/page.tsx
apps/web/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{tsx,jsx}: Prefer functional components with hooks over class components
Use shadcn/ui components when available
Follow consistent naming conventions with PascalCase for component names
Use LoadingContent component for async data with loading and error states
Use result?.serverError with toastError and toastSuccess for mutation error handling

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/utils/action-display.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/components/PlanBadge.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{ts,tsx,js,jsx}: Use proper error handling with try/catch blocks
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments
Add helper functions to the bottom of files, not the top

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/cold-email/send-notification.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/action-display.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/components/PlanBadge.tsx
  • apps/web/utils/ai/actions.ts
apps/web/**/*.{ts,tsx,js,jsx,json,css,md}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Format code with Prettier

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/cold-email/send-notification.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/action-display.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/components/PlanBadge.tsx
  • apps/web/utils/ai/actions.ts
apps/web/**/*.{tsx,jsx,css}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Ensure responsive design with mobile-first approach

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx
  • apps/web/utils/action-display.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx
  • apps/web/app/(landing)/components/page.tsx
  • apps/web/components/PlanBadge.tsx
**/*.validation.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/form-handling.mdc)

**/*.validation.{ts,tsx}: Define validation schemas using Zod
Use descriptive error messages in validation schemas

Files:

  • apps/web/utils/actions/rule.validation.ts
apps/web/utils/actions/*.ts

📄 CodeRabbit inference engine (.cursor/rules/fullstack-workflow.mdc)

apps/web/utils/actions/*.ts: Use next-safe-action with Zod schemas for all server actions (create/update/delete mutations), storing validation schemas in apps/web/utils/actions/*.validation.ts
Server actions should use 'use server' directive and automatically receive authentication context (emailAccountId) from the actionClient

apps/web/utils/actions/*.ts: Create corresponding server action implementation files using the naming convention apps/web/utils/actions/NAME.ts with 'use server' directive
Use 'use server' directive at the top of server action implementation files
Implement all server actions using the next-safe-action library with actionClient, actionClientUser, or adminActionClient for type safety and validation
Use actionClientUser when only authenticated user context (userId) is needed
Use actionClient when both authenticated user context and a specific emailAccountId are needed, with emailAccountId bound when calling from the client
Use adminActionClient for actions restricted to admin users
Add metadata with a meaningful action name using .metadata({ name: "actionName" }) for Sentry instrumentation and monitoring
Use .schema() method with Zod validation schemas from corresponding .validation.ts files in next-safe-action configuration
Access context (userId, emailAccountId, etc.) via the ctx object parameter in the .action() handler
Use revalidatePath or revalidateTag from 'next/cache' within server action handlers when mutations modify data displayed elsewhere

Files:

  • apps/web/utils/actions/rule.validation.ts
apps/web/utils/actions/*.validation.ts

📄 CodeRabbit inference engine (.cursor/rules/fullstack-workflow.mdc)

apps/web/utils/actions/*.validation.ts: Define Zod validation schemas in separate *.validation.ts files and export both the schema and inferred type (e.g., CreateExampleBody)
Export types from Zod schemas using z.infer<> to maintain type safety between validation and client usage

apps/web/utils/actions/*.validation.ts: Create separate validation files for server actions using the naming convention apps/web/utils/actions/NAME.validation.ts containing Zod schemas and inferred types
Define input validation schemas using Zod in .validation.ts files and export both the schema and its inferred TypeScript type

Files:

  • apps/web/utils/actions/rule.validation.ts
apps/web/utils/actions/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

apps/web/utils/actions/**/*.ts: Server actions must be located in apps/web/utils/actions folder
Server action files must start with use server directive

Files:

  • apps/web/utils/actions/rule.validation.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/security.mdc)

**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma's select option. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. All findUnique/findFirst calls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
All findMany queries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g., emailAccount: { id: emailAccountId }) to validate ownership

Files:

  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/cold-email/send-notification.ts
  • apps/web/utils/action-item.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts
  • apps/web/utils/ai/actions.ts
apps/web/**/utils/actions/*.ts

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/utils/actions/*.ts: Use next-safe-action with proper Zod validation for server actions
Call revalidatePath in server actions for cache invalidation after mutations

Files:

  • apps/web/utils/actions/rule.validation.ts
apps/web/**/utils/actions/*.validation.ts

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Create separate Zod validation schema files for server action inputs

Files:

  • apps/web/utils/actions/rule.validation.ts
apps/web/**/{app/api,utils/actions}/**/*.ts

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/{app/api,utils/actions}/**/*.ts: Use server actions for all mutations (create/update/delete operations) instead of POST API routes
Use withAuth for user-level operations and withEmailAccount for email-account-level operations

Files:

  • apps/web/utils/actions/rule.validation.ts
**/{utils,helpers,lib}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)

Logger should be passed as a parameter to helper functions instead of creating their own logger instances

Files:

  • apps/web/utils/actions/rule.validation.ts
  • apps/web/utils/cold-email/send-notification.ts
  • apps/web/utils/action-item.ts
  • apps/web/utils/action-display.tsx
  • apps/web/utils/ai/actions.ts
**/*Form.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/form-handling.mdc)

**/*Form.{ts,tsx}: Use React Hook Form with Zod for validation in form components
Validate form inputs before submission
Show validation errors inline next to form fields

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/**/*{Form,Form.tsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Use React Hook Form with Zod validation for form handling

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/{pages,routes,components}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/gmail-api.mdc)

Never call Gmail API directly from routes or components - always use wrapper functions from the utils folder

Files:

  • apps/web/app/(landing)/components/page.tsx
  • apps/web/components/PlanBadge.tsx
apps/web/components/**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/fullstack-workflow.mdc)

Use LoadingContent component to consistently handle loading and error states, passing loading, error, and children props

Use PascalCase for component file names (e.g., components/Button.tsx)

Files:

  • apps/web/components/PlanBadge.tsx
apps/web/{utils/ai,utils/llms,__tests__}/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/llm.mdc)

LLM-related code must be organized in specific directories: apps/web/utils/ai/ for main implementations, apps/web/utils/llms/ for core utilities and configurations, and apps/web/__tests__/ for LLM-specific tests

Files:

  • apps/web/utils/ai/actions.ts
apps/web/utils/ai/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/llm.mdc)

apps/web/utils/ai/**/*.ts: LLM feature functions must import from zod for schema validation, use createScopedLogger from @/utils/logger, chatCompletionObject and createGenerateObject from @/utils/llms, and import EmailAccountWithAI type from @/utils/llms/types
LLM feature functions must follow a standard structure: accept options with inputData and emailAccount parameters, implement input validation with early returns, define separate system and user prompts, create a Zod schema for response validation, and use createGenerateObject to execute the LLM call
System prompts must define the LLM's role and task specifications
User prompts must contain the actual data and context, and should be kept separate from system prompts
Always define a Zod schema for LLM response validation and make schemas as specific as possible to guide the LLM output
Use descriptive scoped loggers for each LLM feature, log inputs and outputs with appropriate log levels, and include relevant context in log messages
Implement early returns for invalid LLM inputs, use proper error types and logging, implement fallbacks for AI failures, and add retry logic for transient failures using withRetry
Use XML-like tags to structure data in prompts, remove excessive whitespace and truncate long inputs, and format data consistently across similar LLM functions
Use TypeScript types for all LLM function parameters and return values, and define clear interfaces for complex input/output structures
Keep related AI functions in the same file or directory, extract common patterns into utility functions, and document complex AI logic with clear comments

Files:

  • apps/web/utils/ai/actions.ts
🧠 Learnings (25)
📚 Learning: 2025-11-25T14:38:42.022Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/prisma.mdc:0-0
Timestamp: 2025-11-25T14:38:42.022Z
Learning: Applies to **/prisma/schema.prisma : Use PostgreSQL as the database system with Prisma

Applied to files:

  • apps/web/prisma/migrations/20251219012216_add_notify_sender_action_type/migration.sql
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.validation.ts : Create separate validation files for server actions using the naming convention `apps/web/utils/actions/NAME.validation.ts` containing Zod schemas and inferred types

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-12-17T11:18:06.818Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-17T11:18:06.818Z
Learning: Applies to apps/web/**/utils/actions/*.validation.ts : Create separate Zod validation schema files for server action inputs

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `next-safe-action` with Zod schemas for all server actions (create/update/delete mutations), storing validation schemas in `apps/web/utils/actions/*.validation.ts`

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-12-17T11:18:06.818Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-17T11:18:06.818Z
Learning: Applies to apps/web/**/utils/actions/*.ts : Use `next-safe-action` with proper Zod validation for server actions

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `.schema()` method with Zod validation schemas from corresponding `.validation.ts` files in next-safe-action configuration

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/utils/actions/*.validation.ts : Export types from Zod schemas using `z.infer<>` to maintain type safety between validation and client usage

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.validation.ts : Define input validation schemas using Zod in `.validation.ts` files and export both the schema and its inferred TypeScript type

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*.validation.ts : Use descriptive error messages in Zod validation schemas

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/utils/actions/*.validation.ts : Define Zod validation schemas in separate `*.validation.ts` files and export both the schema and inferred type (e.g., `CreateExampleBody`)

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*.validation.ts : Define validation schemas using Zod

Applied to files:

  • apps/web/utils/actions/rule.validation.ts
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Add metadata with a meaningful action name using `.metadata({ name: "actionName" })` for Sentry instrumentation and monitoring

Applied to files:

  • apps/web/utils/action-item.ts
  • apps/web/utils/action-display.tsx
  • apps/web/app/(landing)/components/page.tsx
📚 Learning: 2025-11-25T14:36:36.276Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:36.276Z
Learning: Applies to **/*.{ts,tsx} : Import error and success toast utilities from '@/components/Toast' for displaying notifications

Applied to files:

  • apps/web/utils/action-display.tsx
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `actionClient` when both authenticated user context and a specific emailAccountId are needed, with emailAccountId bound when calling from the client

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/utils/ai/actions.ts
📚 Learning: 2025-07-17T04:19:57.099Z
Learnt from: edulelis
Repo: elie222/inbox-zero PR: 576
File: packages/resend/emails/digest.tsx:78-83
Timestamp: 2025-07-17T04:19:57.099Z
Learning: In packages/resend/emails/digest.tsx, the DigestEmailProps type uses `[key: string]: DigestItem[] | undefined | string | Date | undefined` instead of intersection types like `& Record<string, DigestItem[] | undefined>` due to implementation constraints. This was the initial implementation approach and cannot be changed to more restrictive typing.

Applied to files:

  • packages/resend/emails/cold-email-notification.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For text inputs in forms, use the `Input` component with `type='email'`, `name`, `label`, `registerProps` from react-hook-form, and `error` props

Applied to files:

  • packages/resend/emails/cold-email-notification.tsx
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls

Applied to files:

  • apps/web/app/(landing)/components/page.tsx
  • apps/web/utils/ai/actions.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to apps/web/utils/gmail/**/*.{ts,tsx} : Keep Gmail provider-specific implementation details isolated within the apps/web/utils/gmail/ directory

Applied to files:

  • apps/web/app/(landing)/components/page.tsx
📚 Learning: 2025-11-25T14:42:16.602Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-25T14:42:16.602Z
Learning: The `utils` folder contains core app logic such as Next.js Server Actions and Gmail API requests

Applied to files:

  • apps/web/utils/ai/actions.ts
📚 Learning: 2025-11-25T14:42:11.919Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-25T14:42:11.919Z
Learning: Applies to utils/**/*.{js,ts,jsx,tsx} : The `utils` folder contains core app logic such as Next.js Server Actions and Gmail API requests

Applied to files:

  • apps/web/utils/ai/actions.ts
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/utils/actions/*.ts : Server actions should use 'use server' directive and automatically receive authentication context (`emailAccountId`) from the `actionClient`

Applied to files:

  • apps/web/utils/ai/actions.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : LLM feature functions must import from `zod` for schema validation, use `createScopedLogger` from `@/utils/logger`, `chatCompletionObject` and `createGenerateObject` from `@/utils/llms`, and import `EmailAccountWithAI` type from `@/utils/llms/types`

Applied to files:

  • apps/web/utils/ai/actions.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls

Applied to files:

  • apps/web/utils/ai/actions.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : LLM feature functions must follow a standard structure: accept options with `inputData` and `emailAccount` parameters, implement input validation with early returns, define separate system and user prompts, create a Zod schema for response validation, and use `createGenerateObject` to execute the LLM call

Applied to files:

  • apps/web/utils/ai/actions.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls

Applied to files:

  • apps/web/utils/ai/actions.ts
🧬 Code graph analysis (4)
packages/resend/src/send.tsx (2)
apps/web/utils/cold-email/send-notification.ts (1)
  • sendColdEmailNotification (5-58)
packages/resend/emails/cold-email-notification.tsx (1)
  • ColdEmailNotificationProps (15-17)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)
apps/web/utils/action-display.tsx (1)
  • getActionIcon (89-120)
packages/resend/emails/cold-email-notification.tsx (2)
apps/web/components/new-landing/common/Section.tsx (1)
  • Section (9-15)
apps/web/components/new-landing/icons/Link.tsx (1)
  • Link (1-18)
apps/web/utils/ai/actions.ts (3)
apps/web/utils/email.ts (1)
  • extractEmailAddress (19-52)
apps/web/utils/cold-email/send-notification.ts (1)
  • sendColdEmailNotification (5-58)
packages/resend/src/send.tsx (1)
  • sendColdEmailNotification (211-252)
⏰ 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). (4)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: Review for correctness
  • GitHub Check: test
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (20)
version.txt (1)

1-1: LGTM!

Appropriate minor version bump for the new NOTIFY_SENDER feature addition.

apps/web/utils/actions/rule.validation.ts (1)

29-29: LGTM!

The addition of NOTIFY_SENDER to the validation schema is correct. Unlike actions such as LABEL, FORWARD, or CALL_WEBHOOK that require specific field validation (labelId, to, url), NOTIFY_SENDER doesn't need additional validation rules, which aligns with its implementation.

packages/resend/emails/cold-email-notification.tsx (1)

50-65: LGTM!

The notification message is clear, professional, and appropriately explains to the sender why their email was filtered. The tone is polite while being direct about the filtering action.

apps/web/prisma/migrations/20251219012216_add_notify_sender_action_type/migration.sql (1)

1-2: LGTM!

The migration correctly adds the NOTIFY_SENDER value to the PostgreSQL ActionType enum.

apps/web/app/(landing)/components/page.tsx (1)

333-337: LGTM!

The addition of NOTIFY_SENDER to the demo ActionBadges is appropriate for showcasing the new action type in the component library demo page.

apps/web/components/PlanBadge.tsx (2)

182-183: LGTM!

The label "Notify Sender" is consistent with the action type's purpose and follows the naming convention used for other action types.


228-229: LGTM!

The purple color assignment for NOTIFY_SENDER is consistent with other notification-style actions like CALL_WEBHOOK and DIGEST.

apps/web/utils/action-display.tsx (3)

5-5: LGTM!

Appropriate import of BellIcon for the notification action.


80-81: LGTM!

The display label "Notify Sender" is clear and consistent with the action's purpose.


113-114: LGTM!

BellIcon is a semantically appropriate icon choice for the notification action.

apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)

342-351: LGTM with minor suggestion!

The conditional inclusion of NOTIFY_SENDER only for cold email rules is appropriate and follows the same pattern as the MOVE_FOLDER option for Microsoft providers.

apps/web/app/(app)/[emailAccountId]/assistant/constants.ts (1)

13-13: LGTM! Consistent action type configuration.

The NOTIFY_SENDER action type is properly configured across all three mappings (colors, text colors, and icons). The amber color scheme provides good visual distinction, and BellIcon is an appropriate choice for notification actions.

Also applies to: 29-29, 44-44, 59-59

apps/web/app/(app)/[emailAccountId]/assistant/ActionSteps.tsx (1)

536-544: LGTM! Clean conditional rendering for NOTIFY_SENDER.

The implementation follows the existing pattern used for other action types. The descriptive message clearly explains that the notification is automated and comes from Inbox Zero, not the user's email—which is important for user understanding.

apps/web/app/(app)/[emailAccountId]/assistant/ActionSummaryCard.tsx (1)

206-210: LGTM! Clear summary with helpful tooltip.

The NOTIFY_SENDER case is properly handled with a concise summary and an informative tooltip that clarifies the notification source and purpose.

apps/web/prisma/schema.prisma (1)

1054-1054: LGTM! Proper enum addition with clear documentation.

The NOTIFY_SENDER value is correctly added to the ActionType enum with a helpful comment explaining its purpose and scope (cold email rules only).

apps/web/utils/ai/actions.ts (1)

13-14: LGTM! Proper integration of NOTIFY_SENDER action.

The imports and switch case are correctly added, following the established pattern for other action types.

Also applies to: 78-79

apps/web/utils/action-item.ts (1)

152-154: LGTM! Correct handling for fieldless action.

NOTIFY_SENDER is properly configured with empty fields (similar to ARCHIVE, MARK_SPAM, etc.) and the sanitization logic correctly returns the base object since no additional fields are needed.

Also applies to: 281-283

apps/web/utils/cold-email/send-notification.ts (1)

5-57: LGTM! Robust implementation with excellent error handling.

The function demonstrates good practices:

  • Structured error handling at multiple levels (configuration check, API errors, exceptions)
  • Comprehensive logging for observability (warn/error/info)
  • Clear return type for caller feedback
  • Appropriate subject formatting with "Re: " prefix
packages/resend/src/send.tsx (2)

17-22: LGTM! Good refactoring with constant extraction.

Introducing RESEND_NOT_CONFIGURED_MESSAGE improves consistency and maintainability. The constant is properly reused in the existing sendEmail function.

Also applies to: 43-43


206-252: LGTM! Well-documented function with appropriate design differences.

The implementation correctly handles the unique requirements for cold email notifications:

  • Excellent JSDoc comment explaining why this differs from other email functions
  • No unsubscribe token (since recipient is external sender, not our user)
  • Includes replyTo parameter for proper email threading
  • Proper error handling and logging
  • Returns result for caller observability

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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 13d8561 and e56172c.

📒 Files selected for processing (4)
  • apps/web/components/email-list/EmailMessage.tsx (2 hunks)
  • apps/web/utils/ai/actions.ts (3 hunks)
  • apps/web/utils/cold-email/send-notification.ts (1 hunks)
  • packages/resend/src/send.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/utils/ai/actions.ts
  • packages/resend/src/send.tsx
🧰 Additional context used
📓 Path-based instructions (18)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)

**/*.{ts,tsx}: For API GET requests to server, use the swr package
Use result?.serverError with toastError from @/components/Toast for error handling in async operations

**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls

**/*.{ts,tsx}: For early access feature flags, create hooks using the naming convention use[FeatureName]Enabled that return a boolean from useFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming convention use[FeatureName]Variant that define variant types, use useFeatureFlagVariantKey() with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g., inbox-cleaner, pricing-options-2)
Always define types for A/B test variant flags (e.g., type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting

**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the ! postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Use as const instead of literal types and type annotations
Use either T[] or Array<T> consistently
Initialize each enum member value explicitly
Use export type for types
Use `impo...

Files:

  • apps/web/components/email-list/EmailMessage.tsx
  • apps/web/utils/cold-email/send-notification.ts
apps/web/components/**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/fullstack-workflow.mdc)

Use LoadingContent component to consistently handle loading and error states, passing loading, error, and children props

Use PascalCase for component file names (e.g., components/Button.tsx)

Files:

  • apps/web/components/email-list/EmailMessage.tsx
**/{pages,routes,components}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/gmail-api.mdc)

Never call Gmail API directly from routes or components - always use wrapper functions from the utils folder

Files:

  • apps/web/components/email-list/EmailMessage.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)

Always import Prisma enums from @/generated/prisma/enums instead of @/generated/prisma/client to avoid Next.js bundling errors in client components

Import Prisma using the project's centralized utility: import prisma from '@/utils/prisma'

Files:

  • apps/web/components/email-list/EmailMessage.tsx
  • apps/web/utils/cold-email/send-notification.ts
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Import specific lodash functions rather than entire lodash library to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Use @/ path aliases for imports from project root
Follow tailwindcss patterns with prettier-plugin-tailwindcss class organization
Prefix client-side environment variables with NEXT_PUBLIC_
Leverage TypeScript inference for better developer experience with type exports from API routes

Files:

  • apps/web/components/email-list/EmailMessage.tsx
  • apps/web/utils/cold-email/send-notification.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Use next/image package for images
For API GET requests to server, use the swr package with hooks like useSWR to fetch data
For text inputs, use the Input component with registerProps for form integration and error handling

Files:

  • apps/web/components/email-list/EmailMessage.tsx
  • apps/web/utils/cold-email/send-notification.ts
**/*.{tsx,ts,css}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

Implement responsive design with Tailwind CSS using a mobile-first approach

Files:

  • apps/web/components/email-list/EmailMessage.tsx
  • apps/web/utils/cold-email/send-notification.ts
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.tsx: Use the LoadingContent component to handle loading states instead of manual loading state management
For text areas, use the Input component with type='text', autosizeTextarea prop set to true, and registerProps for form integration

Files:

  • apps/web/components/email-list/EmailMessage.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use accessKey attribute on any HTML element
Don't set aria-hidden="true" on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like <marquee> or <blink>
Only use the scope prop on <th> elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assign tabIndex to non-interactive HTML elements
Don't use positive integers for tabIndex property
Don't include "image", "picture", or "photo" in img alt prop
Don't use explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Always include a title element for SVG elements
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
Assign tabIndex to non-interactive HTML elements with aria-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include a type attribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden)
Always include a lang attribute on the html element
Always include a title attribute for iframe elements
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress
Accompany onMouseOver/onMouseOut with onFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid AR...

Files:

  • apps/web/components/email-list/EmailMessage.tsx
  • apps/web/utils/cold-email/send-notification.ts
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{jsx,tsx}: Don't use unnecessary fragments
Don't pass children as props
Don't use the return value of React.render
Make sure all dependencies are correctly specified in React hooks
Make sure all React hooks are called from the top level of component functions
Don't forget key props in iterators and collection literals
Don't define React components inside other components
Don't use event handlers on non-interactive elements
Don't assign to React component props
Don't use both children and dangerouslySetInnerHTML props on the same element
Don't use dangerous JSX props
Don't use Array index in keys
Don't insert comments as text nodes
Don't assign JSX properties multiple times
Don't add extra closing tags for components without children
Use <>...</> instead of <Fragment>...</Fragment>
Watch out for possible "wrong" semicolons inside JSX elements
Make sure void (self-closing) elements don't have children
Don't use target="_blank" without rel="noopener"
Don't use <img> elements in Next.js projects
Don't use <head> elements in Next.js projects

Files:

  • apps/web/components/email-list/EmailMessage.tsx
!(pages/_document).{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

Don't use the next/head module in pages/_document.js on Next.js projects

Files:

  • apps/web/components/email-list/EmailMessage.tsx
  • apps/web/utils/cold-email/send-notification.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)

**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

Files:

  • apps/web/components/email-list/EmailMessage.tsx
  • apps/web/utils/cold-email/send-notification.ts
apps/web/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{tsx,jsx}: Prefer functional components with hooks over class components
Use shadcn/ui components when available
Follow consistent naming conventions with PascalCase for component names
Use LoadingContent component for async data with loading and error states
Use result?.serverError with toastError and toastSuccess for mutation error handling

Files:

  • apps/web/components/email-list/EmailMessage.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{ts,tsx,js,jsx}: Use proper error handling with try/catch blocks
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments
Add helper functions to the bottom of files, not the top

Files:

  • apps/web/components/email-list/EmailMessage.tsx
  • apps/web/utils/cold-email/send-notification.ts
apps/web/**/*.{ts,tsx,js,jsx,json,css,md}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Format code with Prettier

Files:

  • apps/web/components/email-list/EmailMessage.tsx
  • apps/web/utils/cold-email/send-notification.ts
apps/web/**/*.{tsx,jsx,css}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Ensure responsive design with mobile-first approach

Files:

  • apps/web/components/email-list/EmailMessage.tsx
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/security.mdc)

**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma's select option. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. All findUnique/findFirst calls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
All findMany queries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g., emailAccount: { id: emailAccountId }) to validate ownership

Files:

  • apps/web/utils/cold-email/send-notification.ts
**/{utils,helpers,lib}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)

Logger should be passed as a parameter to helper functions instead of creating their own logger instances

Files:

  • apps/web/utils/cold-email/send-notification.ts
🧠 Learnings (5)
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls

Applied to files:

  • apps/web/components/email-list/EmailMessage.tsx
  • apps/web/utils/cold-email/send-notification.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls

Applied to files:

  • apps/web/components/email-list/EmailMessage.tsx
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls

Applied to files:

  • apps/web/components/email-list/EmailMessage.tsx
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to apps/web/utils/gmail/**/*.{ts,tsx} : Keep Gmail provider-specific implementation details isolated within the apps/web/utils/gmail/ directory

Applied to files:

  • apps/web/utils/cold-email/send-notification.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : LLM feature functions must import from `zod` for schema validation, use `createScopedLogger` from `@/utils/logger`, `chatCompletionObject` and `createGenerateObject` from `@/utils/llms`, and import `EmailAccountWithAI` type from `@/utils/llms/types`

Applied to files:

  • apps/web/utils/cold-email/send-notification.ts
🧬 Code graph analysis (2)
apps/web/components/email-list/EmailMessage.tsx (1)
apps/web/utils/email/subject.ts (1)
  • formatReplySubject (6-13)
apps/web/utils/cold-email/send-notification.ts (4)
packages/resend/src/send.tsx (1)
  • sendColdEmailNotification (211-258)
apps/web/utils/logger.ts (1)
  • Logger (5-5)
apps/web/env.ts (1)
  • env (17-255)
apps/web/utils/email/subject.ts (1)
  • formatReplySubject (6-13)
⏰ 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). (4)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: test
  • GitHub Check: Review for correctness
🔇 Additional comments (4)
apps/web/components/email-list/EmailMessage.tsx (2)

28-28: LGTM! Clean import addition.

The import follows project conventions with the @/ path alias and brings in the utility needed for improved subject formatting.


332-332: Excellent improvement to reply subject formatting.

Replacing manual "Re: " concatenation with formatReplySubject() provides several benefits:

  • Prevents duplicate "Re: Re: ..." chains when replying to messages that already have the prefix
  • Handles edge cases like null/undefined subjects and whitespace
  • Case-insensitive "Re:" detection (handles "re:", "Re:", "RE:")
  • Centralizes subject formatting logic for consistency across the codebase

This aligns well with the broader PR objective of standardizing subject formatting for the NOTIFY_SENDER action and related workflows.

apps/web/utils/cold-email/send-notification.ts (2)

6-62: Well-structured implementation with proper error handling.

The function follows best practices:

  • Logger is correctly passed as a parameter (per guidelines)
  • Comprehensive try-catch error handling
  • Defensive programming with early returns
  • Structured logging with appropriate context
  • Type-safe return type

34-34: NEXT_PUBLIC_BASE_URL is properly defined and correctly used.

The environment variable is defined in apps/web/env.ts with Zod validation (z.string()) in the client section and included in experimental__runtimeEnv. The usage on line 34 of send-notification.ts is appropriate—NEXT_PUBLIC_ variables are available to server components, server actions and route handlers, in addition to client-side code.

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

🧹 Nitpick comments (1)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)

342-356: Consider adding env to the useMemo dependency array.

The memoized typeOptions uses env.NEXT_PUBLIC_IS_RESEND_CONFIGURED but env isn't included in the dependency array. While env is effectively a constant from @t3-oss/env-nextjs and won't change at runtime, including it would satisfy React's exhaustive-deps rule and make the dependencies explicit.

🔎 Proposed fix
-  }, [provider, terminology.label.action, rule.systemType]);
+  }, [provider, terminology.label.action, rule.systemType, env.NEXT_PUBLIC_IS_RESEND_CONFIGURED]);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e56172c and b505600.

📒 Files selected for processing (2)
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (2 hunks)
  • apps/web/env.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (22)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)

**/*.{ts,tsx}: For API GET requests to server, use the swr package
Use result?.serverError with toastError from @/components/Toast for error handling in async operations

**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls

**/*.{ts,tsx}: For early access feature flags, create hooks using the naming convention use[FeatureName]Enabled that return a boolean from useFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming convention use[FeatureName]Variant that define variant types, use useFeatureFlagVariantKey() with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g., inbox-cleaner, pricing-options-2)
Always define types for A/B test variant flags (e.g., type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting

**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the ! postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Use as const instead of literal types and type annotations
Use either T[] or Array<T> consistently
Initialize each enum member value explicitly
Use export type for types
Use `impo...

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/env.ts
**/*Form.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/form-handling.mdc)

**/*Form.{ts,tsx}: Use React Hook Form with Zod for validation in form components
Validate form inputs before submission
Show validation errors inline next to form fields

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/(app)/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)

apps/web/app/(app)/**/*.{ts,tsx}: Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
If we're in a deeply nested component we will use swr to fetch via API
If you need to use onClick in a component, that component is a client component and file must start with use client

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)

Always import Prisma enums from @/generated/prisma/enums instead of @/generated/prisma/client to avoid Next.js bundling errors in client components

Import Prisma using the project's centralized utility: import prisma from '@/utils/prisma'

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/env.ts
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Import specific lodash functions rather than entire lodash library to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Use @/ path aliases for imports from project root
Follow tailwindcss patterns with prettier-plugin-tailwindcss class organization
Prefix client-side environment variables with NEXT_PUBLIC_
Leverage TypeScript inference for better developer experience with type exports from API routes

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/env.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Use next/image package for images
For API GET requests to server, use the swr package with hooks like useSWR to fetch data
For text inputs, use the Input component with registerProps for form integration and error handling

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/env.ts
**/*.{tsx,ts,css}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

Implement responsive design with Tailwind CSS using a mobile-first approach

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/env.ts
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.tsx: Use the LoadingContent component to handle loading states instead of manual loading state management
For text areas, use the Input component with type='text', autosizeTextarea prop set to true, and registerProps for form integration

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use accessKey attribute on any HTML element
Don't set aria-hidden="true" on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like <marquee> or <blink>
Only use the scope prop on <th> elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assign tabIndex to non-interactive HTML elements
Don't use positive integers for tabIndex property
Don't include "image", "picture", or "photo" in img alt prop
Don't use explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Always include a title element for SVG elements
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
Assign tabIndex to non-interactive HTML elements with aria-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include a type attribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden)
Always include a lang attribute on the html element
Always include a title attribute for iframe elements
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress
Accompany onMouseOver/onMouseOut with onFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid AR...

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/env.ts
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{jsx,tsx}: Don't use unnecessary fragments
Don't pass children as props
Don't use the return value of React.render
Make sure all dependencies are correctly specified in React hooks
Make sure all React hooks are called from the top level of component functions
Don't forget key props in iterators and collection literals
Don't define React components inside other components
Don't use event handlers on non-interactive elements
Don't assign to React component props
Don't use both children and dangerouslySetInnerHTML props on the same element
Don't use dangerous JSX props
Don't use Array index in keys
Don't insert comments as text nodes
Don't assign JSX properties multiple times
Don't add extra closing tags for components without children
Use <>...</> instead of <Fragment>...</Fragment>
Watch out for possible "wrong" semicolons inside JSX elements
Make sure void (self-closing) elements don't have children
Don't use target="_blank" without rel="noopener"
Don't use <img> elements in Next.js projects
Don't use <head> elements in Next.js projects

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
!(pages/_document).{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

Don't use the next/head module in pages/_document.js on Next.js projects

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/env.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)

**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/env.ts
apps/web/**/app/**

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Follow NextJS app router structure with (app) directory

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{tsx,jsx}: Prefer functional components with hooks over class components
Use shadcn/ui components when available
Follow consistent naming conventions with PascalCase for component names
Use LoadingContent component for async data with loading and error states
Use result?.serverError with toastError and toastSuccess for mutation error handling

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{ts,tsx,js,jsx}: Use proper error handling with try/catch blocks
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments
Add helper functions to the bottom of files, not the top

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/env.ts
apps/web/**/*.{ts,tsx,js,jsx,json,css,md}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Format code with Prettier

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/env.ts
apps/web/**/*.{tsx,jsx,css}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Ensure responsive design with mobile-first approach

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/**/*{Form,Form.tsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Use React Hook Form with Zod validation for form handling

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/env.ts

📄 CodeRabbit inference engine (.cursor/rules/environment-variables.mdc)

apps/web/env.ts: Add server-only environment variables to apps/web/env.ts under the server object with Zod schema validation
Add client-side environment variables to apps/web/env.ts under the client object with NEXT_PUBLIC_ prefix and Zod schema validation
Add client-side environment variables to apps/web/env.ts under the experimental__runtimeEnv object to enable runtime access

Files:

  • apps/web/env.ts
{.env.example,apps/web/env.ts}

📄 CodeRabbit inference engine (.cursor/rules/environment-variables.mdc)

Client-side environment variables must be prefixed with NEXT_PUBLIC_

Files:

  • apps/web/env.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/security.mdc)

**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma's select option. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. All findUnique/findFirst calls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
All findMany queries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g., emailAccount: { id: emailAccountId }) to validate ownership

Files:

  • apps/web/env.ts
apps/web/**/{.env.example,env.ts,turbo.json}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Add environment variables to .env.example, env.ts, and turbo.json

Files:

  • apps/web/env.ts
🧠 Learnings (22)
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Use test helpers `getEmail`, `getEmailAccount`, and `getRule` from `@/__tests__/helpers` for mocking emails, accounts, and rules

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-12-17T02:38:37.011Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1103
File: apps/web/utils/actions/rule.ts:447-457
Timestamp: 2025-12-17T02:38:37.011Z
Learning: In apps/web/utils/actions/rule.ts, revalidatePath is not needed for toggleAllRulesAction because rules data is fetched client-side using SWR, not server-side. Server-side cache revalidation is only needed when using Next.js server components or server-side data fetching.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Prefer using existing helpers from `@/__tests__/helpers.ts` (`getEmailAccount`, `getEmail`, `getRule`, `getMockMessage`, `getMockExecutedRule`) instead of creating custom test data helpers

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : LLM feature functions must import from `zod` for schema validation, use `createScopedLogger` from `@/utils/logger`, `chatCompletionObject` and `createGenerateObject` from `@/utils/llms`, and import `EmailAccountWithAI` type from `@/utils/llms/types`

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:45.807Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:45.807Z
Learning: Applies to apps/web/env.ts : Add client-side environment variables to `apps/web/env.ts` under the `client` object with `NEXT_PUBLIC_` prefix and Zod schema validation

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/env.ts
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*Form*.tsx : Use React Hook Form with Zod validation (`zodResolver`) for form handling, with form components using `register`, `handleSubmit`, and error handling from the hook

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Validate form inputs before submission using React Hook Form and Zod resolver

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*Form.{ts,tsx} : Use React Hook Form with Zod for form validation

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-12-17T11:18:06.818Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-17T11:18:06.818Z
Learning: Applies to apps/web/**/*{Form,Form.tsx} : Use React Hook Form with Zod validation for form handling

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Use React Hook Form with Zod for validation in form components

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For text inputs in forms, use the `Input` component with `type='email'`, `name`, `label`, `registerProps` from react-hook-form, and `error` props

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For text areas in forms, use the `Input` component with `type='text'`, `autosizeTextarea` prop, `rows`, `name`, `placeholder`, `registerProps` from react-hook-form, and `error` props

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-09T19:50:05.292Z
Learnt from: ppranay20
Repo: elie222/inbox-zero PR: 935
File: apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx:367-369
Timestamp: 2025-11-09T19:50:05.292Z
Learning: In React Hook Form, when using `useMemo` or `useEffect` with form errors, always use `formState` as the dependency rather than `errors` or `formState.errors`. This is because React Hook Form uses a Proxy pattern where the errors object is mutable and won't trigger dependency arrays correctly. The formState dependency ensures proper reactivity when form validation state changes.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:53.147Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:53.147Z
Learning: Applies to **/*Form.{ts,tsx} : Validate form inputs before submission

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2024-08-23T11:37:26.779Z
Learnt from: aryanprince
Repo: elie222/inbox-zero PR: 210
File: apps/web/app/(app)/stats/NewsletterModal.tsx:2-4
Timestamp: 2024-08-23T11:37:26.779Z
Learning: `MoreDropdown` is a React component and `useUnsubscribeButton` is a custom React hook, and they should not be imported using `import type`.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
📚 Learning: 2025-11-25T14:36:43.454Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:43.454Z
Learning: Applies to apps/web/env.ts : For client-side environment variables in `apps/web/env.ts`, prefix them with `NEXT_PUBLIC_` and add them to both the `client` and `experimental__runtimeEnv` sections

Applied to files:

  • apps/web/env.ts
📚 Learning: 2025-12-17T11:18:06.818Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-17T11:18:06.818Z
Learning: Applies to apps/web/**/*.{ts,tsx} : Prefix client-side environment variables with `NEXT_PUBLIC_`

Applied to files:

  • apps/web/env.ts
📚 Learning: 2025-11-25T14:36:45.807Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:45.807Z
Learning: Applies to {.env.example,apps/web/env.ts} : Client-side environment variables must be prefixed with `NEXT_PUBLIC_`

Applied to files:

  • apps/web/env.ts
📚 Learning: 2025-11-25T14:36:45.807Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:45.807Z
Learning: Applies to apps/web/env.ts : Add client-side environment variables to `apps/web/env.ts` under the `experimental__runtimeEnv` object to enable runtime access

Applied to files:

  • apps/web/env.ts
📚 Learning: 2025-11-25T14:36:43.454Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:43.454Z
Learning: Applies to apps/web/env.ts : Define environment variables in `apps/web/env.ts` using Zod schema validation, organizing them into `server` and `client` sections

Applied to files:

  • apps/web/env.ts
📚 Learning: 2025-11-25T14:36:45.807Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:45.807Z
Learning: Applies to apps/web/env.ts : Add server-only environment variables to `apps/web/env.ts` under the `server` object with Zod schema validation

Applied to files:

  • apps/web/env.ts
📚 Learning: 2025-12-17T11:18:06.818Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-17T11:18:06.818Z
Learning: Applies to apps/web/**/{.env.example,env.ts,turbo.json} : Add environment variables to `.env.example`, `env.ts`, and `turbo.json`

Applied to files:

  • apps/web/env.ts
🧬 Code graph analysis (1)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (2)
apps/web/env.ts (1)
  • env (17-258)
apps/web/utils/action-display.tsx (1)
  • getActionIcon (89-120)
⏰ 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). (4)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: test
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Review for correctness
🔇 Additional comments (1)
apps/web/env.ts (1)

193-194: LGTM! Correctly implements derived environment variable.

The NEXT_PUBLIC_IS_RESEND_CONFIGURED flag is properly defined as a derived boolean based on the presence of RESEND_API_KEY. The implementation correctly:

  • Uses the NEXT_PUBLIC_ prefix for client-side access
  • Marks it as optional since RESEND may not be configured
  • Derives the value at runtime using !!process.env.RESEND_API_KEY
  • Includes a clear comment explaining the derivation

This approach ensures the UI can conditionally enable RESEND-dependent features without exposing the API key itself.

Also applies to: 256-256

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

♻️ Duplicate comments (1)
apps/web/utils/cold-email/send-notification.ts (1)

25-25: Validate or provide fallback for empty subjects.

As noted in the previous review, if originalSubject is empty or whitespace-only, formatReplySubject will produce "Re: ", which is malformed and may break email threading.

🧹 Nitpick comments (1)
apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx (1)

20-28: Consider aligning TabsContent order with visual tab order.

The TabsContent blocks (lines 26-51) are ordered as test → cold-emails → rejected → settings, which doesn't match the visual tab order (cold-emails → rejected → test → settings). While this doesn't affect functionality since React matches by the value prop, aligning the code order with the visual order could improve maintainability.

📝 Optional refactor to align content block order
-      <TabsContent value="test" className="mb-10">
-        <ColdEmailTest />
-      </TabsContent>
-
       <TabsContent value="cold-emails" className="mb-10">
         <Card>
           <ColdEmailList />
         </Card>
       </TabsContent>
+
       <TabsContent value="rejected" className="mb-10">
         <Card>
           <ColdEmailRejected />
         </Card>
       </TabsContent>
+
+      <TabsContent value="test" className="mb-10">
+        <ColdEmailTest />
+      </TabsContent>

-      <TabsContent value="rejected" className="mb-10">
-        <Card>
-          <ColdEmailRejected />
-        </Card>
-      </TabsContent>
-
       <TabsContent value="settings" className="mb-10">
         <MessageText className="my-4">
           To manage cold email settings, go to the Assistant Rules tab and click
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b505600 and 06789e4.

📒 Files selected for processing (8)
  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx (1 hunks)
  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts (4 hunks)
  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx (1 hunks)
  • apps/web/utils/ai/actions.ts (3 hunks)
  • apps/web/utils/cold-email/send-notification.ts (1 hunks)
  • apps/web/utils/email/subject.ts (1 hunks)
  • apps/web/utils/error.ts (3 hunks)
  • packages/resend/src/send.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/utils/ai/actions.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/constants.ts
🧰 Additional context used
📓 Path-based instructions (18)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)

**/*.{ts,tsx}: For API GET requests to server, use the swr package
Use result?.serverError with toastError from @/components/Toast for error handling in async operations

**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls

**/*.{ts,tsx}: For early access feature flags, create hooks using the naming convention use[FeatureName]Enabled that return a boolean from useFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming convention use[FeatureName]Variant that define variant types, use useFeatureFlagVariantKey() with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g., inbox-cleaner, pricing-options-2)
Always define types for A/B test variant flags (e.g., type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting

**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the ! postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Use as const instead of literal types and type annotations
Use either T[] or Array<T> consistently
Initialize each enum member value explicitly
Use export type for types
Use `impo...

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
  • apps/web/utils/email/subject.ts
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
  • apps/web/utils/error.ts
  • apps/web/utils/cold-email/send-notification.ts
apps/web/app/(app)/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)

apps/web/app/(app)/**/*.{ts,tsx}: Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
If we're in a deeply nested component we will use swr to fetch via API
If you need to use onClick in a component, that component is a client component and file must start with use client

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)

Always import Prisma enums from @/generated/prisma/enums instead of @/generated/prisma/client to avoid Next.js bundling errors in client components

Import Prisma using the project's centralized utility: import prisma from '@/utils/prisma'

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
  • apps/web/utils/email/subject.ts
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
  • apps/web/utils/error.ts
  • apps/web/utils/cold-email/send-notification.ts
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Import specific lodash functions rather than entire lodash library to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Use @/ path aliases for imports from project root
Follow tailwindcss patterns with prettier-plugin-tailwindcss class organization
Prefix client-side environment variables with NEXT_PUBLIC_
Leverage TypeScript inference for better developer experience with type exports from API routes

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
  • apps/web/utils/email/subject.ts
  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
  • apps/web/utils/error.ts
  • apps/web/utils/cold-email/send-notification.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Use next/image package for images
For API GET requests to server, use the swr package with hooks like useSWR to fetch data
For text inputs, use the Input component with registerProps for form integration and error handling

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
  • apps/web/utils/email/subject.ts
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
  • apps/web/utils/error.ts
  • apps/web/utils/cold-email/send-notification.ts
**/*.{tsx,ts,css}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

Implement responsive design with Tailwind CSS using a mobile-first approach

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
  • apps/web/utils/email/subject.ts
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
  • apps/web/utils/error.ts
  • apps/web/utils/cold-email/send-notification.ts
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.tsx: Use the LoadingContent component to handle loading states instead of manual loading state management
For text areas, use the Input component with type='text', autosizeTextarea prop set to true, and registerProps for form integration

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use accessKey attribute on any HTML element
Don't set aria-hidden="true" on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like <marquee> or <blink>
Only use the scope prop on <th> elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assign tabIndex to non-interactive HTML elements
Don't use positive integers for tabIndex property
Don't include "image", "picture", or "photo" in img alt prop
Don't use explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Always include a title element for SVG elements
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
Assign tabIndex to non-interactive HTML elements with aria-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include a type attribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden)
Always include a lang attribute on the html element
Always include a title attribute for iframe elements
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress
Accompany onMouseOver/onMouseOut with onFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid AR...

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
  • apps/web/utils/email/subject.ts
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
  • apps/web/utils/error.ts
  • apps/web/utils/cold-email/send-notification.ts
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{jsx,tsx}: Don't use unnecessary fragments
Don't pass children as props
Don't use the return value of React.render
Make sure all dependencies are correctly specified in React hooks
Make sure all React hooks are called from the top level of component functions
Don't forget key props in iterators and collection literals
Don't define React components inside other components
Don't use event handlers on non-interactive elements
Don't assign to React component props
Don't use both children and dangerouslySetInnerHTML props on the same element
Don't use dangerous JSX props
Don't use Array index in keys
Don't insert comments as text nodes
Don't assign JSX properties multiple times
Don't add extra closing tags for components without children
Use <>...</> instead of <Fragment>...</Fragment>
Watch out for possible "wrong" semicolons inside JSX elements
Make sure void (self-closing) elements don't have children
Don't use target="_blank" without rel="noopener"
Don't use <img> elements in Next.js projects
Don't use <head> elements in Next.js projects

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
!(pages/_document).{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

Don't use the next/head module in pages/_document.js on Next.js projects

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
  • apps/web/utils/email/subject.ts
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
  • apps/web/utils/error.ts
  • apps/web/utils/cold-email/send-notification.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)

**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
  • apps/web/utils/email/subject.ts
  • packages/resend/src/send.tsx
  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
  • apps/web/utils/error.ts
  • apps/web/utils/cold-email/send-notification.ts
apps/web/**/app/**

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Follow NextJS app router structure with (app) directory

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
apps/web/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{tsx,jsx}: Prefer functional components with hooks over class components
Use shadcn/ui components when available
Follow consistent naming conventions with PascalCase for component names
Use LoadingContent component for async data with loading and error states
Use result?.serverError with toastError and toastSuccess for mutation error handling

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{ts,tsx,js,jsx}: Use proper error handling with try/catch blocks
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments
Add helper functions to the bottom of files, not the top

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
  • apps/web/utils/email/subject.ts
  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
  • apps/web/utils/error.ts
  • apps/web/utils/cold-email/send-notification.ts
apps/web/**/*.{ts,tsx,js,jsx,json,css,md}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Format code with Prettier

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
  • apps/web/utils/email/subject.ts
  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
  • apps/web/utils/error.ts
  • apps/web/utils/cold-email/send-notification.ts
apps/web/**/*.{tsx,jsx,css}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Ensure responsive design with mobile-first approach

Files:

  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/security.mdc)

**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma's select option. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. All findUnique/findFirst calls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
All findMany queries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g., emailAccount: { id: emailAccountId }) to validate ownership

Files:

  • apps/web/utils/email/subject.ts
  • apps/web/utils/error.ts
  • apps/web/utils/cold-email/send-notification.ts
**/{utils,helpers,lib}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)

Logger should be passed as a parameter to helper functions instead of creating their own logger instances

Files:

  • apps/web/utils/email/subject.ts
  • apps/web/utils/error.ts
  • apps/web/utils/cold-email/send-notification.ts
🧠 Learnings (9)
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Add metadata with a meaningful action name using `.metadata({ name: "actionName" })` for Sentry instrumentation and monitoring

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx
📚 Learning: 2025-07-08T13:14:07.449Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 537
File: apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx:30-34
Timestamp: 2025-07-08T13:14:07.449Z
Learning: The clean onboarding page in apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx is intentionally Gmail-specific and should show an error for non-Google email accounts rather than attempting to support multiple providers.

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Use test helpers `getEmail`, `getEmailAccount`, and `getRule` from `@/__tests__/helpers` for mocking emails, accounts, and rules

Applied to files:

  • apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx
📚 Learning: 2025-11-25T14:39:08.150Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-11-25T14:39:08.150Z
Learning: Applies to apps/web/app/api/**/*.{ts,tsx} : Use generic error messages instead of revealing internal details; throw `SafeError` instead of exposing user IDs, resource IDs, or system information

Applied to files:

  • apps/web/utils/error.ts
📚 Learning: 2025-11-25T14:39:27.909Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:27.909Z
Learning: Applies to **/app/api/**/*.ts : Maintain consistent error response format across all API routes to avoid information disclosure while providing meaningful error feedback

Applied to files:

  • apps/web/utils/error.ts
📚 Learning: 2025-11-25T14:39:27.909Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:27.909Z
Learning: Applies to **/*.ts : Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details

Applied to files:

  • apps/web/utils/error.ts
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to app/api/**/*.ts : Use `SafeError` for error responses to prevent information disclosure - provide generic messages (e.g., 'Rule not found' not 'Rule {id} does not exist for user {userId}') without revealing internal IDs or ownership details

Applied to files:

  • apps/web/utils/error.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Implement early returns for invalid LLM inputs, use proper error types and logging, implement fallbacks for AI failures, and add retry logic for transient failures using `withRetry`

Applied to files:

  • apps/web/utils/error.ts
📚 Learning: 2025-12-17T11:18:06.818Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-17T11:18:06.818Z
Learning: Applies to apps/web/**/*.{ts,tsx,js,jsx} : Use proper error handling with try/catch blocks

Applied to files:

  • apps/web/utils/error.ts
🧬 Code graph analysis (1)
packages/resend/src/send.tsx (2)
apps/web/utils/cold-email/send-notification.ts (1)
  • sendColdEmailNotification (7-66)
packages/resend/emails/cold-email-notification.tsx (1)
  • ColdEmailNotificationProps (15-17)
⏰ 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: cubic · AI code reviewer
  • GitHub Check: test
  • GitHub Check: Review for correctness
🔇 Additional comments (5)
apps/web/utils/email/subject.ts (1)

6-17: LGTM! Clean edge-case handling for empty subjects.

The new guard for empty subjects (lines 8-11) correctly returns "Re: (no subject)" as a sensible default, preventing malformed reply subjects. The logic flow is correct: empty check → duplicate "Re:" detection → "Re:" prefix addition.

apps/web/app/(app)/[emailAccountId]/cold-email-blocker/ColdEmailContent.tsx (1)

18-18: LGTM! Default tab now shows primary content.

Setting "cold-emails" as the default value makes excellent UX sense for this feature, allowing users to immediately see their cold emails upon landing on the page.

apps/web/app/(app)/[emailAccountId]/assistant/AvailableActionsPanel.tsx (1)

24-24: LGTM!

The NOTIFY_SENDER action name mapping follows the existing pattern and integrates cleanly with the available actions panel.

apps/web/utils/error.ts (2)

44-51: LGTM!

The sampling logic correctly implements probabilistic error reporting. When Math.random() >= sampleRate, the capture is skipped, which properly reduces error volume in production.


221-249: LGTM!

The getErrorMessage utility provides robust error message extraction with proper fallback handling. The helper functions asRecord and getStringProp safely navigate nested error structures.

Comment on lines +253 to +258
if (result.error) {
console.error("Error sending cold email notification", result.error);
throw new Error(
`Error sending cold email notification: ${result.error.message}`,
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Error handling inconsistency creates dead code in caller.

This function throws when result.error exists, but the caller in apps/web/utils/cold-email/send-notification.ts (lines 39-48) expects to check result.error directly. Because of the throw on line 255, the caller's error check is unreachable dead code—any error will be caught by the outer try-catch block instead.

This is inconsistent with the caller's expectations. Choose one approach:

Option 1 (Recommended): Remove the throw and return the result, allowing the caller to check result.error as it expects.

Option 2: Keep the throw and remove the dead if (result.error) check in the caller (lines 39-48 of send-notification.ts).

🔎 Recommended fix: Remove throw to match caller's pattern
   if (result.error) {
     console.error("Error sending cold email notification", result.error);
-    throw new Error(
-      `Error sending cold email notification: ${result.error.message}`,
-    );
   }

   return result;
📝 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.

Suggested change
if (result.error) {
console.error("Error sending cold email notification", result.error);
throw new Error(
`Error sending cold email notification: ${result.error.message}`,
);
}
if (result.error) {
console.error("Error sending cold email notification", result.error);
}
return result;
🤖 Prompt for AI Agents
In packages/resend/src/send.tsx around lines 253 to 258, the function logs and
then throws when result.error exists, which makes the caller's subsequent if
(result.error) check unreachable; remove the throw and instead return the result
so callers can inspect result.error as they expect, keeping or enhancing the
console.error log as needed to preserve diagnostics.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 7 files (changes from recent commits).

Prompt for AI agents (all 2 issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="apps/web/utils/cold-email/send-notification.ts">

<violation number="1" location="apps/web/utils/cold-email/send-notification.ts:40">
P2: This error check is unreachable dead code. The `sendColdEmailNotificationViaResend` function throws an exception when `result.error` exists, so this `if (result.error)` block will never execute - the error will be caught by the outer try-catch block instead. Either remove this dead code block, or modify the called function to return errors instead of throwing.</violation>
</file>

<file name="apps/web/app/(app)/[emailAccountId]/assistant/constants.ts">

<violation number="1" location="apps/web/app/(app)/[emailAccountId]/assistant/constants.ts:66">
P2: The `lowerExample.includes(&quot;sender&quot;)` check is too broad and will incorrectly match strings like &quot;Reply to sender&quot; or &quot;Forward to original sender&quot;, returning NOTIFY_SENDER color instead of the correct action color. Consider using only `&quot;notify&quot;` as the keyword, or use a combined pattern like `&quot;notify sender&quot;` to be more specific.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

@elie222 elie222 merged commit e5c60f1 into main Dec 19, 2025
10 of 11 checks passed
@elie222 elie222 deleted the feat/cold-email-notify branch December 19, 2025 12:11
});
return {
success: false,
error: error instanceof Error ? error.message : "Unknown error",
Copy link
Contributor

Choose a reason for hiding this comment

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

getErrorMessage is imported but not used, and the manual instanceof Error check may drop detail. Consider using getErrorMessage(error) here (or remove the import if you don’t need it).

Suggested change
error: error instanceof Error ? error.message : "Unknown error",
error: getErrorMessage(error),

🚀 Reply to ask Macroscope to explain or update this suggestion.

👍 Helpful? React to give us feedback.

},
});

logger.info("Cold email notification sent", {
Copy link
Contributor

Choose a reason for hiding this comment

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

sendColdEmailNotification treats a non-throwing { data, error } response as success. Consider checking result.error before logging/returning success and propagate it if present.

+    if (result.error) {
+      logger.error("Resend returned an error when sending cold email notification", { senderEmail, error: result.error });
+      return { success: false, error: getErrorMessage(result.error) };
+    }

🚀 Reply to ask Macroscope to explain or update this suggestion.

👍 Helpful? React to give us feedback.

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.

1 participant

Comments