Skip to content

Outlook support #537

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 90 commits into
base: main
Choose a base branch
from
Open

Outlook support #537

wants to merge 90 commits into from

Conversation

elie222
Copy link
Owner

@elie222 elie222 commented Jul 3, 2025

Summary by CodeRabbit

  • New Features

    • Full Microsoft Outlook (Entra ID) account support including OAuth linking, email reading, sending, labeling, and automation.
    • Unified email operations under a provider-agnostic interface supporting both Google and Microsoft accounts.
    • Added batch fetching, searching, and management endpoints for emails, threads, labels, and attachments across providers.
    • Implemented email watch/unwatch functionality with subscription management for Outlook accounts.
    • Added detailed Microsoft OAuth setup instructions and new environment variables.
  • Improvements

    • UI and navigation updated to be provider-aware, displaying relevant features per email provider.
    • Bulk actions, filters, and automation enhanced for multi-provider compatibility.
    • Improved error handling, logging, and user feedback during account linking and email actions.
    • Generalized label, thread, and message handling with provider-specific adaptations.
    • Enhanced pagination and data fetching logic for messages and threads.
    • Updated email URL generation to support provider-specific URLs.
  • Bug Fixes

    • Fixed label handling, attachment downloads, and bulk operation issues for non-Google accounts.
    • Improved type safety and error reporting throughout the app.
  • Documentation

    • Updated docs and environment variable references for multi-provider support.
    • Added comprehensive Microsoft OAuth credential setup guide.
  • Chores

    • Added Microsoft Graph SDK dependencies and updated environment/config files.
    • Introduced middleware to inject email provider instances into requests.
    • Updated Prisma schema to include Outlook subscription IDs.
    • Removed deprecated Google-specific API routes, replaced with unified provider routes.
  • Style

    • Modernized React imports and usage for cleaner code.
    • Refactored imports and type annotations to use unified email and label types.
  • Tests

    • Updated and extended tests to cover multi-provider logic and ensure cross-platform reliability.

Copy link

claude bot commented Jul 21, 2025

Claude encountered an error —— View job


I'll analyze this and get back to you.

Copy link

claude bot commented Jul 21, 2025

Claude encountered an error —— View job


I'll analyze this and get back to you.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6d1e1a0 and e12132b.

📒 Files selected for processing (1)
  • README.md (5 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
!{.cursor/rules/*.mdc}

📄 CodeRabbit Inference Engine (.cursor/rules/cursor-rules.mdc)

Never place rule files in the project root, in subdirectories outside .cursor/rules, or in any other location

Files:

  • README.md
*{TASKS,ASSISTANT_CHAT,*.md}

📄 CodeRabbit Inference Engine (.cursor/rules/task-list.mdc)

*{TASKS,ASSISTANT_CHAT,*.md}: Create task lists in a markdown file in the project root, using TASKS.md or a descriptive name relevant to the feature (e.g., ASSISTANT_CHAT.md), and include a clear title and description of the feature being implemented.
Structure the task list markdown file with sections: Completed Tasks, In Progress Tasks, Future Tasks, Implementation Plan, and Relevant Files.
Update the task list as you progress: mark tasks as completed by changing [ ] to [x], add new tasks as identified, and move tasks between sections as appropriate.
Keep the 'Relevant Files' section updated with file paths, brief descriptions of each file's purpose, and status indicators (e.g., ✅) for completed components.
Add implementation details to the task list markdown file, including architecture decisions, data flow descriptions, technical components needed, and environment configuration.
When working with task lists, regularly update the task list file after implementing significant components, mark completed tasks with [x], add new tasks discovered during implementation, maintain the 'Relevant Files' section, and document implementation details.
When implementing tasks one by one, first check which task to implement next, and after implementing a task, update the file to reflect progress.

Files:

  • README.md
!pages/_document.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)

!pages/_document.{js,jsx,ts,tsx}: Don't import next/document outside of pages/_document.jsx in Next.js projects.
Don't import next/document outside of pages/_document.jsx in Next.js projects.

Files:

  • README.md
🧠 Learnings (2)
📓 Common learnings
Learnt from: elie222
PR: elie222/inbox-zero#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.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-07-18T15:05:34.890Z
Learning: Applies to apps/web/utils/gmail/**/*.ts : Keep provider-specific implementation details isolated in the appropriate utils subfolder (e.g., 'apps/web/utils/gmail/')
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/index.mdc:0-0
Timestamp: 2025-07-18T15:05:56.618Z
Learning: Guidelines for working with Gmail API
README.md (11)

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to */.env : Never use predictable or weak cron secrets (e.g., 'secret', 'password', 'cron', or short/simple strings) in environment variables.

Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-18T15:04:30.448Z
Learning: Applies to apps/web/**/{.env.example,env.ts} : Client-side environment variables: Prefix with NEXT_PUBLIC_

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Never expose secrets or sensitive data in code or version control; store all secrets in environment variables.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-07-18T15:04:50.510Z
Learning: Applies to apps/web/env.ts : Client-side environment variables must be prefixed with NEXT_PUBLIC_ and added to both the client and experimental__runtimeEnv sections in apps/web/env.ts.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-07-20T09:00:41.952Z
Learning: Applies to apps/web/app/api/**/*.{ts,js} : Do not hardcode weak or plaintext secrets in API route files; secrets must not be directly assigned as string literals.

Learnt from: garnertb
PR: #580
File: apps/web/.env.example:4-7
Timestamp: 2025-07-19T15:06:43.707Z
Learning: In apps/web/.env.example, boolean environment variables follow an unquoted convention (e.g., LOG_ZOD_ERRORS=true, AUTH_TRUST_HOST=true). Logical grouping of related variables (like auth variables together) is preferred over strict alphabetical ordering for better developer experience.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-07-18T15:04:50.510Z
Learning: Applies to apps/web/.env.example : When adding a new environment variable, add it to .env.example with an example value (e.g., NEW_VARIABLE=value_example).

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-07-18T15:04:50.510Z
Learning: Applies to apps/web/env.ts : When adding a new environment variable, add it to apps/web/env.ts in the appropriate section: use server for server-only variables, and for client-side variables, use the client section and also add to experimental__runtimeEnv.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/index.mdc:0-0
Timestamp: 2025-07-18T15:05:56.618Z
Learning: Guidelines for working with Gmail API

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-07-20T09:00:41.952Z
Learning: Applies to apps/web/app/api/**/*.{ts,js} : All cron endpoints in API routes must use hasCronSecret or hasPostCronSecret for authentication.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to /api//route.ts : Cron endpoints MUST use withError middleware and validate the cron secret using hasCronSecret(request) or hasPostCronSecret(request).

🪛 markdownlint-cli2 (0.17.2)
README.md

168-168: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

🔇 Additional comments (3)
README.md (3)

108-111: Verify env-variable propagation

EMAIL_ENCRYPT_SECRET / EMAIL_ENCRYPT_SALT replace the old Google-specific names here.
Please make sure they are:

  1. Added to apps/web/.env.example (guidelines demand every new var appear there).
  2. Declared in the server section of apps/web/env.ts, and, if ever exposed client side, duplicated under client + experimental__runtimeEnv.

Failure to sync these files will break type-safe env validation at boot.


168-226: Fix MD026 & double-check new Microsoft vars

  1. Markdown-lint flags the trailing colon in the heading (MD026).

-### Updating .env file with Microsoft OAuth credentials:
+### Updating .env file with Microsoft OAuth credentials

2. Same env-propagation checklist applies: ensure `MICROSOFT_CLIENT_ID/SECRET` land in `.env.example`, `env.ts`, and `experimental__runtimeEnv` (if ever needed on the client).

[ suggest_nitpick ][ request_verification ]

---

`324-335`: **Unified watch endpoint – confirm route exists & docs fully updated**

Docs now reference `/api/watch/all` (cron + manual link). Please verify:

1. `apps/web/app/api/watch/all/route.ts` (or equivalent) exists and handles all providers.  
2. All residual references to the old `/api/google/watch/all` path have been scrubbed to avoid confusion.

A quick `rg '/api/google/watch/all'` in the repo will catch stragglers.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

@coderabbitai coderabbitai bot mentioned this pull request Jul 21, 2025
Copy link

claude bot commented Jul 23, 2025

Claude encountered an error —— View job


I'll analyze this and get back to you.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🔭 Outside diff range comments (1)
apps/web/utils/types.ts (1)

47-61: Abstract provider-agnostic email message away from Gmail API types

Based on our search, ParsedMessage in apps/web/utils/types.ts still extends gmail_v1.Schema$Message and is consumed by both the Gmail and Outlook providers (e.g. apps/web/utils/outlook/*.ts). This forces every provider to fit its raw data into Gmail’s shape. To decouple our core logic from Gmail-specific types and make it easier to add or adjust providers:

• In apps/web/utils/types.ts, extract a new BaseParsedMessage interface containing only generic fields:

  • id, threadId, subject, date, snippet, attachments, inline, headers, textPlain, textHtml, etc.
    • Rename the existing ParsedMessage to GmailParsedMessage and have it extend both BaseParsedMessage and gmail_v1.Schema$Message.
    • Create an OutlookParsedMessage (or similar) that extends BaseParsedMessage without touching Gmail types, and update the Outlook provider to return that.
    • Change your EmailProvider interface and consumers to reference BaseParsedMessage instead of ParsedMessage.

This split will keep provider-specific details isolated and allow truly provider-agnostic handling in our UI and business logic.

♻️ Duplicate comments (3)
apps/web/utils/outlook/message.ts (3)

183-187: Critical: SQL injection vulnerability still present in combined filter.

The query parameter is still being directly interpolated into the OData filter without proper escaping, maintaining the injection vulnerability flagged in previous reviews.

Apply the fix from previous review:

      const folderFilter = `(parentFolderId eq '${inboxFolderId}' or parentFolderId eq '${archiveFolderId}')`;
-      const combinedFilter = query.trim()
-        ? `${query.trim()} and ${folderFilter}`
-        : folderFilter;
+      const escapedQuery = query.trim().replace(/'/g, "''");
+      const combinedFilter = escapedQuery
+        ? `${escapedQuery} and ${folderFilter}`
+        : folderFilter;

245-245: Critical: SQL injection vulnerability still present in folder filter.

The folderId parameter is still being directly interpolated without validation, maintaining the injection vulnerability flagged in previous reviews.

Apply the validation fix from previous review:

    if (folderId) {
+      // Validate folderId format (should be a GUID)
+      if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(folderId)) {
+        throw new Error("Invalid folder ID format");
+      }
      request = request.filter(`parentFolderId eq '${folderId}'`);
    } else {

366-368: Critical: SQL injection vulnerability in query filter.

The query parameter is directly interpolated into the filter string without proper escaping, similar to the issues in queryBatchMessages.

Apply this fix to escape the query:

  if (options.query) {
-    request = request.filter(`contains(subject, '${options.query}')`);
+    const escapedQuery = options.query.replace(/'/g, "''");
+    request = request.filter(`contains(subject, '${escapedQuery}')`);
  }
🧹 Nitpick comments (1)
apps/web/utils/types.ts (1)

50-50: Document the purpose of the new isReplyInThread property.

The new boolean property lacks documentation explaining its purpose and how it differs from other thread-related logic in the system.

Add a comment explaining the property:

+ /** Indicates if this message is a reply within an existing thread */
  isReplyInThread: boolean;
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e12132b and 6c836ee.

📒 Files selected for processing (9)
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (3 hunks)
  • apps/web/prisma/schema.prisma (1 hunks)
  • apps/web/utils/ai/choose-rule/match-rules.ts (7 hunks)
  • apps/web/utils/ai/choose-rule/run-rules.ts (7 hunks)
  • apps/web/utils/date.ts (1 hunks)
  • apps/web/utils/mail.ts (2 hunks)
  • apps/web/utils/outlook/message.ts (1 hunks)
  • apps/web/utils/thread.ts (0 hunks)
  • apps/web/utils/types.ts (2 hunks)
📓 Path-based instructions (8)
apps/web/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Path aliases: Use @/ for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Leverage TypeScript inference for better DX

Files:

  • apps/web/utils/outlook/message.ts
  • apps/web/utils/types.ts
!{.cursor/rules/*.mdc}

📄 CodeRabbit Inference Engine (.cursor/rules/cursor-rules.mdc)

Never place rule files in the project root, in subdirectories outside .cursor/rules, or in any other location

Files:

  • apps/web/utils/outlook/message.ts
  • apps/web/utils/types.ts
**/*.ts

📄 CodeRabbit Inference Engine (.cursor/rules/form-handling.mdc)

**/*.ts: The same validation should be done in the server action too
Define validation schemas using Zod

Files:

  • apps/web/utils/outlook/message.ts
  • apps/web/utils/types.ts
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/logging.mdc)

**/*.{ts,tsx}: Use createScopedLogger for logging in backend TypeScript files
Typically add the logger initialization at the top of the file when using createScopedLogger
Only use .with() on a logger instance within a specific function, not for a global logger

Import Prisma in the project using import prisma from "@/utils/prisma";

**/*.{ts,tsx}: Don't use TypeScript enums.
Don't use TypeScript const enum.
Don't use the TypeScript directive @ts-ignore.
Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Don't use any or unknown as type constraints.
Don't use implicit any type on variable declarations.
Don't let variables evolve into any type through reassignments.
Don't use non-null assertions with the ! postfix operator.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't use user-defined types.
Use as const instead of literal types and type annotations.
Use export type for types.
Use import type for types.
Don't declare empty interfaces.
Don't merge interfaces and classes unsafely.
Don't use overload signatures that aren't next to each other.
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
Don't use TypeScript namespaces.
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 parameter properties in class constructors.
Use either T[] or Array consistently.
Initialize each enum member value explicitly.
Make sure all enum members are literal values.

Files:

  • apps/web/utils/outlook/message.ts
  • apps/web/utils/types.ts
apps/web/utils/**

📄 CodeRabbit Inference Engine (.cursor/rules/project-structure.mdc)

Create utility functions in utils/ folder for reusable logic

Files:

  • apps/web/utils/outlook/message.ts
  • apps/web/utils/types.ts
apps/web/utils/**/*.ts

📄 CodeRabbit Inference Engine (.cursor/rules/project-structure.mdc)

apps/web/utils/**/*.ts: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size

Files:

  • apps/web/utils/outlook/message.ts
  • apps/web/utils/types.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use elements in Next.js projects.
Don't use elements in Next.js projects.
Don't use namespace imports.
Don't access namespace imports dynamically.
Don't use global eval().
Don't use console.
Don't use debugger.
Don't use var.
Don't use with statements in non-strict contexts.
Don't use the arguments object.
Don't use consecutive spaces in regular expression literals.
Don't use the comma operator.
Don't use unnecessary boolean casts.
Don't use unnecessary callbacks with flatMap.
Use for...of statements instead of Array.forEach.
Don't create classes that only have static members (like a static namespace).
Don't use this and super in static contexts.
Don't use unnecessary catch clauses.
Don't use unnecessary constructors.
Don't use unnecessary continue statements.
Don't export empty modules that don't change anything.
Don't use unnecessary escape sequences in regular expression literals.
Don't use unnecessary labels.
Don't use unnecessary nested block statements.
Don't rename imports, exports, and destructured assignments to the same name.
Don't use unnecessary string or template literal concatenation.
Don't use String.raw in template literals when there are no escape sequences.
Don't use useless case statements in switch statements.
Don't use ternary operators when simpler alternatives exist.
Don't use useless this aliasing.
Don't initialize variables to undefined.
Don't use the void operators (they're not familiar).
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names th...

Files:

  • apps/web/utils/outlook/message.ts
  • apps/web/utils/types.ts
!pages/_document.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)

!pages/_document.{js,jsx,ts,tsx}: Don't import next/document outside of pages/_document.jsx in Next.js projects.
Don't import next/document outside of pages/_document.jsx in Next.js projects.

Files:

  • apps/web/utils/outlook/message.ts
  • apps/web/utils/types.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: elie222
PR: elie222/inbox-zero#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.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-07-18T15:05:34.890Z
Learning: Applies to apps/web/utils/gmail/**/*.ts : Keep provider-specific implementation details isolated in the appropriate utils subfolder (e.g., 'apps/web/utils/gmail/')
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/index.mdc:0-0
Timestamp: 2025-07-18T15:05:56.618Z
Learning: Guidelines for working with Gmail API
apps/web/utils/outlook/message.ts (16)

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-07-18T15:05:34.890Z
Learning: Applies to apps/web/utils/gmail/**/*.ts : Keep provider-specific implementation details isolated in the appropriate utils subfolder (e.g., 'apps/web/utils/gmail/')

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Extract common patterns into utility functions in LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Include relevant context in log messages for LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Define clear interfaces for complex input/output structures in LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Use proper error types and logging in LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-07-19T17:50:28.259Z
Learning: The utils folder also contains core app logic such as Next.js Server Actions and Gmail API requests.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Use descriptive scoped loggers for each LLM feature.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-07-20T09:00:41.952Z
Learning: Applies to apps/web/app/api/**/*.{ts,js} : All Prisma queries in API routes must include user/account filtering (e.g., emailAccountId or userId in WHERE clauses) to prevent unauthorized data access.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Implement fallbacks for AI failures in LLM-related functions.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-07-20T09:00:41.952Z
Learning: Applies to apps/web/app/api/**/*.{ts,js} : All parameters used in API routes must be validated before use; do not use parameters from 'params' or request bodies directly in queries without validation.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to /api//route.ts : ALL database queries in API routes MUST be scoped to the authenticated user/account (e.g., include userId or emailAccountId in query filters).

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to /api//route.ts : Never use direct object references in API routes without ownership checks (prevent IDOR vulnerabilities).

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to /api//route.ts : Prevent mass assignment vulnerabilities by only allowing explicitly whitelisted fields in update operations in API routes.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-07-20T09:00:41.952Z
Learning: Applies to apps/web/app/api/**/*.{ts,js} : Do not hardcode weak or plaintext secrets in API route files; secrets must not be directly assigned as string literals.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to /api//route.ts : All findUnique and findFirst Prisma calls in API routes MUST include ownership filters (e.g., userId or emailAccountId).

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-07-20T09:00:41.952Z
Learning: Applies to apps/web/app/api/**/*.{ts,js} : Review all new withError usage in API routes to ensure custom authentication is implemented where required.

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

Learnt from: edulelis
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.

💤 Files with no reviewable changes (1)
  • apps/web/utils/thread.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • apps/web/utils/date.ts
  • apps/web/utils/mail.ts
  • apps/web/prisma/schema.prisma
  • apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
  • apps/web/utils/ai/choose-rule/run-rules.ts
  • apps/web/utils/ai/choose-rule/match-rules.ts
🧰 Additional context used
📓 Path-based instructions (8)
apps/web/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Path aliases: Use @/ for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Leverage TypeScript inference for better DX

Files:

  • apps/web/utils/outlook/message.ts
  • apps/web/utils/types.ts
!{.cursor/rules/*.mdc}

📄 CodeRabbit Inference Engine (.cursor/rules/cursor-rules.mdc)

Never place rule files in the project root, in subdirectories outside .cursor/rules, or in any other location

Files:

  • apps/web/utils/outlook/message.ts
  • apps/web/utils/types.ts
**/*.ts

📄 CodeRabbit Inference Engine (.cursor/rules/form-handling.mdc)

**/*.ts: The same validation should be done in the server action too
Define validation schemas using Zod

Files:

  • apps/web/utils/outlook/message.ts
  • apps/web/utils/types.ts
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/logging.mdc)

**/*.{ts,tsx}: Use createScopedLogger for logging in backend TypeScript files
Typically add the logger initialization at the top of the file when using createScopedLogger
Only use .with() on a logger instance within a specific function, not for a global logger

Import Prisma in the project using import prisma from "@/utils/prisma";

**/*.{ts,tsx}: Don't use TypeScript enums.
Don't use TypeScript const enum.
Don't use the TypeScript directive @ts-ignore.
Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Don't use any or unknown as type constraints.
Don't use implicit any type on variable declarations.
Don't let variables evolve into any type through reassignments.
Don't use non-null assertions with the ! postfix operator.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't use user-defined types.
Use as const instead of literal types and type annotations.
Use export type for types.
Use import type for types.
Don't declare empty interfaces.
Don't merge interfaces and classes unsafely.
Don't use overload signatures that aren't next to each other.
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
Don't use TypeScript namespaces.
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 parameter properties in class constructors.
Use either T[] or Array consistently.
Initialize each enum member value explicitly.
Make sure all enum members are literal values.

Files:

  • apps/web/utils/outlook/message.ts
  • apps/web/utils/types.ts
apps/web/utils/**

📄 CodeRabbit Inference Engine (.cursor/rules/project-structure.mdc)

Create utility functions in utils/ folder for reusable logic

Files:

  • apps/web/utils/outlook/message.ts
  • apps/web/utils/types.ts
apps/web/utils/**/*.ts

📄 CodeRabbit Inference Engine (.cursor/rules/project-structure.mdc)

apps/web/utils/**/*.ts: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size

Files:

  • apps/web/utils/outlook/message.ts
  • apps/web/utils/types.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use elements in Next.js projects.
Don't use elements in Next.js projects.
Don't use namespace imports.
Don't access namespace imports dynamically.
Don't use global eval().
Don't use console.
Don't use debugger.
Don't use var.
Don't use with statements in non-strict contexts.
Don't use the arguments object.
Don't use consecutive spaces in regular expression literals.
Don't use the comma operator.
Don't use unnecessary boolean casts.
Don't use unnecessary callbacks with flatMap.
Use for...of statements instead of Array.forEach.
Don't create classes that only have static members (like a static namespace).
Don't use this and super in static contexts.
Don't use unnecessary catch clauses.
Don't use unnecessary constructors.
Don't use unnecessary continue statements.
Don't export empty modules that don't change anything.
Don't use unnecessary escape sequences in regular expression literals.
Don't use unnecessary labels.
Don't use unnecessary nested block statements.
Don't rename imports, exports, and destructured assignments to the same name.
Don't use unnecessary string or template literal concatenation.
Don't use String.raw in template literals when there are no escape sequences.
Don't use useless case statements in switch statements.
Don't use ternary operators when simpler alternatives exist.
Don't use useless this aliasing.
Don't initialize variables to undefined.
Don't use the void operators (they're not familiar).
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names th...

Files:

  • apps/web/utils/outlook/message.ts
  • apps/web/utils/types.ts
!pages/_document.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)

!pages/_document.{js,jsx,ts,tsx}: Don't import next/document outside of pages/_document.jsx in Next.js projects.
Don't import next/document outside of pages/_document.jsx in Next.js projects.

Files:

  • apps/web/utils/outlook/message.ts
  • apps/web/utils/types.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: elie222
PR: elie222/inbox-zero#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.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-07-18T15:05:34.890Z
Learning: Applies to apps/web/utils/gmail/**/*.ts : Keep provider-specific implementation details isolated in the appropriate utils subfolder (e.g., 'apps/web/utils/gmail/')
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/index.mdc:0-0
Timestamp: 2025-07-18T15:05:56.618Z
Learning: Guidelines for working with Gmail API
apps/web/utils/outlook/message.ts (16)

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-07-18T15:05:34.890Z
Learning: Applies to apps/web/utils/gmail/**/*.ts : Keep provider-specific implementation details isolated in the appropriate utils subfolder (e.g., 'apps/web/utils/gmail/')

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Extract common patterns into utility functions in LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Include relevant context in log messages for LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Define clear interfaces for complex input/output structures in LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Use proper error types and logging in LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-07-19T17:50:28.259Z
Learning: The utils folder also contains core app logic such as Next.js Server Actions and Gmail API requests.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Use descriptive scoped loggers for each LLM feature.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-07-20T09:00:41.952Z
Learning: Applies to apps/web/app/api/**/*.{ts,js} : All Prisma queries in API routes must include user/account filtering (e.g., emailAccountId or userId in WHERE clauses) to prevent unauthorized data access.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Implement fallbacks for AI failures in LLM-related functions.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-07-20T09:00:41.952Z
Learning: Applies to apps/web/app/api/**/*.{ts,js} : All parameters used in API routes must be validated before use; do not use parameters from 'params' or request bodies directly in queries without validation.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to /api//route.ts : ALL database queries in API routes MUST be scoped to the authenticated user/account (e.g., include userId or emailAccountId in query filters).

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to /api//route.ts : Never use direct object references in API routes without ownership checks (prevent IDOR vulnerabilities).

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to /api//route.ts : Prevent mass assignment vulnerabilities by only allowing explicitly whitelisted fields in update operations in API routes.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-07-20T09:00:41.952Z
Learning: Applies to apps/web/app/api/**/*.{ts,js} : Do not hardcode weak or plaintext secrets in API route files; secrets must not be directly assigned as string literals.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to /api//route.ts : All findUnique and findFirst Prisma calls in API routes MUST include ownership filters (e.g., userId or emailAccountId).

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-07-20T09:00:41.952Z
Learning: Applies to apps/web/app/api/**/*.{ts,js} : Review all new withError usage in API routes to ensure custom authentication is implemented where required.

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

Learnt from: edulelis
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.

🔇 Additional comments (8)
apps/web/utils/outlook/message.ts (8)

1-11: LGTM: Clean imports and proper logger setup.

The imports are well-structured, the scoped logger follows coding guidelines, and the module-level folder cache is appropriate for this use case.


12-24: LGTM: Robust helper function with proper error handling.

The function correctly handles base64 decoding errors and provides safe fallback behavior with appropriate logging.


26-34: LGTM: Well-defined constants with proper TypeScript usage.

Good use of as const for type safety and comprehensive coverage of standard email folders.


36-68: LGTM: Efficient folder ID fetching with proper caching and error handling.

The function uses parallel requests, graceful error handling, and caching to optimize performance while providing good observability through logging.


70-114: LGTM: Comprehensive label mapping with proper null/undefined handling.

The function correctly maps Outlook message properties to standardized labels, handles edge cases appropriately, and provides complete coverage of label types.


116-129: LGTM: Well-structured query function with proper rate limiting and pagination.

The function correctly implements different query strategies (OData filters, search, and basic queries) with appropriate pagination handling and rate limiting protection. The logging provides good observability for debugging.

Also applies to: 130-134, 136-178, 188-237, 238-275


278-310: LGTM: Comprehensive message conversion with proper fallback handling.

The function correctly filters drafts, maps all required fields, and handles optional/undefined values safely with appropriate fallbacks.


312-347: LGTM: Proper single message retrieval with folder ID mapping.

The function correctly fetches folder IDs to ensure proper label mapping for the retrieved message.

Copy link

claude bot commented Jul 23, 2025

Claude encountered an error —— View job


I'll analyze this and get back to you.

Copy link

claude bot commented Jul 23, 2025

Claude encountered an error —— View job


I'll analyze this and get back to you.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🔭 Outside diff range comments (1)
apps/web/utils/scheduled-actions/executor.ts (1)

134-143: Provider-specific error handling needs abstraction

The error handling checks for a Gmail-specific error message "Requested entity was not found." This won't work correctly for other email providers like Outlook, which may have different error messages for missing emails.

Consider creating a provider-agnostic way to handle "not found" errors:

  } catch (error: unknown) {
-   if (
-     error instanceof Error &&
-     error.message === "Requested entity was not found."
-   ) {
+   // Check if it's a "not found" error using provider-agnostic logic
+   if (client.isNotFoundError(error)) {
      logger.info("Email not found during validation", {
        messageId: scheduledAction.messageId,
        scheduledActionId: scheduledAction.id,
      });
      return null;
    }

    throw error;
  }

Alternatively, update the EmailProvider interface to return null for non-existent messages instead of throwing an error.

🧹 Nitpick comments (3)
apps/web/app/api/outlook/webhook/process-history-item.ts (2)

26-91: Consider extracting message parsing logic into a helper function.

The function has good structure with proper logging and deduplication checks. However, the message parsing logic (lines 76-82) could be extracted into a reusable helper function to improve maintainability.

+function parseMessageHeaders(message: Message) {
+  const from = message.from?.emailAddress?.address;
+  const to = message.toRecipients
+    ?.map((r) => r.emailAddress?.address)
+    .filter(Boolean) || [];
+  const subject = message.subject || "";
+  
+  return { from, to, subject };
+}

// Then in the main function:
-    const from = message.from?.emailAddress?.address;
-    const to =
-      message.toRecipients
-        ?.map((r) => r.emailAddress?.address)
-        .filter(Boolean) || [];
-    const subject = message.subject || "";
+    const { from, to, subject } = parseMessageHeaders(message);

197-241: Consider optimizing database query for sender categorization.

The sender categorization logic is functionally correct, but the database query could be optimized by combining the existence check with the categorization logic.

    if (emailAccount.autoCategorizeSenders) {
      const sender = extractEmailAddress(from);
-      const existingSender = await prisma.newsletter.findUnique({
-        where: {
-          email_emailAccountId: { email: sender, emailAccountId },
-        },
-        select: { category: true },
-      });
-      if (!existingSender?.category) {
-        await categorizeSenderWithProvider(sender, emailAccount, emailProvider);
-      }
+      // Only categorize if sender doesn't exist or has no category
+      const shouldCategorize = await prisma.newsletter.findFirst({
+        where: {
+          email: sender,
+          emailAccountId,
+          category: null,
+        },
+        select: { id: true },
+      });
+      
+      if (shouldCategorize || !(await prisma.newsletter.findUnique({
+        where: { email_emailAccountId: { email: sender, emailAccountId } },
+        select: { id: true },
+      }))) {
+        await categorizeSenderWithProvider(sender, emailAccount, emailProvider);
+      }
    }

Actually, let me reconsider this - the original approach is clearer and the performance impact is minimal for this use case.

apps/web/utils/scheduled-actions/executor.ts (1)

1-1: Remove unused Gmail import

The gmail_v1 type import from @googleapis/gmail is no longer used in this file after the provider abstraction refactoring.

-import type { gmail_v1 } from "@googleapis/gmail";
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fd0e0b4 and 5ac3511.

📒 Files selected for processing (8)
  • apps/web/app/api/outlook/webhook/process-history-item.ts (1 hunks)
  • apps/web/app/api/scheduled-actions/execute/route.ts (3 hunks)
  • apps/web/utils/ai/choose-rule/match-rules.ts (7 hunks)
  • apps/web/utils/mail.ts (2 hunks)
  • apps/web/utils/outlook/message.ts (1 hunks)
  • apps/web/utils/scheduled-actions/executor.ts (8 hunks)
  • apps/web/utils/thread.ts (1 hunks)
  • apps/web/utils/types.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • apps/web/utils/types.ts
  • apps/web/utils/mail.ts
  • apps/web/utils/thread.ts
  • apps/web/utils/ai/choose-rule/match-rules.ts
  • apps/web/utils/outlook/message.ts
🧰 Additional context used
📓 Path-based instructions (12)
apps/web/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Path aliases: Use @/ for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Leverage TypeScript inference for better DX

Files:

  • apps/web/app/api/scheduled-actions/execute/route.ts
  • apps/web/utils/scheduled-actions/executor.ts
  • apps/web/app/api/outlook/webhook/process-history-item.ts
apps/web/app/**

📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)

NextJS app router structure with (app) directory

Files:

  • apps/web/app/api/scheduled-actions/execute/route.ts
  • apps/web/app/api/outlook/webhook/process-history-item.ts
apps/web/app/api/**/route.ts

📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)

apps/web/app/api/**/route.ts: Use withAuth for user-level operations
Use withEmailAccount for email-account-level operations
Do NOT use POST API routes for mutations - use server actions instead
No need for try/catch in GET routes when using middleware
Export response types from GET routes

apps/web/app/api/**/route.ts: Wrap all GET API route handlers with withAuth or withEmailAccount middleware for authentication and authorization.
Export response types from GET API routes for type-safe client usage.
Do not use try/catch in GET API routes when using authentication middleware; rely on centralized error handling.

Files:

  • apps/web/app/api/scheduled-actions/execute/route.ts
!{.cursor/rules/*.mdc}

📄 CodeRabbit Inference Engine (.cursor/rules/cursor-rules.mdc)

Never place rule files in the project root, in subdirectories outside .cursor/rules, or in any other location

Files:

  • apps/web/app/api/scheduled-actions/execute/route.ts
  • apps/web/utils/scheduled-actions/executor.ts
  • apps/web/app/api/outlook/webhook/process-history-item.ts
**/*.ts

📄 CodeRabbit Inference Engine (.cursor/rules/form-handling.mdc)

**/*.ts: The same validation should be done in the server action too
Define validation schemas using Zod

Files:

  • apps/web/app/api/scheduled-actions/execute/route.ts
  • apps/web/utils/scheduled-actions/executor.ts
  • apps/web/app/api/outlook/webhook/process-history-item.ts
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/logging.mdc)

**/*.{ts,tsx}: Use createScopedLogger for logging in backend TypeScript files
Typically add the logger initialization at the top of the file when using createScopedLogger
Only use .with() on a logger instance within a specific function, not for a global logger

Import Prisma in the project using import prisma from "@/utils/prisma";

**/*.{ts,tsx}: Don't use TypeScript enums.
Don't use TypeScript const enum.
Don't use the TypeScript directive @ts-ignore.
Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Don't use any or unknown as type constraints.
Don't use implicit any type on variable declarations.
Don't let variables evolve into any type through reassignments.
Don't use non-null assertions with the ! postfix operator.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't use user-defined types.
Use as const instead of literal types and type annotations.
Use export type for types.
Use import type for types.
Don't declare empty interfaces.
Don't merge interfaces and classes unsafely.
Don't use overload signatures that aren't next to each other.
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
Don't use TypeScript namespaces.
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 parameter properties in class constructors.
Use either T[] or Array consistently.
Initialize each enum member value explicitly.
Make sure all enum members are literal values.

Files:

  • apps/web/app/api/scheduled-actions/execute/route.ts
  • apps/web/utils/scheduled-actions/executor.ts
  • apps/web/app/api/outlook/webhook/process-history-item.ts
**/api/**/route.ts

📄 CodeRabbit Inference Engine (.cursor/rules/security.mdc)

**/api/**/route.ts: ALL API routes that handle user data MUST use appropriate authentication and authorization middleware (withAuth or withEmailAccount).
ALL database queries in API routes MUST be scoped to the authenticated user/account (e.g., include userId or emailAccountId in query filters).
Always validate that resources belong to the authenticated user before performing operations (resource ownership validation).
Use withEmailAccount middleware for API routes that operate on a specific email account (i.e., use or require emailAccountId).
Use withAuth middleware for API routes that operate at the user level (i.e., use or require only userId).
Use withError middleware (with proper validation) for public endpoints, custom authentication, or cron endpoints.
Cron endpoints MUST use withError middleware and validate the cron secret using hasCronSecret(request) or hasPostCronSecret(request).
Cron endpoints MUST capture unauthorized attempts with captureException and return a 401 status for unauthorized requests.
All parameters in API routes MUST be validated for type, format, and length before use.
Request bodies in API routes MUST be validated using Zod schemas before use.
All Prisma queries in API routes MUST only return necessary fields and never expose sensitive data.
Error messages in API routes MUST not leak internal information or sensitive data; use generic error messages and SafeError where appropriate.
API routes MUST use a consistent error response format, returning JSON with an error message and status code.
All findUnique and findFirst Prisma calls in API routes MUST include ownership filters (e.g., userId or emailAccountId).
All findMany Prisma calls in API routes MUST be scoped to the authenticated user's data.
Never use direct object references in API routes without ownership checks (prevent IDOR vulnerabilities).
Prevent mass assignment vulnerabilities by only allowing explicitly whitelisted fields in update operations in AP...

Files:

  • apps/web/app/api/scheduled-actions/execute/route.ts
apps/web/app/api/**/*.{ts,js}

📄 CodeRabbit Inference Engine (.cursor/rules/security-audit.mdc)

apps/web/app/api/**/*.{ts,js}: All API route handlers in 'apps/web/app/api/' must use authentication middleware: withAuth, withEmailAccount, or withError (with custom authentication logic).
All Prisma queries in API routes must include user/account filtering (e.g., emailAccountId or userId in WHERE clauses) to prevent unauthorized data access.
All parameters used in API routes must be validated before use; do not use parameters from 'params' or request bodies directly in queries without validation.
Request bodies in API routes should use Zod schemas for validation.
API routes should only return necessary fields using Prisma's 'select' and must not include sensitive data in error messages.
Error messages in API routes must not reveal internal details; use generic errors and SafeError for user-facing errors.
All QStash endpoints (API routes called via publishToQstash or publishToQstashQueue) must use verifySignatureAppRouter to verify request authenticity.
All cron endpoints in API routes must use hasCronSecret or hasPostCronSecret for authentication.
Do not hardcode weak or plaintext secrets in API route files; secrets must not be directly assigned as string literals.
Review all new withError usage in API routes to ensure custom authentication is implemented where required.

Files:

  • apps/web/app/api/scheduled-actions/execute/route.ts
  • apps/web/app/api/outlook/webhook/process-history-item.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use elements in Next.js projects.
Don't use elements in Next.js projects.
Don't use namespace imports.
Don't access namespace imports dynamically.
Don't use global eval().
Don't use console.
Don't use debugger.
Don't use var.
Don't use with statements in non-strict contexts.
Don't use the arguments object.
Don't use consecutive spaces in regular expression literals.
Don't use the comma operator.
Don't use unnecessary boolean casts.
Don't use unnecessary callbacks with flatMap.
Use for...of statements instead of Array.forEach.
Don't create classes that only have static members (like a static namespace).
Don't use this and super in static contexts.
Don't use unnecessary catch clauses.
Don't use unnecessary constructors.
Don't use unnecessary continue statements.
Don't export empty modules that don't change anything.
Don't use unnecessary escape sequences in regular expression literals.
Don't use unnecessary labels.
Don't use unnecessary nested block statements.
Don't rename imports, exports, and destructured assignments to the same name.
Don't use unnecessary string or template literal concatenation.
Don't use String.raw in template literals when there are no escape sequences.
Don't use useless case statements in switch statements.
Don't use ternary operators when simpler alternatives exist.
Don't use useless this aliasing.
Don't initialize variables to undefined.
Don't use the void operators (they're not familiar).
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names th...

Files:

  • apps/web/app/api/scheduled-actions/execute/route.ts
  • apps/web/utils/scheduled-actions/executor.ts
  • apps/web/app/api/outlook/webhook/process-history-item.ts
!pages/_document.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)

!pages/_document.{js,jsx,ts,tsx}: Don't import next/document outside of pages/_document.jsx in Next.js projects.
Don't import next/document outside of pages/_document.jsx in Next.js projects.

Files:

  • apps/web/app/api/scheduled-actions/execute/route.ts
  • apps/web/utils/scheduled-actions/executor.ts
  • apps/web/app/api/outlook/webhook/process-history-item.ts
apps/web/utils/**

📄 CodeRabbit Inference Engine (.cursor/rules/project-structure.mdc)

Create utility functions in utils/ folder for reusable logic

Files:

  • apps/web/utils/scheduled-actions/executor.ts
apps/web/utils/**/*.ts

📄 CodeRabbit Inference Engine (.cursor/rules/project-structure.mdc)

apps/web/utils/**/*.ts: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size

Files:

  • apps/web/utils/scheduled-actions/executor.ts
🧠 Learnings (4)
📓 Common learnings
Learnt from: elie222
PR: elie222/inbox-zero#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.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-07-18T15:05:34.890Z
Learning: Applies to apps/web/utils/gmail/**/*.ts : Keep provider-specific implementation details isolated in the appropriate utils subfolder (e.g., 'apps/web/utils/gmail/')
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/index.mdc:0-0
Timestamp: 2025-07-18T15:05:56.618Z
Learning: Guidelines for working with Gmail API
apps/web/app/api/scheduled-actions/execute/route.ts (13)

Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-18T15:04:30.448Z
Learning: Applies to apps/web/app/api/**/route.ts : Use withEmailAccount for email-account-level operations

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-07-18T17:27:58.220Z
Learning: Applies to apps/web/utils/actions/*.ts : Use actionClient when both authenticated user context and a specific emailAccountId are needed. The emailAccountId must be bound when calling the action from the client.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to /api//route.ts : Use withEmailAccount middleware for API routes that operate on a specific email account (i.e., use or require emailAccountId).

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-07-18T15:05:16.118Z
Learning: Applies to apps/web/utils/actions/**/*.ts : Use server actions (with next-safe-action) for all mutations (create/update/delete operations); do NOT use POST API routes for mutations.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-07-20T09:00:41.952Z
Learning: Applies to apps/web/app/api/**/*.{ts,js} : All Prisma queries in API routes must include user/account filtering (e.g., emailAccountId or userId in WHERE clauses) to prevent unauthorized data access.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/get-api-route.mdc:0-0
Timestamp: 2025-07-18T15:05:26.685Z
Learning: Applies to app/api/**/route.ts : Always wrap the handler with withAuth or withEmailAccount for consistent error handling and authentication in GET API routes.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to /api//route.ts : ALL database queries in API routes MUST be scoped to the authenticated user/account (e.g., include userId or emailAccountId in query filters).

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/get-api-route.mdc:0-0
Timestamp: 2025-07-18T15:05:26.685Z
Learning: Applies to app/api/**/route.ts : Use Prisma for database queries in GET API routes.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-07-18T17:27:58.220Z
Learning: Applies to apps/web/utils/actions/*.ts : Access necessary context (like userId, emailAccountId, etc.) provided by the safe action client via the ctx object in the .action() handler.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-07-18T17:27:58.220Z
Learning: Applies to apps/web/utils/actions/*.ts : Implement all server actions using the next-safe-action library for type safety, input validation, context management, and error handling. Refer to apps/web/utils/actions/safe-action.ts for client definitions (actionClient, actionClientUser, adminActionClient).

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/prisma.mdc:0-0
Timestamp: 2025-06-23T12:26:53.882Z
Learning: In this project, Prisma should be imported using 'import prisma from "@/utils/prisma";' in TypeScript files.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-07-19T17:50:28.259Z
Learning: The utils folder also contains core app logic such as Next.js Server Actions and Gmail API requests.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to /api//route.ts : All findUnique and findFirst Prisma calls in API routes MUST include ownership filters (e.g., userId or emailAccountId).

apps/web/utils/scheduled-actions/executor.ts (11)

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-07-18T17:27:58.220Z
Learning: Applies to apps/web/utils/actions/*.ts : Use actionClient when both authenticated user context and a specific emailAccountId are needed. The emailAccountId must be bound when calling the action from the client.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-07-18T17:27:58.220Z
Learning: Applies to apps/web/utils/actions/*.ts : Use adminActionClient for actions restricted to admin users.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-07-18T15:05:34.890Z
Learning: Applies to apps/web/utils/gmail/**/*.ts : Keep provider-specific implementation details isolated in the appropriate utils subfolder (e.g., 'apps/web/utils/gmail/')

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-07-18T17:27:58.220Z
Learning: Applies to apps/web/utils/actions/*.ts : Use actionClientUser when only authenticated user context (userId) is needed.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-07-18T17:27:58.220Z
Learning: Applies to apps/web/utils/actions/*.ts : Access necessary context (like userId, emailAccountId, etc.) provided by the safe action client via the ctx object in the .action() handler.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-07-18T17:27:58.220Z
Learning: Applies to apps/web/utils/actions/*.ts : Implement all server actions using the next-safe-action library for type safety, input validation, context management, and error handling. Refer to apps/web/utils/actions/safe-action.ts for client definitions (actionClient, actionClientUser, adminActionClient).

Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-18T15:04:30.448Z
Learning: Applies to apps/web/app/api/**/route.ts : Use withEmailAccount for email-account-level operations

Learnt from: elie222
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.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-07-18T15:05:16.118Z
Learning: Applies to apps/web/utils/actions/**/*.ts : Use server actions (with next-safe-action) for all mutations (create/update/delete operations); do NOT use POST API routes for mutations.

Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-18T15:04:30.448Z
Learning: Applies to apps/web/utils/actions/**/*.ts : Use server actions for all mutations (create/update/delete operations)

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to /api//route.ts : Use withEmailAccount middleware for API routes that operate on a specific email account (i.e., use or require emailAccountId).

apps/web/app/api/outlook/webhook/process-history-item.ts (10)

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-07-18T15:05:34.890Z
Learning: Applies to apps/web/utils/gmail/**/*.ts : Keep provider-specific implementation details isolated in the appropriate utils subfolder (e.g., 'apps/web/utils/gmail/')

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Include relevant context in log messages for LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Document complex AI logic with clear comments in LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Implement fallbacks for AI failures in LLM-related functions.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Follow the standard structure for LLM-related functions: use a scoped logger, define a Zod schema for output, validate inputs early, separate system and user prompts, log inputs and outputs, call chatCompletionObject with proper configuration, and return validated results.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Define clear interfaces for complex input/output structures in LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Remove excessive whitespace and truncate long inputs in LLM prompts.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Keep system prompts and user prompts separate in LLM-related code.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-07-18T15:06:40.243Z
Learning: Applies to apps/web/utils/{ai,llms}/**/*.ts : Implement early returns for invalid inputs in LLM-related functions.

Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/task-list.mdc:0-0
Timestamp: 2025-07-18T17:28:14.611Z
Learning: Applies to {TASKS,ASSISTANT_CHAT,.md} : Keep the 'Relevant Files' section updated with file paths, brief descriptions of each file's purpose, and status indicators (e.g., ✅) for completed components.

🧬 Code Graph Analysis (2)
apps/web/app/api/scheduled-actions/execute/route.ts (2)
apps/web/utils/email/provider.ts (1)
  • createEmailProvider (1609-1624)
apps/web/utils/scheduled-actions/executor.ts (1)
  • executeScheduledAction (25-102)
apps/web/utils/scheduled-actions/executor.ts (2)
apps/web/utils/logger.ts (1)
  • createScopedLogger (17-65)
apps/web/utils/ai/types.ts (1)
  • EmailForAction (4-13)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Static Code Analysis Js
  • GitHub Check: Jit Security
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (10)
apps/web/app/api/outlook/webhook/process-history-item.ts (7)

1-24: LGTM! Clean import organization and proper provider abstraction.

The imports are well-organized and correctly use the provider-agnostic utilities as intended. The use of type imports for TypeScript types follows best practices.


93-135: Good assistant email handling with proper early returns.

The assistant email detection and processing logic is well-structured with appropriate early returns and proper logging. The message transformation for the processAssistantEmail function is comprehensive.


137-150: Verify outbound detection logic is case-insensitive.

The outbound detection uses toLowerCase() which is correct for email comparison. The delegation to handleOutbound is appropriate.


152-195: Excellent defensive programming with proper error handling.

The unsubscribed email blocking and cold email detection logic is well-structured with appropriate conditional checks and proper logging. The use of shouldRunColdEmailBlocker helper function improves readability.


242-255: Robust error handling with appropriate message filtering.

The error handling correctly identifies and handles specific Outlook API errors (ItemNotFound, ResourceNotFound) while allowing other errors to propagate. This is appropriate for webhook processing where messages may be deleted between notification and processing.


257-342: Well-structured outbound message handling with proper error isolation.

The handleOutbound function demonstrates excellent error handling patterns:

  • Uses Promise.allSettled to prevent one operation from blocking another
  • Logs errors without throwing to maintain processing flow
  • Proper sequential execution where cleanup must happen after tracking/outbound handling

344-354: Clean utility function with clear logic.

The shouldRunColdEmailBlocker function is well-structured with clear boolean logic and proper type checking.

apps/web/app/api/scheduled-actions/execute/route.ts (1)

47-57: Security: Enforce ownership filter on scheduledAction lookup

The findUnique call isn’t scoping to the owning emailAccountId, which can lead to cross-account data exposure if someone obtains a valid scheduledActionId. Update the query to include the emailAccountId filter and handle “not found” as unauthorized.

– File: apps/web/app/api/scheduled-actions/execute/route.ts
– Location: the prisma.scheduledAction lookup (around lines 47–57)

Suggested change:

- const scheduledAction = await prisma.scheduledAction.findUnique({
-   where: { id: payload.scheduledActionId },
-   include: {
-     emailAccount: { include: { account: true } },
-     executedRule: true,
-   },
- });
+ const scheduledAction = await prisma.scheduledAction.findFirst({
+   where: {
+     id: payload.scheduledActionId,
+     emailAccountId: payload.emailAccountId,
+   },
+   include: {
+     emailAccount: { include: { account: true } },
+     executedRule: true,
+   },
+ });
+ if (!scheduledAction) {
+   return new NextResponse(null, { status: 404 });
+ }

This ensures only the scheduled action belonging to the given emailAccountId is returned, preventing unauthorized access.

⛔ Skipped due to learnings
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-07-20T09:00:41.952Z
Learning: Applies to apps/web/app/api/**/*.{ts,js} : Review all new withError usage in API routes to ensure custom authentication is implemented where required.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to **/api/**/route.ts : All `findUnique` and `findFirst` Prisma calls in API routes MUST include ownership filters (e.g., userId or emailAccountId).
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-07-20T09:00:41.952Z
Learning: Applies to apps/web/app/api/**/*.{ts,js} : All Prisma queries in API routes must include user/account filtering (e.g., emailAccountId or userId in WHERE clauses) to prevent unauthorized data access.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to **/api/**/route.ts : ALL database queries in API routes MUST be scoped to the authenticated user/account (e.g., include userId or emailAccountId in query filters).
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to **/api/**/route.ts : Never use direct object references in API routes without ownership checks (prevent IDOR vulnerabilities).
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-07-20T09:00:41.952Z
Learning: During code review, verify that all new API routes follow security patterns: middleware usage, user scoping, input validation, and error handling.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-07-20T09:00:41.952Z
Learning: Applies to apps/web/app/api/**/*.{ts,js} : All QStash endpoints (API routes called via publishToQstash or publishToQstashQueue) must use verifySignatureAppRouter to verify request authenticity.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-07-18T15:05:16.118Z
Learning: Applies to apps/web/utils/actions/**/*.ts : Use server actions (with `next-safe-action`) for all mutations (create/update/delete operations); do NOT use POST API routes for mutations.
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-18T15:04:30.448Z
Learning: Applies to apps/web/app/api/**/route.ts : Use `withEmailAccount` for email-account-level operations
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-07-18T17:27:46.378Z
Learning: Applies to **/api/**/route.ts : All `findMany` Prisma calls in API routes MUST be scoped to the authenticated user's data.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-07-18T17:27:58.220Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `actionClient` when both authenticated user context and a specific `emailAccountId` are needed. The `emailAccountId` must be bound when calling the action from the client.
apps/web/utils/scheduled-actions/executor.ts (2)

25-28: Good refactoring to support multiple email providers

The function signature change to accept a generic EmailProvider client is a clean abstraction that enables support for multiple email providers. The implementation correctly passes the client to all dependent functions.


205-206: No action needed: Header mapping is consistent
Both Gmail and Outlook providers normalize the raw header arrays into a headers object with direct subject and date properties. Accessing emailMessage.headers.subject and emailMessage.headers.date in executeDelayedAction is therefore safe across providers, and the existing fallbacks guard against any rare missing values.

@coderabbitai coderabbitai bot mentioned this pull request Jul 24, 2025
Copy link

claude bot commented Jul 25, 2025

Claude encountered an error —— View job


I'll analyze this and get back to you.

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.

4 participants