Skip to content

feat: handle invalid_grant errors with reconnection emails#1169

Merged
elie222 merged 3 commits intomainfrom
feat/handle-invalid-grant
Jan 1, 2026
Merged

feat: handle invalid_grant errors with reconnection emails#1169
elie222 merged 3 commits intomainfrom
feat/handle-invalid-grant

Conversation

@elie222
Copy link
Copy Markdown
Owner

@elie222 elie222 commented Jan 1, 2026

User description

auth: implement robust handling for Gmail invalid_grant errors

Sends reconnection emails, marks accounts as disconnected, and adds in-app notifications when OAuth tokens are revoked or expired.

  • Added disconnectedAt field to Account model
  • Created reconnection email template and sender function
  • Implemented cleanup logic with early bailing for disconnected accounts
  • Added in-app error message system for disconnections
  • Updated webhook and watch-manager to filter out disconnected accounts
  • Verified with unit tests for token cleanup, webhook validation, and token saving

Summary by CodeRabbit

  • New Features

    • Reconnection emails with a CTA to restore OAuth connections; sending flow added.
  • Improvements

    • Accounts now record disconnection timestamps and are excluded from active monitoring until reconnected.
    • Token-save and linking flows now clear stale user error messages automatically.
    • Validation short-circuits for disconnected accounts to avoid further processing.
    • Error messaging includes an explicit "Account disconnected" type.
  • Tests

    • Expanded tests for token cleanup, reconnection emails, webhook handling, and related flows.

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


Generated description

Below is a concise technical summary of the changes proposed in this PR:

graph LR
    subgraph "inbox-zero-ai" ["inbox-zero-ai"]
    cleanupInvalidTokens_("cleanupInvalidTokens"):::modified
    PRISMA_("PRISMA"):::modified
    RESEND_("RESEND"):::added
    addUserErrorMessage_("addUserErrorMessage"):::modified
    handleLinkAccount_("handleLinkAccount"):::modified
    clearUserErrorMessages_("clearUserErrorMessages"):::modified
    saveTokens_("saveTokens"):::modified
    handleError_("handleError"):::modified
    cleanupInvalidTokens_ -- "Now reads disconnectedAt and metadata before cleanup." --> PRISMA_
    cleanupInvalidTokens_ -- "Also sets disconnectedAt when clearing OAuth tokens." --> PRISMA_
    cleanupInvalidTokens_ -- "Sends reconnection email to watched account's email." --> RESEND_
    cleanupInvalidTokens_ -- "Records ACCOUNT_DISCONNECTED error for affected user." --> addUserErrorMessage_
    handleLinkAccount_ -- "Upserts emailAccount transactionally, preserving OAuth data." --> PRISMA_
    handleLinkAccount_ -- "Clears disconnectedAt marking account active again." --> PRISMA_
    handleLinkAccount_ -- "Clears user's error messages upon successful linking." --> clearUserErrorMessages_
    saveTokens_ -- "Resets disconnectedAt when saving refreshed OAuth tokens." --> PRISMA_
    saveTokens_ -- "Updates account tokens and returns userId after update." --> PRISMA_
    saveTokens_ -- "Clears user's error messages after token persistence." --> clearUserErrorMessages_
    handleError_ -- "Now reports LLM errors tied to userId." --> addUserErrorMessage_
    addUserErrorMessage_ -- "Now looks up user by id before adding error." --> PRISMA_
    clearUserErrorMessages_ -- "Clears errorMessages with error handling and exception capture." --> PRISMA_
    classDef added stroke:#15AA7A
    classDef removed stroke:#CD5270
    classDef modified stroke:#EDAC4C
    linkStyle default stroke:#CBD5E1,font-size:13px
    end
    subgraph "@inboxzero/resend" ["@inboxzero/resend"]
    sendReconnectionEmail_("sendReconnectionEmail"):::added
    ReconnectionEmail_("ReconnectionEmail"):::added
    EMAIL_SERVICE_("EMAIL_SERVICE"):::modified
    Footer_("Footer"):::added
    GETINBOXZERO_("GETINBOXZERO"):::added
    sendReconnectionEmail_ -- "Renders ReconnectionEmail with email/unsubscribeToken; sends reconnection subject." --> ReconnectionEmail_
    sendReconnectionEmail_ -- "Sends rendered email including unsubscribeToken and reconnection category tag." --> EMAIL_SERVICE_
    ReconnectionEmail_ -- "Appends Footer adding unsubscribe link with encoded unsubscribeToken." --> Footer_
    ReconnectionEmail_ -- "Uses baseUrl for branding, CTA and navigation links." --> GETINBOXZERO_
    Footer_ -- "Generates unsubscribe/support/privacy links using baseUrl and token." --> GETINBOXZERO_
    classDef added stroke:#15AA7A
    classDef removed stroke:#CD5270
    classDef modified stroke:#EDAC4C
    linkStyle default stroke:#CBD5E1,font-size:13px
    end
Loading

Implement robust handling for invalid_grant OAuth errors by introducing a disconnectedAt field in the Account model to track disconnections, sending targeted reconnection emails to users, and displaying in-app notifications. Prevent disconnected accounts from being processed by the watch-manager and webhooks, and automatically clear the disconnected status and associated error messages upon successful re-authentication.

TopicDetails
Disconnected State Management Manages the system-wide state of disconnected accounts by preventing them from being actively monitored or processed. This involves modifying the watch-manager and webhook validation to filter out accounts with a disconnectedAt timestamp. Additionally, it implements logic within saveTokens and handleLinkAccount to clear the disconnectedAt timestamp and any associated user error messages when an account successfully re-authenticates or re-links, ensuring a clean reconnection process. Minor test infrastructure updates are also included.
Modified files (9)
  • apps/web/utils/email/reply-all.ts
  • apps/web/utils/email/watch-manager.ts
  • apps/web/utils/auth.ts
  • apps/web/utils/webhook/validate-webhook-account.test.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • apps/web/utils/email/reply-all.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/auth.test.ts
Latest Contributors(2)
UserCommitDate
elie222fix-update-meeting-bri...January 01, 2026
eduardoleliss@gmail.comRefactor-org-and-membe...September 18, 2025
Account Disconnection Flow Establishes a comprehensive system to detect, track, and notify users about disconnected OAuth accounts. This includes adding a disconnectedAt field to the Account model, updating the cleanupInvalidTokens utility to mark accounts as disconnected, sending a ReconnectionEmail to prompt user action, and integrating an in-app error message system to inform users of the disconnection. It also updates LLM-related error handling to use userId for message attribution.
Modified files (8)
  • packages/resend/emails/reconnection.tsx
  • packages/resend/src/send.tsx
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/prisma/migrations/20260101221942_account_disconnected_at/migration.sql
  • apps/web/prisma/schema.prisma
Latest Contributors(2)
UserCommitDate
elie222Add-cold-email-notifierDecember 19, 2025
cursoragent@cursor.comRefactor-Use-emailAcco...September 22, 2025
This pull request is reviewed by Baz. Review like a pro on (Baz).

@vercel
Copy link
Copy Markdown

vercel bot commented Jan 1, 2026

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

Project Deployment Review Updated (UTC)
inbox-zero Ready Ready Preview Jan 1, 2026 11:22pm

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jan 1, 2026

Note

Other AI code review bot(s) detected

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

📝 Walkthrough

Walkthrough

Adds Account.disconnectedAt, sets it when OAuth tokens are invalidated, clears user error messages when tokens/accounts are updated, sends reconnection emails for watched accounts, and short-circuits webhook/watch flows for disconnected accounts.

Changes

Cohort / File(s) Summary
Database schema
apps/web/prisma/migrations/20260101221942_account_disconnected_at/migration.sql, apps/web/prisma/schema.prisma
Add disconnectedAt TIMESTAMP(3) / DateTime? disconnectedAt to Account.
Token cleanup & reconnection flow
apps/web/utils/auth/cleanup-invalid-tokens.ts, apps/web/utils/auth/cleanup-invalid-tokens.test.ts
Read account.disconnectedAt, bail if already disconnected, set disconnectedAt when invalidating tokens, generate unsubscribe token, send reconnection email for watched accounts, and add user-facing ACCOUNT_DISCONNECTED messages; tests cover scenarios.
Auth & token saving
apps/web/utils/auth.ts, apps/web/utils/auth.test.ts
Add saveTokens flow, clear user error messages after emailAccount/account updates, update link-account transaction to clear errors, and tests for token save behaviors.
Email template & sender
packages/resend/emails/reconnection.tsx, packages/resend/src/send.tsx
New ReconnectionEmail component and sendReconnectionEmail() helper to send reconnection CTA with unsubscribe token and category tag.
Watch & webhook logic
apps/web/utils/email/watch-manager.ts, apps/web/utils/webhook/validate-webhook-account.ts, apps/web/utils/webhook/validate-webhook-account.test.ts
Exclude accounts with disconnectedAt != null from watch list, include disconnectedAt in queries, and short-circuit webhook validation for disconnected accounts; tests updated.
Error messages & propagation
apps/web/utils/error-messages/index.ts, apps/web/utils/llms/index.ts
Change addUserErrorMessage to accept userId, add ACCOUNT_DISCONNECTED error type, improve clearUserErrorMessages error handling, and propagate userId through LLM error reporting and addUserErrorMessage calls.
Misc tests & formatting
apps/web/utils/auth.test.ts, apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts, apps/web/utils/meeting-briefs/recipient-context.test.ts, apps/web/utils/email/reply-all.ts, apps/web/utils/email/reply-all.test.ts
Test scaffolding and mocks updated (env, UTC time mocking), minor import/formatting tweaks, and expanded mocks to support new flows.

Sequence Diagram(s)

sequenceDiagram
    participant Provider as OAuth Provider
    participant System as App Server
    participant DB as Database
    participant Email as Email Service
    participant User as End User

    rect rgb(245,248,255)
    Note over Provider,System: Token refresh fails (invalid_grant / insufficient_permissions)
    Provider->>System: refresh error
    System->>System: cleanupInvalidTokens()
    end

    rect rgb(255,245,240)
    System->>DB: fetch emailAccount (includes account.disconnectedAt)
    DB-->>System: emailAccount + account.disconnectedAt
    alt account.disconnectedAt already set
        System->>System: log & short-circuit (no further action)
    else account not disconnected
        System->>DB: update account set disconnectedAt = now()
        DB-->>System: updated account
    end
    end

    rect rgb(240,255,245)
    alt reason == invalid_grant and account is watched
        System->>System: createUnsubscribeToken()
        System->>Email: sendReconnectionEmail(to, props, unsubscribeToken)
        Email-->>User: reconnection email with CTA
    else watched == false
        System->>System: log (skip reconnection email)
    end
    end

    rect rgb(255,250,240)
    System->>DB: addUserErrorMessage(userId, ACCOUNT_DISCONNECTED, message)
    DB-->>System: stored
    System->>System: clearUserErrorMessages(userId) [async]
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • anakarentorosserrano-star
  • baz-reviewer

Poem

🐰 I nudged a token, marked a dot,
A tiny timestamp—now it's not.
I sent a carrot-shaped reconnect,
So inboxes and users reconnect. ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: handle invalid_grant errors with reconnection emails' accurately summarizes the main feature being implemented, which is clearly demonstrated across multiple file changes that add disconnection handling, reconnection email templates, and error messaging.
✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp bot commented Jan 1, 2026

Handle invalid_grant by marking accounts disconnected, clearing tokens, and sending reconnection emails in auth.cleanupInvalidTokens and gate watchers/webhooks by Account.disconnectedAt

Add Account.disconnectedAt with migration and schema updates; update auth.handleLinkAccount and auth.saveTokens to clear disconnectedAt and user error messages on successful token save; extend auth.cleanupInvalidTokens to clear tokens, set disconnectedAt, add a user error message, and send reconnection emails; exclude disconnected accounts in email watch management and webhook validation; switch error messaging to key by userId; add reconnection email template and sender.

📍Where to Start

Start with the disconnection flow in auth.cleanupInvalidTokens in cleanup-invalid-tokens.ts, then review how disconnectedAt is cleared in auth.handleLinkAccount and auth.saveTokens in auth.ts.


Macroscope summarized 289fceb.

Comment thread apps/web/utils/auth/cleanup-invalid-tokens.ts
Comment thread packages/resend/emails/reconnection.tsx Outdated
Comment thread apps/web/utils/auth.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (5)
apps/web/prisma/schema.prisma (1)

28-28: LGTM! Well-designed field addition.

The disconnectedAt field is appropriately nullable and well-documented. The naming and positioning are logical.

For future optimization, consider adding a partial index if the volume of disconnected accounts grows:

@@index([disconnectedAt], map: "idx_account_connected", where: "disconnectedAt IS NULL")

This would optimize the filter in watch-manager.ts (line 40: account: { disconnectedAt: null }). However, given that most accounts remain connected, this optimization can be deferred until performance metrics indicate it's needed.

apps/web/utils/email/watch-manager.ts (1)

53-53: Field selected but not used in this file.

The disconnectedAt field is included in the select statement but isn't referenced in the downstream functions (watchEmailAccounts, watchEmailAccount). This might be for future use or consistency with other queries.

If there's no immediate plan to use this field in this file, consider removing it from the select to keep the query lean:

       account: {
         select: {
           provider: true,
           access_token: true,
           refresh_token: true,
           expires_at: true,
-          disconnectedAt: true,
         },
       },

However, if this is being included for logging, debugging, or upcoming features, it's fine to keep as-is.

apps/web/utils/auth.ts (1)

449-531: Consider harmonizing return values across both code paths.

The emailAccountId path (lines 499-505) returns void, while the providerAccountId path (lines 517-530) returns the updated account. For consistency and potential future use cases, consider returning the account (or relevant data) from both paths.

🔎 Proposed refactor to return consistent values
   if (emailAccountId) {
     // Encrypt tokens in data directly
     // Usually we do this in prisma-extensions.ts but we need to do it here because we're updating the account via the emailAccount
     // We could also edit prisma-extensions.ts to handle this case but this is easier for now
     if (data.access_token)
       data.access_token = encryptToken(data.access_token) || undefined;
     if (data.refresh_token)
       data.refresh_token = encryptToken(data.refresh_token) || "";

     const emailAccount = await prisma.emailAccount.update({
       where: { id: emailAccountId },
       data: { account: { update: data } },
-      select: { userId: true },
+      select: { userId: true, account: true },
     });

     await clearUserErrorMessages({ userId: emailAccount.userId });
+    
+    return emailAccount.account;
   } else {
apps/web/utils/auth.test.ts (1)

116-179: Good test coverage for the happy path.

The tests verify the core behavior of saveTokens for both code paths (emailAccountId and providerAccountId), ensuring that disconnectedAt is cleared and user error messages are properly cleaned up.

Consider adding test cases for edge scenarios:

  • Behavior when refresh_token is null (should return early per line 475-481 in auth.ts)
  • Error handling if clearUserErrorMessages throws
  • Error handling if the database update fails

These additional tests would improve robustness and catch potential regressions.

packages/resend/emails/reconnection.tsx (1)

107-139: Consider using email-safe component instead of div.

The Footer component includes a div at line 120 which may not render consistently across all email clients. Consider using a Text or Section component instead.

🔎 Proposed refactor
-      <div className="mt-2">
+      <Text className="mt-2">
         <Link
           href={`${baseUrl}/api/unsubscribe?token=${unsubscribeToken}`}
           className="text-gray-500 underline mr-4"
         >
           Unsubscribe
         </Link>
         <Link
           href={`${baseUrl}/support`}
           className="text-gray-500 underline mr-4"
         >
           Support
         </Link>
         <Link href={`${baseUrl}/privacy`} className="text-gray-500 underline">
           Privacy Policy
         </Link>
-      </div>
+      </Text>
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3f01c0a and b2bf3aa.

📒 Files selected for processing (14)
  • apps/web/prisma/migrations/20260101221942_account_disconnected_at/migration.sql
  • apps/web/prisma/schema.prisma
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/email/reply-all.test.ts
  • apps/web/utils/email/reply-all.ts
  • apps/web/utils/email/watch-manager.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/webhook/validate-webhook-account.test.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • packages/resend/emails/reconnection.tsx
  • packages/resend/src/send.tsx
🧰 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 the swr package
Use result?.serverError with toastError from @/components/Toast for error handling in async operations

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

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

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

Files:

  • apps/web/utils/email/watch-manager.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • packages/resend/src/send.tsx
  • apps/web/utils/email/reply-all.ts
  • apps/web/utils/email/reply-all.test.ts
  • packages/resend/emails/reconnection.tsx
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.ts
**/*.{ts,tsx,js,jsx}

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

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

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

Files:

  • apps/web/utils/email/watch-manager.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • packages/resend/src/send.tsx
  • apps/web/utils/email/reply-all.ts
  • apps/web/utils/email/reply-all.test.ts
  • packages/resend/emails/reconnection.tsx
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.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/email/watch-manager.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • apps/web/utils/email/reply-all.ts
  • apps/web/utils/email/reply-all.test.ts
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.ts
**/*.ts

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

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

Files:

  • apps/web/utils/email/watch-manager.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • apps/web/utils/email/reply-all.ts
  • apps/web/utils/email/reply-all.test.ts
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.ts
**/*.{tsx,ts}

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

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

Files:

  • apps/web/utils/email/watch-manager.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • packages/resend/src/send.tsx
  • apps/web/utils/email/reply-all.ts
  • apps/web/utils/email/reply-all.test.ts
  • packages/resend/emails/reconnection.tsx
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.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/email/watch-manager.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • packages/resend/src/send.tsx
  • apps/web/utils/email/reply-all.ts
  • apps/web/utils/email/reply-all.test.ts
  • packages/resend/emails/reconnection.tsx
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.ts
**/*.{js,jsx,ts,tsx}

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

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

Files:

  • apps/web/utils/email/watch-manager.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • packages/resend/src/send.tsx
  • apps/web/utils/email/reply-all.ts
  • apps/web/utils/email/reply-all.test.ts
  • packages/resend/emails/reconnection.tsx
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.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/email/watch-manager.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth.ts
  • apps/web/prisma/schema.prisma
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • packages/resend/src/send.tsx
  • apps/web/utils/email/reply-all.ts
  • apps/web/utils/email/reply-all.test.ts
  • packages/resend/emails/reconnection.tsx
  • apps/web/utils/auth.test.ts
  • apps/web/prisma/migrations/20260101221942_account_disconnected_at/migration.sql
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.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/email/watch-manager.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • packages/resend/src/send.tsx
  • apps/web/utils/email/reply-all.ts
  • apps/web/utils/email/reply-all.test.ts
  • packages/resend/emails/reconnection.tsx
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.ts
**/{utils,helpers,lib}/**/*.{ts,tsx}

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

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

Files:

  • apps/web/utils/email/watch-manager.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • apps/web/utils/email/reply-all.ts
  • apps/web/utils/email/reply-all.test.ts
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.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/email/watch-manager.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • apps/web/utils/email/reply-all.ts
  • apps/web/utils/email/reply-all.test.ts
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.ts
apps/web/**/*.{ts,tsx,js,jsx,json,css}

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

Format code with Prettier

Files:

  • apps/web/utils/email/watch-manager.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • apps/web/utils/email/reply-all.ts
  • apps/web/utils/email/reply-all.test.ts
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.ts
apps/web/**/*.{example,ts,json}

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

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

Files:

  • apps/web/utils/email/watch-manager.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • apps/web/utils/email/reply-all.ts
  • apps/web/utils/email/reply-all.test.ts
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.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
**/*.tsx

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

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

Files:

  • packages/resend/src/send.tsx
  • packages/resend/emails/reconnection.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 both children and dangerouslySetInnerHTML props on the same element
Don't use dangerous JSX props
Don't use Array index in keys
Don't insert comments as text nodes
Don't assign JSX properties multiple times
Don't add extra closing tags for components without children
Use <>...</> instead of <Fragment>...</Fragment>
Watch out for possible "wrong" semicolons inside JSX elements
Make sure void (self-closing) elements don't have children
Don't use target="_blank" without rel="noopener"
Don't use <img> elements in Next.js projects
Don't use <head> elements in Next.js projects

Files:

  • packages/resend/src/send.tsx
  • packages/resend/emails/reconnection.tsx
**/*.{test,spec}.{js,jsx,ts,tsx}

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

**/*.{test,spec}.{js,jsx,ts,tsx}: Don't nest describe() blocks too deeply in test files
Don't use callbacks in asynchronous tests and hooks
Don't have duplicate hooks in describe blocks
Don't use export or module.exports in test files
Don't use focused tests
Make sure the assertion function, like expect, is placed inside an it() function call
Don't use disabled tests

Files:

  • apps/web/utils/email/reply-all.test.ts
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.ts
apps/web/**/*.test.{ts,tsx}

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

Co-locate test files next to source files (e.g., utils/example.test.ts). Only E2E and AI tests go in __tests__/

Files:

  • apps/web/utils/email/reply-all.test.ts
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.ts
**/*.test.{js,jsx,ts,tsx}

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

Co-locate test files next to source files (e.g., utils/example.test.ts). Only E2E and AI tests go in __tests__/

Files:

  • apps/web/utils/email/reply-all.test.ts
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.ts
**/*.test.{ts,tsx}

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

**/*.test.{ts,tsx}: Use vitest as the testing framework
Colocate test files next to the tested file with .test.ts or .test.tsx naming convention (e.g., dir/format.ts and dir/format.test.ts)
Mock server-only using vi.mock("server-only", () => ({}))
Mock Prisma using vi.mock("@/utils/prisma") and the provided mock from @/utils/__mocks__/prisma
Use test helper functions getEmail, getEmailAccount, and getRule from @/__tests__/helpers for creating mock data
Clear all mocks between tests using beforeEach(() => { vi.clearAllMocks(); })
Use descriptive test names that clearly indicate what is being tested
Do not mock the Logger in tests

Files:

  • apps/web/utils/email/reply-all.test.ts
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.ts
🧠 Learnings (40)
📚 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/email/watch-manager.ts
  • apps/web/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.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/utils/email/watch-manager.ts
  • apps/web/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/webhook/validate-webhook-account.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/email/watch-manager.ts
  • apps/web/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/webhook/validate-webhook-account.ts
  • apps/web/utils/auth.test.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 **/*.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/utils/email/watch-manager.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/utils/email/watch-manager.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
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/email/watch-manager.ts
  • packages/resend/src/send.tsx
  • apps/web/utils/email/reply-all.test.ts
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.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/email/watch-manager.ts
  • apps/web/utils/email/reply-all.test.ts
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.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/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.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 : 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/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.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/utils/auth.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.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 `withAuth` middleware for user-level operations such as user settings, API keys, and referrals that use only `userId`

Applied to files:

  • apps/web/utils/auth.ts
  • apps/web/utils/auth.test.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/auth.ts
  • apps/web/utils/email/reply-all.test.ts
  • apps/web/utils/auth.test.ts
📚 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/utils/auth.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 **/*.ts : Always validate that resources belong to the authenticated user before any operation - use ownership checks in queries (e.g., `emailAccount: { id: emailAccountId }`) and throw `SafeError` if validation fails

Applied to files:

  • apps/web/utils/auth/cleanup-invalid-tokens.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 **/*.ts : Prevent Insecure Direct Object References (IDOR) by validating resource ownership in all queries - always include ownership filters (e.g., `emailAccount: { id: emailAccountId }`) when accessing user-specific resources

Applied to files:

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

Applied to files:

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

Applied to files:

  • apps/web/utils/email/reply-all.ts
  • apps/web/utils/email/reply-all.test.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 : Use vitest imports (`describe`, `expect`, `test`, `vi`, `beforeEach`) in LLM test files

Applied to files:

  • apps/web/utils/email/reply-all.test.ts
  • apps/web/utils/auth.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.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/utils/email/reply-all.test.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/email/reply-all.test.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/**/*.test.{ts,tsx} : Co-locate test files next to source files (e.g., `utils/example.test.ts`). Only E2E and AI tests go in `__tests__/`

Applied to files:

  • apps/web/utils/email/reply-all.test.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/utils/email/reply-all.test.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,utils/llms,__tests__}/**/*.ts : LLM-related code must be organized in specific directories: `apps/web/utils/ai/` for main implementations, `apps/web/utils/llms/` for core utilities and configurations, and `apps/web/__tests__/` for LLM-specific tests

Applied to files:

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

Applied to files:

  • packages/resend/emails/reconnection.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/app/api/**/*.ts : Create GET API routes wrapped with `withAuth` or `withEmailAccount` middleware for fetching data

Applied to files:

  • apps/web/utils/auth.test.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 `withAuth` middleware for user-level operations (user settings, API keys, referrals) - provides only `userId` in `request.auth`

Applied to files:

  • apps/web/utils/auth.test.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 **/*.test.ts : Include security tests in test suites to verify: authentication is required, IDOR protection works (other users cannot access resources), parameter validation rejects invalid inputs, and error messages don't leak information

Applied to files:

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

Applied to files:

  • apps/web/utils/auth.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Applies to **/*.test.{ts,tsx} : Mock Prisma using `vi.mock("@/utils/prisma")` and the provided mock from `@/utils/__mocks__/prisma`

Applied to files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.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/auth.test.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/auth.test.ts
📚 Learning: 2025-11-25T14:37:11.434Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/get-api-route.mdc:0-0
Timestamp: 2025-11-25T14:37:11.434Z
Learning: Applies to **/app/**/route.ts : Always wrap GET API route handlers with `withAuth` or `withEmailAccount` middleware for consistent error handling and authentication in Next.js App Router

Applied to files:

  • apps/web/utils/auth.test.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/auth.test.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 : Mock 'server-only' module with empty object in LLM test files: `vi.mock("server-only", () => ({}))`

Applied to files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Applies to **/*.test.{ts,tsx} : Clear all mocks between tests using `beforeEach(() => { vi.clearAllMocks(); })`

Applied to files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/webhook/validate-webhook-account.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Applies to **/*.test.{ts,tsx} : Use descriptive test names that clearly indicate what is being tested

Applied to files:

  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Applies to **/*.test.{ts,tsx} : Mock `server-only` using `vi.mock("server-only", () => ({}))`

Applied to files:

  • apps/web/utils/webhook/validate-webhook-account.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Applies to **/*.test.{ts,tsx} : Do not mock the Logger in tests

Applied to files:

  • apps/web/utils/webhook/validate-webhook-account.test.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/{scripts,tests,__tests__}/**/*.{ts,tsx} : Use createScopedLogger only for code that doesn't run within a middleware chain, such as standalone scripts or tests

Applied to files:

  • apps/web/utils/webhook/validate-webhook-account.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Mock external dependencies in tests

Applied to files:

  • apps/web/utils/webhook/validate-webhook-account.test.ts
🧬 Code graph analysis (5)
apps/web/utils/auth.ts (1)
apps/web/utils/error-messages/index.ts (1)
  • clearUserErrorMessages (52-61)
apps/web/utils/auth/cleanup-invalid-tokens.ts (4)
apps/web/utils/unsubscribe.ts (1)
  • createUnsubscribeToken (5-21)
packages/resend/src/send.tsx (1)
  • sendReconnectionEmail (182-207)
apps/web/env.ts (1)
  • env (17-258)
apps/web/utils/error-messages/index.ts (2)
  • addUserErrorMessage (25-50)
  • ErrorType (63-70)
packages/resend/src/send.tsx (1)
packages/resend/emails/reconnection.tsx (1)
  • ReconnectionEmailProps (16-20)
apps/web/utils/email/reply-all.ts (1)
apps/web/utils/email.ts (1)
  • extractEmailAddress (32-65)
apps/web/utils/webhook/validate-webhook-account.test.ts (1)
apps/web/utils/webhook/validate-webhook-account.ts (1)
  • validateWebhookAccount (118-200)
⏰ 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). (5)
  • GitHub Check: Baz Reviewer
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: test
  • GitHub Check: Macroscope - Correctness Check
🔇 Additional comments (24)
apps/web/utils/email/reply-all.ts (1)

99-101: LGTM! Formatting improvement.

The multi-line format for the Set construction improves readability without changing behavior.

apps/web/utils/email/reply-all.test.ts (1)

2-6: LGTM! Formatting improvement.

The multi-line import format improves maintainability without changing test behavior.

apps/web/prisma/migrations/20260101221942_account_disconnected_at/migration.sql (1)

1-2: LGTM! Clean migration.

The migration correctly adds the nullable disconnectedAt column with appropriate precision (TIMESTAMP(3) for milliseconds). Existing accounts will have NULL values, correctly indicating they are connected.

apps/web/utils/email/watch-manager.ts (1)

40-40: LGTM! Essential filter for disconnected accounts.

Correctly excludes accounts with revoked OAuth tokens from the watch operation. This prevents unnecessary API calls and auth errors for disconnected accounts.

apps/web/utils/error-messages/index.ts (1)

69-69: LGTM!

The new error type constant follows the established pattern and provides a clear, user-facing message for account disconnection scenarios.

apps/web/utils/auth.ts (1)

406-421: Well-implemented atomic operation.

Using a transaction to atomically upsert the email account and clear the disconnection state, followed by clearing user error messages, ensures consistency and proper cleanup when an account is reconnected.

apps/web/utils/webhook/validate-webhook-account.ts (2)

32-32: Necessary field addition for disconnection tracking.

Adding disconnectedAt to the select clause enables the validation logic to check account disconnection state.


127-130: Proper early exit for disconnected accounts.

The guard correctly skips webhook processing for disconnected accounts, preventing operations on accounts with revoked OAuth tokens. The pattern is consistent with other validation bailouts (non-premium, no AI access, etc.).

apps/web/utils/webhook/validate-webhook-account.test.ts (3)

16-16: Good cleanup of placeholder comment.

Replacing the commented note with actual imports improves code clarity.


99-118: Comprehensive test coverage for disconnected accounts.

The test verifies that disconnected accounts are properly handled with an early exit, ensuring webhook processing is skipped for accounts with revoked OAuth tokens. The test follows the established pattern and properly validates the response structure.


49-49: Proper test data normalization.

Adding disconnectedAt: null to existing mock account objects ensures consistency across all test cases and makes the disconnection state explicit.

Also applies to: 204-204, 228-228

packages/resend/src/send.tsx (2)

13-15: LGTM!

Import statements are properly structured.


182-207: LGTM!

The sendReconnectionEmail function follows the established pattern used by other email sender functions in this file. The implementation correctly uses the ReconnectionEmailProps type, includes the email address in the subject line, properly passes the unsubscribe token, and categorizes the email appropriately.

apps/web/utils/auth/cleanup-invalid-tokens.ts (5)

3-6: LGTM!

Imports are correctly structured for the new functionality.


27-37: LGTM!

The expanded select query correctly retrieves all necessary fields for the disconnection flow, including the new disconnectedAt field from the related account.


45-48: LGTM!

Good defensive programming - the early return prevents duplicate processing and unnecessary operations when an account is already marked as disconnected.


50-58: LGTM!

The account update correctly sets disconnectedAt along with clearing the OAuth tokens. This properly marks the account as disconnected in the database.


60-96: LGTM!

The invalid_grant handling logic is well-structured:

  • Conditionally sends reconnection email only for watched accounts
  • Properly handles errors during email sending without blocking the flow
  • Always adds a user error message to surface the disconnection in-app

NEXT_PUBLIC_BASE_URL is properly configured and available in the server-side context. The NEXT_PUBLIC_* prefix is specifically designed to expose variables to both server and client in Next.js, and the env configuration correctly maps it through experimental__runtimeEnv.

packages/resend/emails/reconnection.tsx (4)

16-20: LGTM!

The ReconnectionEmailProps type is correctly defined with all necessary fields for the reconnection email flow.


22-30: LGTM!

The component type definition and default props follow the pattern established in other email templates in this codebase.


31-103: LGTM!

The email template is well-structured with clear sections (header, main content, CTA, footer) and uses React Email components appropriately. The reconnect URL construction and button styling are correct.


141-145: LGTM!

Preview props are correctly defined for development and testing purposes.

apps/web/utils/auth/cleanup-invalid-tokens.test.ts (2)

1-20: LGTM!

Test setup follows the coding guidelines correctly:

  • Uses vitest as the testing framework
  • Mocks Prisma using the provided mock
  • Properly mocks external dependencies
  • Does not mock the Logger (as per guidelines)

22-104: LGTM!

The test suite provides comprehensive coverage:

  • Properly clears mocks between tests using beforeEach
  • Uses descriptive test names that clearly indicate what is being tested
  • Covers all critical paths: watched/unwatched accounts, already disconnected, and different reasons
  • Verifies both positive cases (email sent) and negative cases (email not sent)
  • Properly validates database interactions and side effects

The test implementation aligns with all coding guidelines and best practices.

Copy link
Copy Markdown
Contributor

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

Choose a reason for hiding this comment

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

5 issues found across 14 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/auth.ts">

<violation number="1" location="apps/web/utils/auth.ts:421">
P2: `clearUserErrorMessages` is non-critical, but if it throws, the entire `handleLinkAccount` fails after the account was already successfully linked. This could cause the user to see an error even though their account was linked correctly. Consider making this call best-effort by catching and logging any errors.</violation>
</file>

<file name="packages/resend/emails/reconnection.tsx">

<violation number="1" location="packages/resend/emails/reconnection.tsx:122">
P2: The `unsubscribeToken` should be URL-encoded with `encodeURIComponent()` to prevent broken URLs if the token contains special characters. This matches the pattern used in `summary.tsx`.</violation>
</file>

<file name="apps/web/utils/auth/cleanup-invalid-tokens.ts">

<violation number="1" location="apps/web/utils/auth/cleanup-invalid-tokens.ts:45">
P1: The disconnected guard is non-atomic; concurrent calls can both pass the check and send duplicate reconnection emails/notifications. Make the disconnect update conditional (e.g., updateMany with `disconnectedAt: null`) and bail if no rows were updated.</violation>

<violation number="2" location="apps/web/utils/auth/cleanup-invalid-tokens.ts:61">
P2: `isWatched` should account for expiration, not just non-null. Otherwise expired watch dates can still trigger reconnection emails.</violation>

<violation number="3" location="apps/web/utils/auth/cleanup-invalid-tokens.ts:91">
P2: `addUserErrorMessage` receives `emailAccount.email`, but this function looks up users by their email. The connected email account&#39;s email may differ from the user&#39;s primary email, causing the error message to be dropped or misattributed. Consider fetching the owning user&#39;s email or updating `addUserErrorMessage` to accept `userId` directly.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread apps/web/utils/auth.ts
Comment thread packages/resend/emails/reconnection.tsx Outdated
Comment thread apps/web/utils/auth/cleanup-invalid-tokens.ts Outdated
Comment thread apps/web/utils/auth/cleanup-invalid-tokens.ts
Comment thread apps/web/utils/auth/cleanup-invalid-tokens.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
apps/web/utils/meeting-briefs/recipient-context.test.ts (1)

53-60: Remove the logger mock.

The coding guidelines explicitly state: "Do not mock the Logger in tests". Pass a real logger instance instead of creating a mock.

As per coding guidelines: "Do not mock the Logger in tests"

♻️ Duplicate comments (1)
apps/web/utils/auth/cleanup-invalid-tokens.ts (1)

62-62: Verify watch expiration, not just non-null status.

The isWatched check should verify that the watch hasn't expired, not just that the field is non-null. An expired watch means the account is no longer actively monitored.

🔎 Proposed fix
-    const isWatched = !!emailAccount.watchEmailsExpirationDate;
+    const isWatched =
+      !!emailAccount.watchEmailsExpirationDate &&
+      emailAccount.watchEmailsExpirationDate > new Date();
🧹 Nitpick comments (2)
apps/web/utils/meeting-briefs/recipient-context.test.ts (1)

98-98: Remove console.log statements from tests.

Multiple console.log statements are present in the test file. Per coding guidelines, console usage should be avoided. These debugging statements should be removed or replaced with proper test assertions if the output needs to be verified.

Remove console.log statements
-      // Readable prompt text:
-      console.log("Prompt:", result);
-

Apply this pattern to remove all console.log statements at lines 98, 126, 157, 189, 211, and 229.

As per coding guidelines: "Don't use console"

Also applies to: 126-126, 157-157, 189-189, 211-211, 229-229

apps/web/utils/auth/cleanup-invalid-tokens.ts (1)

46-59: Consider atomic update to prevent race conditions.

The current guard-then-update pattern could allow concurrent calls to both pass the check and send duplicate reconnection emails. Consider using an atomic update with a conditional where clause as suggested in past reviews:

const updated = await prisma.account.updateMany({
  where: { id: emailAccount.accountId, disconnectedAt: null },
  data: {
    access_token: null,
    refresh_token: null,
    expires_at: null,
    disconnectedAt: new Date(),
  },
});

if (updated.count === 0) {
  logger.info("Account already marked as disconnected");
  return;
}

This ensures only one concurrent call proceeds to send reconnection emails.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b2bf3aa and ebd93e7.

📒 Files selected for processing (8)
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
  • packages/resend/emails/reconnection.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/resend/emails/reconnection.tsx
🧰 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 the swr package
Use result?.serverError with toastError from @/components/Toast for error handling in async operations

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

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

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

Files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
**/*.{ts,tsx,js,jsx}

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

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

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

Files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.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/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
**/*.ts

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

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

Files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
**/*.{tsx,ts}

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

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

Files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.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/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
**/*.{js,jsx,ts,tsx}

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

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

Files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
**/*.{test,spec}.{js,jsx,ts,tsx}

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

**/*.{test,spec}.{js,jsx,ts,tsx}: Don't nest describe() blocks too deeply in test files
Don't use callbacks in asynchronous tests and hooks
Don't have duplicate hooks in describe blocks
Don't use export or module.exports in test files
Don't use focused tests
Make sure the assertion function, like expect, is placed inside an it() function call
Don't use disabled tests

Files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.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/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.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/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.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/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.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/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
apps/web/**/*.{ts,tsx,js,jsx,json,css}

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

Format code with Prettier

Files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
apps/web/**/*.test.{ts,tsx}

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

Co-locate test files next to source files (e.g., utils/example.test.ts). Only E2E and AI tests go in __tests__/

Files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
apps/web/**/*.{example,ts,json}

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

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

Files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
**/*.test.{js,jsx,ts,tsx}

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

Co-locate test files next to source files (e.g., utils/example.test.ts). Only E2E and AI tests go in __tests__/

Files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
**/*.test.{ts,tsx}

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

**/*.test.{ts,tsx}: Use vitest as the testing framework
Colocate test files next to the tested file with .test.ts or .test.tsx naming convention (e.g., dir/format.ts and dir/format.test.ts)
Mock server-only using vi.mock("server-only", () => ({}))
Mock Prisma using vi.mock("@/utils/prisma") and the provided mock from @/utils/__mocks__/prisma
Use test helper functions getEmail, getEmailAccount, and getRule from @/__tests__/helpers for creating mock data
Clear all mocks between tests using beforeEach(() => { vi.clearAllMocks(); })
Use descriptive test names that clearly indicate what is being tested
Do not mock the Logger in tests

Files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
apps/web/{utils/ai,utils/llms,__tests__}/**/*.ts

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

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

Files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/llms/index.ts
apps/web/utils/ai/**/*.ts

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

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

Files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
apps/web/utils/llms/{index,model}.ts

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

Core LLM functionality must be defined in utils/llms/index.ts, model definitions and configurations in utils/llms/model.ts, and usage tracking in utils/usage.ts

Files:

  • apps/web/utils/llms/index.ts
🧠 Learnings (47)
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
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/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.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/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.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 **/*.test.ts : Include security tests in test suites to verify: authentication is required, IDOR protection works (other users cannot access resources), parameter validation rejects invalid inputs, and error messages don't leak information

Applied to files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.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/auth.test.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.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 `withAuth` middleware for user-level operations such as user settings, API keys, and referrals that use only `userId`

Applied to files:

  • apps/web/utils/auth.test.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/utils/auth.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Applies to **/*.test.{ts,tsx} : Mock Prisma using `vi.mock("@/utils/prisma")` and the provided mock from `@/utils/__mocks__/prisma`

Applied to files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
  • apps/web/utils/error-messages/index.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/auth.test.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/auth.test.ts
📚 Learning: 2025-11-25T14:37:11.434Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/get-api-route.mdc:0-0
Timestamp: 2025-11-25T14:37:11.434Z
Learning: Applies to **/app/**/route.ts : Always wrap GET API route handlers with `withAuth` or `withEmailAccount` middleware for consistent error handling and authentication in Next.js App Router

Applied to files:

  • apps/web/utils/auth.test.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 `withAuth` middleware for user-level operations (user settings, API keys, referrals) - provides only `userId` in `request.auth`

Applied to files:

  • apps/web/utils/auth.test.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/auth.test.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 : Use vitest imports (`describe`, `expect`, `test`, `vi`, `beforeEach`) in LLM test files

Applied to files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.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 : Mock 'server-only' module with empty object in LLM test files: `vi.mock("server-only", () => ({}))`

Applied to files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Applies to **/*.test.{ts,tsx} : Clear all mocks between tests using `beforeEach(() => { vi.clearAllMocks(); })`

Applied to files:

  • apps/web/utils/auth.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Applies to **/*.test.{ts,tsx} : Use descriptive test names that clearly indicate what is being tested

Applied to files:

  • apps/web/utils/auth/cleanup-invalid-tokens.test.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 : Place all LLM-related tests in `apps/web/__tests__/` directory

Applied to files:

  • apps/web/utils/auth/cleanup-invalid-tokens.test.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 : Use `console.debug()` for outputting generated LLM content in tests, e.g., `console.debug("Generated content:\n", result.content);`

Applied to files:

  • apps/web/utils/auth/cleanup-invalid-tokens.test.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 : Set timeout constant `const TIMEOUT = 15_000;` for LLM tests

Applied to files:

  • apps/web/utils/auth/cleanup-invalid-tokens.test.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 : Use `describe.runIf(isAiTest)` with environment variable `RUN_AI_TESTS === "true"` to conditionally run LLM tests

Applied to files:

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

Applied to files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Applies to **/*.test.{ts,tsx} : Mock `server-only` using `vi.mock("server-only", () => ({}))`

Applied to files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Applies to **/__tests__/**/*.{ts,tsx} : Place AI tests in the `__tests__` directory and do not run them by default as they use a real LLM

Applied to files:

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

Applied to files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/error-messages/index.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/llms/index.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/utils/llms/index.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.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/llms/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Implement early returns for invalid LLM inputs, use proper error types and logging, implement fallbacks for AI failures, and add retry logic for transient failures using `withRetry`

Applied to files:

  • apps/web/utils/llms/index.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.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 TypeScript types for all LLM function parameters and return values, and define clear interfaces for complex input/output structures

Applied to files:

  • apps/web/utils/llms/index.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/utils/llms/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.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/utils/llms/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.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/utils/llms/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.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/utils/llms/index.ts
  • apps/web/utils/error-messages/index.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.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} : Use generic error messages instead of revealing internal details; throw `SafeError` instead of exposing user IDs, resource IDs, or system information

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • apps/web/utils/error-messages/index.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/utils/actions/**/*.ts : Use proper error handling with try/catch blocks

Applied to files:

  • apps/web/utils/error-messages/index.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 **/*.{ts,tsx,js,jsx} : Import Prisma using the project's centralized utility: `import prisma from '@/utils/prisma'`

Applied to files:

  • apps/web/utils/error-messages/index.ts
📚 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/utils/error-messages/index.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 `withError` middleware only for public endpoints or custom authentication logic - cron endpoints MUST validate with `hasCronSecret(request)` or `hasPostCronSecret(request)` and capture unauthorized attempts with `captureException`

Applied to files:

  • apps/web/utils/error-messages/index.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/{scripts,tests,__tests__}/**/*.{ts,tsx} : Use createScopedLogger only for code that doesn't run within a middleware chain, such as standalone scripts or tests

Applied to files:

  • apps/web/utils/error-messages/index.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 **/*.ts : Prevent Insecure Direct Object References (IDOR) by validating resource ownership in all queries - always include ownership filters (e.g., `emailAccount: { id: emailAccountId }`) when accessing user-specific resources

Applied to files:

  • apps/web/utils/auth/cleanup-invalid-tokens.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 **/*.ts : Always validate that resources belong to the authenticated user before any operation - use ownership checks in queries (e.g., `emailAccount: { id: emailAccountId }`) and throw `SafeError` if validation fails

Applied to files:

  • apps/web/utils/auth/cleanup-invalid-tokens.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 : 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/utils/auth/cleanup-invalid-tokens.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 : User prompts must contain the actual data and context, and should be kept separate from system prompts

Applied to files:

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

Applied to files:

  • apps/web/utils/auth/cleanup-invalid-tokens.ts
🧬 Code graph analysis (5)
apps/web/utils/auth.test.ts (2)
apps/web/utils/auth.ts (1)
  • saveTokens (449-531)
apps/web/utils/error-messages/index.ts (1)
  • clearUserErrorMessages (53-70)
apps/web/utils/auth/cleanup-invalid-tokens.test.ts (4)
apps/web/utils/logger.ts (1)
  • createScopedLogger (18-82)
apps/web/utils/auth/cleanup-invalid-tokens.ts (1)
  • cleanupInvalidTokens (14-100)
packages/resend/src/send.tsx (1)
  • sendReconnectionEmail (182-207)
apps/web/utils/error-messages/index.ts (1)
  • addUserErrorMessage (26-51)
apps/web/utils/llms/index.ts (2)
apps/web/utils/llms/types.ts (1)
  • EmailAccountWithAI (10-32)
apps/web/utils/error-messages/index.ts (2)
  • ErrorType (72-79)
  • addUserErrorMessage (26-51)
apps/web/utils/error-messages/index.ts (1)
apps/web/utils/error.ts (1)
  • captureException (46-76)
apps/web/utils/auth/cleanup-invalid-tokens.ts (4)
apps/web/utils/unsubscribe.ts (1)
  • createUnsubscribeToken (5-21)
packages/resend/src/send.tsx (1)
  • sendReconnectionEmail (182-207)
apps/web/env.ts (1)
  • env (17-258)
apps/web/utils/error-messages/index.ts (2)
  • addUserErrorMessage (26-51)
  • ErrorType (72-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). (5)
  • GitHub Check: Baz Reviewer
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: test
  • GitHub Check: Macroscope - Correctness Check
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (21)
apps/web/utils/meeting-briefs/recipient-context.test.ts (1)

15-15: LGTM! UTC conversion improves test reliability.

The changes to use UTC-based date methods (getUTCDay(), getUTCMonth(), etc.) make the tests timezone-independent and deterministic. The updated test expectations correctly reflect UTC times for the given ISO date strings. This ensures tests produce consistent results regardless of the system's timezone configuration.

Also applies to: 40-44, 103-103, 105-105, 131-131, 163-163, 168-168, 234-234

apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts (1)

31-148: Well-structured tests with clear documentation.

The test cases are well-written with descriptive names and helpful comments explaining the timezone bug fix. Using toMatchInlineSnapshot is appropriate for regression testing the prompt output. The tests correctly focus on unit testing the prompt building logic without calling real LLMs.

apps/web/utils/error-messages/index.ts (4)

3-3: LGTM!

The import of captureException supports the enhanced error handling in clearUserErrorMessages.


26-35: LGTM! Correctly resolves past review concerns.

The signature change from userEmail to userId ensures the error message is correctly attributed to the owning user. This addresses the concern raised in past reviews that emailAccount.email may differ from user.email.


58-69: LGTM!

The try/catch wrapper provides appropriate error handling and logging for potential Prisma update failures, ensuring the function degrades gracefully.


78-78: LGTM!

The ACCOUNT_DISCONNECTED error type appropriately supports the new OAuth disconnection handling flow.

apps/web/utils/llms/index.ts (3)

51-51: LGTM!

The type extension to include userId in emailAccount correctly supports the userId-based error handling flow.

Also applies to: 146-146


116-124: LGTM!

The handleError signature and all call sites have been consistently updated to propagate userId through the error handling pipeline.

Also applies to: 128-136, 209-217, 299-314


318-355: LGTM!

All addUserErrorMessage calls have been correctly updated to pass userId instead of userEmail, consistent with the signature change in the error-messages module.

apps/web/utils/auth.test.ts (3)

5-28: LGTM!

The expanded imports and mock setup correctly support the new saveTokens tests, following vitest testing patterns and project conventions.


121-148: LGTM!

The test correctly verifies that saving tokens via emailAccountId clears disconnectedAt and error messages, ensuring proper reconnection flow.


150-179: LGTM!

The test correctly verifies that saving tokens via providerAccountId clears disconnectedAt and error messages, covering the alternative reconnection path.

apps/web/utils/auth/cleanup-invalid-tokens.ts (4)

3-6: LGTM!

The new imports appropriately support the reconnection email flow and error messaging functionality.


25-39: LGTM!

The extended select appropriately fetches all fields required for the reconnection flow and disconnection state management.


64-90: LGTM!

The reconnection email flow is well-structured with proper error handling, logging, and graceful degradation if email sending fails.


92-96: LGTM! Correctly uses userId.

The addUserErrorMessage call now correctly uses userId instead of userEmail, resolving the concern from past reviews about potential email mismatch.

apps/web/utils/auth/cleanup-invalid-tokens.test.ts (5)

1-27: LGTM!

The test setup follows project testing conventions with proper mocking and cleanup between tests.


38-61: LGTM!

The test correctly verifies the full reconnection flow for watched accounts, including account disconnection, email sending, and error message creation.


63-82: LGTM!

The test correctly verifies that unwatched accounts skip email sending but still get marked as disconnected with an error message.


84-98: LGTM!

The test correctly verifies the idempotency guard that prevents repeated processing of already disconnected accounts.


100-113: LGTM!

The test correctly verifies that insufficient_permissions reason triggers disconnection without sending reconnection emails or error messages.

Comment thread apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
Comment thread apps/web/utils/auth/cleanup-invalid-tokens.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
apps/web/utils/auth/cleanup-invalid-tokens.ts (2)

88-93: Consider removing email addresses from logs to reduce PII exposure.

Logging email at lines 88 and 91 may introduce compliance/privacy concerns. The emailAccountId is already available in the logging context and can be used for debugging without exposing PII.

🔎 Suggested change
-        logger.info("Reconnection email sent", { email: emailAccount.email });
+        logger.info("Reconnection email sent");
       } catch (error) {
         logger.error("Failed to send reconnection email", {
-          email: emailAccount.email,
           error,
         });

101-108: Consider wrapping addUserErrorMessage in try-catch for consistency.

The reconnection email is wrapped in try-catch to prevent notification failures from blocking the flow. For consistency, consider applying the same pattern to addUserErrorMessage so that a database error doesn't prevent the final log from executing.

🔎 Suggested change
-    await addUserErrorMessage(
-      emailAccount.userId,
-      ErrorType.ACCOUNT_DISCONNECTED,
-      `The connection for ${emailAccount.email} was disconnected. Please reconnect your account to resume automation.`,
-    );
+    try {
+      await addUserErrorMessage(
+        emailAccount.userId,
+        ErrorType.ACCOUNT_DISCONNECTED,
+        `The connection for ${emailAccount.email} was disconnected. Please reconnect your account to resume automation.`,
+      );
+    } catch (error) {
+      logger.error("Failed to add user error message", { error });
+    }
   }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ebd93e7 and 289fceb.

📒 Files selected for processing (3)
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
  • apps/web/utils/auth/cleanup-invalid-tokens.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/utils/auth/cleanup-invalid-tokens.test.ts
🧰 Additional context used
📓 Path-based instructions (19)
**/*.{ts,tsx}

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

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

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

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

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

Files:

  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
**/*.{ts,tsx,js,jsx}

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

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

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

Files:

  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.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/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
**/*.ts

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

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

Files:

  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
**/*.{tsx,ts}

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

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

Files:

  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.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/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
**/*.{js,jsx,ts,tsx}

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

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

Files:

  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.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/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.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/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.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/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.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/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
apps/web/**/*.{ts,tsx,js,jsx,json,css}

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

Format code with Prettier

Files:

  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
apps/web/**/*.{example,ts,json}

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

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

Files:

  • apps/web/utils/auth/cleanup-invalid-tokens.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
apps/web/{utils/ai,utils/llms,__tests__}/**/*.ts

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

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

Files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
apps/web/utils/ai/**/*.ts

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

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

Files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
**/*.{test,spec}.{js,jsx,ts,tsx}

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

**/*.{test,spec}.{js,jsx,ts,tsx}: Don't nest describe() blocks too deeply in test files
Don't use callbacks in asynchronous tests and hooks
Don't have duplicate hooks in describe blocks
Don't use export or module.exports in test files
Don't use focused tests
Make sure the assertion function, like expect, is placed inside an it() function call
Don't use disabled tests

Files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
apps/web/**/*.test.{ts,tsx}

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

Co-locate test files next to source files (e.g., utils/example.test.ts). Only E2E and AI tests go in __tests__/

Files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
**/*.test.{js,jsx,ts,tsx}

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

Co-locate test files next to source files (e.g., utils/example.test.ts). Only E2E and AI tests go in __tests__/

Files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
**/*.test.{ts,tsx}

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

**/*.test.{ts,tsx}: Use vitest as the testing framework
Colocate test files next to the tested file with .test.ts or .test.tsx naming convention (e.g., dir/format.ts and dir/format.test.ts)
Mock server-only using vi.mock("server-only", () => ({}))
Mock Prisma using vi.mock("@/utils/prisma") and the provided mock from @/utils/__mocks__/prisma
Use test helper functions getEmail, getEmailAccount, and getRule from @/__tests__/helpers for creating mock data
Clear all mocks between tests using beforeEach(() => { vi.clearAllMocks(); })
Use descriptive test names that clearly indicate what is being tested
Do not mock the Logger in tests

Files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
🧠 Learnings (28)
📚 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/auth/cleanup-invalid-tokens.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/auth/cleanup-invalid-tokens.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/utils/auth/cleanup-invalid-tokens.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/utils/auth/cleanup-invalid-tokens.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 **/*.ts : Always validate that resources belong to the authenticated user before any operation - use ownership checks in queries (e.g., `emailAccount: { id: emailAccountId }`) and throw `SafeError` if validation fails

Applied to files:

  • apps/web/utils/auth/cleanup-invalid-tokens.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/utils/auth/cleanup-invalid-tokens.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 : 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/utils/auth/cleanup-invalid-tokens.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/utils/auth/cleanup-invalid-tokens.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 **/*.ts : Prevent Insecure Direct Object References (IDOR) by validating resource ownership in all queries - always include ownership filters (e.g., `emailAccount: { id: emailAccountId }`) when accessing user-specific resources

Applied to files:

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

Applied to files:

  • apps/web/utils/auth/cleanup-invalid-tokens.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 : User prompts must contain the actual data and context, and should be kept separate from system prompts

Applied to files:

  • apps/web/utils/auth/cleanup-invalid-tokens.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 : Use vitest imports (`describe`, `expect`, `test`, `vi`, `beforeEach`) in LLM test files

Applied to files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Applies to **/*.test.{ts,tsx} : Clear all mocks between tests using `beforeEach(() => { vi.clearAllMocks(); })`

Applied to files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.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 : Mock 'server-only' module with empty object in LLM test files: `vi.mock("server-only", () => ({}))`

Applied to files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
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/ai/meeting-briefs/generate-briefing.test.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 : Use `describe.runIf(isAiTest)` with environment variable `RUN_AI_TESTS === "true"` to conditionally run LLM tests

Applied to files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.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/ai/meeting-briefs/generate-briefing.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Applies to **/*.test.{ts,tsx} : Mock Prisma using `vi.mock("@/utils/prisma")` and the provided mock from `@/utils/__mocks__/prisma`

Applied to files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Applies to **/*.test.{ts,tsx} : Mock `server-only` using `vi.mock("server-only", () => ({}))`

Applied to files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Applies to **/__tests__/**/*.{ts,tsx} : Place AI tests in the `__tests__` directory and do not run them by default as they use a real LLM

Applied to files:

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

Applied to files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Applies to **/*.test.{ts,tsx} : Use descriptive test names that clearly indicate what is being tested

Applied to files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Mock external dependencies in tests

Applied to files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Each test should be independent with no shared state between tests

Applied to files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
📚 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 **/*.{test,spec}.{js,jsx,ts,tsx} : Don't have duplicate hooks in describe blocks

Applied to files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Applies to **/*.test.{ts,tsx} : Use `vitest` as the testing framework

Applied to files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
📚 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 **/*.{test,spec}.{js,jsx,ts,tsx} : Make sure the assertion function, like expect, is placed inside an it() function call

Applied to files:

  • apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts
🧬 Code graph analysis (1)
apps/web/utils/auth/cleanup-invalid-tokens.ts (4)
apps/web/utils/unsubscribe.ts (1)
  • createUnsubscribeToken (5-21)
packages/resend/src/send.tsx (1)
  • sendReconnectionEmail (182-207)
apps/web/env.ts (1)
  • env (17-258)
apps/web/utils/error-messages/index.ts (2)
  • addUserErrorMessage (26-51)
  • ErrorType (72-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). (3)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: test
  • GitHub Check: Macroscope - Correctness Check
🔇 Additional comments (8)
apps/web/utils/ai/meeting-briefs/generate-briefing.test.ts (3)

1-29: LGTM! Mock setup follows testing guidelines.

The import and mock setup is well-structured:

  • Vitest imports including beforeEach are correct
  • The server-only mock follows the required pattern
  • The new @/env mock provides deterministic test values for API keys and LLM provider
  • Explicit unmocking of date utilities is appropriate for testing timezone formatting

31-33: LGTM! Previous feedback addressed.

The beforeEach block properly clears all mocks between tests, preventing state leakage. This addresses the previous review comment and follows the testing guidelines.


35-151: LGTM! Well-structured test cases.

Both test cases are well-designed:

  • Descriptive test names clearly indicate the scenarios being tested
  • The first test documents the timezone bug fix with helpful comments
  • Inline snapshot assertions are appropriate for verifying formatted output
  • Test data is constructed inline (appropriate since no helper exists for MeetingBriefingData)
  • Tests are independent with no shared state
apps/web/utils/auth/cleanup-invalid-tokens.ts (5)

1-6: LGTM!

Imports are well-organized, using the centralized Prisma utility and proper type-only import for Logger. All imports are placed at the top of the file as per coding guidelines.


25-44: LGTM!

The Prisma query properly uses select to return only necessary fields (following security guidelines) and is correctly scoped by emailAccountId. The logger is appropriately passed as a parameter per coding guidelines for helper functions.


46-66: LGTM!

The atomic update pattern correctly addresses the concurrency concern raised in past reviews. Using updateMany with disconnectedAt: null in the WHERE clause ensures only one caller proceeds with notifications, preventing duplicate emails. The early guard at lines 46-49 serves as a useful optimization to avoid unnecessary update calls.


101-106: LGTM!

The addUserErrorMessage correctly uses userId instead of email (addressing past review feedback). Placing this outside the reconnection email try-catch ensures users receive in-app notifications even if email sending fails.


68-99: LGTM on the reconnection flow!

The isWatched logic correctly validates both presence and future expiration of watchEmailsExpirationDate (addressing past review feedback). The conditional notification approach—sending emails only for actively watched accounts—is a sensible design that avoids unnecessary emails to inactive users.

@elie222 elie222 merged commit d139179 into main Jan 1, 2026
40 checks passed
@elie222 elie222 deleted the feat/handle-invalid-grant branch January 1, 2026 23:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant