Conversation
|
@jshwrnr is attempting to deploy a commit to the Inbox Zero OSS Program Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughAdds follow‑up reminders: DB schema + migrations, settings UI and server action, cron API + processor to apply follow‑up labels and optionally generate drafts, label/draft helpers and cleanup utilities, and integrations to remove follow‑up labels during inbound/outbound flows. Changes
Sequence Diagram(s)sequenceDiagram
participant UI as Settings UI
participant Action as updateFollowUpSettingsAction
participant DB as Prisma (EmailAccount)
participant Cron as Cron/Invoker
participant API as /api/follow-up-reminders
participant Processor as processAllFollowUpReminders
participant Provider as EmailProvider
participant Draft as Draft Generation
participant Cleanup as cleanupStaleDrafts
UI->>Action: save settings
Action->>DB: update followUp fields
DB-->>Action: result
Action-->>UI: success/toast
Cron->>API: invoke (cron secret)
API->>Processor: processAllFollowUpReminders(logger)
Processor->>DB: fetch eligible accounts
DB-->>Processor: accounts
loop per account
Processor->>Provider: init provider
Processor->>DB: fetch trackers past thresholds (AWAITING / NEEDS_REPLY)
DB-->>Processor: trackers
loop AWAITING trackers
Processor->>Provider: applyFollowUpLabel
alt auto-draft enabled
Processor->>Draft: generateFollowUpDraft
end
Processor->>DB: set followUpAppliedAt
end
loop NEEDS_REPLY trackers
Processor->>Provider: applyFollowUpLabel
Processor->>DB: set followUpAppliedAt
end
Processor->>Cleanup: cleanupStaleDrafts
end
Processor-->>API: summary (total, success, errors)
API-->>Cron: response
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In
@apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx:
- Around line 40-56: The useAction call binds updateFollowUpSettingsAction to
data?.id ?? "" too early so it captures an empty emailAccountId; fix by not
initializing the component until data is loaded—add a guard like if (!data)
return null or a loader and only then call
useAction(updateFollowUpSettingsAction.bind(null, data.id), {...}); after this
change remove the subsequent defensive if (!data) return; checks around the
execute/isExecuting handlers and keep mutate/toast logic in the
onSuccess/onError callbacks referencing data now that it is guaranteed to exist.
In @apps/web/app/api/follow-up-reminders/process.ts:
- Around line 39-43: Don't log full email addresses for privacy: in the loop
over emailAccounts where you create accountLogger via logger.with (currently
including emailAccount.email and emailAccount.id), remove emailAccount.email and
only include emailAccount.id, or replace the email field with a redacted value
(e.g., deterministic hash or masked/truncated string) produced by a helper
(e.g., hashEmail or maskEmail) before calling logger.with; update any downstream
usage that expects a plain email in accountLogger metadata accordingly.
- Around line 94-98: The code assumes emailAccount.account is always present
before calling createEmailProvider; add a null check for emailAccount.account
(the OAuth account relation) before accessing account.provider and creating the
provider. If emailAccount.account is null, log a clear warning/error via logger
(including emailAccount.id or emailAccount.email), skip or return early from the
process, and avoid calling createEmailProvider; ensure references to
createEmailProvider, emailAccount, and the local provider variable are updated
accordingly to handle the early-exit path.
In @apps/web/utils/follow-up/cleanup.ts:
- Around line 63-67: The code repeatedly calls provider.getDrafts(...) per stale
tracker and then filters into threadDrafts, causing redundant fetches; change
the logic to fetch drafts once per account (call provider.getDrafts({
maxResults: 100 }) a single time outside the tracker loop and reuse the drafts
array) or, if the provider supports server-side filtering, call
provider.getDrafts({ threadId: tracker.threadId, maxResults: 100 }) instead of
fetching all and filtering; update references to drafts and threadDrafts
accordingly and remove per-tracker provider.getDrafts calls so deletion uses the
cached or filtered results.
🧹 Nitpick comments (5)
apps/web/utils/follow-up/generate-draft.ts (1)
58-91: Consider idempotency safeguards.The implementation is well-structured with proper error handling and logging. However, there's no check to prevent creating duplicate drafts if this function is called multiple times for the same thread.
Given that the schema includes
ThreadTracker.followUpAppliedAtfor tracking, consider either:
- Checking for existing drafts before creating a new one
- Documenting that the caller is responsible for idempotency
- Updating
followUpAppliedAtafter draft creation to prevent re-processing💡 Example: Add idempotency check
try { + // Check if we've already processed this thread + const tracker = await prisma.threadTracker.findFirst({ + where: { + emailAccountId, + threadId, + followUpAppliedAt: { not: null }, + }, + }); + + if (tracker) { + logger.info("Follow-up draft already exists", { threadId }); + return; + } + // Get the thread to find the last message const thread = await provider.getThread(threadId);apps/web/utils/reply-tracker/handle-outbound.ts (1)
62-73: Consider parallelizing with existing operations.The follow-up label removal could be included in the
Promise.allSettledblock at lines 29-48 to execute in parallel with other outbound processing tasks, potentially improving performance. This would maintain the same error isolation while reducing total execution time.♻️ Proposed refactor
await Promise.allSettled([ trackSentDraftStatus({ emailAccountId: emailAccount.id, message, provider, logger, }).catch((error) => { logger.error("Error tracking sent draft status", { error }); captureException(error, { emailAccountId: emailAccount.id }); }), handleOutboundReply({ emailAccount, message, provider, logger, }).catch((error) => { logger.error("Error handling outbound reply", { error }); captureException(error, { emailAccountId: emailAccount.id }); }), + removeFollowUpLabelIfPresent({ + emailAccountId: emailAccount.id, + threadId: message.threadId, + provider, + logger, + }).catch((error) => { + logger.error("Error removing follow-up label", { error }); + captureException(error, { emailAccountId: emailAccount.id }); + }), ]); try { await cleanupThreadAIDrafts({ threadId: message.threadId, emailAccountId: emailAccount.id, provider, logger, }); } catch (error) { logger.error("Error during thread draft cleanup", { error }); captureException(error, { emailAccountId: emailAccount.id }); } - - // Remove follow-up label if present (user replied, so follow-up no longer needed) - try { - await removeFollowUpLabelIfPresent({ - emailAccountId: emailAccount.id, - threadId: message.threadId, - provider, - logger, - }); - } catch (error) { - logger.error("Error removing follow-up label", { error }); - captureException(error, { emailAccountId: emailAccount.id }); - }apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx (1)
164-181: Consider using SelectValue for better accessibility.The Select component manually renders the selected label in the SelectTrigger instead of using the built-in SelectValue component. This might cause accessibility issues as screen readers may not properly announce the selected value.
♻️ Proposed refactor
<Select value={awaitingDays.toString()} onValueChange={handleAwaitingDaysChange} disabled={!enabled || isExecuting} > - <SelectTrigger id="awaiting-days"> - {dayOptions.find( - (d) => d.value === awaitingDays.toString(), - )?.label ?? "Select..."} - </SelectTrigger> + <SelectTrigger id="awaiting-days" /> <SelectContent> {dayOptions.map((option) => ( <SelectItem key={option.value} value={option.value}> {option.label} </SelectItem> ))} </SelectContent> </Select>Apply the same pattern to the other Select component at lines 192-209.
Note: This assumes the shadcn/ui Select component automatically renders SelectValue when no children are provided in SelectTrigger. If not, add
<SelectValue />explicitly.apps/web/app/api/follow-up-reminders/process.ts (1)
210-213: Logged counts may be inaccurate.The logged
awaitingProcessedandneedsReplyProcessedvalues reflect the number of trackers found, not the number successfully processed. Consider tracking actual success counts for accurate observability.apps/web/utils/follow-up/labels.ts (1)
3-5: Consider accepting logger as a parameter per coding guidelines.Per the coding guidelines for utility functions: "Logger should be passed as a parameter to helper functions instead of creating their own logger instances." This enables better context enrichment and log correlation in the calling code.
Example for applyFollowUpLabel
export async function applyFollowUpLabel({ provider, threadId, messageId, + logger, }: { provider: EmailProvider; threadId: string; messageId: string; + logger: Logger; }): Promise<void> {
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
3 issues found across 15 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="apps/web/utils/follow-up/cleanup.ts">
<violation number="1" location="apps/web/utils/follow-up/cleanup.ts:64">
P1: N+1 API call issue: `provider.getDrafts()` is called inside the loop for each stale tracker. If there are 10 trackers, this makes 10 identical API calls to fetch the same drafts list. Move the `getDrafts` call outside the loop to fetch once and reuse.</violation>
</file>
<file name="apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx">
<violation number="1" location="apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx:52">
P2: Potential runtime error: `error.error.serverError` could throw if `error.error` is undefined. Use optional chaining to safely access nested properties.</violation>
</file>
<file name="apps/web/app/api/follow-up-reminders/process.ts">
<violation number="1" location="apps/web/app/api/follow-up-reminders/process.ts:204">
P2: The `cleanupStaleDrafts` call is not wrapped in try/catch. If cleanup fails, the error propagates up and the account is counted as failed, even though the actual follow-up processing (labels + drafts) succeeded. Consider wrapping this in try/catch to prevent a non-critical cleanup failure from marking the entire account processing as failed.
(Based on your team's feedback about non-critical helper functions having internal error handling so failures don't impact the main flow.) [FEEDBACK_USED]</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
Outdated
Show resolved
Hide resolved
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
1 issue found across 3 files (changes from recent commits).
Prompt for AI agents (all 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/settings/FollowUpRemindersSetting.tsx">
<violation number="1" location="apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx:57">
P2: Consider removing the `mutate()` call in `onError` to avoid unnecessary refetching on failure. The optimistic update will remain stale, but SWR will eventually revalidate. Alternatively, store the previous state before optimistic updates and restore it on error.
(Based on your team's feedback about avoiding refetching on useAction failure.) [FEEDBACK_USED]</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @apps/web/app/api/follow-up-reminders/process.ts:
- Around line 149-176: The tracker processing block can partially succeed
(labels/draft created) but fail to mark the tracker
(prisma.threadTracker.update), causing duplicate reprocessing; wrap the
per-tracker work in a Prisma transaction so the label/draft creation and the
update are atomic: call prisma.$transaction and run applyFollowUpLabel and
generateFollowUpDraft inside it (or adapt those functions to accept a
transaction client) and then perform tx.threadTracker.update({ where: { id:
tracker.id }, data: { followUpAppliedAt: now } }) within the same transaction,
logging with trackerLogger and capturing exceptions as before.
🧹 Nitpick comments (1)
apps/web/app/api/follow-up-reminders/process.ts (1)
39-57: Consider parallel processing limits for scalability.The current implementation processes accounts sequentially, which is safe and prevents overwhelming external services. However, for a large number of accounts, consider implementing controlled parallel processing with a concurrency limit (e.g., using
Promise.allwith batches or a library likep-limit).💡 Optional enhancement
import pLimit from 'p-limit'; // Process with concurrency limit of 5 const limit = pLimit(5); const promises = emailAccounts.map(emailAccount => limit(() => processAccountFollowUps({ emailAccount, logger: accountLogger })) ); const results = await Promise.allSettled(promises); // Handle results...This would maintain API rate limit safety while improving throughput for many accounts.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsxapps/web/app/api/follow-up-reminders/process.tsapps/web/utils/follow-up/cleanup.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/web/utils/follow-up/cleanup.ts
🧰 Additional context used
📓 Path-based instructions (20)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)
**/*.{ts,tsx}: For API GET requests to server, use theswrpackage
Useresult?.serverErrorwithtoastErrorfrom@/components/Toastfor 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 conventionuse[FeatureName]Enabledthat return a boolean fromuseFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming conventionuse[FeatureName]Variantthat define variant types, useuseFeatureFlagVariantKey()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
Useas constinstead of literal types and type annotations
Use eitherT[]orArray<T>consistently
Initialize each enum member value explicitly
Useexport typefor types
Use `impo...
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)
Always import Prisma enums from
@/generated/prisma/enumsinstead of@/generated/prisma/clientto avoid Next.js bundling errors in client componentsImport Prisma using the project's centralized utility:
import prisma from '@/utils/prisma'
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
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
Do not export types/interfaces that are only used within the same file. Export later if needed
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
apps/web/app/api/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/security-audit.mdc)
apps/web/app/api/**/*.{ts,tsx}: API routes must usewithAuth,withEmailAccount, orwithErrormiddleware for authentication
All database queries must include user scoping withemailAccountIdoruserIdfiltering in WHERE clauses
Request parameters must be validated before use; avoid direct parameter usage without type checking
Use generic error messages instead of revealing internal details; throwSafeErrorinstead of exposing user IDs, resource IDs, or system information
API routes should only return necessary fields usingselectin database queries to prevent unintended information disclosure
Cron endpoints must usehasCronSecretorhasPostCronSecretto validate cron requests and prevent unauthorized access
Request bodies should use Zod schemas for validation to ensure type safety and prevent injection attacks
Files:
apps/web/app/api/follow-up-reminders/process.ts
**/app/api/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/security.mdc)
**/app/api/**/*.ts: ALL API routes that handle user data MUST use appropriate middleware: usewithEmailAccountfor email-scoped operations, usewithAuthfor user-scoped operations, or usewithErrorwith proper validation for public/custom auth endpoints
UsewithEmailAccountmiddleware for operations scoped to a specific email account, including reading/writing emails, rules, schedules, or any operation usingemailAccountId
UsewithAuthmiddleware for user-level operations such as user settings, API keys, and referrals that use onlyuserId
UsewithErrormiddleware only for public endpoints, custom authentication logic, or cron endpoints. For cron endpoints, MUST usehasCronSecret()orhasPostCronSecret()validation
Cron endpoints without proper authentication can be triggered by anyone. CRITICAL: All cron endpoints MUST validate cron secret usinghasCronSecret(request)orhasPostCronSecret(request)and capture unauthorized attempts withcaptureException()
Always validate request bodies using Zod schemas to ensure type safety and prevent invalid data from reaching database operations
Maintain consistent error response format across all API routes to avoid information disclosure while providing meaningful error feedback
Files:
apps/web/app/api/follow-up-reminders/process.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'sselectoption. 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. AllfindUnique/findFirstcalls 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
AllfindManyqueries 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/app/api/follow-up-reminders/process.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Usenext/imagepackage for images
For API GET requests to server, use theswrpackage with hooks likeuseSWRto fetch data
For text inputs, use theInputcomponent withregisterPropsfor form integration and error handling
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
**/*.{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/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useaccessKeyattribute on any HTML element
Don't setaria-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 thescopeprop 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 assigntabIndexto non-interactive HTML elements
Don't use positive integers fortabIndexproperty
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 atitleelement 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
AssigntabIndexto non-interactive HTML elements witharia-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 atypeattribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden)
Always include alangattribute on the html element
Always include atitleattribute for iframe elements
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress
AccompanyonMouseOver/onMouseOutwithonFocus/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/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.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/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.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/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx,js,jsx}: Use@/path aliases for imports from project root
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
All imports go at the top of files, no mid-file dynamic imports
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
apps/web/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Follow NextJS app router structure with (app) directory
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
apps/web/**/*.{ts,tsx,js,jsx,json,css}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Format code with Prettier
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
apps/web/**/*.{example,ts,json}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Add environment variables to
.env.example,env.ts, andturbo.json
Files:
apps/web/app/api/follow-up-reminders/process.ts
apps/web/app/api/**/*.ts
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/app/api/**/*.ts: Create GET API routes wrapped withwithAuthorwithEmailAccountmiddleware for fetching data
Export response types from GET API routes usingexport type GetXResponse = Awaited<ReturnType<typeof getData>>
Files:
apps/web/app/api/follow-up-reminders/process.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 inpage.tsx, or in theapps/web/app/(app)/PAGE_NAMEfolder
If we're in a deeply nested component we will useswrto fetch via API
If you need to useonClickin a component, that component is a client component and file must start withuse client
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.tsx: Use theLoadingContentcomponent to handle loading states instead of manual loading state management
For text areas, use theInputcomponent withtype='text',autosizeTextareaprop set to true, andregisterPropsfor form integration
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
**/*.{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 bothchildrenanddangerouslySetInnerHTMLprops 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 usetarget="_blank"withoutrel="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/settings/FollowUpRemindersSetting.tsx
apps/web/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{tsx,jsx}: Follow tailwindcss patterns with prettier-plugin-tailwindcss for class sorting
Prefer functional components with hooks in React
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach in components
Follow consistent naming conventions using PascalCase for components
Use LoadingContent component for async data with loading and error states
Use React Hook Form with Zod validation for form handling
Useresult?.serverErrorwithtoastErrorandtoastSuccessfor error handling in forms
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
🧠 Learnings (30)
📚 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/app/api/follow-up-reminders/process.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 : Use `withEmailAccount` middleware for operations scoped to a specific email account, including reading/writing emails, rules, schedules, or any operation using `emailAccountId`
Applied to files:
apps/web/app/api/follow-up-reminders/process.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 label operations from @/utils/gmail/label.ts instead of direct API calls
Applied to files:
apps/web/app/api/follow-up-reminders/process.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/app/api/follow-up-reminders/process.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/app/api/follow-up-reminders/process.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/app/api/follow-up-reminders/process.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 : Use descriptive scoped loggers for each LLM feature, log inputs and outputs with appropriate log levels, and include relevant context in log messages
Applied to files:
apps/web/app/api/follow-up-reminders/process.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} : Always use wrapper functions from @/utils/gmail/ for Gmail API operations instead of direct provider API calls
Applied to files:
apps/web/app/api/follow-up-reminders/process.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/api/follow-up-reminders/process.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 `withEmailAccount` middleware for operations scoped to a specific email account (reading/writing emails, rules, schedules, etc.) - provides `emailAccountId`, `userId`, and `email` in `request.auth`
Applied to files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.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} : All database queries must include user scoping with `emailAccountId` or `userId` filtering in WHERE clauses
Applied to files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:39:04.892Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-11-25T14:39:04.892Z
Learning: Applies to apps/web/app/api/**/route.ts : All database queries must include user/account filtering with `emailAccountId` or `userId` in WHERE clauses to prevent IDOR vulnerabilities
Applied to files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.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/api/follow-up-reminders/process.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 : ALL API routes that handle user data MUST use appropriate middleware: `withEmailAccount` for email-scoped operations, `withAuth` for user-scoped operations, or `withError` with proper validation for public/cron endpoints
Applied to files:
apps/web/app/api/follow-up-reminders/process.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 `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/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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 **/*.ts : ALL database queries MUST be scoped to the authenticated user/account - include user/account filtering in `where` clauses (e.g., `emailAccountId`, `userId`) to ensure users only access their own resources
Applied to files:
apps/web/app/api/follow-up-reminders/process.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/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/utils/actions/**/*.ts : Use proper error handling with try/catch blocks
Applied to files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-12-31T23:49:09.597Z
Learnt from: rsnodgrass
Repo: elie222/inbox-zero PR: 1154
File: apps/web/app/api/user/setup-progress/route.ts:0-0
Timestamp: 2025-12-31T23:49:09.597Z
Learning: In apps/web/app/api/user/setup-progress/route.ts, Reply Zero enabled status should be determined solely by checking if the TO_REPLY rule is enabled, as it is the critical/canonical rule that Reply Zero is based on. The other conversation status types (FYI, AWAITING_REPLY, ACTIONED) should not be checked for determining Reply Zero setup progress.
<!-- </add_learning>
Applied to files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.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} : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in server actions
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use optional chaining where undefined values aren't allowed
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:36:40.146Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:40.146Z
Learning: Applies to **/*.{ts,tsx} : Use `result?.serverError` with `toastError` from `@/components/Toast` for error handling in async operations
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in forms
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-07T21:07:06.691Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1230
File: apps/web/app/(app)/[emailAccountId]/drive/page.tsx:47-70
Timestamp: 2026-01-07T21:07:06.691Z
Learning: In TSX files across the codebase, prefer direct server action calls with manual error handling (e.g., check result?.serverError and handle errors explicitly). The useAction hook pattern is not required; you can call server actions directly and use try/finally to ensure cleanup (such as resetting loading states) regardless of the hook. Apply consistently for components that perform server interactions.
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-05T14:59:55.884Z
Learnt from: jshwrnr
Repo: elie222/inbox-zero PR: 1198
File: apps/web/app/(marketing)/(alternatives)/best-fyxer-alternative/content.tsx:10-10
Timestamp: 2026-01-05T14:59:55.884Z
Learning: In apps/web/app/(marketing)/**/content.tsx files, the pattern `metadata as unknown as AlternativeComparisonProps` (or similar double casts for MDX metadata) is used consistently across marketing pages (alternatives, case-studies). This is an intentional pattern for marketing content where runtime validation overhead is not justified, and should be kept for consistency.
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use LoadingContent component for async data with loading and error states
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:37:30.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:30.660Z
Learning: Custom hooks should encapsulate reusable stateful logic, especially for data fetching or complex UI interactions
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
🧬 Code graph analysis (1)
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx (6)
apps/web/utils/actions/follow-up-reminders.ts (1)
updateFollowUpSettingsAction(7-30)apps/web/components/Toast.tsx (2)
toastSuccess(3-12)toastError(14-19)apps/web/components/SettingCard.tsx (1)
SettingCard(3-34)apps/web/components/LoadingContent.tsx (1)
LoadingContent(13-31)apps/web/components/Input.tsx (1)
Label(116-132)apps/web/components/Toggle.tsx (1)
Toggle(18-50)
⏰ 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). (2)
- GitHub Check: cubic · AI code reviewer
- GitHub Check: test
🔇 Additional comments (6)
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx (3)
63-120: LGTM - Well-implemented handlers with optimistic updates.The callback handlers follow best practices:
- Proper guard clauses prevent execution when data is unavailable
- Optimistic updates use the correct pattern with
mutate(optimisticData, false)Number.parseIntincludes the radix parameter as required- Dependency arrays are complete and accurate
157-161: LGTM - Correct use of LoadingContent.The component properly uses
LoadingContentto handle loading and error states with an appropriate skeleton loader.
45-61: Remove.bind()- actionClient provides emailAccountId from context.The action uses
actionClientwhich automatically providesemailAccountIdfrom the authenticated context (ctx). Binding it as a parameter is incorrect and won't work as intended. TheactionClientpattern doesn't accept emailAccountId as a bound parameter.🔧 Proposed fix
- const { execute, isExecuting } = useAction( - updateFollowUpSettingsAction.bind(null, data?.id ?? ""), - { + const { execute, isExecuting } = useAction(updateFollowUpSettingsAction, { onSuccess: () => { toastSuccess({ description: "Follow-up reminder settings updated!", }); mutate(); }, onError: (error) => { mutate(); toastError({ description: error.error?.serverError ?? "Failed to update settings", }); }, - }, - ); + });Based on learnings: actionClient actions receive
emailAccountIdfrom the authenticated context automatically, not as bound parameters.⛔ Skipped due to learnings
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 clientLearnt 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`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 : Access context (userId, emailAccountId, etc.) via the `ctx` object parameter in the `.action()` handlerLearnt from: elie222 Repo: elie222/inbox-zero PR: 1230 File: apps/web/app/(app)/[emailAccountId]/drive/page.tsx:47-70 Timestamp: 2026-01-07T21:07:06.691Z Learning: Direct server action calls with manual error handling (checking result?.serverError) are a valid pattern in this codebase. The useAction hook pattern is not required; developers can call server actions directly and handle errors manually, especially when using try/finally for cleanup operations like resetting loading states.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 `actionClientUser` when only authenticated user context (userId) is neededLearnt 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 `withEmailAccount` middleware for operations scoped to a specific email account (reading/writing emails, rules, schedules, etc.) - provides `emailAccountId`, `userId`, and `email` in `request.auth`Learnt from: CR Repo: elie222/inbox-zero PR: 0 File: .cursor/rules/data-fetching.mdc:0-0 Timestamp: 2025-11-25T14:36:40.146Z Learning: Applies to **/*{.action,.server}.{ts,tsx} : For mutating data, use Next.js server actionsapps/web/app/api/follow-up-reminders/process.ts (3)
16-32: LGTM - Database queries properly scoped.All database queries correctly include user scoping with
emailAccountIdfiltering in WHERE clauses, preventing unauthorized data access. The premium filter is also properly applied.Based on learnings: All database queries must include user scoping with
emailAccountIdoruserIdfiltering in WHERE clauses.Also applies to: 109-117, 126-134
44-56: LGTM - Comprehensive error handling.The error handling strategy is well-implemented:
- Individual failures don't stop batch processing
- All errors are captured via
captureException- Cleanup is non-blocking and wrapped in try-catch
- Logging provides appropriate context at each level
Also applies to: 149-175, 186-204, 208-217
1-1: No changes needed. Theimport { subDays } from "date-fns/subDays"syntax is correct for date-fns v3+, which uses named exports from submodule files. This import pattern is consistently used throughout the codebase in multiple files.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In
@apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx:
- Around line 64-81: handleToggle can start overlapping requests because it
calls execute() without checking isExecuting; add an early return if isExecuting
is true to prevent concurrent calls (i.e., at the top of handleToggle check if
isExecuting then return), and apply the same guard to handleAwaitingDaysChange
and handleNeedsReplyDaysChange so each handler skips calling execute() while a
request is in flight; keep the optimistic mutate behavior but only call execute
when not isExecuting.
🧹 Nitpick comments (1)
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx (1)
124-136: Consider showing loading state in the disabled button.When
datais loading, the button shows "Configure" in a disabled state without any loading indicator. Users might not realize the component is still loading data.♻️ Optional: Add loading indicator
right={ - <Button variant="outline" size="sm" disabled> - Configure + <Button variant="outline" size="sm" disabled> + {isLoading ? "Loading..." : "Configure"} </Button> }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
🧰 Additional context used
📓 Path-based instructions (15)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)
**/*.{ts,tsx}: For API GET requests to server, use theswrpackage
Useresult?.serverErrorwithtoastErrorfrom@/components/Toastfor 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 conventionuse[FeatureName]Enabledthat return a boolean fromuseFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming conventionuse[FeatureName]Variantthat define variant types, useuseFeatureFlagVariantKey()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
Useas constinstead of literal types and type annotations
Use eitherT[]orArray<T>consistently
Initialize each enum member value explicitly
Useexport typefor types
Use `impo...
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.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 inpage.tsx, or in theapps/web/app/(app)/PAGE_NAMEfolder
If we're in a deeply nested component we will useswrto fetch via API
If you need to useonClickin a component, that component is a client component and file must start withuse client
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)
Always import Prisma enums from
@/generated/prisma/enumsinstead of@/generated/prisma/clientto avoid Next.js bundling errors in client componentsImport Prisma using the project's centralized utility:
import prisma from '@/utils/prisma'
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
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
Do not export types/interfaces that are only used within the same file. Export later if needed
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Usenext/imagepackage for images
For API GET requests to server, use theswrpackage with hooks likeuseSWRto fetch data
For text inputs, use theInputcomponent withregisterPropsfor form integration and error handling
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
**/*.{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/settings/FollowUpRemindersSetting.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.tsx: Use theLoadingContentcomponent to handle loading states instead of manual loading state management
For text areas, use theInputcomponent withtype='text',autosizeTextareaprop set to true, andregisterPropsfor form integration
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useaccessKeyattribute on any HTML element
Don't setaria-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 thescopeprop 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 assigntabIndexto non-interactive HTML elements
Don't use positive integers fortabIndexproperty
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 atitleelement 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
AssigntabIndexto non-interactive HTML elements witharia-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 atypeattribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden)
Always include alangattribute on the html element
Always include atitleattribute for iframe elements
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress
AccompanyonMouseOver/onMouseOutwithonFocus/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/settings/FollowUpRemindersSetting.tsx
**/*.{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 bothchildrenanddangerouslySetInnerHTMLprops 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 usetarget="_blank"withoutrel="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/settings/FollowUpRemindersSetting.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/settings/FollowUpRemindersSetting.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/settings/FollowUpRemindersSetting.tsx
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx,js,jsx}: Use@/path aliases for imports from project root
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
All imports go at the top of files, no mid-file dynamic imports
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
apps/web/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Follow NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
apps/web/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{tsx,jsx}: Follow tailwindcss patterns with prettier-plugin-tailwindcss for class sorting
Prefer functional components with hooks in React
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach in components
Follow consistent naming conventions using PascalCase for components
Use LoadingContent component for async data with loading and error states
Use React Hook Form with Zod validation for form handling
Useresult?.serverErrorwithtoastErrorandtoastSuccessfor error handling in forms
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
apps/web/**/*.{ts,tsx,js,jsx,json,css}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Format code with Prettier
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
🧠 Learnings (22)
📚 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/settings/FollowUpRemindersSetting.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} : All database queries must include user scoping with `emailAccountId` or `userId` filtering in WHERE clauses
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:39:04.892Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-11-25T14:39:04.892Z
Learning: Applies to apps/web/app/api/**/route.ts : All database queries must include user/account filtering with `emailAccountId` or `userId` in WHERE clauses to prevent IDOR vulnerabilities
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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 `withEmailAccount` middleware for operations scoped to a specific email account (reading/writing emails, rules, schedules, etc.) - provides `emailAccountId`, `userId`, and `email` in `request.auth`
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.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} : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in server actions
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in forms
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:36:40.146Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:40.146Z
Learning: Applies to **/*.{ts,tsx} : Use `result?.serverError` with `toastError` from `@/components/Toast` for error handling in async operations
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use optional chaining where undefined values aren't allowed
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/utils/actions/**/*.ts : Use proper error handling with try/catch blocks
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.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 : 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/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-07T21:07:06.691Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1230
File: apps/web/app/(app)/[emailAccountId]/drive/page.tsx:47-70
Timestamp: 2026-01-07T21:07:06.691Z
Learning: In TSX files across the codebase, prefer direct server action calls with manual error handling (e.g., check result?.serverError and handle errors explicitly). The useAction hook pattern is not required; you can call server actions directly and use try/finally to ensure cleanup (such as resetting loading states) regardless of the hook. Apply consistently for components that perform server interactions.
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make sure to pass a message value when creating a built-in error
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use LoadingContent component for async data with loading and error states
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:37:30.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:30.660Z
Learning: Custom hooks should encapsulate reusable stateful logic, especially for data fetching or complex UI interactions
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-12-31T23:49:09.597Z
Learnt from: rsnodgrass
Repo: elie222/inbox-zero PR: 1154
File: apps/web/app/api/user/setup-progress/route.ts:0-0
Timestamp: 2025-12-31T23:49:09.597Z
Learning: In apps/web/app/api/user/setup-progress/route.ts, Reply Zero enabled status should be determined solely by checking if the TO_REPLY rule is enabled, as it is the critical/canonical rule that Reply Zero is based on. The other conversation status types (FYI, AWAITING_REPLY, ACTIONED) should not be checked for determining Reply Zero setup progress.
<!-- </add_learning>
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.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: For mutating data, use Next.js server actions instead of SWR
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/hooks/**/*.{ts,tsx} : Call `mutate()` after successful mutations in SWR hooks to refresh data
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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/hooks/use*.ts : Call `mutate()` on SWR hooks after successful mutations to refresh cached data
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:36:40.146Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:40.146Z
Learning: Applies to **/*{.action,.server}.{ts,tsx} : For mutating data, use Next.js server actions
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (3)
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx (3)
1-35: LGTM! Clean imports and configuration.The imports follow project conventions and the
dayOptionsarray correctly includes all day values mentioned in the PR (1, 3, 7, 14, 30 days).
138-174: LGTM! Proper dialog structure and loading states.The dialog implementation follows best practices:
- Proper accessibility with
LabelandhtmlForLoadingContentwrapper with skeleton for loading state- Toggle disabled during execution to prevent race conditions at the UI level
- Clean separation of concerns
176-234: LGTM! Well-structured select controls with good UX.Both select controls follow a consistent pattern:
- Properly disabled based on
enabledstate andisExecutingflag- Display the selected value correctly with a fallback
- Include helpful description text for users
- Map options cleanly from the
dayOptionsarrayThe defensive fallback to "Select..." is good practice even though it shouldn't occur with the current data defaults.
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
Show resolved
Hide resolved
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/web/utils/webhook/process-history-item.ts (1)
167-180: Well-structured follow-up label cleanup with proper error handling.The implementation correctly clears follow-up labels after processing inbound messages. The try-catch prevents errors from propagating, and the use of
captureExceptionensures issues are tracked in Sentry.🛡️ Optional: Add defensive guard clause for threadId
While
actualThreadIdshould always be defined in practice (email providers always supply threadIds), adding an explicit guard would make the code more defensive:} + // Guard: Only attempt to clear follow-up if we have a thread ID + if (!actualThreadId) { + logger.warn("No threadId available for follow-up cleanup"); + return; + } + // Remove follow-up label if present (they replied, so follow-up no longer needed) // This handles the case where we were awaiting a reply from them try {This prevents unnecessary API calls and potential type issues if the threadId is somehow missing.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/web/utils/follow-up/cleanup.tsapps/web/utils/reply-tracker/handle-outbound.tsapps/web/utils/webhook/process-history-item.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/web/utils/reply-tracker/handle-outbound.ts
- apps/web/utils/follow-up/cleanup.ts
🧰 Additional context used
📓 Path-based instructions (13)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)
**/*.{ts,tsx}: For API GET requests to server, use theswrpackage
Useresult?.serverErrorwithtoastErrorfrom@/components/Toastfor 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 conventionuse[FeatureName]Enabledthat return a boolean fromuseFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming conventionuse[FeatureName]Variantthat define variant types, useuseFeatureFlagVariantKey()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
Useas constinstead of literal types and type annotations
Use eitherT[]orArray<T>consistently
Initialize each enum member value explicitly
Useexport typefor types
Use `impo...
Files:
apps/web/utils/webhook/process-history-item.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)
Always import Prisma enums from
@/generated/prisma/enumsinstead of@/generated/prisma/clientto avoid Next.js bundling errors in client componentsImport Prisma using the project's centralized utility:
import prisma from '@/utils/prisma'
Files:
apps/web/utils/webhook/process-history-item.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
Do not export types/interfaces that are only used within the same file. Export later if needed
Files:
apps/web/utils/webhook/process-history-item.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'sselectoption. 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. AllfindUnique/findFirstcalls 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
AllfindManyqueries 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/webhook/process-history-item.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Usenext/imagepackage for images
For API GET requests to server, use theswrpackage with hooks likeuseSWRto fetch data
For text inputs, use theInputcomponent withregisterPropsfor form integration and error handling
Files:
apps/web/utils/webhook/process-history-item.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/utils/webhook/process-history-item.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useaccessKeyattribute on any HTML element
Don't setaria-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 thescopeprop 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 assigntabIndexto non-interactive HTML elements
Don't use positive integers fortabIndexproperty
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 atitleelement 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
AssigntabIndexto non-interactive HTML elements witharia-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 atypeattribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden)
Always include alangattribute on the html element
Always include atitleattribute for iframe elements
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress
AccompanyonMouseOver/onMouseOutwithonFocus/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/utils/webhook/process-history-item.ts
!(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/utils/webhook/process-history-item.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/utils/webhook/process-history-item.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/webhook/process-history-item.ts
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx,js,jsx}: Use@/path aliases for imports from project root
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
All imports go at the top of files, no mid-file dynamic imports
Files:
apps/web/utils/webhook/process-history-item.ts
apps/web/**/*.{ts,tsx,js,jsx,json,css}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Format code with Prettier
Files:
apps/web/utils/webhook/process-history-item.ts
apps/web/**/*.{example,ts,json}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Add environment variables to
.env.example,env.ts, andturbo.json
Files:
apps/web/utils/webhook/process-history-item.ts
🧠 Learnings (13)
📚 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/utils/webhook/process-history-item.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/webhook/process-history-item.ts
📚 Learning: 2026-01-01T10:42:29.775Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.775Z
Learning: Applies to **/*.test.{ts,tsx} : Use test helper functions `getEmail`, `getEmailAccount`, and `getRule` from `@/__tests__/helpers` for creating mock data
Applied to files:
apps/web/utils/webhook/process-history-item.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/webhook/process-history-item.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} : Always use wrapper functions from @/utils/gmail/ for Gmail API operations instead of direct provider API calls
Applied to files:
apps/web/utils/webhook/process-history-item.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/webhook/process-history-item.ts
📚 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/utils/webhook/process-history-item.ts
📚 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/webhook/process-history-item.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 **/{pages,routes,components}/**/*.{ts,tsx} : Never call Gmail API directly from routes or components - always use wrapper functions from the utils folder
Applied to files:
apps/web/utils/webhook/process-history-item.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/webhook/process-history-item.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 : Use `withEmailAccount` middleware for operations scoped to a specific email account, including reading/writing emails, rules, schedules, or any operation using `emailAccountId`
Applied to files:
apps/web/utils/webhook/process-history-item.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/webhook/process-history-item.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 `withEmailAccount` middleware for operations scoped to a specific email account (reading/writing emails, rules, schedules, etc.) - provides `emailAccountId`, `userId`, and `email` in `request.auth`
Applied to files:
apps/web/utils/webhook/process-history-item.ts
🧬 Code graph analysis (1)
apps/web/utils/webhook/process-history-item.ts (2)
apps/web/utils/follow-up/cleanup.ts (1)
clearFollowUpLabel(103-143)apps/web/utils/error.ts (1)
captureException(46-76)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (1)
apps/web/utils/webhook/process-history-item.ts (1)
7-7: LGTM!The new imports follow the project's path alias conventions and are used correctly in the follow-up label cleanup logic below.
Also applies to: 16-16
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx (1)
47-48: Consider guarding the action binding against missingdata.id.The action is bound with
data?.id ?? ""which creates a binding with an empty string when data hasn't loaded. While the handlers correctly guard withif (!data) return;, the binding itself could theoretically be invoked with an invalidemailAccountId.This is currently safe due to the early return at line 148, but consider using a more defensive pattern:
♻️ Suggested improvement
const { execute, isExecuting } = useAction( - updateFollowUpSettingsAction.bind(null, data?.id ?? ""), + updateFollowUpSettingsAction.bind(null, data?.id || ""), {Alternatively, you could conditionally create the action only when data exists, though the current implementation is functionally safe.
apps/web/prisma/schema.prisma (1)
756-757: Consider adding a composite index for follow-up processing queries.The
process.tsfile queriesThreadTrackerwith:WHERE emailAccountId = ? AND type = ? AND resolved = false AND followUpAppliedAt IS NULL AND sentAt < ?The existing indexes cover
(emailAccountId, type, resolved, sentAt)but notfollowUpAppliedAt. For better query performance as data grows, consider adding a composite index:💡 Suggested index
@@index([emailAccountId, resolved]) @@index([emailAccountId, resolved, sentAt, type]) @@index([emailAccountId, type, resolved, sentAt]) + @@index([emailAccountId, type, resolved, followUpAppliedAt, sentAt]) }This is optional for now but may become important at scale.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsxapps/web/app/api/follow-up-reminders/process.tsapps/web/app/api/user/email-account/route.tsapps/web/prisma/migrations/20260108121515_add_follow_up_auto_draft_setting/migration.sqlapps/web/prisma/schema.prismaapps/web/utils/actions/follow-up-reminders.tsapps/web/utils/actions/follow-up-reminders.validation.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/web/utils/actions/follow-up-reminders.validation.ts
- apps/web/utils/actions/follow-up-reminders.ts
🧰 Additional context used
📓 Path-based instructions (25)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)
**/*.{ts,tsx}: For API GET requests to server, use theswrpackage
Useresult?.serverErrorwithtoastErrorfrom@/components/Toastfor 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 conventionuse[FeatureName]Enabledthat return a boolean fromuseFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming conventionuse[FeatureName]Variantthat define variant types, useuseFeatureFlagVariantKey()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
Useas constinstead of literal types and type annotations
Use eitherT[]orArray<T>consistently
Initialize each enum member value explicitly
Useexport typefor types
Use `impo...
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsxapps/web/app/api/user/email-account/route.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)
Always import Prisma enums from
@/generated/prisma/enumsinstead of@/generated/prisma/clientto avoid Next.js bundling errors in client componentsImport Prisma using the project's centralized utility:
import prisma from '@/utils/prisma'
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsxapps/web/app/api/user/email-account/route.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
Do not export types/interfaces that are only used within the same file. Export later if needed
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsxapps/web/app/api/user/email-account/route.ts
apps/web/app/api/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/security-audit.mdc)
apps/web/app/api/**/*.{ts,tsx}: API routes must usewithAuth,withEmailAccount, orwithErrormiddleware for authentication
All database queries must include user scoping withemailAccountIdoruserIdfiltering in WHERE clauses
Request parameters must be validated before use; avoid direct parameter usage without type checking
Use generic error messages instead of revealing internal details; throwSafeErrorinstead of exposing user IDs, resource IDs, or system information
API routes should only return necessary fields usingselectin database queries to prevent unintended information disclosure
Cron endpoints must usehasCronSecretorhasPostCronSecretto validate cron requests and prevent unauthorized access
Request bodies should use Zod schemas for validation to ensure type safety and prevent injection attacks
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/api/user/email-account/route.ts
**/app/api/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/security.mdc)
**/app/api/**/*.ts: ALL API routes that handle user data MUST use appropriate middleware: usewithEmailAccountfor email-scoped operations, usewithAuthfor user-scoped operations, or usewithErrorwith proper validation for public/custom auth endpoints
UsewithEmailAccountmiddleware for operations scoped to a specific email account, including reading/writing emails, rules, schedules, or any operation usingemailAccountId
UsewithAuthmiddleware for user-level operations such as user settings, API keys, and referrals that use onlyuserId
UsewithErrormiddleware only for public endpoints, custom authentication logic, or cron endpoints. For cron endpoints, MUST usehasCronSecret()orhasPostCronSecret()validation
Cron endpoints without proper authentication can be triggered by anyone. CRITICAL: All cron endpoints MUST validate cron secret usinghasCronSecret(request)orhasPostCronSecret(request)and capture unauthorized attempts withcaptureException()
Always validate request bodies using Zod schemas to ensure type safety and prevent invalid data from reaching database operations
Maintain consistent error response format across all API routes to avoid information disclosure while providing meaningful error feedback
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/api/user/email-account/route.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'sselectoption. 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. AllfindUnique/findFirstcalls 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
AllfindManyqueries 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/app/api/follow-up-reminders/process.tsapps/web/app/api/user/email-account/route.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Usenext/imagepackage for images
For API GET requests to server, use theswrpackage with hooks likeuseSWRto fetch data
For text inputs, use theInputcomponent withregisterPropsfor form integration and error handling
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsxapps/web/app/api/user/email-account/route.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/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsxapps/web/app/api/user/email-account/route.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useaccessKeyattribute on any HTML element
Don't setaria-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 thescopeprop 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 assigntabIndexto non-interactive HTML elements
Don't use positive integers fortabIndexproperty
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 atitleelement 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
AssigntabIndexto non-interactive HTML elements witharia-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 atypeattribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden)
Always include alangattribute on the html element
Always include atitleattribute for iframe elements
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress
AccompanyonMouseOver/onMouseOutwithonFocus/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/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsxapps/web/app/api/user/email-account/route.ts
!(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/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsxapps/web/app/api/user/email-account/route.tsapps/web/prisma/schema.prismaapps/web/prisma/migrations/20260108121515_add_follow_up_auto_draft_setting/migration.sql
**/*.{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/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsxapps/web/app/api/user/email-account/route.ts
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx,js,jsx}: Use@/path aliases for imports from project root
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
All imports go at the top of files, no mid-file dynamic imports
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsxapps/web/app/api/user/email-account/route.ts
apps/web/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Follow NextJS app router structure with (app) directory
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsxapps/web/app/api/user/email-account/route.ts
apps/web/**/*.{ts,tsx,js,jsx,json,css}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Format code with Prettier
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsxapps/web/app/api/user/email-account/route.ts
apps/web/**/*.{example,ts,json}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Add environment variables to
.env.example,env.ts, andturbo.json
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/api/user/email-account/route.ts
apps/web/app/api/**/*.ts
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/app/api/**/*.ts: Create GET API routes wrapped withwithAuthorwithEmailAccountmiddleware for fetching data
Export response types from GET API routes usingexport type GetXResponse = Awaited<ReturnType<typeof getData>>
Files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/api/user/email-account/route.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 inpage.tsx, or in theapps/web/app/(app)/PAGE_NAMEfolder
If we're in a deeply nested component we will useswrto fetch via API
If you need to useonClickin a component, that component is a client component and file must start withuse client
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.tsx: Use theLoadingContentcomponent to handle loading states instead of manual loading state management
For text areas, use theInputcomponent withtype='text',autosizeTextareaprop set to true, andregisterPropsfor form integration
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
**/*.{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 bothchildrenanddangerouslySetInnerHTMLprops 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 usetarget="_blank"withoutrel="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/settings/FollowUpRemindersSetting.tsx
apps/web/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{tsx,jsx}: Follow tailwindcss patterns with prettier-plugin-tailwindcss for class sorting
Prefer functional components with hooks in React
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach in components
Follow consistent naming conventions using PascalCase for components
Use LoadingContent component for async data with loading and error states
Use React Hook Form with Zod validation for form handling
Useresult?.serverErrorwithtoastErrorandtoastSuccessfor error handling in forms
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
apps/web/app/api/**/route.ts
📄 CodeRabbit inference engine (.cursor/rules/fullstack-workflow.mdc)
apps/web/app/api/**/route.ts: Create GET API routes usingwithAuthorwithEmailAccountmiddleware inapps/web/app/api/*/route.ts, export response types asGetExampleResponsetype alias for client-side type safety
Always export response types from GET routes asGet[Feature]Responseusing type inference from the data fetching function for type-safe client consumption
Do NOT use POST API routes for mutations - always use server actions withnext-safe-actioninstead
Files:
apps/web/app/api/user/email-account/route.ts
**/app/**/route.ts
📄 CodeRabbit inference engine (.cursor/rules/get-api-route.mdc)
**/app/**/route.ts: Always wrap GET API route handlers withwithAuthorwithEmailAccountmiddleware for consistent error handling and authentication in Next.js App Router
Infer and export response type for GET API routes usingAwaited<ReturnType<typeof functionName>>pattern in Next.js
Use Prisma for database queries in GET API routes
Return responses usingNextResponse.json()in GET API routes
Do not use try/catch blocks in GET API route handlers when usingwithAuthorwithEmailAccountmiddleware, as the middleware handles error handling
Files:
apps/web/app/api/user/email-account/route.ts
apps/web/app/**/[!.]*/route.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
Use kebab-case for route directories in Next.js App Router (e.g.,
api/hello-world/route)
Files:
apps/web/app/api/user/email-account/route.ts
**/{app,pages}/**/{route,+page}.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)
**/{app,pages}/**/{route,+page}.{ts,tsx}: Use middleware wrappers (withError, withAuth, withEmailAccount, withEmailProvider) that automatically create loggers with request context in API routes
Enrich logger context within route handlers using logger.with() to add request-specific fields like messageId
Files:
apps/web/app/api/user/email-account/route.ts
**/prisma/schema.prisma
📄 CodeRabbit inference engine (.cursor/rules/prisma.mdc)
Use PostgreSQL as the database system with Prisma
Files:
apps/web/prisma/schema.prisma
🧠 Learnings (41)
📚 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/app/api/follow-up-reminders/process.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 label operations from @/utils/gmail/label.ts instead of direct API calls
Applied to files:
apps/web/app/api/follow-up-reminders/process.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/app/api/follow-up-reminders/process.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 : Use `withEmailAccount` middleware for operations scoped to a specific email account, including reading/writing emails, rules, schedules, or any operation using `emailAccountId`
Applied to files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/api/user/email-account/route.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/app/api/follow-up-reminders/process.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} : Always use wrapper functions from @/utils/gmail/ for Gmail API operations instead of direct provider API calls
Applied to files:
apps/web/app/api/follow-up-reminders/process.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 : Use descriptive scoped loggers for each LLM feature, log inputs and outputs with appropriate log levels, and include relevant context in log messages
Applied to files:
apps/web/app/api/follow-up-reminders/process.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/api/follow-up-reminders/process.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/app/api/follow-up-reminders/process.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 `withEmailAccount` middleware for operations scoped to a specific email account (reading/writing emails, rules, schedules, etc.) - provides `emailAccountId`, `userId`, and `email` in `request.auth`
Applied to files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsxapps/web/app/api/user/email-account/route.ts
📚 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} : All database queries must include user scoping with `emailAccountId` or `userId` filtering in WHERE clauses
Applied to files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsxapps/web/app/api/user/email-account/route.ts
📚 Learning: 2025-11-25T14:39:04.892Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-11-25T14:39:04.892Z
Learning: Applies to apps/web/app/api/**/route.ts : All database queries must include user/account filtering with `emailAccountId` or `userId` in WHERE clauses to prevent IDOR vulnerabilities
Applied to files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsxapps/web/app/api/user/email-account/route.ts
📚 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/api/follow-up-reminders/process.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 : ALL API routes that handle user data MUST use appropriate middleware: `withEmailAccount` for email-scoped operations, `withAuth` for user-scoped operations, or `withError` with proper validation for public/cron endpoints
Applied to files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/api/user/email-account/route.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 `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/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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 **/*.ts : ALL database queries MUST be scoped to the authenticated user/account - include user/account filtering in `where` clauses (e.g., `emailAccountId`, `userId`) to ensure users only access their own resources
Applied to files:
apps/web/app/api/follow-up-reminders/process.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/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/utils/actions/**/*.ts : Use proper error handling with try/catch blocks
Applied to files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:37:22.822Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/get-api-route.mdc:0-0
Timestamp: 2025-11-25T14:37:22.822Z
Learning: Applies to **/app/**/route.ts : Do not use try/catch blocks in GET API route handlers when using `withAuth` or `withEmailAccount` middleware, as the middleware handles error handling
Applied to files:
apps/web/app/api/follow-up-reminders/process.ts
📚 Learning: 2025-12-31T23:49:09.597Z
Learnt from: rsnodgrass
Repo: elie222/inbox-zero PR: 1154
File: apps/web/app/api/user/setup-progress/route.ts:0-0
Timestamp: 2025-12-31T23:49:09.597Z
Learning: In apps/web/app/api/user/setup-progress/route.ts, Reply Zero enabled status should be determined solely by checking if the TO_REPLY rule is enabled, as it is the critical/canonical rule that Reply Zero is based on. The other conversation status types (FYI, AWAITING_REPLY, ACTIONED) should not be checked for determining Reply Zero setup progress.
<!-- </add_learning>
Applied to files:
apps/web/app/api/follow-up-reminders/process.tsapps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-07T21:07:34.062Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1230
File: apps/web/utils/ai/document-filing/parse-filing-reply.ts:1-4
Timestamp: 2026-01-07T21:07:34.062Z
Learning: In apps/web/utils/ai/**/*.ts files, when using createGenerateObject with a label parameter, a separate scoped logger is not needed because createGenerateObject handles logging internally via the label. Adding a scoped logger in these cases would duplicate logs.
Applied to files:
apps/web/app/api/follow-up-reminders/process.ts
📚 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} : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in server actions
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in forms
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:36:40.146Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:40.146Z
Learning: Applies to **/*.{ts,tsx} : Use `result?.serverError` with `toastError` from `@/components/Toast` for error handling in async operations
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use optional chaining where undefined values aren't allowed
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-07T21:07:06.691Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1230
File: apps/web/app/(app)/[emailAccountId]/drive/page.tsx:47-70
Timestamp: 2026-01-07T21:07:06.691Z
Learning: In TSX files across the codebase, prefer direct server action calls with manual error handling (e.g., check result?.serverError and handle errors explicitly). The useAction hook pattern is not required; you can call server actions directly and use try/finally to ensure cleanup (such as resetting loading states) regardless of the hook. Apply consistently for components that perform server interactions.
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make sure to pass a message value when creating a built-in error
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use LoadingContent component for async data with loading and error states
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:37:30.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:30.660Z
Learning: Custom hooks should encapsulate reusable stateful logic, especially for data fetching or complex UI interactions
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.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: For mutating data, use Next.js server actions instead of SWR
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/hooks/**/*.{ts,tsx} : Call `mutate()` after successful mutations in SWR hooks to refresh data
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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/hooks/use*.ts : Call `mutate()` on SWR hooks after successful mutations to refresh cached data
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:36:40.146Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:40.146Z
Learning: Applies to **/*{.action,.server}.{ts,tsx} : For mutating data, use Next.js server actions
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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 : ALL API routes that handle user data MUST use appropriate middleware: use `withEmailAccount` for email-scoped operations, use `withAuth` for user-scoped operations, or use `withError` with proper validation for public/custom auth endpoints
Applied to files:
apps/web/app/api/user/email-account/route.ts
📚 Learning: 2025-11-25T14:39:04.892Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-11-25T14:39:04.892Z
Learning: Applies to apps/web/app/api/**/route.ts : API responses should use `select` to return only necessary fields and avoid exposing sensitive data
Applied to files:
apps/web/app/api/user/email-account/route.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 : 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
Applied to files:
apps/web/app/api/user/email-account/route.ts
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/app/api/**/*.ts : Create GET API routes wrapped with `withAuth` or `withEmailAccount` middleware for fetching data
Applied to files:
apps/web/app/api/user/email-account/route.ts
📚 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} : API routes should only return necessary fields using `select` in database queries to prevent unintended information disclosure
Applied to files:
apps/web/app/api/user/email-account/route.ts
🧬 Code graph analysis (1)
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx (7)
apps/web/utils/actions/follow-up-reminders.ts (1)
updateFollowUpSettingsAction(7-32)apps/web/components/Toast.tsx (2)
toastSuccess(3-12)toastError(14-19)apps/web/components/SettingCard.tsx (1)
SettingCard(3-34)apps/web/components/LoadingContent.tsx (1)
LoadingContent(13-31)apps/web/components/Input.tsx (1)
Label(116-132)apps/web/components/Toggle.tsx (1)
Toggle(18-50)apps/web/components/ui/select.tsx (4)
Select(150-150)SelectTrigger(153-153)SelectContent(154-154)SelectItem(156-156)
⏰ 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). (2)
- GitHub Check: cubic · AI code reviewer
- GitHub Check: test
🔇 Additional comments (10)
apps/web/prisma/migrations/20260108121515_add_follow_up_auto_draft_setting/migration.sql (1)
1-2: LGTM!The migration correctly adds the
followUpAutoDraftEnabledboolean column with a sensible default oftrue, ensuring existing accounts automatically have the feature enabled. This aligns with the Prisma schema definition.apps/web/app/api/user/email-account/route.ts (1)
27-30: LGTM!The new follow-up settings fields are correctly added to the select clause. The route properly uses
withEmailAccountmiddleware for authentication, scopes the query toemailAccountId, usesSafeErrorfor error handling, and exports the response type following theGet[Feature]Responsepattern. Based on learnings and coding guidelines.apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx (3)
37-63: Well-structured hook usage and error handling.The component correctly:
- Defines all hooks before conditional returns (React hooks rules)
- Uses
useActionwith properonSuccess/onErrorcallbacks- Implements toast notifications following the coding guidelines (
toastErrorwithserverError)- Calls
mutate()after mutations to refresh SWR cache
65-145: Optimistic updates implemented correctly.Each handler properly:
- Guards against missing data
- Creates optimistic data and calls
mutate(optimisticData, false)to update UI immediately- Executes the server action
- Reverts on error via the
onErrorcallback'smutate()call
200-216: Good UX: Auto-draft toggle disabled when reminders are off.The auto-draft toggle is correctly disabled when
!enabled, preventing users from configuring a sub-feature when the parent feature is disabled.apps/web/prisma/schema.prisma (1)
148-152: LGTM!The new follow-up settings fields are well-designed:
followUpRemindersEnableddefaults tofalse(opt-in feature)- Day thresholds default to 3 days (reasonable default)
followUpAutoDraftEnableddefaults totrue(expected behavior when enabling reminders)apps/web/app/api/follow-up-reminders/process.ts (4)
12-71: LGTM! Well-structured batch processing with proper error isolation.The function correctly:
- Filters accounts by
followUpRemindersEnabledAND premium status- Uses
selectto fetch only necessary fields (per coding guidelines)- Isolates per-account errors with try/catch and
captureException- Continues processing other accounts on failure
- Returns useful summary metrics
94-104: Good defensive check for missing provider.The early return when
account.provideris null prevents runtime errors and logs the skip appropriately.
213-223: LGTM! Non-critical cleanup properly isolated.The stale drafts cleanup is correctly wrapped in its own try/catch since it's a maintenance task that shouldn't fail the overall processing.
151-182: No action needed—applyFollowUpLabelis already idempotent.The function is safe to call multiple times on the same message. Gmail's API inherently handles duplicate label additions as no-ops, and Outlook's implementation explicitly checks for existing labels before applying. If
generateFollowUpDraftfails and the tracker is retried, reapplying the label will not cause issues.Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
.claude/commands/write-tests.md (1)
49-55: Step 0 auto-detection command scope could be clearer.The comment "Auto-detect: staged → branch diff → specified files" followed by a single
git diff --cachedcommand suggests a linear fallback strategy, but the implementation shows only one command. Consider clarifying the intended flow:
- Does
--cachedrepresent staged changes?- Should the instructions show fallback commands for other scenarios (e.g.,
git diff main...HEADfor branch-relative changes)?Adding a brief comment explaining when each command applies would improve clarity for users unfamiliar with git diff semantics.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
.claude/commands/write-tests.md
🧰 Additional context used
📓 Path-based instructions (1)
!(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:
.claude/commands/write-tests.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (1)
.claude/commands/write-tests.md (1)
100-100: Clarify the "Do NOT use sandbox" constraint.Line 100 states "Do NOT use sandbox for test commands" without explanation. This instruction stands out as potentially context-dependent or stale. Please clarify:
- Why should the sandbox be avoided?
- What is the impact if someone uses it (e.g., does
pnpm testfail in sandbox)?- Is this a known limitation of the testing environment?
This will help future readers understand the constraint and avoid confusion.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @apps/web/prisma/schema.prisma:
- Around line 757-758: Add a Prisma index that includes followUpAppliedAt to
speed up the follow-up queries: add a composite index covering emailAccountId,
type, resolved, followUpAppliedAt, sentAt to the model that defines the
followUpAppliedAt field (or alternatively add two indexes: one on
emailAccountId+type+resolved+followUpAppliedAt and a second on
emailAccountId+followUpAppliedAt) so the processor queries using WHERE
followUpAppliedAt IS NULL and the cleanup query using WHERE followUpAppliedAt <
threshold will use an index.
🧹 Nitpick comments (1)
apps/web/prisma/schema.prisma (1)
150-151: Consider more explicit field naming.The fields
followUpAwaitingReplyDaysandfollowUpNeedsReplyDayscould be more explicit about their purpose. Consider names likefollowUpAwaitingReplyReminderDaysandfollowUpNeedsReplyReminderDaysto clarify that these represent the delay before a reminder is triggered, not just a general time period.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
.claude/commands/write-tests.mdapps/web/prisma/schema.prismaapps/web/utils/webhook/process-history-item.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- .claude/commands/write-tests.md
- apps/web/utils/webhook/process-history-item.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/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
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (1)
apps/web/prisma/schema.prisma (1)
148-153: Application-level validation is already properly enforced.The
followUpAwaitingReplyDaysandfollowUpNeedsReplyDaysfields are validated inapps/web/utils/actions/follow-up-reminders.validation.tswith Zod constraints (z.number().int().min(1).max(30)), which ensures only positive integers between 1 and 30 are accepted. Database-level CHECK constraints are not necessary given the existing application-level validation pattern used throughout the codebase.Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx (1)
55-59: UsegetActionErrorMessageutility for error extraction.Per coding guidelines, error messages should be extracted using the centralized utility rather than accessing
serverErrordirectly.♻️ Suggested refactor
Add the import at the top of the file:
import { getActionErrorMessage } from "@/utils/error";Then update the error handler:
onError: (error) => { mutate(); toastError({ - description: error.error?.serverError ?? "Failed to update settings", + description: getActionErrorMessage(error.error, "Failed to update settings"), }); },
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)
**/*.{ts,tsx}: For API GET requests to server, use theswrpackage
Useresult?.serverErrorwithtoastErrorfrom@/components/Toastfor 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 conventionuse[FeatureName]Enabledthat return a boolean fromuseFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming conventionuse[FeatureName]Variantthat define variant types, useuseFeatureFlagVariantKey()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
Useas constinstead of literal types and type annotations
Use eitherT[]orArray<T>consistently
Initialize each enum member value explicitly
Useexport typefor types
Use `impo...
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.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 inpage.tsx, or in theapps/web/app/(app)/PAGE_NAMEfolder
If we're in a deeply nested component we will useswrto fetch via API
If you need to useonClickin a component, that component is a client component and file must start withuse client
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)
Always import Prisma enums from
@/generated/prisma/enumsinstead of@/generated/prisma/clientto avoid Next.js bundling errors in client componentsImport Prisma using the project's centralized utility:
import prisma from '@/utils/prisma'
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
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
Do not export types/interfaces that are only used within the same file. Export later if needed
Infer types from Zod schemas usingz.infer<typeof schema>instead of duplicating as separate interfaces
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Usenext/imagepackage for images
For API GET requests to server, use theswrpackage with hooks likeuseSWRto fetch data
For text inputs, use theInputcomponent withregisterPropsfor form integration and error handling
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
**/*.{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/settings/FollowUpRemindersSetting.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.tsx: Use theLoadingContentcomponent to handle loading states instead of manual loading state management
For text areas, use theInputcomponent withtype='text',autosizeTextareaprop set to true, andregisterPropsfor form integration
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useaccessKeyattribute on any HTML element
Don't setaria-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 thescopeprop 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 assigntabIndexto non-interactive HTML elements
Don't use positive integers fortabIndexproperty
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 atitleelement 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
AssigntabIndexto non-interactive HTML elements witharia-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 atypeattribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden)
Always include alangattribute on the html element
Always include atitleattribute for iframe elements
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress
AccompanyonMouseOver/onMouseOutwithonFocus/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/settings/FollowUpRemindersSetting.tsx
**/*.{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 bothchildrenanddangerouslySetInnerHTMLprops 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 usetarget="_blank"withoutrel="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/settings/FollowUpRemindersSetting.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/settings/FollowUpRemindersSetting.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')
**/*.{js,ts,jsx,tsx}: Add helper functions to the bottom of files, not the top!
All imports go at the top of files, no mid-file dynamic imports.
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx,js,jsx}: Use@/path aliases for imports from project root
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. Never add comments that just describe what the code does. Only add comments for 'why' not 'what'
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports
UsegetActionErrorMessage(error.error)from@/utils/errorto extract user-friendly error messages
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
apps/web/**/*.{ts,tsx,css}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Follow tailwindcss patterns with prettier-plugin-tailwindcss
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
apps/web/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{tsx,jsx}: Prefer functional components with hooks
Use shadcn/ui components when available
Follow consistent naming conventions (PascalCase for components)
Use LoadingContent component for async data with loading and error states
Use React Hook Form with Zod validation for form handling
UseuseActionhook fromnext-safe-action/hookswithonSuccessandonErrorcallbacks for form submission
Use LoadingContent component to handle loading and error states consistently
Callmutate()after successful mutations to refresh SWR data
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
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/settings/FollowUpRemindersSetting.tsx
apps/web/**/*.{ts,tsx,js,jsx,json}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Client-side environment variables must be prefixed with
NEXT_PUBLIC_
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php,rs,kt,swift,m}
📄 CodeRabbit inference engine (.cursor/rules/notes.mdc)
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments. Never add comments that just describe what the code does - code should explain itself. Only add comments for 'why' not 'what'.
Files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
🧠 Learnings (29)
📚 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} : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling in server actions
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:36:40.146Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:40.146Z
Learning: Applies to **/*.{ts,tsx} : Use `result?.serverError` with `toastError` from `@/components/Toast` for error handling in async operations
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/components/**/*.tsx : Use `getActionErrorMessage(error.error)` utility to extract user-friendly error messages from server actions, supporting optional `prefix` parameter
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/**/*.{ts,tsx,js,jsx} : Use `getActionErrorMessage(error.error)` from `@/utils/error` to extract user-friendly error messages
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-09T17:27:19.225Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1234
File: apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx:65-83
Timestamp: 2026-01-09T17:27:19.225Z
Learning: In the elie222/inbox-zero repo, for React components using next-safe-action, using optimistic updates with mutate on success/error is an accepted approach to address race conditions in toggle handlers. It is acceptable for components not to guard rapid toggles with isExecuting (disable) when the optimistic UI state is reconciled by mutate. Apply this guidance to similar TSX components in the web app where appropriate.
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use optional chaining where undefined values aren't allowed
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/**/*.{ts,tsx,js,jsx} : Use proper error handling with try/catch blocks
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.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 : 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/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-07T21:07:06.691Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 1230
File: apps/web/app/(app)/[emailAccountId]/drive/page.tsx:47-70
Timestamp: 2026-01-07T21:07:06.691Z
Learning: In TSX files across the codebase, prefer direct server action calls with manual error handling (e.g., check result?.serverError and handle errors explicitly). The useAction hook pattern is not required; you can call server actions directly and use try/finally to ensure cleanup (such as resetting loading states) regardless of the hook. Apply consistently for components that perform server interactions.
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use LoadingContent component for async data with loading and error states
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:37:30.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:30.660Z
Learning: Custom hooks should encapsulate reusable stateful logic, especially for data fetching or complex UI interactions
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/utils/actions/!(*.validation).ts : Use `next-safe-action` for all server actions with `actionClient`, `.metadata()`, `.inputSchema()`, and `.action()` chain pattern
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/components/**/*.tsx : Use `useAction` hook with `onSuccess` and `onError` callbacks for handling server action responses in forms
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.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/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-12-31T23:49:09.597Z
Learnt from: rsnodgrass
Repo: elie222/inbox-zero PR: 1154
File: apps/web/app/api/user/setup-progress/route.ts:0-0
Timestamp: 2025-12-31T23:49:09.597Z
Learning: In apps/web/app/api/user/setup-progress/route.ts, Reply Zero enabled status should be determined solely by checking if the TO_REPLY rule is enabled, as it is the critical/canonical rule that Reply Zero is based on. The other conversation status types (FYI, AWAITING_REPLY, ACTIONED) should not be checked for determining Reply Zero setup progress.
<!-- </add_learning>
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `next-safe-action` with proper Zod validation for server actions
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-08T15:09:06.736Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2026-01-08T15:09:06.736Z
Learning: Applies to apps/web/(hooks|components)/**/*.ts?(x) : Call `mutate()` after successful mutations to refresh SWR data
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.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: For mutating data, use Next.js server actions instead of SWR
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Call `mutate()` after successful mutations to refresh SWR data
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:36:40.146Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:40.146Z
Learning: Applies to **/*{.action,.server}.{ts,tsx} : For mutating data, use Next.js server actions
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/utils/actions/*.ts : Call `revalidatePath` in server actions after successful mutations
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.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} : All database queries must include user scoping with `emailAccountId` or `userId` filtering in WHERE clauses
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 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 `withEmailAccount` middleware for operations scoped to a specific email account (reading/writing emails, rules, schedules, etc.) - provides `emailAccountId`, `userId`, and `email` in `request.auth`
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Components with `onClick` handlers must be client components marked with the `use client` directive
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.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 : Implement all server actions using the `next-safe-action` library with actionClient, actionClientUser, or adminActionClient for type safety and validation
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.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 `actionClientUser` when only authenticated user context (userId) is needed
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
📚 Learning: 2026-01-09T21:51:15.182Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2026-01-09T21:51:15.182Z
Learning: Applies to apps/web/utils/actions/*.ts : Server actions should use `actionClient.metadata({ name: 'actionName' }).schema(schema).action(...)` pattern
Applied to files:
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx
🧬 Code graph analysis (1)
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx (8)
apps/web/utils/actions/follow-up-reminders.ts (1)
updateFollowUpSettingsAction(7-32)apps/web/components/Toast.tsx (2)
toastSuccess(3-12)toastError(14-19)apps/web/components/SettingCard.tsx (1)
SettingCard(3-34)apps/web/components/Toggle.tsx (1)
Toggle(18-50)apps/web/components/ui/dialog.tsx (6)
Dialog(116-116)DialogTrigger(120-120)DialogContent(121-121)DialogHeader(122-122)DialogTitle(124-124)DialogDescription(125-125)apps/web/components/LoadingContent.tsx (1)
LoadingContent(13-31)apps/web/components/Input.tsx (1)
Label(116-132)apps/web/components/ui/select.tsx (4)
Select(150-150)SelectTrigger(153-153)SelectContent(154-154)SelectItem(156-156)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (3)
apps/web/app/(app)/[emailAccountId]/assistant/settings/FollowUpRemindersSetting.tsx (3)
64-82: LGTM — Optimistic update handlers are well-implemented.All four handlers follow a consistent pattern: guard against missing data, apply optimistic update via
mutate(optimisticData, false), then execute the server action. The dependency arrays are correctly specified. Based on learnings, this optimistic approach with mutate reconciliation is an accepted pattern in this codebase.Also applies to: 84-103, 105-124, 126-144
146-162: LGTM — Early return provides graceful loading state.Returning a disabled toggle when data is unavailable prevents actions from being called with undefined values and provides clear UX feedback.
164-280: LGTM — Component structure and Dialog implementation are well-organized.The SettingCard with conditional Configure button, Dialog with form controls, and LoadingContent wrapper follow established patterns. The Select components properly use controlled values with handlers, and the Toggle component correctly receives disabled state during execution within the dialog.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/web/utils/follow-up/generate-draft.ts (1)
62-62: Useat(-1)for accessing the last array element.Per coding guidelines, prefer
at()over integer index access for array elements.♻️ Suggested change
- const lastMessage = thread.messages[thread.messages.length - 1]; + const lastMessage = thread.messages.at(-1);Note: With this change,
lastMessagebecomesParsedMessage | undefined, but since you've already validatedthread.messages?.lengthis truthy, TypeScript may require a non-null assertion or guard. You could use:const lastMessage = thread.messages.at(-1)!;
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/utils/follow-up/generate-draft.ts
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)
**/*.{ts,tsx}: For API GET requests to server, use theswrpackage
Useresult?.serverErrorwithtoastErrorfrom@/components/Toastfor 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 conventionuse[FeatureName]Enabledthat return a boolean fromuseFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming conventionuse[FeatureName]Variantthat define variant types, useuseFeatureFlagVariantKey()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
Useas constinstead of literal types and type annotations
Use eitherT[]orArray<T>consistently
Initialize each enum member value explicitly
Useexport typefor types
Use `impo...
Files:
apps/web/utils/follow-up/generate-draft.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)
Always import Prisma enums from
@/generated/prisma/enumsinstead of@/generated/prisma/clientto avoid Next.js bundling errors in client componentsImport Prisma using the project's centralized utility:
import prisma from '@/utils/prisma'
Files:
apps/web/utils/follow-up/generate-draft.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
Do not export types/interfaces that are only used within the same file. Export later if needed
Infer types from Zod schemas usingz.infer<typeof schema>instead of duplicating as separate interfaces
Files:
apps/web/utils/follow-up/generate-draft.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'sselectoption. 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. AllfindUnique/findFirstcalls 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
AllfindManyqueries 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/follow-up/generate-draft.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Usenext/imagepackage for images
For API GET requests to server, use theswrpackage with hooks likeuseSWRto fetch data
For text inputs, use theInputcomponent withregisterPropsfor form integration and error handling
Files:
apps/web/utils/follow-up/generate-draft.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/utils/follow-up/generate-draft.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useaccessKeyattribute on any HTML element
Don't setaria-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 thescopeprop 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 assigntabIndexto non-interactive HTML elements
Don't use positive integers fortabIndexproperty
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 atitleelement 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
AssigntabIndexto non-interactive HTML elements witharia-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 atypeattribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden)
Always include alangattribute on the html element
Always include atitleattribute for iframe elements
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress
AccompanyonMouseOver/onMouseOutwithonFocus/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/utils/follow-up/generate-draft.ts
!(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/utils/follow-up/generate-draft.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')
**/*.{js,ts,jsx,tsx}: Add helper functions to the bottom of files, not the top!
All imports go at the top of files, no mid-file dynamic imports.
Files:
apps/web/utils/follow-up/generate-draft.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/follow-up/generate-draft.ts
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx,js,jsx}: Use@/path aliases for imports from project root
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. Never add comments that just describe what the code does. Only add comments for 'why' not 'what'
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports
UsegetActionErrorMessage(error.error)from@/utils/errorto extract user-friendly error messages
Files:
apps/web/utils/follow-up/generate-draft.ts
apps/web/**/*.{ts,tsx,css}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Follow tailwindcss patterns with prettier-plugin-tailwindcss
Files:
apps/web/utils/follow-up/generate-draft.ts
apps/web/**/*.{ts,tsx,js,jsx,json}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Client-side environment variables must be prefixed with
NEXT_PUBLIC_
Files:
apps/web/utils/follow-up/generate-draft.ts
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php,rs,kt,swift,m}
📄 CodeRabbit inference engine (.cursor/rules/notes.mdc)
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments. Never add comments that just describe what the code does - code should explain itself. Only add comments for 'why' not 'what'.
Files:
apps/web/utils/follow-up/generate-draft.ts
🧠 Learnings (4)
📚 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/follow-up/generate-draft.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/follow-up/generate-draft.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/follow-up/generate-draft.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/follow-up/generate-draft.ts
🧬 Code graph analysis (1)
apps/web/utils/follow-up/generate-draft.ts (3)
apps/web/utils/email/types.ts (1)
EmailProvider(45-251)apps/web/utils/logger.ts (1)
Logger(6-6)apps/web/utils/reply-tracker/generate-draft.ts (1)
fetchMessagesAndGenerateDraft(29-79)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (3)
apps/web/utils/follow-up/generate-draft.ts (3)
1-20: LGTM!Imports follow project conventions - using centralized prisma, proper type imports, and logger passed as parameter per coding guidelines for helper functions.
64-87: LGTM!Draft generation and creation logic is well-structured:
- Correctly uses
fetchMessagesAndGenerateDraftfor LLM-based content generation- Properly interfaces with
EmailProvider.draftEmail- Error handling logs context before rethrowing for upstream handling
- Success logging includes actionable identifiers (threadId, draftId)
24-47: No type compatibility issues found. The Prisma query selects exactly the fields required byEmailAccountWithAI, including all nesteduserandaccountrelations. The fields are structurally identical to the type definition.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @apps/web/utils/webhook/process-history-item.ts:
- Around line 174-185: Add a guard to avoid calling clearFollowUpLabel with an
undefined thread id: check that actualThreadId (resolved from the function
parameter threadId or parsedMessage.threadId) is a non-empty string before
invoking clearFollowUpLabel; if it is falsy, skip the call (and the try/catch)
so you don't pass undefined into clearFollowUpLabel, and keep existing
logging/exception capture only around the actual call when actualThreadId is
present.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/prisma/schema.prismaapps/web/utils/webhook/process-history-item.ts
🧰 Additional context used
📓 Path-based instructions (15)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)
**/*.{ts,tsx}: For API GET requests to server, use theswrpackage
Useresult?.serverErrorwithtoastErrorfrom@/components/Toastfor 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 conventionuse[FeatureName]Enabledthat return a boolean fromuseFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming conventionuse[FeatureName]Variantthat define variant types, useuseFeatureFlagVariantKey()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
Useas constinstead of literal types and type annotations
Use eitherT[]orArray<T>consistently
Initialize each enum member value explicitly
Useexport typefor types
Use `impo...
Files:
apps/web/utils/webhook/process-history-item.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)
Always import Prisma enums from
@/generated/prisma/enumsinstead of@/generated/prisma/clientto avoid Next.js bundling errors in client componentsImport Prisma using the project's centralized utility:
import prisma from '@/utils/prisma'
Files:
apps/web/utils/webhook/process-history-item.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
Do not export types/interfaces that are only used within the same file. Export later if needed
Infer types from Zod schemas usingz.infer<typeof schema>instead of duplicating as separate interfaces
Files:
apps/web/utils/webhook/process-history-item.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'sselectoption. 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. AllfindUnique/findFirstcalls 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
AllfindManyqueries 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/webhook/process-history-item.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Usenext/imagepackage for images
For API GET requests to server, use theswrpackage with hooks likeuseSWRto fetch data
For text inputs, use theInputcomponent withregisterPropsfor form integration and error handling
Files:
apps/web/utils/webhook/process-history-item.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/utils/webhook/process-history-item.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useaccessKeyattribute on any HTML element
Don't setaria-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 thescopeprop 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 assigntabIndexto non-interactive HTML elements
Don't use positive integers fortabIndexproperty
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 atitleelement 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
AssigntabIndexto non-interactive HTML elements witharia-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 atypeattribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden)
Always include alangattribute on the html element
Always include atitleattribute for iframe elements
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress
AccompanyonMouseOver/onMouseOutwithonFocus/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/utils/webhook/process-history-item.ts
!(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/utils/webhook/process-history-item.tsapps/web/prisma/schema.prisma
**/*.{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')
**/*.{js,ts,jsx,tsx}: Add helper functions to the bottom of files, not the top!
All imports go at the top of files, no mid-file dynamic imports.
Files:
apps/web/utils/webhook/process-history-item.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/webhook/process-history-item.ts
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx,js,jsx}: Use@/path aliases for imports from project root
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. Never add comments that just describe what the code does. Only add comments for 'why' not 'what'
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports
UsegetActionErrorMessage(error.error)from@/utils/errorto extract user-friendly error messages
Files:
apps/web/utils/webhook/process-history-item.ts
apps/web/**/*.{ts,tsx,css}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Follow tailwindcss patterns with prettier-plugin-tailwindcss
Files:
apps/web/utils/webhook/process-history-item.ts
apps/web/**/*.{ts,tsx,js,jsx,json}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Client-side environment variables must be prefixed with
NEXT_PUBLIC_
Files:
apps/web/utils/webhook/process-history-item.ts
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php,rs,kt,swift,m}
📄 CodeRabbit inference engine (.cursor/rules/notes.mdc)
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments. Never add comments that just describe what the code does - code should explain itself. Only add comments for 'why' not 'what'.
Files:
apps/web/utils/webhook/process-history-item.ts
**/prisma/schema.prisma
📄 CodeRabbit inference engine (.cursor/rules/prisma.mdc)
Use PostgreSQL as the database system with Prisma
Files:
apps/web/prisma/schema.prisma
🧠 Learnings (14)
📚 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/utils/webhook/process-history-item.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/webhook/process-history-item.ts
📚 Learning: 2026-01-01T10:42:29.775Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.775Z
Learning: Applies to **/*.test.{ts,tsx} : Use test helper functions `getEmail`, `getEmailAccount`, and `getRule` from `@/__tests__/helpers` for creating mock data
Applied to files:
apps/web/utils/webhook/process-history-item.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/webhook/process-history-item.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} : Always use wrapper functions from @/utils/gmail/ for Gmail API operations instead of direct provider API calls
Applied to files:
apps/web/utils/webhook/process-history-item.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/webhook/process-history-item.ts
📚 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/utils/webhook/process-history-item.ts
📚 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/webhook/process-history-item.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 **/{pages,routes,components}/**/*.{ts,tsx} : Never call Gmail API directly from routes or components - always use wrapper functions from the utils folder
Applied to files:
apps/web/utils/webhook/process-history-item.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/webhook/process-history-item.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 : Use `withEmailAccount` middleware for operations scoped to a specific email account, including reading/writing emails, rules, schedules, or any operation using `emailAccountId`
Applied to files:
apps/web/utils/webhook/process-history-item.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/webhook/process-history-item.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 `withEmailAccount` middleware for operations scoped to a specific email account (reading/writing emails, rules, schedules, etc.) - provides `emailAccountId`, `userId`, and `email` in `request.auth`
Applied to files:
apps/web/utils/webhook/process-history-item.ts
📚 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/schema.prisma
🧬 Code graph analysis (1)
apps/web/utils/webhook/process-history-item.ts (2)
apps/web/utils/follow-up/cleanup.ts (1)
clearFollowUpLabel(103-143)apps/web/utils/error.ts (1)
captureException(47-77)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (4)
apps/web/utils/webhook/process-history-item.ts (1)
7-7: LGTM!The imports are correctly placed and both utilities are properly used in the follow-up label cleanup logic.
Also applies to: 16-16
apps/web/prisma/schema.prisma (3)
148-152: LGTM! Consider user expectations for auto-draft default.The follow-up reminder fields are well-designed with appropriate types and defaults. The
followUpAutoDraftEnabledfield defaults totrue, which means auto-draft generation will be enabled by default when users enable follow-up reminders. While this is just a configurable default, ensure the UI clearly communicates this behavior to avoid surprises.
757-757: LGTM!The
followUpAppliedAtfield appropriately tracks when follow-up labels are applied, with nullable type to indicate threads without follow-up labels. This supports idempotent follow-up processing.
766-766: LGTM!The composite index is well-designed for follow-up reminder queries that filter by account, tracker type, resolution status, and follow-up application state, then order by sent date. The column ordering supports efficient query execution.
| // Remove follow-up label if present (they replied, so follow-up no longer needed) | ||
| try { | ||
| await clearFollowUpLabel({ | ||
| emailAccountId, | ||
| threadId: actualThreadId, | ||
| provider, | ||
| logger, | ||
| }); | ||
| } catch (error) { | ||
| logger.error("Error removing follow-up label on inbound", { error }); | ||
| captureException(error, { emailAccountId }); | ||
| } |
There was a problem hiding this comment.
Add guard clause for undefined threadId.
The actualThreadId could theoretically be undefined if both threadId parameter and parsedMessage.threadId are falsy. While rare (email messages typically have thread IDs), this would pass an undefined value to clearFollowUpLabel, which expects a string.
🛡️ Proposed fix
// Remove follow-up label if present (they replied, so follow-up no longer needed)
+if (actualThreadId) {
try {
await clearFollowUpLabel({
emailAccountId,
threadId: actualThreadId,
provider,
logger,
});
} catch (error) {
logger.error("Error removing follow-up label on inbound", { error });
captureException(error, { emailAccountId });
}
+}📝 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.
| // Remove follow-up label if present (they replied, so follow-up no longer needed) | |
| try { | |
| await clearFollowUpLabel({ | |
| emailAccountId, | |
| threadId: actualThreadId, | |
| provider, | |
| logger, | |
| }); | |
| } catch (error) { | |
| logger.error("Error removing follow-up label on inbound", { error }); | |
| captureException(error, { emailAccountId }); | |
| } | |
| // Remove follow-up label if present (they replied, so follow-up no longer needed) | |
| if (actualThreadId) { | |
| try { | |
| await clearFollowUpLabel({ | |
| emailAccountId, | |
| threadId: actualThreadId, | |
| provider, | |
| logger, | |
| }); | |
| } catch (error) { | |
| logger.error("Error removing follow-up label on inbound", { error }); | |
| captureException(error, { emailAccountId }); | |
| } | |
| } |
🤖 Prompt for AI Agents
In @apps/web/utils/webhook/process-history-item.ts around lines 174 - 185, Add a
guard to avoid calling clearFollowUpLabel with an undefined thread id: check
that actualThreadId (resolved from the function parameter threadId or
parsedMessage.threadId) is a non-empty string before invoking
clearFollowUpLabel; if it is falsy, skip the call (and the try/catch) so you
don't pass undefined into clearFollowUpLabel, and keep existing
logging/exception capture only around the actual call when actualThreadId is
present.
Adds automated follow-up reminders for sent emails that haven't received a response.
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.