Skip to content

Conversation

@mfts
Copy link
Owner

@mfts mfts commented Aug 2, 2025

Summary by CodeRabbit

  • New Features

    • Introduced email notifications for team members (ADMIN or MANAGER) when a visitor sends a message in a conversation.
    • Added a new email template for team notifications with conversation and dataroom details.
    • Implemented delayed notification scheduling to prevent duplicate notifications.
    • Added a new API endpoint to send conversation notifications to team members.
    • Enhanced notification tasks with retry logic and improved scheduling.
  • Bug Fixes

    • Improved notification logic to ensure only one pending notification per conversation within a 5-minute window.
  • Style

    • Updated email footer to use plain text for the company name.
  • Chores

    • Removed unused imports for cleaner code.

@vercel
Copy link

vercel bot commented Aug 2, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
papermark ✅ Ready (Inspect) Visit Preview 💬 Add feedback Aug 2, 2025 4:28pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 2, 2025

Walkthrough

The changes introduce a new notification system for conversations, targeting both individual viewers and team members (admins/managers). New tasks and API endpoints handle delayed, deduplicated notification scheduling and sending. Email templates and logic for team notifications are added, and imports/exports are updated for integration. Minor refactoring and cleanup are also performed.

Changes

Cohort / File(s) Change Summary
Conversation Notification Scheduling & Deduplication
ee/features/conversations/api/conversations-route.ts
Implements delayed notification scheduling and deduplication for conversation events. Cancels existing queued notification runs for a conversation before scheduling a new one with a 5-minute delay. Updates viewerId to required in message creation. Integrates with trigger system and uses @trigger.dev/sdk/v3 and @vercel/functions.
Team Member Notification API
ee/features/conversations/api/send-conversation-team-member-notification.ts, pages/api/jobs/send-conversation-team-member-notification.ts
Adds a new internal API endpoint to send notifications to team admins/managers. Handles authentication, filters eligible recipients, fetches conversation/dataroom details, and sends a single email to all recipients. The route is re-exported for API routing.
Team Notification Email Template & Sender
ee/features/conversations/emails/components/conversation-team-notification.tsx, ee/features/conversations/emails/lib/send-conversation-team-notification.ts
Adds a new React email template component for team notifications and a utility function to send these emails, supporting multiple recipients and error handling.
Notification Task Logic
ee/features/conversations/lib/trigger/conversation-message-notification.ts, lib/trigger/conversation-message-notification.ts
Introduces a new task for notifying team admins/managers about new messages, with retry logic and internal API calls. Updates imports/exports to include both viewer and team member notification tasks.
Email Footer Update
ee/features/conversations/emails/components/conversation-notification.tsx
Simplifies the copyright footer in the existing conversation notification email template.
Component Import Cleanup
ee/features/conversations/components/conversation-view-sidebar.tsx
Removes unused imports for cleaner code. No functional changes.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant API (conversations-route)
    participant Trigger System
    participant Notification Task
    participant Team Notification API
    participant Email Sender

    User->>API (conversations-route): Create conversation or add message
    API (conversations-route)->>Trigger System: Cancel existing notification runs (by conversationId)
    API (conversations-route)->>Trigger System: Schedule new notification task (5 min delay)
    Trigger System->>Notification Task: Invoke after delay
    Notification Task->>Team Notification API: POST send-conversation-team-member-notification
    Team Notification API->>Email Sender: Send notification email to team admins/managers
    Email Sender-->>Team Notification API: Email sent
    Team Notification API-->>Notification Task: Success/failure response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1caf722 and 24cee1d.

📒 Files selected for processing (2)
  • ee/features/conversations/api/send-conversation-team-member-notification.ts (1 hunks)
  • ee/features/conversations/emails/components/conversation-team-notification.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • ee/features/conversations/emails/components/conversation-team-notification.tsx
  • ee/features/conversations/api/send-conversation-team-member-notification.ts
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch cursor/notify-team-members-of-new-conversation-messages-311d

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need 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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (4)
ee/features/conversations/emails/lib/send-conversation-team-notification.ts (2)

24-36: Verify CC field handling and improve logging.

The CC field receives a comma-separated string from teamMemberEmails.slice(1).join(","). Based on the sendEmail function signature in lib/resend.ts (lines 11-94), the cc parameter accepts string | string[], so this approach is valid.

However, consider using the log utility from @/lib/utils instead of console.log for consistency with the rest of the codebase.

    await sendEmail({
      to: teamMemberEmails[0], // Send to first team member
-     cc: teamMemberEmails.slice(1).join(","), // Send to all other team members
+     cc: teamMemberEmails.slice(1), // Send to all other team members as array
      subject: `New visitor message in ${dataroomName}`,
      react: ConversationTeamNotification({
        senderEmail,
        conversationTitle,
        dataroomName,
        url,
      }),
      test: process.env.NODE_ENV === "development",
      system: true,
    });

20-21: Replace console logging with proper logging utility.

Use the log utility from @/lib/utils for consistent logging across the codebase, as seen in other parts of the application.

+ import { log } from "@/lib/utils";

    if (!teamMemberEmails || teamMemberEmails.length === 0) {
-     console.log("No team member emails provided");
+     await log({
+       message: "No team member emails provided for conversation notification",
+       type: "info",
+     });
      return;
    }
  } catch (e) {
-   console.error("Failed to send team member notification:", e);
+   await log({
+     message: `Failed to send team member notification: ${e}`,
+     type: "error",
+     mention: true,
+   });
  }

Also applies to: 38-39

ee/features/conversations/lib/trigger/conversation-message-notification.ts (1)

247-269: Consider more specific error handling for different HTTP status codes.

The current error handling is good, but you could provide more specific handling for different HTTP status codes to improve debugging.

      if (!response.ok) {
+       const errorText = await response.text();
        logger.error("Failed to send team member notifications", {
          dataroomId: payload.dataroomId,
          teamId: payload.teamId,
-         error: await response.text(),
+         status: response.status,
+         statusText: response.statusText,
+         error: errorText,
        });
+       
+       // Log different status codes with appropriate severity
+       if (response.status >= 500) {
+         logger.error("Server error occurred", { status: response.status });
+       } else if (response.status === 404) {
+         logger.warn("Resource not found", { status: response.status });
+       }
      } else {
ee/features/conversations/api/send-conversation-team-member-notification.ts (1)

111-122: Clarify sender lookup logic.

The comment on Line 111 says "First try to find as a user" but the query is against the viewer table. This seems intentional based on the context, but the comment could be clearer.

-   // First try to find as a user
+   // Find the sender in the viewer table
    const userSender = await prisma.viewer.findUnique({
      where: { id: senderUserId },
      select: { email: true },
    });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad15f5d and 1caf722.

📒 Files selected for processing (9)
  • ee/features/conversations/api/conversations-route.ts (5 hunks)
  • ee/features/conversations/api/send-conversation-team-member-notification.ts (1 hunks)
  • ee/features/conversations/components/conversation-view-sidebar.tsx (1 hunks)
  • ee/features/conversations/emails/components/conversation-notification.tsx (1 hunks)
  • ee/features/conversations/emails/components/conversation-team-notification.tsx (1 hunks)
  • ee/features/conversations/emails/lib/send-conversation-team-notification.ts (1 hunks)
  • ee/features/conversations/lib/trigger/conversation-message-notification.ts (1 hunks)
  • lib/trigger/conversation-message-notification.ts (1 hunks)
  • pages/api/jobs/send-conversation-team-member-notification.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/trigger/**/*.ts

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

**/trigger/**/*.ts: You MUST use @trigger.dev/sdk/v3 when implementing Trigger.dev tasks.
You MUST NEVER use client.defineJob in Trigger.dev task files, as it is deprecated and will break the application.
You MUST export every task, including subtasks, in Trigger.dev task files.
If you are able to generate an example payload for a task, do so.
When implementing a Trigger.dev task, always use the task function from @trigger.dev/sdk/v3 and follow the correct pattern for task definition.
When implementing scheduled (cron) tasks, use schedules.task from @trigger.dev/sdk/v3 and follow the correct pattern for schedule definition.
When implementing schema-validated tasks, use schemaTask from @trigger.dev/sdk/v3 and provide a schema using Zod or another supported library.
When triggering tasks from backend code, use the tasks.trigger, tasks.batchTrigger, or tasks.triggerAndPoll methods from @trigger.dev/sdk/v3 and use type-only imports for type safety.
When triggering a task from inside another task, use the correct methods (trigger, batchTrigger, triggerAndWait, batchTriggerAndWait) on the task instance as shown in the guide.
When using metadata in tasks, use the metadata API from @trigger.dev/sdk/v3 only inside run functions or task lifecycle hooks.
When using idempotency, use the idempotencyKeys API from @trigger.dev/sdk/v3 and provide an idempotencyKey when triggering tasks.
When logging inside tasks, use the logger API from @trigger.dev/sdk/v3 and provide a message and a key-value object.

Files:

  • lib/trigger/conversation-message-notification.ts
  • ee/features/conversations/lib/trigger/conversation-message-notification.ts
🧠 Learnings (11)
📚 Learning: applies to **/trigger/**/*.ts : you must `export` every task, including subtasks, in trigger.dev tas...
Learnt from: CR
PR: mfts/papermark#0
File: .cursor/rules/rule-trigger-typescript.mdc:0-0
Timestamp: 2025-07-19T07:46:44.421Z
Learning: Applies to **/trigger/**/*.ts : You MUST `export` every task, including subtasks, in Trigger.dev task files.

Applied to files:

  • lib/trigger/conversation-message-notification.ts
  • ee/features/conversations/lib/trigger/conversation-message-notification.ts
📚 Learning: applies to **/trigger/**/*.ts : when triggering tasks from backend code, use the `tasks.trigger`, `t...
Learnt from: CR
PR: mfts/papermark#0
File: .cursor/rules/rule-trigger-typescript.mdc:0-0
Timestamp: 2025-07-19T07:46:44.421Z
Learning: Applies to **/trigger/**/*.ts : When triggering tasks from backend code, use the `tasks.trigger`, `tasks.batchTrigger`, or `tasks.triggerAndPoll` methods from `@trigger.dev/sdk/v3` and use type-only imports for type safety.

Applied to files:

  • lib/trigger/conversation-message-notification.ts
  • ee/features/conversations/api/conversations-route.ts
  • ee/features/conversations/lib/trigger/conversation-message-notification.ts
📚 Learning: applies to **/trigger/**/*.ts : when triggering a task from inside another task, use the correct met...
Learnt from: CR
PR: mfts/papermark#0
File: .cursor/rules/rule-trigger-typescript.mdc:0-0
Timestamp: 2025-07-19T07:46:44.421Z
Learning: Applies to **/trigger/**/*.ts : When triggering a task from inside another task, use the correct methods (`trigger`, `batchTrigger`, `triggerAndWait`, `batchTriggerAndWait`) on the task instance as shown in the guide.

Applied to files:

  • lib/trigger/conversation-message-notification.ts
  • ee/features/conversations/api/conversations-route.ts
  • ee/features/conversations/lib/trigger/conversation-message-notification.ts
📚 Learning: applies to **/trigger/**/*.ts : when implementing a trigger.dev task, always use the `task` function...
Learnt from: CR
PR: mfts/papermark#0
File: .cursor/rules/rule-trigger-typescript.mdc:0-0
Timestamp: 2025-07-19T07:46:44.421Z
Learning: Applies to **/trigger/**/*.ts : When implementing a Trigger.dev task, always use the `task` function from `@trigger.dev/sdk/v3` and follow the correct pattern for task definition.

Applied to files:

  • lib/trigger/conversation-message-notification.ts
  • ee/features/conversations/lib/trigger/conversation-message-notification.ts
📚 Learning: before generating any code for trigger.dev tasks, verify that you are importing from `@trigger.dev/s...
Learnt from: CR
PR: mfts/papermark#0
File: .cursor/rules/rule-trigger-typescript.mdc:0-0
Timestamp: 2025-07-19T07:46:44.421Z
Learning: Before generating any code for Trigger.dev tasks, verify that you are importing from `@trigger.dev/sdk/v3`, exporting every task, and not generating any deprecated code patterns.

Applied to files:

  • lib/trigger/conversation-message-notification.ts
📚 Learning: applies to **/trigger/**/*.ts : when implementing scheduled (cron) tasks, use `schedules.task` from ...
Learnt from: CR
PR: mfts/papermark#0
File: .cursor/rules/rule-trigger-typescript.mdc:0-0
Timestamp: 2025-07-19T07:46:44.421Z
Learning: Applies to **/trigger/**/*.ts : When implementing scheduled (cron) tasks, use `schedules.task` from `@trigger.dev/sdk/v3` and follow the correct pattern for schedule definition.

Applied to files:

  • lib/trigger/conversation-message-notification.ts
  • ee/features/conversations/api/conversations-route.ts
  • ee/features/conversations/lib/trigger/conversation-message-notification.ts
📚 Learning: applies to **/trigger/**/*.ts : you must use `@trigger.dev/sdk/v3` when implementing trigger.dev tas...
Learnt from: CR
PR: mfts/papermark#0
File: .cursor/rules/rule-trigger-typescript.mdc:0-0
Timestamp: 2025-07-19T07:46:44.421Z
Learning: Applies to **/trigger/**/*.ts : You MUST use `@trigger.dev/sdk/v3` when implementing Trigger.dev tasks.

Applied to files:

  • lib/trigger/conversation-message-notification.ts
  • ee/features/conversations/lib/trigger/conversation-message-notification.ts
📚 Learning: applies to **/trigger/**/*.ts : if you are able to generate an example payload for a task, do so....
Learnt from: CR
PR: mfts/papermark#0
File: .cursor/rules/rule-trigger-typescript.mdc:0-0
Timestamp: 2025-07-19T07:46:44.421Z
Learning: Applies to **/trigger/**/*.ts : If you are able to generate an example payload for a task, do so.

Applied to files:

  • lib/trigger/conversation-message-notification.ts
  • ee/features/conversations/lib/trigger/conversation-message-notification.ts
📚 Learning: applies to **/trigger/**/*.ts : when implementing schema-validated tasks, use `schematask` from `@tr...
Learnt from: CR
PR: mfts/papermark#0
File: .cursor/rules/rule-trigger-typescript.mdc:0-0
Timestamp: 2025-07-19T07:46:44.421Z
Learning: Applies to **/trigger/**/*.ts : When implementing schema-validated tasks, use `schemaTask` from `@trigger.dev/sdk/v3` and provide a schema using Zod or another supported library.

Applied to files:

  • lib/trigger/conversation-message-notification.ts
  • ee/features/conversations/lib/trigger/conversation-message-notification.ts
📚 Learning: applies to **/trigger/**/*.ts : when using idempotency, use the `idempotencykeys` api from `@trigger...
Learnt from: CR
PR: mfts/papermark#0
File: .cursor/rules/rule-trigger-typescript.mdc:0-0
Timestamp: 2025-07-19T07:46:44.421Z
Learning: Applies to **/trigger/**/*.ts : When using idempotency, use the `idempotencyKeys` API from `@trigger.dev/sdk/v3` and provide an `idempotencyKey` when triggering tasks.

Applied to files:

  • lib/trigger/conversation-message-notification.ts
  • ee/features/conversations/api/conversations-route.ts
📚 Learning: applies to **/trigger/**/*.ts : when using metadata in tasks, use the `metadata` api from `@trigger....
Learnt from: CR
PR: mfts/papermark#0
File: .cursor/rules/rule-trigger-typescript.mdc:0-0
Timestamp: 2025-07-19T07:46:44.421Z
Learning: Applies to **/trigger/**/*.ts : When using metadata in tasks, use the `metadata` API from `@trigger.dev/sdk/v3` only inside run functions or task lifecycle hooks.

Applied to files:

  • ee/features/conversations/api/conversations-route.ts
🧬 Code Graph Analysis (2)
ee/features/conversations/emails/lib/send-conversation-team-notification.ts (2)
lib/resend.ts (1)
  • sendEmail (12-95)
ee/features/conversations/emails/components/conversation-team-notification.tsx (1)
  • ConversationTeamNotification (16-80)
ee/features/conversations/api/send-conversation-team-member-notification.ts (2)
ee/features/conversations/emails/lib/send-conversation-team-notification.ts (1)
  • sendConversationTeamNotification (5-40)
lib/utils.ts (1)
  • log (52-112)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (13)
ee/features/conversations/components/conversation-view-sidebar.tsx (2)

11-11: Import cleanup looks good

cn was unused and is now removed, leaving only the still-used fetcher. This reduces dead code with no functional impact.


16-16: Pruned unused sheet components

Eliminating SheetHeader and SheetTitle keeps the import list minimal and avoids pulling unnecessary code into the bundle.

ee/features/conversations/emails/components/conversation-notification.tsx (1)

65-65: LGTM!

The simplification of the copyright footer to plain text is consistent with the new ConversationTeamNotification component and follows common email template practices.

pages/api/jobs/send-conversation-team-member-notification.ts (1)

1-2: LGTM!

Clean re-export pattern that properly exposes the EE feature through the API route structure.

lib/trigger/conversation-message-notification.ts (1)

1-9: LGTM!

The import and export of both notification tasks follows the required pattern for trigger files. Both tasks are properly exported as mandated by the coding guidelines.

ee/features/conversations/emails/components/conversation-team-notification.tsx (1)

66-74: Verify the absence of unsubscribe functionality.

Unlike the ConversationNotification component, this team notification doesn't include an unsubscribe link. Please confirm this is intentional, as team members might still want to manage their notification preferences.

ee/features/conversations/api/conversations-route.ts (3)

124-154: Well-implemented notification deduplication logic!

The implementation correctly:

  • Queries for existing delayed/queued runs within a 5-minute window
  • Cancels them to prevent duplicate notifications
  • Uses comprehensive idempotency keys and tags
  • Employs waitUntil for non-blocking execution

164-164: Good change making viewerId required.

Making viewerId required ensures proper message attribution and prevents potential null reference errors.


180-210: Consistent notification scheduling implementation!

The notification scheduling logic properly mirrors the conversation creation endpoint with the same deduplication strategy and delay mechanism.

ee/features/conversations/lib/trigger/conversation-message-notification.ts (2)

183-191: LGTM! Follows Trigger.dev v3 guidelines correctly.

The task definition properly uses the task function from @trigger.dev/sdk/v3, includes appropriate retry configuration, and uses the logger API correctly throughout the implementation.


194-220: Well-structured database query with proper filtering.

The query correctly filters for ADMIN/MANAGER roles and excludes blocked team members. The early return with logging when no team members are found is appropriate.

ee/features/conversations/api/send-conversation-team-member-notification.ts (2)

35-148: Well-structured API handler with comprehensive functionality.

The handler properly validates team members, filters by notification preferences, fetches required data, and integrates well with the email notification system. The error handling and logging are appropriate.


149-156: Excellent error handling with detailed logging.

The error handling uses the proper logging utility with appropriate metadata and mention flag for critical errors. The structured error response is also appropriate.

@mfts mfts merged commit 4079299 into main Aug 2, 2025
9 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Aug 2, 2025
@mfts mfts deleted the cursor/notify-team-members-of-new-conversation-messages-311d branch August 19, 2025 07:59
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants