Conversation
|
@edulelis is attempting to deploy a commit to the Inbox Zero Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughThis update introduces delayed execution for rule actions in the email assistant application. It adds a Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI
participant Backend
participant QStash
participant Executor
User->>UI: Configure rule with delayed action
UI->>Backend: Save rule (with delayInMinutes)
Backend->>Backend: Persist rule and action
Backend->>QStash: Schedule delayed action (with notBefore)
QStash->>Backend: POST /api/scheduled-actions/execute (at scheduled time)
Backend->>Executor: Mark action as executing
Executor->>Backend: Execute scheduled action
Executor->>Backend: Update status (completed/failed)
Estimated code review effort4 (60–120 minutes) The changes span multiple layers (UI, validation, types, backend, scheduling, execution, and tests), introduce a new model and API, and require careful review for correctness, consistency, and security, especially around scheduling, cancellation, and error handling. Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (5)
apps/web/app/api/cron/scheduled-actions/route.ts (1)
6-6: Use import type for NextRequest.The static analysis tool correctly identifies that
NextRequestis only used as a type. Consider usingimport typefor better tree-shaking.-import { NextRequest } from "next/server"; +import type { NextRequest } from "next/server";apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)
1450-1451: Consider more robust number parsing.The current implementation might not handle all edge cases properly.
Consider using a more defensive approach:
- const numValue = Number.parseInt(value, 10); - if (Number.isNaN(numValue) || numValue <= 0) return null; + const trimmedValue = value.trim(); + if (!trimmedValue || !/^\d+$/.test(trimmedValue)) return null; + const numValue = Number.parseInt(trimmedValue, 10); + if (Number.isNaN(numValue) || numValue <= 0) return null;This ensures only valid numeric strings are parsed.
apps/web/utils/scheduled-actions/executor.ts (1)
155-157: Consider using static import instead of dynamic import.Dynamic imports add overhead and complexity when not needed.
Move to top-level import:
+import { parseMessage } from "@/utils/mail"; // In the function: - const parsedMessage = await import("@/utils/mail").then((m) => - m.parseMessage(message), - ); + const parsedMessage = await parseMessage(message);apps/web/utils/scheduled-actions/scheduler.ts (1)
83-136: Consider using database transactions for consistency.When scheduling multiple delayed actions, consider wrapping the operations in a transaction to ensure all-or-nothing behavior.
Example approach:
const scheduledActions = await prisma.$transaction(async (tx) => { const actions = []; for (const actionItem of delayedActions) { const scheduledFor = new Date( emailInternalDate.getTime() + actionItem.delayInMinutes! * 60 * 1000, ); const action = await tx.scheduledAction.create({ data: { /* ... */ } }); actions.push(action); } return actions; });This ensures either all actions are scheduled or none are, preventing partial scheduling on errors.
apps/web/prisma/schema.prisma (1)
348-348: Consider adding a comment about delay constraintsThe documentation mentions delays should be between 1 minute and 30 days (43200 minutes). Consider adding a comment here to document these constraints for future developers.
- delayInMinutes Int? // Optional delay in minutes (1 min to 30 days) + delayInMinutes Int? // Optional delay in minutes (min: 1, max: 43200 = 30 days)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
DELAYED_ACTIONS.mdc(1 hunks)apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx(3 hunks)apps/web/app/api/cron/scheduled-actions/route.ts(1 hunks)apps/web/prisma/schema.prisma(7 hunks)apps/web/utils/actions/rule.validation.ts(1 hunks)apps/web/utils/ai/choose-rule/run-rules.ts(5 hunks)apps/web/utils/ai/types.ts(1 hunks)apps/web/utils/delayed-actions.ts(1 hunks)apps/web/utils/scheduled-actions/executor.test.ts(1 hunks)apps/web/utils/scheduled-actions/executor.ts(1 hunks)apps/web/utils/scheduled-actions/scheduler.test.ts(1 hunks)apps/web/utils/scheduled-actions/scheduler.ts(1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
apps/web/app/api/cron/scheduled-actions/route.ts
[error] 6-6: All these imports are only used as types.
Importing the types with import type ensures that they are removed by the compilers and avoids loading unnecessary modules.
Safe fix: Use import type.
(lint/style/useImportType)
🔇 Additional comments (21)
apps/web/utils/delayed-actions.ts (1)
1-17: LGTM! Clean and well-structured utility module.The implementation correctly defines the supported delayed action types and provides a type-safe validation function. The documentation is clear and the code follows good practices.
apps/web/utils/ai/types.ts (1)
25-25: LGTM! Appropriate type addition for delayed actions.The optional and nullable
delayInMinutesfield is correctly typed and well-documented, maintaining backward compatibility while supporting the new delayed actions feature.apps/web/utils/actions/rule.validation.ts (1)
76-76: LGTM! Appropriate validation constraints for delay field.The validation correctly enforces a 1-minute minimum and 30-day maximum (43,200 minutes) for delayed actions, with proper optional/nullable typing that matches the type definitions.
apps/web/utils/scheduled-actions/scheduler.test.ts (1)
1-94: Excellent test coverage for scheduler functionality.The test suite is comprehensive and well-structured, covering both positive and negative scenarios for action type validation and scheduled action cancellation. The proper mocking and clear assertions provide good confidence in the scheduler implementation.
apps/web/app/api/cron/scheduled-actions/route.ts (1)
20-102: Robust cron job implementation with excellent error handling.The handler is well-implemented with:
- Proper authorization and logging
- Sequential processing to avoid race conditions
- Comprehensive error handling at multiple levels
- Good result tracking and monitoring
- Appropriate timeout configuration (5 minutes)
The duplicate processing prevention using
markActionAsExecutingis a nice touch for reliability.apps/web/utils/scheduled-actions/executor.test.ts (2)
1-52: Well-structured test setup with comprehensive mocking.The test setup properly mocks all dependencies and provides a complete mock scheduled action object with all required fields.
53-213: Comprehensive test coverage for executor functionality.The test cases effectively cover:
- Successful execution with proper status updates
- Error handling with retry logic
- Permanent failure scenarios
Good job on testing both the happy path and error conditions.
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (2)
94-94: Clean integration of delay input for supported actions.The conditional rendering using
isSupportedDelayedActionensures the delay input only appears for action types that support delays.Also applies to: 1227-1237
1409-1531: Well-implemented delay input component with proper unit conversion.The component correctly handles:
- Conversion between minutes, hours, and days
- Validation constraints (1 minute to 30 days)
- Bidirectional sync between display value and stored minutes
- Hidden input for form integration
Good UX with the unit selector and clear max limit display.
apps/web/utils/scheduled-actions/executor.ts (1)
20-362: Solid implementation of scheduled action execution with robust error handling.The executor properly handles:
- Email validation before execution
- Error classification (permanent vs transient)
- Retry logic with appropriate delays
- Status updates and completion tracking
- Comprehensive logging for monitoring
Good architectural decisions on retry attempts and error categorization.
apps/web/utils/ai/choose-rule/run-rules.ts (2)
102-110: Good practice: Cancel superseded scheduled actions.Canceling existing scheduled actions before applying new rules prevents duplicate or conflicting actions. The test mode check appropriately skips this in test scenarios.
112-149: Well-structured separation of immediate and delayed action handling.The implementation correctly:
- Filters actions based on delay criteria
- Saves only immediate actions to ExecutedActions
- Schedules delayed actions separately with proper metadata
- Sets appropriate status (SCHEDULED vs PENDING) based on action types
This maintains a clean separation between immediate execution and scheduled execution paths.
Also applies to: 224-228
apps/web/utils/scheduled-actions/scheduler.ts (3)
32-36: Good validation of supported action types.Early validation with a clear error message prevents invalid scheduled actions from being created.
113-113: Safe use of non-null assertion.The non-null assertion on
delayInMinutes!is safe here because the filter on lines 99-103 ensures it's defined and greater than 0.
1-246: Well-implemented scheduler service with comprehensive functionality.The scheduler properly handles:
- Action validation and type checking
- Scheduling with proper time calculations
- Cancellation of superseded actions
- Retrieval of due actions for execution
- Concurrency control with status updates
Good architectural decisions and error handling throughout.
apps/web/prisma/schema.prisma (3)
122-122: IsdigestSchedulerelated to the delayed actions feature?This field appears to be for digest email scheduling rather than the delayed actions feature that this PR implements. Consider moving this to a separate PR to keep changes focused.
468-469: Well-designed indexes for performanceThe indexes are properly optimized for the cron job queries and cancellation operations. Good performance considerations.
846-846: Appropriate status addition for delayed actionsThe
SCHEDULEDstatus properly represents rules with pending delayed actions, aligning with the documented status flow.DELAYED_ACTIONS.mdc (3)
120-120: ****
298-315: Excellent production readiness documentationThe performance metrics and deployment checklist provide valuable operational guidance. The future enhancement ideas are well thought out.
251-252: Clarify WIP status vs. completion claimsThe document claims the implementation is 100% complete, but the PR title indicates "WIP: Delayed actions". Please clarify whether this is still a work in progress or ready for review.
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (3)
apps/web/app/api/admin/scheduled-actions/[id]/retry/route.ts (1)
1-1: Fix import type usage for NextRequest.Same issue as the cancel route - NextRequest should be imported as a type since it's only used for type annotation.
-import { NextRequest, NextResponse } from "next/server"; +import { NextResponse, type NextRequest } from "next/server";apps/web/app/api/admin/scheduled-actions/route.ts (1)
1-1: Fix import type usage for NextRequest.NextRequest should be imported as a type since it's only used for type annotation.
-import { type NextRequest, NextResponse } from "next/server"; +import { NextResponse, type NextRequest } from "next/server";apps/web/utils/scheduled-actions/executor.ts (1)
24-24: Great improvement on type safety!The previous type safety concerns have been properly addressed:
- Function parameter uses proper
ScheduledActiontype- No more
as anytype casting in the codeAlso applies to: 216-223
🧹 Nitpick comments (3)
apps/web/utils/delayed-actions.ts (1)
1-16: LGTM! Well-structured utility for action delay validation.The utility provides a clean, client-safe way to check action delay support. The choice of unsupported actions (MARK_SPAM, TRACK_THREAD, DIGEST) makes sense as these are typically immediate-effect actions.
Consider documenting why these specific actions don't support delays to help future maintainers understand the rationale.
apps/web/app/api/admin/scheduled-actions/[id]/cancel/route.ts (1)
1-1: Fix import type usage for NextRequest.NextRequest is only used as a type parameter, so it should be imported with
import typeto ensure it's removed during compilation.-import { type NextRequest, NextResponse } from "next/server"; +import { NextResponse, type NextRequest } from "next/server";apps/web/utils/scheduled-actions/scheduler.ts (1)
138-186: Consider persisting the cancellation reason in the database.The
reasonparameter is only used for logging but not stored in the database. For better audit trails and debugging, consider adding acancellationReasonfield to theScheduledActionmodel.Add the cancellation reason to the update data:
data: { status: ScheduledActionStatus.CANCELLED, + cancellationReason: reason, },This would require adding a
cancellationReasonfield to the Prisma schema.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (30)
apps/web/__tests__/ai-choose-rule.test.ts(1 hunks)apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx(10 hunks)apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx(2 hunks)apps/web/app/(app)/[emailAccountId]/assistant/onboarding/CategoriesSetup.tsx(1 hunks)apps/web/app/(app)/admin/page.tsx(2 hunks)apps/web/app/(app)/admin/scheduled-actions/ScheduledActionsTable.tsx(1 hunks)apps/web/app/(app)/admin/scheduled-actions/page.tsx(1 hunks)apps/web/app/(app)/admin/scheduled-actions/types.ts(1 hunks)apps/web/app/api/admin/scheduled-actions/[id]/cancel/route.ts(1 hunks)apps/web/app/api/admin/scheduled-actions/[id]/retry/route.ts(1 hunks)apps/web/app/api/admin/scheduled-actions/route.ts(1 hunks)apps/web/app/api/cron/scheduled-actions/route.ts(1 hunks)apps/web/components/TooltipExplanation.tsx(2 hunks)apps/web/prisma/migrations/20250625053006_add_delayed_actions/migration.sql(1 hunks)apps/web/prisma/schema.prisma(6 hunks)apps/web/utils/action-item.ts(2 hunks)apps/web/utils/actions/rule.ts(10 hunks)apps/web/utils/actions/rule.validation.ts(3 hunks)apps/web/utils/ai/assistant/chat.ts(4 hunks)apps/web/utils/ai/choose-rule/run-rules.ts(3 hunks)apps/web/utils/ai/rule/create-rule-schema.ts(2 hunks)apps/web/utils/date.ts(1 hunks)apps/web/utils/delayed-actions.ts(1 hunks)apps/web/utils/reply-tracker/enable.ts(1 hunks)apps/web/utils/rule/rule.ts(1 hunks)apps/web/utils/schedule.test.ts(1 hunks)apps/web/utils/scheduled-actions/executor.test.ts(1 hunks)apps/web/utils/scheduled-actions/executor.ts(1 hunks)apps/web/utils/scheduled-actions/scheduler.test.ts(1 hunks)apps/web/utils/scheduled-actions/scheduler.ts(1 hunks)
✅ Files skipped from review due to trivial changes (8)
- apps/web/app/(app)/admin/page.tsx
- apps/web/utils/reply-tracker/enable.ts
- apps/web/tests/ai-choose-rule.test.ts
- apps/web/app/(app)/admin/scheduled-actions/page.tsx
- apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
- apps/web/app/(app)/admin/scheduled-actions/types.ts
- apps/web/utils/schedule.test.ts
- apps/web/utils/date.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- apps/web/utils/ai/choose-rule/run-rules.ts
- apps/web/utils/scheduled-actions/scheduler.test.ts
- apps/web/utils/actions/rule.validation.ts
- apps/web/prisma/schema.prisma
🧰 Additional context used
📓 Path-based instructions (17)
`apps/web/**/app/**`: Follow NextJS app router structure by organizing code within the app directory.
apps/web/**/app/**: Follow NextJS app router structure by organizing code within the app directory.
apps/web/app/(app)/[emailAccountId]/assistant/onboarding/CategoriesSetup.tsxapps/web/app/api/admin/scheduled-actions/[id]/cancel/route.tsapps/web/app/api/admin/scheduled-actions/route.tsapps/web/app/api/cron/scheduled-actions/route.tsapps/web/app/(app)/admin/scheduled-actions/ScheduledActionsTable.tsxapps/web/app/api/admin/scheduled-actions/[id]/retry/route.tsapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
`apps/web/**/*.{ts,tsx}`: Use TypeScript with strict null checks enabled. Use path aliases with @/ for imports from the project root. Use proper error handling with try/catch block...
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks enabled.
Use path aliases with @/ for imports from the project root.
Use proper error handling with try/catch blocks.
Use the LoadingContent component for async data loading states.
Prefix client-side environment variables with NEXT_PUBLIC_.
apps/web/app/(app)/[emailAccountId]/assistant/onboarding/CategoriesSetup.tsxapps/web/utils/rule/rule.tsapps/web/utils/delayed-actions.tsapps/web/utils/action-item.tsapps/web/utils/ai/rule/create-rule-schema.tsapps/web/components/TooltipExplanation.tsxapps/web/app/api/admin/scheduled-actions/[id]/cancel/route.tsapps/web/app/api/admin/scheduled-actions/route.tsapps/web/app/api/cron/scheduled-actions/route.tsapps/web/utils/scheduled-actions/executor.tsapps/web/utils/scheduled-actions/executor.test.tsapps/web/utils/ai/assistant/chat.tsapps/web/app/(app)/admin/scheduled-actions/ScheduledActionsTable.tsxapps/web/utils/actions/rule.tsapps/web/utils/scheduled-actions/scheduler.tsapps/web/app/api/admin/scheduled-actions/[id]/retry/route.tsapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
`apps/web/**/*.{ts,tsx,js,jsx}`: Format code with Prettier and follow tailwindcss patterns using prettier-plugin-tailwindcss.
apps/web/**/*.{ts,tsx,js,jsx}: Format code with Prettier and follow tailwindcss patterns using prettier-plugin-tailwindcss.
apps/web/app/(app)/[emailAccountId]/assistant/onboarding/CategoriesSetup.tsxapps/web/utils/rule/rule.tsapps/web/utils/delayed-actions.tsapps/web/utils/action-item.tsapps/web/utils/ai/rule/create-rule-schema.tsapps/web/components/TooltipExplanation.tsxapps/web/app/api/admin/scheduled-actions/[id]/cancel/route.tsapps/web/app/api/admin/scheduled-actions/route.tsapps/web/app/api/cron/scheduled-actions/route.tsapps/web/utils/scheduled-actions/executor.tsapps/web/utils/scheduled-actions/executor.test.tsapps/web/utils/ai/assistant/chat.tsapps/web/app/(app)/admin/scheduled-actions/ScheduledActionsTable.tsxapps/web/utils/actions/rule.tsapps/web/utils/scheduled-actions/scheduler.tsapps/web/app/api/admin/scheduled-actions/[id]/retry/route.tsapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
`apps/web/**`: Install packages only within the 'apps/web' directory, not at the repository root.
apps/web/**: Install packages only within the 'apps/web' directory, not at the repository root.
apps/web/app/(app)/[emailAccountId]/assistant/onboarding/CategoriesSetup.tsxapps/web/utils/rule/rule.tsapps/web/utils/delayed-actions.tsapps/web/utils/action-item.tsapps/web/utils/ai/rule/create-rule-schema.tsapps/web/components/TooltipExplanation.tsxapps/web/app/api/admin/scheduled-actions/[id]/cancel/route.tsapps/web/app/api/admin/scheduled-actions/route.tsapps/web/app/api/cron/scheduled-actions/route.tsapps/web/utils/scheduled-actions/executor.tsapps/web/utils/scheduled-actions/executor.test.tsapps/web/utils/ai/assistant/chat.tsapps/web/app/(app)/admin/scheduled-actions/ScheduledActionsTable.tsxapps/web/utils/actions/rule.tsapps/web/utils/scheduled-actions/scheduler.tsapps/web/app/api/admin/scheduled-actions/[id]/retry/route.tsapps/web/prisma/migrations/20250625053006_add_delayed_actions/migration.sqlapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
`apps/web/app/(app)/**/*.{js,jsx,ts,tsx}`: If you need to use onClick in a component, that component is a client component and file must start with 'use client'.
apps/web/app/(app)/**/*.{js,jsx,ts,tsx}: If you need to use onClick in a component, that component is a client component and file must start with 'use client'.
apps/web/app/(app)/[emailAccountId]/assistant/onboarding/CategoriesSetup.tsxapps/web/app/(app)/admin/scheduled-actions/ScheduledActionsTable.tsxapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
`**/*.{js,jsx,ts,tsx}`: Use Shadcn UI and Tailwind for components and styling. Implement responsive design with Tailwind CSS using a mobile-first approach. Use the `next/image` pac...
**/*.{js,jsx,ts,tsx}: Use Shadcn UI and Tailwind for components and styling.
Implement responsive design with Tailwind CSS using a mobile-first approach.
Use thenext/imagepackage for images.
apps/web/app/(app)/[emailAccountId]/assistant/onboarding/CategoriesSetup.tsxapps/web/utils/rule/rule.tsapps/web/utils/delayed-actions.tsapps/web/utils/action-item.tsapps/web/utils/ai/rule/create-rule-schema.tsapps/web/components/TooltipExplanation.tsxapps/web/app/api/admin/scheduled-actions/[id]/cancel/route.tsapps/web/app/api/admin/scheduled-actions/route.tsapps/web/app/api/cron/scheduled-actions/route.tsapps/web/utils/scheduled-actions/executor.tsapps/web/utils/scheduled-actions/executor.test.tsapps/web/utils/ai/assistant/chat.tsapps/web/app/(app)/admin/scheduled-actions/ScheduledActionsTable.tsxapps/web/utils/actions/rule.tsapps/web/utils/scheduled-actions/scheduler.tsapps/web/app/api/admin/scheduled-actions/[id]/retry/route.tsapps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
`apps/web/utils/**/*`: Create utility functions in utils/ folder for reusable logic.
apps/web/utils/**/*: Create utility functions in utils/ folder for reusable logic.
apps/web/utils/rule/rule.tsapps/web/utils/delayed-actions.tsapps/web/utils/action-item.tsapps/web/utils/ai/rule/create-rule-schema.tsapps/web/utils/scheduled-actions/executor.tsapps/web/utils/scheduled-actions/executor.test.tsapps/web/utils/ai/assistant/chat.tsapps/web/utils/actions/rule.tsapps/web/utils/scheduled-actions/scheduler.ts
`apps/web/utils/ai/**`: Main LLM implementations should be placed in this directory.
apps/web/utils/ai/**: Main LLM implementations should be placed in this directory.
apps/web/utils/ai/rule/create-rule-schema.tsapps/web/utils/ai/assistant/chat.ts
`apps/web/**/components/**/*.{ts,tsx}`: Use PascalCase naming convention for component files. Prefer functional components with hooks. Use shadcn/ui components when available. Ensu...
apps/web/**/components/**/*.{ts,tsx}: Use PascalCase naming convention for component files.
Prefer functional components with hooks.
Use shadcn/ui components when available.
Ensure responsive design with a mobile-first approach.
apps/web/components/TooltipExplanation.tsx
`apps/web/components/**/*`: All other components are in components/.
apps/web/components/**/*: All other components are in components/.
apps/web/components/TooltipExplanation.tsx
`apps/web/app/api/**/*`: All API route handlers must use authentication middleware such as withAuth, withEmailAccount, or withError with custom authentication logic. All database q...
apps/web/app/api/**/*: All API route handlers must use authentication middleware such as withAuth, withEmailAccount, or withError with custom authentication logic.
All database queries must include user/account filtering, using emailAccountId or userId in WHERE clauses.
Parameters must be validated before use; do not use direct parameter values in queries without validation.
Request bodies should use Zod schemas for validation.
Only necessary fields should be returned in API responses; use Prisma's select to limit fields.
Do not include sensitive data in error messages; use generic errors and SafeError for user-facing errors.
Cron endpoints must use hasCronSecret or hasPostCronSecret for authentication.
Do not hardcode weak secrets in cron endpoints; secrets should not be plain strings in code except for environment variables like CRON_SECRET.
apps/web/app/api/admin/scheduled-actions/[id]/cancel/route.tsapps/web/app/api/admin/scheduled-actions/route.tsapps/web/app/api/cron/scheduled-actions/route.tsapps/web/app/api/admin/scheduled-actions/[id]/retry/route.ts
`**/api/**/*.ts`: ALL API routes that handle user data MUST use appropriate authentication and authorization middleware such as withAuth or withEmailAccount. ALL database queries i...
**/api/**/*.ts: ALL API routes that handle user data MUST use appropriate authentication and authorization middleware such as 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 being accessed or modified belong to the authenticated user before performing operations.
All parameters (route, query, body) in API routes MUST be validated for type, format, and length before use.
Request bodies in API routes MUST be validated using Zod schemas or equivalent.
Error responses in API routes MUST NOT leak sensitive information; use generic error messages and consistent error formats.
All findUnique/findFirst database calls in API routes MUST include ownership filters (e.g., userId or emailAccountId).
All findMany database calls in API routes MUST be scoped to the authenticated user's data.
API routes MUST NOT return sensitive fields or data from other users.
API routes MUST NOT use direct object references (IDs) without ownership checks to prevent IDOR vulnerabilities.
API routes MUST use explicit whitelisting of allowed fields for updates to prevent mass assignment and privilege escalation.
API routes MUST NOT use user input directly in queries; always validate and sanitize inputs.
API routes MUST use SafeError or equivalent for error handling to prevent information disclosure.
API routes MUST use withError middleware (not withAuth or withEmailAccount) for public endpoints, webhooks, or cron endpoints, and MUST implement custom authentication/validation as appropriate.
apps/web/app/api/admin/scheduled-actions/[id]/cancel/route.tsapps/web/app/api/admin/scheduled-actions/route.tsapps/web/app/api/cron/scheduled-actions/route.tsapps/web/app/api/admin/scheduled-actions/[id]/retry/route.ts
`**/api/**/cron/**/*.ts`: Cron endpoints MUST use withError middleware and validate cron secret using hasCronSecret(request) or hasPostCronSecret(request). Cron endpoints MUST capt...
**/api/**/cron/**/*.ts: Cron endpoints MUST use withError middleware and validate cron secret using hasCronSecret(request) or hasPostCronSecret(request).
Cron endpoints MUST capture unauthorized attempts with captureException and return 401 status for unauthorized requests.
Cron endpoints MUST NOT use predictable or weak secrets for authentication; use strong, random secrets stored in environment variables.
apps/web/app/api/cron/scheduled-actions/route.ts
`**/*.test.ts`: Tests should be colocated next to the tested file, following the pattern: 'dir/format.ts' and 'dir/format.test.ts'.
**/*.test.ts: Tests should be colocated next to the tested file, following the pattern: 'dir/format.ts' and 'dir/format.test.ts'.
apps/web/utils/scheduled-actions/executor.test.ts
`apps/web/utils/actions/**/*`: Server actions are in apps/web/utils/actions folder.
apps/web/utils/actions/**/*: Server actions are in apps/web/utils/actions folder.
apps/web/utils/actions/rule.ts
`apps/web/utils/actions/*`: Server action files must start with 'use server'.
apps/web/utils/actions/*: Server action files must start with 'use server'.
apps/web/utils/actions/rule.ts
`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. Use the ap...
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. Use the appropriate client (actionClientUser, actionClient, or adminActionClient) as needed.
Server Actions are strictly for mutations (operations that change data, e.g., creating, updating, deleting). Do NOT use Server Actions for data fetching (GET operations).
Use the .metadata({ name: "actionName" }) method to provide a meaningful name for monitoring and instrumentation.
If an action modifies data displayed elsewhere, use revalidatePath or revalidateTag from next/cache within the action handler as needed for cache invalidation.
apps/web/utils/actions/rule.ts
🪛 Biome (1.9.4)
apps/web/app/api/admin/scheduled-actions/[id]/retry/route.ts
[error] 1-1: Some named imports are only used as types.
This import is only used as a type.
Importing the types with import type ensures that they are removed by the compilers and avoids loading unnecessary modules.
Safe fix: Add inline type keywords.
(lint/style/useImportType)
🔇 Additional comments (27)
apps/web/app/(app)/[emailAccountId]/assistant/onboarding/CategoriesSetup.tsx (1)
210-212: LGTM! Clean addition of delayed archive option.The new "Label + Archive after a week" option follows the existing SelectItem pattern and provides a clear, user-friendly description of the delayed action functionality.
apps/web/utils/rule/rule.ts (1)
350-350: LGTM! Consistent field mapping for delay support.The addition of
delayInMinutesto the action field mapping follows the existing pattern and properly handles the optional nature of the field.apps/web/utils/ai/rule/create-rule-schema.ts (2)
7-7: LGTM! Proper import for validation constant.Good practice importing the NINETY_DAYS_MINUTES constant for consistent validation limits across the application.
80-87: LGTM! Well-structured delay field validation.The delayInMinutes field is properly implemented with:
- Appropriate type and constraints (1 minute to 90 days)
- Nullish for optional nature
- Clear, descriptive validation messages
- Helpful field description
The validation range strikes a good balance between flexibility and preventing abuse.
apps/web/utils/action-item.ts (2)
165-174: LGTM! Consistent type extension for delay support.The ActionFieldsSelection type properly includes delayInMinutes alongside existing action fields, maintaining consistency with the existing pattern.
179-189: LGTM! Proper initialization of delay field.The delayInMinutes field is correctly initialized in the base object using the same null-coalescing pattern as other optional fields, ensuring consistent handling throughout the sanitization process.
apps/web/app/api/admin/scheduled-actions/[id]/cancel/route.ts (1)
7-58: LGTM! Solid admin API implementation with proper security checks.The route correctly implements:
- Session authentication and admin authorization
- Resource existence validation
- Business logic validation (only PENDING actions can be cancelled)
- Proper status transition and error handling
apps/web/app/api/admin/scheduled-actions/[id]/retry/route.ts (1)
7-58: LGTM! Consistent implementation with proper retry logic.The route correctly:
- Validates that only FAILED actions can be retried
- Transitions status from FAILED back to PENDING for reprocessing
- Follows the same secure patterns as the cancel route
apps/web/app/api/cron/scheduled-actions/route.ts (1)
15-74: LGTM! Excellent cron job implementation with proper safeguards.The implementation correctly follows all coding guidelines:
- Uses
withErrormiddleware andhasPostCronSecretfor authentication- Implements proper concurrency control by marking actions as executing
- Isolates errors so individual failures don't stop batch processing
- Includes comprehensive logging for monitoring and debugging
- Has appropriate timeout (5 minutes) for long-running operations
apps/web/components/TooltipExplanation.tsx (1)
4-52: LGTM! Excellent refactor to controlled tooltip system.The refactor effectively addresses modal tooltip positioning issues by:
- Adding controlled state for manual tooltip visibility management
- Introducing configurable
sidepositioning prop- Implementing onClick toggle for better user control in complex UI contexts
The implementation follows React best practices and maintains type safety.
apps/web/app/api/admin/scheduled-actions/route.ts (1)
6-148: LGTM! Comprehensive admin API with excellent filtering and performance optimization.The implementation excels in:
- Flexible filtering system (email, status, rule name search)
- Performance optimization with concurrent Promise.all queries
- Proper data aggregation for status counts and totals
- Reasonable result limiting (100 items) to prevent performance issues
- Comprehensive error handling and proper admin authorization
apps/web/utils/ai/assistant/chat.ts (1)
18-18: Well-implemented delay feature integration!The addition of
delayInMinutesfield is properly implemented with:
- Appropriate validation constraints (1 minute to 90 days)
- Clear description for API consumers
- Consistent type definitions
- Correct handling in the execution flow
Also applies to: 95-103, 126-126, 766-766
apps/web/utils/scheduled-actions/executor.test.ts (1)
1-274: Excellent test coverage for the executor module!The test suite comprehensively covers:
- Successful execution with proper state transitions
- Error handling with failed status updates
- Edge case of missing email account
All dependencies are properly mocked and assertions validate the expected behavior.
apps/web/utils/actions/rule.ts (1)
48-48: Solid implementation of delayed actions in rule management!The changes properly integrate the delay feature:
- Correctly handles
delayInMinutesin both create and update operations- Implements the new "label_archive_1_week" onboarding option consistently
- Updates user-facing descriptions appropriately
Also applies to: 80-101, 232-232, 251-251, 483-484, 559-566, 598-605, 622-627
apps/web/utils/scheduled-actions/executor.ts (1)
255-267: I didn’t find theScheduledActionmodel via ast-grep. Let’s locate the Prisma schema file and print theScheduledActionblock to check for anerrorfield:#!/bin/bash # Locate a Prisma schema file schema_file=$(fd --extension prisma | head -n1) echo "Using schema file: $schema_file" # Print the ScheduledAction model definition sed -n '/model ScheduledAction {/,/}/p' "$schema_file"apps/web/utils/scheduled-actions/scheduler.ts (4)
1-78: LGTM! Well-structured scheduler service with comprehensive error handling.The
createScheduledActionfunction properly validates action types, stores all necessary ActionItem data, and includes appropriate error handling with logging.
80-136: Function correctly handles scheduling of delayed actions.The non-null assertion on line 113 is safe due to the filtering logic that ensures
delayInMinutesis not null. The time calculation properly adds the delay to the email's internal date.
188-219: Efficient query for retrieving due scheduled actions.The function properly filters for PENDING actions that are due, includes necessary relations, and implements sensible ordering and limiting.
221-245: Good implementation of optimistic locking for concurrent execution prevention.The function correctly uses the status field in the WHERE clause to prevent race conditions when multiple workers might try to execute the same action.
apps/web/prisma/migrations/20250625053006_add_delayed_actions/migration.sql (2)
1-21: Verify the intentional removal ofdigestScheduleIdcolumn.The migration will drop the
digestScheduleIdcolumn from theEmailAccounttable, resulting in data loss. Please confirm this is intentional and that any existing digest schedule data has been migrated or is no longer needed.
22-63: Well-designed ScheduledAction table with appropriate indexes.The table structure includes all necessary fields for delayed action execution, and the indexes are optimized for the expected query patterns (finding due actions and querying by email).
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (6)
94-94: LGTM! Appropriate import for delayed action support.
129-142: Correctly preserves delayInMinutes when loading existing rules.
860-864: Appropriate default value for new actions.Setting
delayInMinutes: nullensures new actions don't have delays by default, which is the expected behavior.
1082-1139: Well-structured UI for delay configuration.The toggle controls are properly organized and only shown for relevant action types. The tooltip provides clear guidance about the delay feature.
1481-1582: Excellent implementation of delay input with unit conversion.The
DelayInputControlscomponent properly handles conversion between minutes, hours, and days, with correct calculations and good UX.
1286-1297: ```shell
#!/bin/bash
echo "=== create-rule-schema.ts around delayInMinutes ==="
rg -n 'delayInMinutes' -A 5 apps/web/utils/ai/rule/create-rule-schema.tsecho "=== rule.validation.ts around delayInMinutes ==="
rg -n 'delayInMinutes' -A 5 apps/web/utils/actions/rule.validation.ts</details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
apps/web/app/(app)/admin/scheduled-actions/ScheduledActionsTable.tsx
Outdated
Show resolved
Hide resolved
apps/web/app/(app)/admin/scheduled-actions/ScheduledActionsTable.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
apps/web/components/ui/tooltip.tsx (1)
16-27: Excellent portal implementation with one consideration.The portal wrapping is a best practice that prevents z-index and overflow issues. However, the z-index value of
9999is extremely high and might cause issues if other elements need to appear above tooltips.Consider using a more reasonable z-index value like
z-[100]orz-[200]unless there's a specific requirement for such a high value.- "z-[9999] overflow-hidden rounded-md border border-slate-700 bg-gray-900 px-3 py-1.5 text-sm text-slate-50 shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:border-slate-100 dark:bg-slate-50 dark:text-slate-950", + "z-[100] overflow-hidden rounded-md border border-slate-700 bg-gray-900 px-3 py-1.5 text-sm text-slate-50 shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:border-slate-100 dark:bg-slate-50 dark:text-slate-950",
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
.cursor/rules/features/delayed-actions.mdc(1 hunks)apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx(10 hunks)apps/web/app/api/admin/scheduled-actions/[id]/cancel/route.ts(1 hunks)apps/web/app/api/admin/scheduled-actions/[id]/retry/route.ts(1 hunks)apps/web/app/api/scheduled-actions/execute/route.ts(1 hunks)apps/web/components/ui/tooltip.tsx(1 hunks)apps/web/prisma/migrations/20250626043046_add_scheduled_actions/migration.sql(1 hunks)apps/web/prisma/schema.prisma(6 hunks)apps/web/utils/ai/choose-rule/run-rules.ts(4 hunks)apps/web/utils/scheduled-actions/executor.ts(1 hunks)apps/web/utils/scheduled-actions/scheduler.test.ts(1 hunks)apps/web/utils/scheduled-actions/scheduler.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
- apps/web/utils/ai/choose-rule/run-rules.ts
- apps/web/utils/scheduled-actions/scheduler.test.ts
- apps/web/app/api/admin/scheduled-actions/[id]/cancel/route.ts
- apps/web/utils/scheduled-actions/executor.ts
- apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
- apps/web/prisma/schema.prisma
- apps/web/app/api/admin/scheduled-actions/[id]/retry/route.ts
🧰 Additional context used
📓 Path-based instructions (11)
`apps/web/**/*.{ts,tsx}`: Use TypeScript with strict null checks enabled. Use pa...
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks enabled.
Use path aliases with @/ for imports from the project root.
Use proper error handling with try/catch blocks.
Use the LoadingContent component for async data loading states.
Prefix client-side environment variables with NEXT_PUBLIC_.
📄 Source: CodeRabbit Inference Engine (apps/web/CLAUDE.md)
List of files the instruction was applied to:
apps/web/components/ui/tooltip.tsxapps/web/app/api/scheduled-actions/execute/route.tsapps/web/utils/scheduled-actions/scheduler.ts
`apps/web/**/*.{ts,tsx,js,jsx}`: Format code with Prettier and follow tailwindcss patterns using prettier-plugin-tailwindcss.
apps/web/**/*.{ts,tsx,js,jsx}: Format code with Prettier and follow tailwindcss patterns using prettier-plugin-tailwindcss.
📄 Source: CodeRabbit Inference Engine (apps/web/CLAUDE.md)
List of files the instruction was applied to:
apps/web/components/ui/tooltip.tsxapps/web/app/api/scheduled-actions/execute/route.tsapps/web/utils/scheduled-actions/scheduler.ts
`apps/web/**/components/**/*.{ts,tsx}`: Use PascalCase naming convention for com...
apps/web/**/components/**/*.{ts,tsx}: Use PascalCase naming convention for component files.
Prefer functional components with hooks.
Use shadcn/ui components when available.
Ensure responsive design with a mobile-first approach.
📄 Source: CodeRabbit Inference Engine (apps/web/CLAUDE.md)
List of files the instruction was applied to:
apps/web/components/ui/tooltip.tsx
`apps/web/**`: Install packages only within the 'apps/web' directory, not at the repository root.
apps/web/**: Install packages only within the 'apps/web' directory, not at the repository root.
📄 Source: CodeRabbit Inference Engine (.cursor/rules/installing-packages.mdc)
List of files the instruction was applied to:
apps/web/components/ui/tooltip.tsxapps/web/app/api/scheduled-actions/execute/route.tsapps/web/utils/scheduled-actions/scheduler.tsapps/web/prisma/migrations/20250626043046_add_scheduled_actions/migration.sql
`apps/web/components/ui/**/*`: Shadcn components are in components/ui.
apps/web/components/ui/**/*: Shadcn components are in components/ui.
📄 Source: CodeRabbit Inference Engine (.cursor/rules/project-structure.mdc)
List of files the instruction was applied to:
apps/web/components/ui/tooltip.tsx
`apps/web/components/**/*`: All other components are in components/.
apps/web/components/**/*: All other components are in components/.
📄 Source: CodeRabbit Inference Engine (.cursor/rules/project-structure.mdc)
List of files the instruction was applied to:
apps/web/components/ui/tooltip.tsx
`**/*.{js,jsx,ts,tsx}`: Use Shadcn UI and Tailwind for components and styling. I...
**/*.{js,jsx,ts,tsx}: Use Shadcn UI and Tailwind for components and styling.
Implement responsive design with Tailwind CSS using a mobile-first approach.
Use thenext/imagepackage for images.
📄 Source: CodeRabbit Inference Engine (.cursor/rules/ui-components.mdc)
List of files the instruction was applied to:
apps/web/components/ui/tooltip.tsxapps/web/app/api/scheduled-actions/execute/route.tsapps/web/utils/scheduled-actions/scheduler.ts
`apps/web/**/app/**`: Follow NextJS app router structure by organizing code within the app directory.
apps/web/**/app/**: Follow NextJS app router structure by organizing code within the app directory.
📄 Source: CodeRabbit Inference Engine (apps/web/CLAUDE.md)
List of files the instruction was applied to:
apps/web/app/api/scheduled-actions/execute/route.ts
`apps/web/app/api/**/*`: All API route handlers must use authentication middlewa...
apps/web/app/api/**/*: All API route handlers must use authentication middleware such as withAuth, withEmailAccount, or withError with custom authentication logic.
All database queries must include user/account filtering, using emailAccountId or userId in WHERE clauses.
Parameters must be validated before use; do not use direct parameter values in queries without validation.
Request bodies should use Zod schemas for validation.
Only necessary fields should be returned in API responses; use Prisma's select to limit fields.
Do not include sensitive data in error messages; use generic errors and SafeError for user-facing errors.
Cron endpoints must use hasCronSecret or hasPostCronSecret for authentication.
Do not hardcode weak secrets in cron endpoints; secrets should not be plain strings in code except for environment variables like CRON_SECRET.
📄 Source: CodeRabbit Inference Engine (.cursor/rules/security-audit.mdc)
List of files the instruction was applied to:
apps/web/app/api/scheduled-actions/execute/route.ts
`**/api/**/*.ts`: ALL API routes that handle user data MUST use appropriate auth...
**/api/**/*.ts: ALL API routes that handle user data MUST use appropriate authentication and authorization middleware such as 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 being accessed or modified belong to the authenticated user before performing operations.
All parameters (route, query, body) in API routes MUST be validated for type, format, and length before use.
Request bodies in API routes MUST be validated using Zod schemas or equivalent.
Error responses in API routes MUST NOT leak sensitive information; use generic error messages and consistent error formats.
All findUnique/findFirst database calls in API routes MUST include ownership filters (e.g., userId or emailAccountId).
All findMany database calls in API routes MUST be scoped to the authenticated user's data.
API routes MUST NOT return sensitive fields or data from other users.
API routes MUST NOT use direct object references (IDs) without ownership checks to prevent IDOR vulnerabilities.
API routes MUST use explicit whitelisting of allowed fields for updates to prevent mass assignment and privilege escalation.
API routes MUST NOT use user input directly in queries; always validate and sanitize inputs.
API routes MUST use SafeError or equivalent for error handling to prevent information disclosure.
API routes MUST use withError middleware (not withAuth or withEmailAccount) for public endpoints, webhooks, or cron endpoints, and MUST implement custom authentication/validation as appropriate.
📄 Source: CodeRabbit Inference Engine (.cursor/rules/security.mdc)
List of files the instruction was applied to:
apps/web/app/api/scheduled-actions/execute/route.ts
`apps/web/utils/**/*`: Create utility functions in utils/ folder for reusable logic.
apps/web/utils/**/*: Create utility functions in utils/ folder for reusable logic.
📄 Source: CodeRabbit Inference Engine (.cursor/rules/project-structure.mdc)
List of files the instruction was applied to:
apps/web/utils/scheduled-actions/scheduler.ts
🧬 Code Graph Analysis (2)
apps/web/components/ui/tooltip.tsx (1)
apps/web/utils/index.ts (1)
cn(4-6)
apps/web/utils/scheduled-actions/scheduler.ts (4)
apps/web/utils/logger.ts (1)
createScopedLogger(17-65)apps/web/utils/ai/types.ts (1)
ActionItem(15-26)apps/web/utils/delayed-actions.ts (1)
canActionBeDelayed(14-16)apps/web/utils/cron.ts (1)
getCronSecretHeader(26-28)
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Static Code Analysis Js
- GitHub Check: Secret Detection
- GitHub Check: Jit Security
🔇 Additional comments (19)
apps/web/components/ui/tooltip.tsx (4)
11-11: LGTM! Good addition for flexibility.Adding
TooltipPortalas a separate export provides flexibility for cases where direct portal control is needed.
13-13: Good TypeScript improvement.The change from
React.ElementReftoReact.ComponentRefis the correct modern TypeScript pattern for component refs.
22-22: Verify the dark theme styling is intentional.The tooltip styling has changed from a light default theme to a dark theme (gray-900 background). This is a significant visual change that will affect the appearance across the application.
Please confirm this dark theme styling is intentional and aligns with the overall design system.
31-37: LGTM! Clean export structure.The export structure is well-organized and includes the new
TooltipPortalcomponent appropriately.apps/web/app/api/scheduled-actions/execute/route.ts (3)
42-48: Database query appears secure.The query properly filters by the scheduled action ID and includes necessary relations. No user input is directly used in the query, which prevents injection attacks.
100-103: Comprehensive error handling implemented.The try-catch block properly handles unexpected errors and provides appropriate logging and HTTP responses.
74-76: Verify atomic operation behavior.The
markQStashActionAsExecutingfunction should use an atomic update with a WHERE condition to prevent race conditions.#!/bin/bash # Check the implementation of markQStashActionAsExecuting for atomic updates ast-grep --pattern 'export async function markQStashActionAsExecuting($$$) { $$$ }'.cursor/rules/features/delayed-actions.mdc (1)
1-151: Comprehensive and well-structured feature documentation.The documentation effectively covers:
- Architecture overview and use cases
- Database schema design
- QStash integration details
- API endpoints and error handling
- Benefits over alternative approaches
The code examples are accurate and the explanations are clear for developers implementing or maintaining this feature.
apps/web/prisma/migrations/20250626043046_add_scheduled_actions/migration.sql (4)
8-8: Well-designed status enum for action lifecycle.The
ScheduledActionStatusenum covers all necessary states: PENDING, EXECUTING, COMPLETED, FAILED, CANCELLED. This provides clear status tracking throughout the action lifecycle.
23-46: Comprehensive table design with proper field coverage.The
ScheduledActiontable includes:
- All necessary action metadata (type, timing, status)
- Email context (messageId, threadId, emailAccountId)
- Action-specific fields (label, subject, content, etc.)
- QStash integration (qstashMessageId)
- Execution tracking (executedAt, executedActionId)
The design supports all documented action types and use cases.
48-58: Efficient indexing strategy implemented.The indexes are well-chosen for the expected query patterns:
status_scheduledFor_idx: For finding pending actions to executeemailAccountId_messageId_idx: For canceling actions by emailqstashMessageId_idx: For QStash message managementThis should provide good performance for the scheduler operations.
60-67: Proper foreign key relationships with appropriate cascade behavior.The foreign key constraints ensure data integrity:
executedRuleId→ExecutedRulewith CASCADE DELETE (appropriate for audit trail)executedActionId→ExecutedActionwith SET NULL (allows independent lifecycle)emailAccountId→EmailAccountwith CASCADE DELETE (proper cleanup)apps/web/utils/scheduled-actions/scheduler.ts (7)
27-30: Proper environment-based QStash client initialization.The client factory function correctly handles the case where QStash token is not available, returning null for graceful degradation.
50-54: Essential validation for action type support.The function properly validates that the action type supports delayed execution before proceeding, preventing invalid scheduled actions.
58-76: Comprehensive database record creation.The scheduled action creation includes all necessary fields from the ActionItem and properly maps the data structure for storage.
266-286: Robust error handling for QStash cancellation.The code properly handles QStash cancellation failures without failing the entire operation, which is appropriate since database state is the source of truth.
334-334: Environment variable fallback strategy.The URL construction properly falls back from
WEBHOOK_URLtoNEXT_PUBLIC_BASE_URL, providing flexibility for different deployment environments.
340-348: Secure QStash message publishing configuration.The QStash publishing configuration includes proper security headers and deduplication settings:
- Uses cron secret headers for authentication
- Disables content-based deduplication in favor of explicit IDs
- Uses absolute timestamps for precise scheduling
407-415: Atomic database operation for status transitions.The
markQStashActionAsExecutingfunction uses a proper WHERE condition with the PENDING status, ensuring atomic updates and preventing race conditions.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
apps/web/app/(app)/[emailAccountId]/assistant/DraftReplies.tsx(1 hunks)apps/web/app/(app)/[emailAccountId]/assistant/RuleDialog.tsx(2 hunks)apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx(18 hunks)apps/web/prisma/migrations/20250626043046_add_scheduled_actions/migration.sql(1 hunks)apps/web/prisma/schema.prisma(6 hunks)apps/web/utils/action-item.ts(2 hunks)apps/web/utils/ai/choose-rule/run-rules.ts(4 hunks)apps/web/utils/scheduled-actions/scheduler.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- apps/web/utils/ai/choose-rule/run-rules.ts
- apps/web/utils/action-item.ts
- apps/web/utils/scheduled-actions/scheduler.ts
- apps/web/prisma/schema.prisma
- apps/web/prisma/migrations/20250626043046_add_scheduled_actions/migration.sql
🧰 Additional context used
📓 Path-based instructions (5)
apps/web/**/*.{ts,tsx}
Instructions used from:
Sources:
📄 CodeRabbit Inference Engine
- apps/web/CLAUDE.md
apps/web/app/**/*
Instructions used from:
Sources:
📄 CodeRabbit Inference Engine
- apps/web/CLAUDE.md
apps/web/**/*.tsx
Instructions used from:
Sources:
📄 CodeRabbit Inference Engine
- apps/web/CLAUDE.md
**/*.tsx
Instructions used from:
Sources:
📄 CodeRabbit Inference Engine
- .cursor/rules/data-fetching.mdc
- .cursor/rules/form-handling.mdc
**/*.{ts,tsx}
Instructions used from:
Sources:
📄 CodeRabbit Inference Engine
- .cursor/rules/form-handling.mdc
🧠 Learnings (2)
apps/web/app/(app)/[emailAccountId]/assistant/RuleDialog.tsx (6)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-07-03T12:02:38.024Z
Learning: For mutating data, use Next.js server actions
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.tsx : Prefer functional components with hooks
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.tsx : Validate form inputs before submission
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.tsx : Use LoadingContent component for async data
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-06-23T12:27:33.499Z
Learning: To handle loading and error states in UI components, wrap content with a `LoadingContent` component that takes `loading` and `error` props, and only renders the main content when data is available.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.tsx : Use React Hook Form with Zod for validation
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (18)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-06-23T12:27:33.499Z
Learning: For form text inputs in React using Shadcn UI, use the `Input` component with `registerProps` from a form library (such as react-hook-form) and pass any validation errors to the `error` prop.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.tsx : Validate form inputs before submission
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.tsx : Prefer functional components with hooks
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.tsx : Use shadcn/ui components when available
Learnt from: aryanprince
PR: elie222/inbox-zero#210
File: apps/web/app/(app)/stats/NewsletterModal.tsx:2-4
Timestamp: 2024-08-23T11:37:26.779Z
Learning: `MoreDropdown` is a React component and `useUnsubscribeButton` is a custom React hook, and they should not be imported using `import type`.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-06-23T12:27:33.499Z
Learning: For multi-line text input, use the `Input` component with `type="text"`, `autosizeTextarea`, and `rows` props to create an autosizing textarea, and handle validation and errors similarly to single-line inputs.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.tsx : Show validation errors inline next to form fields
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-06-23T12:27:23.938Z
Learning: Input validation schemas for server actions should be defined using Zod in dedicated .validation.ts files, which can be reused on the client for form validation.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.{ts,tsx} : Use descriptive error messages
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-06-23T12:27:17.978Z
Learning: Error responses should use generic messages and consistent formats (e.g., SafeError) to avoid leaking sensitive information or internal logic.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-06-23T12:27:05.686Z
Learning: Error messages returned to clients should not reveal internal details or sensitive data; use generic error messages and SafeError for consistent and secure error responses.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-06-23T12:26:16.769Z
Learning: Each custom React hook should have a single responsibility and be kept as simple as possible.
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/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.tsx : Use React Hook Form with Zod for validation
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-06-23T12:26:16.769Z
Learning: Custom React hooks should encapsulate reusable stateful logic, especially for data fetching or complex UI interactions.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-07-03T12:02:38.024Z
Learning: For mutating data, use Next.js server actions
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-06-23T12:26:16.769Z
Learning: For data fetching in custom React hooks, prefer using the useSWR hook. The custom hook should typically wrap useSWR, handle the API endpoint URL, and return the data, loading state, error state, and potentially the mutate function from SWR.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-06-23T12:27:23.938Z
Learning: Server actions must only be used for mutations (create, update, delete operations) and never for data fetching (GET operations); data fetching should be handled via dedicated GET API routes and SWR hooks.
🧬 Code Graph Analysis (1)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)
apps/web/utils/delayed-actions.ts (1)
canActionBeDelayed(15-17)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Static Code Analysis Js
- GitHub Check: Jit Security
🔇 Additional comments (18)
apps/web/app/(app)/[emailAccountId]/assistant/RuleDialog.tsx (2)
31-31: LGTM - Proper extraction of mutate functionThe addition of
mutateto the destructuring is correct and follows the established pattern for SWR data mutations.
55-55: LGTM - Proper prop passing for optimistic updatesPassing the
mutatefunction toRuleFormenables optimistic UI updates for the delayed actions feature, which is essential for a smooth user experience.apps/web/app/(app)/[emailAccountId]/assistant/DraftReplies.tsx (1)
95-95: LGTM - Proper schema alignment for delayed actionsAdding
delayInMinutes: nullto the optimistic update object ensures consistency with the updated action schema that supports delayed execution. Thenullvalue correctly represents no delay by default.apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (15)
94-94: LGTM - Proper import for delay validationThe import of
canActionBeDelayedutility function is correctly added to support the delayed actions feature.
103-103: LGTM - Proper mutate prop handlingThe addition of
mutateto theuseRulehook destructuring and passing it toRuleFormenables optimistic updates for the delayed actions feature.Also applies to: 107-114
123-123: LGTM - Proper prop definition for mutate functionThe
mutateprop is correctly typed as optional and properly defined in the component interface.Also applies to: 129-129
142-142: LGTM - Proper delay field initializationThe
delayInMinutesfield is correctly included in the form default values, maintaining the existing value from the rule data.
209-232: LGTM - Proper optimistic update implementationThe optimistic update logic for
delayInMinutesis well-implemented. It updates the delay state immediately to prevent stale data when the modal is reopened, then properly handles revalidation on both success and error cases.
286-296: LGTM - Proper dependency array updateThe dependency array for the
onSubmitcallback is correctly updated to include the newmutateandruledependencies.
335-335: LGTM - Proper action type orderingMoving the "Digest" action to appear after "Mark spam" improves the logical grouping of action types in the UI.
877-877: LGTM - Proper prop renaming for clarityRenaming the prop from
mutatetomutateLabelsimproves code clarity by distinguishing between different mutation functions.
908-923: LGTM - Improved tooltip positioningAdding
side="left"to the tooltip improves the user experience by ensuring proper positioning relative to the toggle control.
1038-1044: LGTM - Proper delay capability checkThe
useMemohook correctly computes whether an action can be delayed based on its type, with proper dependency tracking.
1147-1150: LGTM - Consistent tooltip positioningAdding
side="left"to the tooltip maintains consistent positioning throughout the UI.
1288-1328: LGTM - Well-implemented delay controlsThe delay controls are properly implemented with:
- Conditional rendering based on action capability
- Proper error handling and validation
- Clear tooltip explanation
- Intuitive toggle functionality
The implementation follows React best practices and integrates well with the existing form structure.
1437-1437: LGTM - Consistent tooltip positioningAdding
side="left"to theThreadsExplanationtooltip maintains UI consistency.
1499-1564: LGTM - Well-implemented delay input controlsThe
DelayInputControlscomponent is properly implemented with:
- Correct time unit conversion logic
- Proper form integration with
setValue- Input validation and sanitization
- Clear UI with appropriate styling
The implementation follows React Hook Form patterns and provides a good user experience.
1566-1596: LGTM - Correct time conversion utilitiesThe helper functions
getDisplayValueAndUnitandconvertToMinutesare correctly implemented:
- Proper handling of null/undefined values
- Correct time unit conversions (minutes, hours, days)
- Appropriate fallback values
- Clear separation of concerns
The logic properly converts between internal storage format (minutes) and user-friendly display format.
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (2)
apps/web/utils/delayed-actions.ts (1)
1-18: Implementation looks good, but consider past review feedback.The centralized approach for defining delay-supported actions is solid and follows good practices. The function is simple and the logic is clear.
However, based on past review comments, consider:
- The naming suggestion to change to "SUPPORTED_DELAYED_ACTIONS" (which appears to already be implemented)
- The concern about permissiveness - though the current implementation is actually restrictive since new actions must be explicitly added to the array
The explicit allowlist approach is secure and maintainable.
apps/web/components/ui/tooltip.tsx (1)
37-59: TooltipContent implementation addresses past review feedback.The use of
TooltipPrimitive.Portalaligns with the past review comment about using the latest shadcn code with portal support. The styling update to primary colors and the explicit arrow element improve the visual consistency.However, consider verifying this implementation against the latest shadcn tooltip component to ensure full compatibility:
What is the current shadcn/ui tooltip component implementation and does it match this code structure?
🧹 Nitpick comments (9)
apps/web/utils/schedule.test.ts (1)
330-334: Spec title is misleadingThe test name says “on same day if time has passed”, yet the expected date is the 22nd (next Monday), not the 15th. Rename the spec (e.g. “should schedule for next week when time has passed”) or adjust the expectation for clarity.
apps/web/__tests__/ai-choose-rule.test.ts (1)
65-81: Consider creating a helper function for action objects.While the
delayInMinutesaddition is correct, the inline action object creation could benefit from a helper function to ensure consistency and reduce duplication across tests.Consider creating a helper function like:
function getAction(overrides: Partial<Action> = {}): Action { return { id: "id", createdAt: new Date(), updatedAt: new Date(), type: ActionType.REPLY, ruleId: "ruleId", label: null, subject: null, content: "{{Write a joke}}", to: null, cc: null, bcc: null, url: null, delayInMinutes: null, ...overrides, }; }This would align with the learning about using helper functions for common test data.
apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx (1)
155-170: Consider adding delayInMinutes to DIGEST action for schema consistency.While the DIGEST action type may not support delays (based on the delayed-actions.ts utility), adding
delayInMinutes: nullwould ensure schema consistency across all action objects.Consider adding the field for consistency:
emailAccountData?.coldEmailDigest ? { id: "cold-email-blocker-digest", type: ActionType.DIGEST, label: null, createdAt: new Date(), updatedAt: new Date(), ruleId: COLD_EMAIL_BLOCKER_RULE_ID, to: null, subject: null, content: null, cc: null, bcc: null, url: null, + delayInMinutes: null, } : null,apps/web/app/(app)/[emailAccountId]/assistant/RuleDialog.tsx (1)
55-55: Consider consistency: mutate prop missing for create mode.While the mutate prop is correctly passed to RuleForm in edit mode, the create mode RuleForm (lines 60-73) doesn't receive this prop. This could lead to inconsistent behavior between create and edit modes.
<RuleForm rule={{ name: "", actions: [], conditions: [], automate: true, runOnThreads: true, conditionalOperator: "AND" as const, ...initialRule, }} alwaysEditMode={true} onSuccess={handleSuccess} isDialog={true} + mutate={mutate} />apps/web/utils/scheduled-actions/scheduler.test.ts (1)
44-47: Create helper functions for test data.Following the project's testing best practices, create helper functions to reduce duplication and improve type safety.
Add a helper function at the top of the test file:
function createMockScheduledAction(overrides?: Partial<any>) { return { id: "action-1", scheduledId: "qstash-msg-1", ...overrides, }; }Then use it in tests:
- prisma.scheduledAction.findMany.mockResolvedValue([ - { id: "action-1", scheduledId: "qstash-msg-1" }, - { id: "action-2", scheduledId: "qstash-msg-2" }, - ] as any); + prisma.scheduledAction.findMany.mockResolvedValue([ + createMockScheduledAction(), + createMockScheduledAction({ id: "action-2", scheduledId: "qstash-msg-2" }), + ]);Also applies to: 96-98
apps/web/utils/scheduled-actions/executor.test.ts (2)
35-55: Extract mock data to a helper function.Following testing best practices, create a helper function for the mock scheduled action data.
function createMockScheduledAction(overrides: Partial<any> = {}) { return { id: "scheduled-action-123", executedRuleId: "rule-123", actionType: ActionType.ARCHIVE, messageId: "msg-123", threadId: "thread-123", emailAccountId: "account-123", scheduledFor: new Date("2024-01-01T12:00:00Z"), status: ScheduledActionStatus.PENDING, label: null, subject: null, content: null, to: null, cc: null, bcc: null, url: null, createdAt: new Date(), updatedAt: new Date(), executedAt: null, executedActionId: null, ...overrides, }; }Then use it in each test:
- const mockScheduledAction = { - id: "scheduled-action-123", - // ... all fields - } as any; + const mockScheduledAction = createMockScheduledAction();
104-149: Extract common mock setup to reduce duplication.The mock setup for parseMessage, getEmailAccountWithAiAndTokens, and other utilities is duplicated across tests.
Create setup helper functions:
function setupCommonMocks() { const { runActionFunction } = vi.hoisted(() => ({ runActionFunction: vi.fn() })); const { parseMessage } = vi.hoisted(() => ({ parseMessage: vi.fn().mockReturnValue({ id: "msg-123", threadId: "thread-123", headers: {}, textPlain: "test content", textHtml: "<p>test content</p>", attachments: [], internalDate: "1234567890", snippet: "", historyId: "", inline: [], }) })); // ... other common mocks return { runActionFunction, parseMessage, /* ... */ }; }This would significantly reduce the test file size and improve maintainability.
Also applies to: 198-245
apps/web/utils/scheduled-actions/executor.ts (1)
200-213: Consider using a more specific type instead of ParsedMessage.The hardcoded empty values for
snippet,historyId, andinlinesuggest thatParsedMessagecontains fields unnecessary for action execution. Consider creating a more specific interface or using TypeScript'sPickutility type to only include the required fields.- // Create a ParsedMessage from EmailForAction - const parsedMessage: ParsedMessage = { - id: emailMessage.id, - threadId: emailMessage.threadId, - headers: emailMessage.headers, - textPlain: emailMessage.textPlain, - textHtml: emailMessage.textHtml, - attachments: emailMessage.attachments, - internalDate: emailMessage.internalDate, - // Required ParsedMessage fields that aren't used in action execution - snippet: "", - historyId: "", - inline: [], - }; + // Use only the fields required for action execution + type EmailForExecution = Pick<ParsedMessage, + 'id' | 'threadId' | 'headers' | 'textPlain' | 'textHtml' | 'attachments' | 'internalDate' + >; + + const emailForExecution: EmailForExecution = { + id: emailMessage.id, + threadId: emailMessage.threadId, + headers: emailMessage.headers, + textPlain: emailMessage.textPlain, + textHtml: emailMessage.textHtml, + attachments: emailMessage.attachments, + internalDate: emailMessage.internalDate, + };Then update
runActionFunctionto accept this more specific type.apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)
1565-1595: Consider using null instead of -1 for invalid valuesThe time conversion functions are well-implemented. However, consider returning
nullinstead of-1for invalid values to be more explicit about the absence of a valid delay:- if (minutes === -1 || minutes <= 0) return { value: "", unit: "hours" }; + if (minutes === null || minutes <= 0) return { value: "", unit: "hours" };- if (Number.isNaN(numValue) || numValue <= 0) return -1; + if (Number.isNaN(numValue) || numValue <= 0) return null;
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (27)
.cursor/rules/features/delayed-actions.mdc(1 hunks)apps/web/__tests__/ai-choose-rule.test.ts(1 hunks)apps/web/app/(app)/[emailAccountId]/assistant/DraftReplies.tsx(1 hunks)apps/web/app/(app)/[emailAccountId]/assistant/RuleDialog.tsx(2 hunks)apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx(18 hunks)apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx(2 hunks)apps/web/app/(app)/[emailAccountId]/assistant/onboarding/CategoriesSetup.tsx(1 hunks)apps/web/app/api/scheduled-actions/execute/route.ts(1 hunks)apps/web/components/TooltipExplanation.tsx(2 hunks)apps/web/components/ui/tooltip.tsx(1 hunks)apps/web/prisma/migrations/20250626043046_add_scheduled_actions/migration.sql(1 hunks)apps/web/prisma/schema.prisma(6 hunks)apps/web/utils/action-item.ts(2 hunks)apps/web/utils/actions/rule.ts(10 hunks)apps/web/utils/actions/rule.validation.ts(3 hunks)apps/web/utils/ai/assistant/chat.ts(4 hunks)apps/web/utils/ai/choose-rule/run-rules.ts(4 hunks)apps/web/utils/ai/rule/create-rule-schema.ts(2 hunks)apps/web/utils/ai/types.ts(1 hunks)apps/web/utils/date.ts(1 hunks)apps/web/utils/delayed-actions.ts(1 hunks)apps/web/utils/rule/rule.ts(1 hunks)apps/web/utils/schedule.test.ts(1 hunks)apps/web/utils/scheduled-actions/executor.test.ts(1 hunks)apps/web/utils/scheduled-actions/executor.ts(1 hunks)apps/web/utils/scheduled-actions/scheduler.test.ts(1 hunks)apps/web/utils/scheduled-actions/scheduler.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (17)
apps/web/utils/schedule.test.ts (1)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-06-23T12:26:27.693Z
Learning: When writing tests for LLM-related functionality in TypeScript (e.g., in 'apps/web/__tests__/*.test.ts'), always create helper functions for common test data to ensure consistency and reduce duplication.
apps/web/app/(app)/[emailAccountId]/assistant/RuleDialog.tsx (5)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-07-03T12:02:38.024Z
Learning: For mutating data, use Next.js server actions
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.tsx : Prefer functional components with hooks
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.tsx : Validate form inputs before submission
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.tsx : Use LoadingContent component for async data
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-06-23T12:27:33.499Z
Learning: To handle loading and error states in UI components, wrap content with a `LoadingContent` component that takes `loading` and `error` props, and only renders the main content when data is available.
apps/web/__tests__/ai-choose-rule.test.ts (1)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-06-23T12:26:27.693Z
Learning: When writing tests for LLM-related functionality in TypeScript (e.g., in 'apps/web/__tests__/*.test.ts'), always create helper functions for common test data to ensure consistency and reduce duplication.
apps/web/app/(app)/[emailAccountId]/assistant/onboarding/CategoriesSetup.tsx (6)
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/cursor-rules.mdc:0-0
Timestamp: 2025-07-03T12:02:24.598Z
Learning: Applies to .cursor/rules/[a-z0-9\-]*.mdc : Use kebab-case for filenames of Cursor rule files
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/cursor-rules.mdc:0-0
Timestamp: 2025-07-03T12:02:24.598Z
Learning: Applies to .cursor/rules/*.mdc : Make Cursor rule file names descriptive of the rule's purpose
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Consult .cursor/rules for environment variable management
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/posthog-feature-flags.mdc:0-0
Timestamp: 2025-06-23T12:26:51.119Z
Learning: When implementing feature flags using PostHog in a TypeScript React codebase, always use kebab-case for flag keys (e.g., 'inbox-cleaner', 'pricing-options-2') to maintain consistency.
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.tsx : Follow consistent naming conventions (PascalCase for components)
apps/web/utils/ai/choose-rule/run-rules.ts (3)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-06-23T12:27:35.927Z
Learning: Import specific lodash functions (e.g., 'import groupBy from "lodash/groupBy";') instead of the entire library to minimize bundle size.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-06-23T12:26:59.468Z
Learning: When importing lodash utilities in TypeScript/JavaScript projects, import specific functions (e.g., import groupBy from 'lodash/groupBy') to minimize bundle size.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-06-23T12:27:35.927Z
Learning: Use lodash utilities for common operations involving arrays, objects, and strings to promote code consistency and reliability.
apps/web/utils/delayed-actions.ts (1)
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/types/**/*.{ts,d.ts} : Centralize types in dedicated type files when shared
apps/web/utils/scheduled-actions/scheduler.test.ts (3)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-06-23T12:26:27.693Z
Learning: When writing tests for LLM-related functionality in TypeScript (e.g., in 'apps/web/__tests__/*.test.ts'), always create helper functions for common test data to ensure consistency and reduce duplication.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-06-23T12:27:30.570Z
Learning: When mocking Prisma in Vitest, import the Prisma mock from '@/utils/__mocks__/prisma', mock '@/utils/prisma', and clear all mocks in a beforeEach hook to ensure test isolation.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-06-23T12:27:30.570Z
Learning: When using Vitest for testing, each test should be independent, use descriptive test names, mock external dependencies, and clean up mocks between tests.
apps/web/utils/ai/assistant/chat.ts (1)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-06-23T12:26:36.694Z
Learning: When implementing LLM-related functions in TypeScript, follow a standard structure: create a scoped logger, define a Zod schema for output validation, perform early input validation and returns, separate system and user prompts, log inputs and outputs, call the LLM with proper configuration, and return the validated result.
apps/web/components/TooltipExplanation.tsx (4)
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.tsx : Prefer functional components with hooks
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.tsx : Use shadcn/ui components when available
Learnt from: aryanprince
PR: elie222/inbox-zero#210
File: apps/web/app/(app)/stats/NewsletterModal.tsx:2-4
Timestamp: 2024-08-23T11:37:26.779Z
Learning: `MoreDropdown` is a React component and `useUnsubscribeButton` is a custom React hook, and they should not be imported using `import type`.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-06-23T12:26:59.468Z
Learning: For components with onClick handlers in Next.js App Router, ensure they are client components by including the 'use client' directive at the top of the file.
apps/web/utils/actions/rule.ts (1)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/posthog-feature-flags.mdc:0-0
Timestamp: 2025-06-23T12:26:51.119Z
Learning: For A/B test feature flags, always define a TypeScript type for the possible variants and ensure the hook returns a default fallback value (such as 'control') if the flag is not set.
apps/web/utils/actions/rule.validation.ts (3)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-06-23T12:27:23.938Z
Learning: Input validation schemas for server actions should be defined using Zod in dedicated .validation.ts files, which can be reused on the client for form validation.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.{ts,tsx} : Define validation schemas using Zod
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.tsx : Use React Hook Form with Zod for validation
apps/web/utils/scheduled-actions/executor.ts (8)
Learnt from: elie222
PR: elie222/inbox-zero#537
File: apps/web/app/api/user/stats/newsletters/route.ts:235-239
Timestamp: 2025-07-08T13:14:03.250Z
Learning: The user prefers proper TypeScript error type checking (using `error instanceof Error`) over type assertions with `as any` for better type safety and code quality.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-06-23T12:26:36.694Z
Learning: Use TypeScript types for all parameters and return values, and define clear interfaces for complex input and output structures to ensure type safety.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.{ts,tsx} : Use descriptive error messages
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.{ts,tsx} : Use proper error handling with try/catch blocks
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-06-23T12:26:27.693Z
Learning: When writing tests for LLM-related functionality in TypeScript (e.g., in 'apps/web/__tests__/*.test.ts'), always create helper functions for common test data to ensure consistency and reduce duplication.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-06-23T12:26:14.189Z
Learning: Always use wrapper functions from the utils folder (e.g., apps/web/utils/gmail/message.ts) to interact with provider APIs, ensuring maintainability and easier future provider support.
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/server-actions.mdc:0-0
Timestamp: 2025-06-23T12:27:23.938Z
Learning: In Next.js projects, server actions should be implemented using the next-safe-action library to ensure type safety, input validation, context management, and centralized error handling.
apps/web/app/api/scheduled-actions/execute/route.ts (19)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-06-23T12:27:05.686Z
Learning: Cron endpoints in API routes must be protected with secret validation middleware such as hasCronSecret or hasPostCronSecret to prevent unauthorized access.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-06-23T12:27:17.978Z
Learning: All input parameters (route, query, body) must be validated for type, format, and length before use; use libraries like Zod for request body validation.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-06-23T12:27:23.938Z
Learning: Input validation schemas for server actions should be defined using Zod in dedicated .validation.ts files, which can be reused on the client for form validation.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.{ts,tsx} : Define validation schemas using Zod
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-06-23T12:27:05.686Z
Learning: Never use request parameters directly in database queries; always validate parameters (e.g., check type and presence) before use, and prefer using Zod schemas for request body validation.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-06-23T12:27:23.938Z
Learning: In Next.js projects, server actions should be implemented using the next-safe-action library to ensure type safety, input validation, context management, and centralized error handling.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-06-23T12:26:36.694Z
Learning: When implementing LLM-related functions in TypeScript, follow a standard structure: create a scoped logger, define a Zod schema for output validation, perform early input validation and returns, separate system and user prompts, log inputs and outputs, call the LLM with proper configuration, and return the validated result.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.tsx : Use React Hook Form with Zod for validation
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/testing.mdc:0-0
Timestamp: 2025-06-23T12:27:30.570Z
Learning: When mocking Prisma in Vitest, import the Prisma mock from '@/utils/__mocks__/prisma', mock '@/utils/prisma', and clear all mocks in a beforeEach hook to ensure test isolation.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/prisma.mdc:0-0
Timestamp: 2025-06-23T12:26:53.882Z
Learning: The project uses PostgreSQL as the database with Prisma.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/get-api-route.mdc:0-0
Timestamp: 2025-06-23T12:26:11.276Z
Learning: In Next.js App Router, GET API route handlers should be wrapped with either `withAuth` or `withEmailAccount` middleware to ensure consistent error handling and authentication.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-06-23T12:27:05.686Z
Learning: In Next.js API routes under apps/web/app/api/, always use authentication middleware such as withAuth or withEmailAccount, or ensure custom authentication logic is present if using withError.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-07-03T12:02:38.024Z
Learning: For mutating data, use Next.js server actions
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-06-23T12:27:23.938Z
Learning: Server actions must only be used for mutations (create, update, delete operations) and never for data fetching (GET operations); data fetching should be handled via dedicated GET API routes and SWR hooks.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-06-23T12:27:17.978Z
Learning: In Next.js/TypeScript API routes, always use authentication middleware (withAuth for user-level, withEmailAccount for account-level) to protect endpoints that handle user data.
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/app/**/* : NextJS app router structure with (app) directory
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-06-23T12:27:17.978Z
Learning: Cron endpoints must use withError middleware and validate requests with strong secrets (hasCronSecret/hasPostCronSecret); never use weak or predictable secrets.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/get-api-route.mdc:0-0
Timestamp: 2025-06-23T12:26:11.276Z
Learning: Responses from GET API routes in Next.js should be returned using `NextResponse.json()` for consistency and proper response formatting.
apps/web/utils/ai/rule/create-rule-schema.ts (3)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-06-23T12:27:23.938Z
Learning: Input validation schemas for server actions should be defined using Zod in dedicated .validation.ts files, which can be reused on the client for form validation.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.{ts,tsx} : Define validation schemas using Zod
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.
apps/web/components/ui/tooltip.tsx (10)
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.tsx : Prefer functional components with hooks
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.tsx : Use shadcn/ui components when available
Learnt from: aryanprince
PR: elie222/inbox-zero#210
File: apps/web/app/(app)/stats/NewsletterModal.tsx:2-4
Timestamp: 2024-08-23T11:37:26.779Z
Learning: `MoreDropdown` is a React component and `useUnsubscribeButton` is a custom React hook, and they should not be imported using `import type`.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-06-23T12:26:59.468Z
Learning: For components with onClick handlers in Next.js App Router, ensure they are client components by including the 'use client' directive at the top of the file.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.tsx : Use React Hook Form with Zod for validation
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.tsx : Use LoadingContent component for async data
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-06-23T12:26:16.769Z
Learning: Custom React hooks should encapsulate reusable stateful logic, especially for data fetching or complex UI interactions.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-07-03T12:02:38.024Z
Learning: Applies to **/*.tsx : Use `result?.serverError` with `toastError` and `toastSuccess` for error handling; success toast is optional
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-06-23T12:26:16.769Z
Learning: Each custom React hook should have a single responsibility and be kept as simple as possible.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-06-23T12:27:33.499Z
Learning: For form text inputs in React using Shadcn UI, use the `Input` component with `registerProps` from a form library (such as react-hook-form) and pass any validation errors to the `error` prop.
apps/web/utils/scheduled-actions/executor.test.ts (3)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-06-23T12:26:27.693Z
Learning: When writing tests for LLM-related functionality in TypeScript (e.g., in 'apps/web/__tests__/*.test.ts'), always create helper functions for common test data to ensure consistency and reduce duplication.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-06-23T12:27:30.570Z
Learning: When mocking Prisma in Vitest, import the Prisma mock from '@/utils/__mocks__/prisma', mock '@/utils/prisma', and clear all mocks in a beforeEach hook to ensure test isolation.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-06-23T12:27:30.570Z
Learning: When using Vitest for testing, each test should be independent, use descriptive test names, mock external dependencies, and clean up mocks between tests.
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (19)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-06-23T12:27:33.499Z
Learning: For form text inputs in React using Shadcn UI, use the `Input` component with `registerProps` from a form library (such as react-hook-form) and pass any validation errors to the `error` prop.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.tsx : Validate form inputs before submission
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.tsx : Prefer functional components with hooks
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.tsx : Use shadcn/ui components when available
Learnt from: aryanprince
PR: elie222/inbox-zero#210
File: apps/web/app/(app)/stats/NewsletterModal.tsx:2-4
Timestamp: 2024-08-23T11:37:26.779Z
Learning: `MoreDropdown` is a React component and `useUnsubscribeButton` is a custom React hook, and they should not be imported using `import type`.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-06-23T12:27:33.499Z
Learning: For multi-line text input, use the `Input` component with `type="text"`, `autosizeTextarea`, and `rows` props to create an autosizing textarea, and handle validation and errors similarly to single-line inputs.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.tsx : Show validation errors inline next to form fields
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-06-23T12:27:23.938Z
Learning: Input validation schemas for server actions should be defined using Zod in dedicated .validation.ts files, which can be reused on the client for form validation.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.{ts,tsx} : Use descriptive error messages
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-06-23T12:27:17.978Z
Learning: Error responses should use generic messages and consistent formats (e.g., SafeError) to avoid leaking sensitive information or internal logic.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/security-audit.mdc:0-0
Timestamp: 2025-06-23T12:27:05.686Z
Learning: Error messages returned to clients should not reveal internal details or sensitive data; use generic error messages and SafeError for consistent and secure error responses.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-06-23T12:26:16.769Z
Learning: Each custom React hook should have a single responsibility and be kept as simple as possible.
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/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.tsx : Use React Hook Form with Zod for validation
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-06-23T12:26:16.769Z
Learning: Custom React hooks should encapsulate reusable stateful logic, especially for data fetching or complex UI interactions.
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.tsx : Follow consistent naming conventions (PascalCase for components)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-07-03T12:02:38.024Z
Learning: For mutating data, use Next.js server actions
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-06-23T12:26:16.769Z
Learning: For data fetching in custom React hooks, prefer using the useSWR hook. The custom hook should typically wrap useSWR, handle the API endpoint URL, and return the data, loading state, error state, and potentially the mutate function from SWR.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-06-23T12:27:23.938Z
Learning: Server actions must only be used for mutations (create, update, delete operations) and never for data fetching (GET operations); data fetching should be handled via dedicated GET API routes and SWR hooks.
🧬 Code Graph Analysis (9)
apps/web/app/(app)/[emailAccountId]/assistant/RuleDialog.tsx (1)
apps/web/hooks/useRule.tsx (1)
useRule(4-8)
apps/web/utils/ai/choose-rule/run-rules.ts (2)
apps/web/utils/scheduled-actions/scheduler.ts (2)
cancelScheduledActions(175-256)scheduleDelayedActions(121-170)apps/web/utils/action-item.ts (1)
sanitizeActionFields(176-252)
apps/web/utils/scheduled-actions/scheduler.test.ts (2)
apps/web/utils/delayed-actions.ts (1)
canActionBeDelayed(15-17)apps/web/utils/scheduled-actions/scheduler.ts (1)
cancelScheduledActions(175-256)
apps/web/utils/ai/assistant/chat.ts (1)
apps/web/utils/actions/rule.validation.ts (1)
delayInMinutesSchema(11-15)
apps/web/components/TooltipExplanation.tsx (2)
apps/web/components/ui/tooltip.tsx (3)
TooltipProvider(61-61)TooltipTrigger(61-61)TooltipContent(61-61)apps/web/utils/index.ts (1)
cn(4-6)
apps/web/utils/actions/rule.ts (1)
apps/web/utils/date.ts (1)
ONE_WEEK_MINUTES(12-12)
apps/web/utils/actions/rule.validation.ts (1)
apps/web/utils/date.ts (1)
NINETY_DAYS_MINUTES(13-13)
apps/web/utils/ai/rule/create-rule-schema.ts (1)
apps/web/utils/actions/rule.validation.ts (1)
delayInMinutesSchema(11-15)
apps/web/components/ui/tooltip.tsx (1)
apps/web/utils/index.ts (1)
cn(4-6)
🔇 Additional comments (60)
apps/web/utils/date.ts (1)
10-14: LGTM! Time constants are mathematically correct and well-named.The new minute-based constants follow the existing pattern and provide the standardized time units needed for the delayed actions feature. The calculations are accurate and the naming is consistent with the existing millisecond constants.
apps/web/components/ui/tooltip.tsx (2)
8-19: TooltipProvider implementation looks good.The functional component approach with default
delayDuration={0}anddata-slotattributes follows modern React patterns. The explicit props handling is clean.
21-29: Tooltip component correctly integrates TooltipProvider.The automatic wrapping with
TooltipProviderensures consistent delay behavior across all tooltip instances.apps/web/__tests__/ai-choose-rule.test.ts (1)
79-79: Correct addition of delayInMinutes field.The
delayInMinutes: nulladdition properly aligns the test data with the updated Action schema for the delayed actions feature.apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx (2)
136-136: Correct addition of delayInMinutes for LABEL action.The
delayInMinutes: nulladdition properly aligns the cold email blocker rule with the updated action schema.
152-152: Correct addition of delayInMinutes for ARCHIVE action.The
delayInMinutes: nulladdition is consistent with the schema changes and appropriate for cold email blocker rules.apps/web/utils/ai/types.ts (1)
25-25: LGTM: Clean type extension for delayed actions support.The addition of the optional
delayInMinutesfield properly supports the new delayed actions feature with appropriate typing (number | null).apps/web/app/(app)/[emailAccountId]/assistant/RuleDialog.tsx (1)
31-31: LGTM: Proper destructuring of mutate function from useRule hook.The addition of
mutateto the destructuring enables optimistic UI updates in the RuleForm component, which improves user experience.apps/web/app/(app)/[emailAccountId]/assistant/DraftReplies.tsx (1)
95-95: LGTM: Proper addition of delayInMinutes field for type consistency.Adding
delayInMinutes: nullto the optimistic update object maintains consistency with the extended ActionItem type. Setting it to null is appropriate for draft replies, which shouldn't have delays.apps/web/utils/rule/rule.ts (1)
350-350: LGTM: Essential mapping for delayInMinutes field persistence.The addition of
delayInMinutes: a.delayInMinutesto the mapActionFields function ensures the delayed action field is properly persisted to the database, completing the data flow for the delayed actions feature.apps/web/app/(app)/[emailAccountId]/assistant/onboarding/CategoriesSetup.tsx (2)
208-208: LGTM: Improved text casing for consistency.The change to lowercase "skip inbox" aligns with the previous feedback about using sentence case for better readability and modern UI patterns.
210-212: LGTM: Well-integrated delayed archive option.The addition of the "Label + archive after a week" option effectively integrates the delayed actions feature into the onboarding flow. The option text is clear and user-friendly.
apps/web/utils/ai/rule/create-rule-schema.ts (2)
7-7: LGTM! Good use of reusable validation schema.The import of
delayInMinutesSchemafrom the dedicated validation module follows the established pattern for schema reuse.
80-80: Proper integration of delay validation.The
delayInMinutesfield is correctly added to the action schema using the imported validation schema, ensuring consistent validation across the system.apps/web/utils/action-item.ts (2)
163-174: Correct type extension for delayed actions.The
ActionFieldsSelectiontype is properly extended to includedelayInMinutes, maintaining consistency with the Prisma schema.
179-189: Proper initialization of delayInMinutes field.The
delayInMinutesfield is correctly initialized in the base object and handled consistently with other nullable fields.apps/web/utils/ai/choose-rule/run-rules.ts (6)
20-24: Good imports for delayed actions functionality.The imports for scheduling utilities and lodash groupBy are appropriate for the delayed actions feature implementation.
106-110: Effective partitioning of immediate vs delayed actions.The use of lodash
groupBywith a clear predicate effectively separates actions based on whether they have a positive delay. This addresses the past review comment about using lodash groupBy for cleaner code.
123-123: Correct handling of immediate actions in executed rule.Only immediate actions are saved as
ExecutedActions, which is appropriate since delayed actions are handled separately through the scheduling system.
128-143: Proper delayed action scheduling and cancellation.The logic correctly:
- Cancels existing scheduled actions to avoid duplicates when rules re-fire
- Schedules new delayed actions only for automated, non-test rules
- Handles the case where delayed actions exist
This addresses the past review comments about cancellation placement and rescheduling behavior.
145-146: Correct execution condition for immediate actions.The condition properly checks for automated rules and immediate actions before executing, ensuring delayed actions are not executed immediately.
219-225: Proper exclusion of delayInMinutes from executed actions.The destructuring to exclude
delayInMinutesfromexecutedActionFieldsis correct since executed actions represent completed actions, not scheduled ones.apps/web/utils/ai/assistant/chat.ts (4)
18-18: Correct import of reusable validation schema.The import of
delayInMinutesSchemafrom the validation module follows the established pattern for schema reuse, addressing the past review comment about duplicated zod types.
95-95: Proper integration of delay validation in action schema.The
delayInMinutesfield is correctly added to the action schema using the imported validation schema.
119-119: Correct type extension for delayed actions result.The
UpdateRuleActionsResulttype is properly extended to include the optionaldelayInMinutesfield.
759-759: Proper handling of delayInMinutes in rule actions update.The
delayInMinutesvalue is correctly extracted from the action input and passed to theupdateRuleActionsfunction, ensuring delays are preserved when updating rules.apps/web/utils/actions/rule.validation.ts (4)
9-9: Correct import of date constant.The import of
NINETY_DAYS_MINUTESfrom date utilities is appropriate for defining the maximum delay constraint.
11-15: Well-defined delay validation schema.The
delayInMinutesSchemais properly constructed with:
- Appropriate minimum (1 minute) and maximum (90 days) constraints
- Nullish type allowing optional delays
- Clear validation messages for constraint violations
This provides a reusable validation schema for delayed actions across the system.
83-83: Proper integration of delay validation in action schema.The
delayInMinutesfield is correctly added to thezodActionschema using the dedicated validation schema, ensuring consistent validation across all action definitions.
174-179: Appropriate extension of category actions.The addition of
"label_archive_delayed"to thecategoryActionenum properly supports the delayed action feature for onboarding and category-based rules.apps/web/components/TooltipExplanation.tsx (1)
31-53: Well-implemented tooltip enhancement!The refactoring to a controlled tooltip system with placement control is a good improvement. The
sideprop addition addresses the positioning needs mentioned in the past review comments.apps/web/utils/scheduled-actions/scheduler.test.ts (1)
22-39: Good test coverage for action delay eligibility.The tests comprehensively cover both supported and unsupported action types, ensuring the
canActionBeDelayedfunction behaves correctly.apps/web/utils/actions/rule.ts (3)
80-101: Proper implementation of delayInMinutes in action creation.The
delayInMinutesfield is correctly integrated into the action creation flow, maintaining consistency with other action fields.
232-232: Consistent handling of delayInMinutes in rule updates.The field is properly integrated into both update and create operations within the rule update flow.
Also applies to: 251-251
557-567: Well-implemented delayed archive feature in onboarding.The delayed archive option is properly integrated with:
- Correct delay value (ONE_WEEK_MINUTES)
- Appropriate prompt instruction updates
- Consistent handling across create and update operations
Also applies to: 598-606, 622-627
apps/web/utils/scheduled-actions/executor.test.ts (1)
1-33: Excellent test setup following project conventions.The mock configuration is comprehensive and properly isolates the executor logic for testing.
apps/web/app/api/scheduled-actions/execute/route.ts (3)
1-18: Proper security setup with QStash verification and validation.The route correctly implements:
- QStash signature verification for security
- Zod schema validation for input
- Appropriate max duration for long-running tasks
28-76: Excellent validation and status checking.The implementation properly:
- Validates input with detailed error logging
- Handles missing scheduled actions
- Gracefully handles cancelled and non-pending actions
- Returns appropriate HTTP status codes
77-103: Well-implemented execution flow with concurrency control.The implementation correctly:
- Prevents duplicate processing with atomic status updates
- Handles both success and failure cases appropriately
- Provides detailed logging for debugging
- Returns proper HTTP status codes
apps/web/utils/scheduled-actions/executor.ts (3)
23-105: Well-structured execution orchestration!The function properly handles the scheduled action execution flow with comprehensive error handling, structured logging, and clear status management.
107-155: Robust email validation with proper error handling!The function correctly handles Gmail API errors and distinguishes between "not found" and other errors. The conversion to EmailForAction format is complete and type-safe.
240-306: Clean helper functions with proper state management!The helper functions correctly handle database updates and status transitions with appropriate logging.
.cursor/rules/features/delayed-actions.mdc (1)
1-219: Comprehensive feature documentation!The documentation thoroughly covers the delayed actions feature with clear explanations of architecture, implementation details, and usage examples. The QStash integration benefits and migration safety considerations are particularly well-documented.
apps/web/utils/scheduled-actions/scheduler.ts (4)
118-170: Clean implementation of batch scheduling!The function efficiently filters and schedules multiple delayed actions. The non-null assertion on line 148 is safe due to the filter conditions.
172-256: Robust cancellation logic with proper error handling!The function correctly cancels QStash messages first and handles partial failures gracefully without failing the entire operation.
258-336: Proper handling of QStash unavailability!The function correctly fails fast when QStash is unavailable and updates the database status to reflect the failure, preventing orphaned scheduled actions.
357-382: Excellent race condition prevention!The atomic update with status condition effectively prevents duplicate execution of scheduled actions.
apps/web/prisma/schema.prisma (3)
330-346: Correct addition of delay field to Action model!The optional
delayInMinutesfield is properly typed and maintains backward compatibility.
429-461: Well-designed ScheduledAction model!The model properly addresses previous concerns:
- No restrictive unique constraints that would prevent multiple actions of the same type
- Clear field naming with
scheduledIdinstead of ambiguous names- Appropriate indexes for query performance
- Proper cascade behavior on relations
892-904: Comprehensive status tracking enums!Both enums provide necessary states for tracking the lifecycle of scheduled actions and their scheduling status.
apps/web/prisma/migrations/20250626043046_add_scheduled_actions/migration.sql (1)
1-55: Safe and comprehensive migration!The migration properly uses
IF NOT EXISTSclauses for idempotency and creates all necessary database objects with appropriate constraints and indexes.apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (9)
173-173: Use consistent naming for mutate functionsThe rename from
mutatetomutateLabelsimproves clarity by making the purpose explicit. Good change!
209-242: Well-implemented optimistic updatesThe optimistic update pattern for
delayInMinutesis properly implemented with appropriate error handling and revalidation. This prevents UI inconsistencies when the modal is reopened immediately after saving.
335-335: Logical grouping of action typesMoving the Digest action after Mark spam creates a more logical grouping of organizational actions, improving the user experience.
911-911: Consistent tooltip positioningThe tooltip positioning changes to
side="left"improve UI consistency and prevent tooltips from being cut off at the screen edge.Also applies to: 1148-1148, 1436-1436
1184-1194: Appropriate input type for AI-generated labelsUsing a text input for AI-generated labels is the correct approach, as it allows users to enter template syntax like
{{prompt}}which wouldn't work with a combobox.
1241-1247: Improved form registrationAdding
nameandregisterPropsto the Input component ensures proper integration with react-hook-form, improving form validation and submission handling.
1287-1327: Well-implemented delay action controlsThe delay action implementation is comprehensive with:
- Proper conditional rendering based on action type support
- Clear user guidance via tooltip
- Sensible default of 60 minutes
- Proper error handling and validation
1498-1563: Clean delay input implementationThe
DelayInputControlscomponent provides an excellent user experience with:
- Intuitive unit selection (minutes/hours/days)
- Proper input sanitization
- Clean separation between display and storage formats
1038-1042: Efficient memoization of action delay checkGood use of
useMemoto optimize thecanActionBeDelayedcheck, with the correct dependency onaction.type.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
apps/web/utils/scheduled-actions/scheduler.ts (2)
148-148: Non-null assertion is safe but could be more explicitThe non-null assertion on
delayInMinutesis safe because the filter on lines 134-138 ensures it's not null and > 0. However, consider removing the assertion and using the value directly since TypeScript should infer it's not null after the filter.- const scheduledFor = addMinutes(new Date(), actionItem.delayInMinutes!); + const scheduledFor = addMinutes(new Date(), actionItem.delayInMinutes);
53-116: Consider transaction safety for consistencyWhile the current error handling with status updates provides reasonable consistency, consider wrapping the database operations in a transaction for stronger consistency guarantees, especially in
createScheduledActionwhere a database record is created before QStash scheduling.// Example with transaction const scheduledAction = await prisma.$transaction(async (tx) => { const action = await tx.scheduledAction.create({ data: { // ... existing data }, }); const scheduledId = await scheduleMessage({ payload: { scheduledActionId: action.id }, delayInMinutes: actionItem.delayInMinutes, deduplicationId: `scheduled-action-${action.id}`, }); if (scheduledId) { await tx.scheduledAction.update({ where: { id: action.id }, data: { scheduledId, schedulingStatus: "SCHEDULED" as const, }, }); } return action; });
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx(3 hunks)apps/web/components/TooltipExplanation.tsx(2 hunks)apps/web/utils/schedule.test.ts(1 hunks)apps/web/utils/scheduled-actions/scheduler.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx
- apps/web/utils/schedule.test.ts
- apps/web/components/TooltipExplanation.tsx
🧰 Additional context used
📓 Path-based instructions (2)
apps/web/**/*.{ts,tsx}
Instructions used from:
Sources:
📄 CodeRabbit Inference Engine
- apps/web/CLAUDE.md
**/*.{ts,tsx}
Instructions used from:
Sources:
📄 CodeRabbit Inference Engine
- .cursor/rules/form-handling.mdc
🧬 Code Graph Analysis (1)
apps/web/utils/scheduled-actions/scheduler.ts (4)
apps/web/utils/logger.ts (1)
createScopedLogger(17-65)apps/web/utils/ai/types.ts (1)
ActionItem(15-26)apps/web/utils/delayed-actions.ts (1)
canActionBeDelayed(15-17)apps/web/utils/cron.ts (1)
getCronSecretHeader(26-28)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Static Code Analysis Js
- GitHub Check: Jit Security
🔇 Additional comments (6)
apps/web/utils/scheduled-actions/scheduler.ts (6)
1-21: LGTM - Clean imports and setupThe imports are well-organized and the QStash client setup properly handles the optional token scenario with null checking.
46-51: Good fix - Validation moved before database creationThe validation for
delayInMinutesis now properly placed before creating the database record, which prevents orphaned records if validation fails. This addresses the previous review comment.
175-256: Well-implemented cancellation logicThe function properly handles both QStash cancellation and database updates with appropriate error handling. The resilient approach of continuing with database updates even if QStash cancellation fails is good design.
301-318: Good fix - Prevents orphaned actions when QStash is unavailableThe function now properly handles the case when QStash client is not available by updating the database record with "FAILED" status and throwing an error. This prevents orphaned actions and addresses the previous review comment.
341-355: LGTM - Clean QStash message cancellationThe function properly uses the QStash HTTP API for message cancellation with appropriate error handling and logging.
361-382: Excellent concurrency control implementationThe function uses the database status as a condition in the where clause to prevent duplicate execution, which is a robust approach for handling concurrent access. The graceful failure pattern is appropriate for this use case.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
apps/web/utils/scheduled-actions/scheduler.ts (3)
141-141: Remove non-null assertion - it's safe after filter validation.The non-null assertion on
actionItem.delayInMinutes!is unnecessary since the filter on lines 127-132 already ensuresdelayInMinutesis not null and is greater than 0.- const scheduledFor = addMinutes(new Date(), actionItem.delayInMinutes!); + const scheduledFor = addMinutes(new Date(), actionItem.delayInMinutes);
286-304: Inconsistent error handling when QStash client is unavailable.The code now correctly throws an error when QStash client is unavailable and updates the scheduling status to "FAILED", which is an improvement over the previous implementation that would create orphaned records. However, this creates inconsistency with the error handling in the catch block.
Consider whether the scheduling status update should be done in the catch block as well, or if the error should be thrown immediately without the status update here.
305-320: Ensure consistent scheduling status updates on all failures.The catch block updates the scheduling status to "FAILED" when scheduling fails, which is good. However, there's a potential issue if the database update itself fails - the error would be swallowed by the subsequent
throw error.Consider wrapping the database update in a try-catch to handle potential database failures gracefully:
} catch (error) { logger.error("Failed to schedule with QStash", { error, scheduledActionId: payload.scheduledActionId, deduplicationId, }); - await prisma.scheduledAction.update({ - where: { id: payload.scheduledActionId }, - data: { - schedulingStatus: "FAILED" as const, - }, - }); + try { + await prisma.scheduledAction.update({ + where: { id: payload.scheduledActionId }, + data: { + schedulingStatus: "FAILED" as const, + }, + }); + } catch (dbError) { + logger.error("Failed to update scheduling status", { + scheduledActionId: payload.scheduledActionId, + error: dbError, + }); + } throw error; }
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/utils/scheduled-actions/scheduler.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
apps/web/**/*.{ts,tsx}
Instructions used from:
Sources:
📄 CodeRabbit Inference Engine
- apps/web/CLAUDE.md
**/*.{ts,tsx}
Instructions used from:
Sources:
📄 CodeRabbit Inference Engine
- .cursor/rules/form-handling.mdc
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Static Code Analysis Js
- GitHub Check: Jit Security
🔇 Additional comments (6)
apps/web/utils/scheduled-actions/scheduler.ts (6)
1-11: LGTM! Clean imports and logger setup.The imports are well-organized with proper TypeScript types and the scoped logger configuration follows best practices.
13-20: LGTM! Well-defined interface and QStash client factory.The
ScheduledActionPayloadinterface is properly typed and thegetQstashClientfunction correctly handles the optional token configuration.
43-47: LGTM! Validation has been moved to the correct location.The validation for
delayInMinutesis now properly placed before the database record creation, addressing the previous review comment about preventing orphaned records.
339-360: LGTM! Proper atomic update with appropriate error handling.The
markQStashActionAsExecutingfunction correctly uses atomic updates with a WHERE clause condition to prevent race conditions and handles failures gracefully by returning null.
323-337: LGTM! Clean QStash message cancellation implementation.The
cancelMessagefunction properly handles the QStash HTTP API for message cancellation with appropriate error handling and logging.
165-245: LGTM! Comprehensive cancellation logic with proper error handling.The
cancelScheduledActionsfunction properly handles both QStash message cancellation and database status updates, with appropriate error handling that doesn't fail the entire operation if QStash cancellation fails.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (1)
128-128: Improve type safety by avoidinganytypeThe
mutatefunction parameter usesanytypes which goes against the coding guidelines. Consider using proper SWR mutate function typing.- mutate?: (data?: any, options?: any) => void; + mutate?: () => void;Or use the proper SWR mutate function type if you need the full signature.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx(19 hunks)apps/web/utils/ai/assistant/chat.ts(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/web/utils/ai/assistant/chat.ts
🧰 Additional context used
📓 Path-based instructions (14)
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/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/**
📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)
NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/**/*.tsx
📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)
apps/web/**/*.tsx: Follow tailwindcss patterns with prettier-plugin-tailwindcss
Prefer functional components with hooks
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Follow consistent naming conventions (PascalCase for components)
Use LoadingContent component for async data
Useresult?.serverErrorwithtoastErrorandtoastSuccess
UseLoadingContentcomponent to handle loading and error states consistently
Passloading,error, and children props toLoadingContent
Files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
!{.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/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.tsx
📄 CodeRabbit Inference Engine (.cursor/rules/form-handling.mdc)
**/*.tsx: Use React Hook Form with Zod for validation
Validate form inputs before submission
Show validation errors inline next to form fields
Files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/logging.mdc)
**/*.{ts,tsx}: UsecreateScopedLoggerfor logging in backend TypeScript files
Typically add the logger initialization at the top of the file when usingcreateScopedLogger
Only use.with()on a logger instance within a specific function, not for a global loggerImport 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/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/(app)/*/**
📄 CodeRabbit Inference Engine (.cursor/rules/page-structure.mdc)
Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
Files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/(app)/*/**/*.tsx
📄 CodeRabbit Inference Engine (.cursor/rules/page-structure.mdc)
If you need to use onClick in a component, that component is a client component and file must start with 'use client'
Files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/(app)/*/**/**/*.tsx
📄 CodeRabbit Inference Engine (.cursor/rules/page-structure.mdc)
If we're in a deeply nested component we will use swr to fetch via API
Files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
apps/web/app/**/*.tsx
📄 CodeRabbit Inference Engine (.cursor/rules/project-structure.mdc)
Components with
onClickmust be client components withuse clientdirective
Files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useelements 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/(app)/[emailAccountId]/assistant/RuleForm.tsx
!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/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{jsx,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)
**/*.{jsx,tsx}: Don't destructure props inside JSX components in Solid projects.
Don't use both children and dangerouslySetInnerHTML props on the same element.
Don't use Array index in keys.
Don't assign to React component props.
Don't define React components inside other components.
Don't use event handlers on non-interactive elements.
Don't assign JSX properties multiple times.
Don't add extra closing tags for components without children.
Use <>...</> instead of ....
Don't insert comments as text nodes.
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 use unnecessary fragments.
Don't pass children as props.
Use semantic elements instead of role attributes in JSX.
Files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx
**/*.{html,jsx,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)
**/*.{html,jsx,tsx}: Don't use or elements.
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.
Only use the scope prop on 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.
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 ARIA state and property values.
Use valid values for the autocomplete attribute on input eleme...Files:
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx🧠 Learnings (1)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (62)
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 : Use XML-like tags to structure data in LLM prompts.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 (withnext-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/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 : Format data consistently across similar LLM-related functions.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/hooks/**/*.{ts,tsx} : Callmutate()after successful mutations to refresh dataLearnt 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 : System prompt should define the LLM's role and task specifications.Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-20T09:03:06.287Z
Learning: Applies to **/*.{jsx,tsx} : Use semantic elements instead of role attributes in JSX.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/ui-components.mdc:0-0
Timestamp: 2025-07-19T17:50:22.043Z
Learning: Applies to components/**/*.tsx : Use theInputcomponent for text inputs, passingregisterPropsanderrorprops for form handlingLearnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-07-19T17:50:22.043Z
Learning: Applies to components/**/*.tsx : Use theInputcomponent withautosizeTextareaand appropriate props for text areasLearnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-18T15:04:57.098Z
Learning: Applies to **/*.tsx : Validate form inputs before submissionLearnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-20T09:03:06.287Z
Learning: Applies to **/*.{html,jsx,tsx} : Make sure label elements have text content and are associated with an input.Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-20T09:03:06.287Z
Learning: Applies to **/*.{jsx,tsx} : Don't use event handlers on non-interactive elements.Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-20T09:03:06.287Z
Learning: Applies to **/*.{jsx,tsx} : Don't define React components inside other components.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/**/*.tsx : Prefer functional components with hooksLearnt 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: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-18T15:04:30.448Z
Learning: Applies to apps/web/**/*.tsx : Use shadcn/ui components when availableLearnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-20T09:03:06.287Z
Learning: Applies to **/*.{jsx,tsx} : Don't assign to React component props.Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-18T15:04:57.098Z
Learning: Applies to **/*.ts : The same validation should be done in the server action tooLearnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-18T15:04:57.098Z
Learning: Applies to **/*.tsx : Show validation errors inline next to form fieldsLearnt 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 : If an action modifies data displayed elsewhere, userevalidatePathorrevalidateTagfromnext/cachewithin the action handler as needed.Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-18T15:04:57.098Z
Learning: Use descriptive error messagesLearnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-20T09:03:06.287Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make sure to pass a message value when creating a built-in error.Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/index.mdc:0-0
Timestamp: 2025-07-18T15:05:56.618Z
Learning: Form handling using React Hook Form and ZodLearnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/index.mdc:0-0
Timestamp: 2025-07-18T15:05:56.618Z
Learning: Util functionsLearnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-07-20T09:00:16.480Z
Learning: Applies to apps/web/utils/**/*.ts : Import specific lodash functions to minimize bundle sizeLearnt 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/ultracite.mdc:0-0
Timestamp: 2025-07-20T09:03:06.287Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Remove redundant terms from logical expressions.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: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-18T15:04:30.448Z
Learning: Applies to apps/web/components/**/*.tsx : Use React Hook Form with Zod validation for form handlingLearnt 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/ultracite.mdc:0-0
Timestamp: 2025-07-20T09:03:06.287Z
Learning: Applies to **/*.{html,jsx,tsx} : Use valid values for the autocomplete attribute on input elements.Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-18T15:04:57.098Z
Learning: Applies to **/*.tsx : Use React Hook Form with Zod for validationLearnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-20T09:03:06.287Z
Learning: Applies to **/*.{ts,tsx} : Don't use any or unknown as type constraints.Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-20T09:03:06.287Z
Learning: Applies to **/*.{ts,tsx} : Don't use implicit any type on variable declarations.Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-20T09:03:06.287Z
Learning: Applies to **/*.{ts,tsx} : Don't use user-defined types.Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-20T09:03:06.287Z
Learning: Applies to **/*.{ts,tsx} : Don't use empty type parameters in type aliases and interfaces.Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-07-18T15:05:41.696Z
Learning: Applies to apps/web/hooks/use*.{js,jsx,ts,tsx} : Custom hooks should encapsulate reusable stateful logic, especially for data fetching or complex UI interactions.Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-07-18T15:05:41.696Z
Learning: Applies to apps/web/hooks/use*.{js,jsx,ts,tsx} : Keep custom hooks focused on a single responsibility.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 : User prompt should contain the actual data and context.Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-20T09:03:06.287Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use unnecessary labels.Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-20T09:03:06.287Z
Learning: Applies to **/*.{html,jsx,tsx} : Don't use explicit role property that's the same as the implicit/default role.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/components/**/*Form.tsx : Use React Hook Form with Zod resolver for form handling and validation.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 creating custom React hooksLearnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/posthog-feature-flags.mdc:0-0
Timestamp: 2025-07-18T15:07:12.388Z
Learning: Applies to apps/web/hooks/useFeatureFlags.ts : Always define types for variant flagsLearnt 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/hooks/**/*.ts : Callmutate()after successful mutations to refresh SWR data on the client.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/components/**/*.tsx : Use theLoadingContentcomponent to handle loading and error states consistently in data-fetching components.Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-07-18T15:04:44.809Z
Learning: Applies to app/**/*.{ts,tsx} : For mutating data, use Next.js server actionsLearnt 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/**/*.tsx : UseLoadingContentcomponent to handle loading and error states consistentlyLearnt 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/hooks.mdc:0-0
Timestamp: 2025-07-18T15:05:41.696Z
Learning: Applies to apps/web/hooks/use*.{js,jsx,ts,tsx} : Create dedicated hooks for specific data types (e.g.,useAccounts,useLabels).Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-07-18T15:05:41.696Z
Learning: Applies to apps/web/hooks/use*.{js,jsx,ts,tsx} : Name custom hooks with theuseprefix (e.g.,useAccounts.ts).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 : UserevalidatePathin server actions to invalidate cache after mutations.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 : Server Actions are strictly for mutations (operations that change data, e.g., creating, updating, deleting). Do NOT use Server Actions for data fetching (GET operations). For data fetching, use dedicated GET API Routes combined with SWR Hooks.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 : Do NOT use POST API routes for mutations - use server actions insteadLearnt 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/**/*.tsx : Useresult?.serverErrorwithtoastErrorandtoastSuccessLearnt 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 | undefinedinstead 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.Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/posthog-feature-flags.mdc:0-0
Timestamp: 2025-07-18T15:07:12.388Z
Learning: Applies to apps/web/hooks/useFeatureFlags.ts : Use kebab-case for feature flag keys (e.g., 'inbox-cleaner', 'pricing-options-2')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 (likeuserId,emailAccountId, etc.) provided by the safe action client via thectxobject 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 : UseactionClientwhen both authenticated user context and a specificemailAccountIdare needed. TheemailAccountIdmust be bound when calling the action from the client.🧬 Code Graph Analysis (1)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (8)
apps/web/hooks/useRule.tsx (1)
useRule(4-8)apps/web/hooks/useLabels.ts (1)
useLabels(37-52)apps/web/components/TooltipExplanation.tsx (1)
TooltipExplanation(33-60)apps/web/hooks/useFeatureFlags.ts (1)
useDelayedActionsEnabled(45-47)apps/web/utils/delayed-actions.ts (1)
canActionBeDelayed(15-17)apps/web/components/Input.tsx (2)
Input(34-112)Label(116-132)apps/web/components/Toggle.tsx (1)
Toggle(19-70)apps/web/components/ui/select.tsx (4)
SelectTrigger(116-116)SelectValue(115-115)SelectContent(117-117)SelectItem(119-119)⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Static Code Analysis Js
- GitHub Check: Jit Security
🔇 Additional comments (7)
apps/web/app/(app)/[emailAccountId]/assistant/RuleForm.tsx (7)
92-93: LGTM: Clean imports for delayed actions featureThe new imports properly support the delayed actions functionality and follow the established path alias patterns.
102-115: LGTM: Proper SWR mutate function integrationGood addition of the
mutatefunction fromuseRulehook to enable optimistic updates in the RuleForm component.
208-241: LGTM: Well-implemented optimistic updatesThe optimistic update logic is properly implemented following SWR patterns:
- Updates UI immediately with optimistic data
- Reverts on error by calling mutate()
- Revalidates after success to ensure data consistency
The implementation correctly handles the delayInMinutes field updates.
991-1291: LGTM: Comprehensive delayed actions UI implementationExcellent implementation of the delayed actions UI in ActionCard:
- Proper feature flag integration with
useDelayedActionsEnabled- Performance-optimized
actionCanBeDelayedcomputation usinguseMemo- Clean toggle interface for enabling/disabling delays
- Well-integrated
DelayInputControlscomponent- Proper error handling and validation feedback
The UI layout and conditional rendering logic are well-structured.
1111-1114: LGTM: Improved tooltip positioningGood improvement to tooltip positioning using the
side="left"prop for better user experience.
1462-1527: LGTM: Well-designed DelayInputControls componentExcellent implementation of the delay input controls:
- Clean functional component structure
- Proper TypeScript typing
- Good use of shadcn/ui components (Input, Select)
- Proper React Hook Form integration with setValue
- Clear separation of concerns with dedicated handlers
The component follows the coding guidelines for functional components and shadcn/ui usage.
1529-1559: LGTM: Solid utility functions for time conversionWell-implemented helper functions:
getDisplayValueAndUnit: Properly converts minutes to user-friendly display formatconvertToMinutes: Correctly handles conversion from display format back to minutes- Good edge case handling for null/undefined values
- Clear logic for different time units (minutes, hours, days)
- Functions are pure and have single responsibilities
The conversion logic is mathematically correct and handles the common time unit scenarios appropriately.
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests
Chores