Skip to content

Conversation

@dcodesdev
Copy link
Owner

@dcodesdev dcodesdev commented Jun 21, 2025

Summary by CodeRabbit

  • New Features

    • Added comprehensive webhook support for real-time email event notifications with customizable endpoints, authentication, and payload transformation.
    • Introduced a "Webhooks" tab in settings for managing webhooks, including creation, editing, deletion, and detailed request log views.
    • Integrated Monaco Code Editor for webhook code editing.
    • Added new message statuses: "Awaiting Webhook," "Complained," and "Cancelled" for improved message lifecycle tracking.
    • Implemented detailed webhook request logging with pagination and status indicators.
    • Enhanced message ID display with a copy-to-clipboard dialog and enabled webhook URL copying.
    • Added webhook cleanup cron job to periodically delete old webhook logs.
  • Bug Fixes

    • Improved unsubscribe functionality to atomically cancel pending messages upon unsubscription.
  • Documentation

    • Added detailed webhook setup, authentication, transformation, and event reference documentation.
    • Documented environment variables for webhook runtime resource limits.
  • Chores

    • Centralized message status definitions across backend modules.
    • Added debug-level logging and enhanced backend logging utilities.
    • Updated dependencies and internal utilities to support webhook features and maintainability.

@vercel
Copy link

vercel bot commented Jun 21, 2025

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

Name Status Preview Comments Updated (UTC)
letter-space-docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 22, 2025 3:33pm
1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
letter-space-landing-page ⬜️ Ignored (Inspect) Visit Preview Jun 22, 2025 3:33pm

@coderabbitai
Copy link

coderabbitai bot commented Jun 21, 2025

Walkthrough

This update introduces a comprehensive webhook system, enabling real-time email event notifications through customizable endpoints. It adds database schema changes, backend API routes, event processing logic with sandboxed code execution, and an enhanced UI for managing webhooks. Documentation and shared constants for webhook events are included, along with improved message status handling and type safety.

Changes

Files/Groups Change Summary
.cursor/rules/general.mdc Changed alwaysApply flag to true for unconditional rule application.
RELEASE_NOTES.md, todo.md Updated release notes with detailed webhook support and added a todo list for features and bugs.
apps/backend/package.json Added quickjs-emscripten dependency; removed Prettier from SQL generation script.
apps/backend/prisma/schema.prisma, prisma/migrations/.../migration.sql Added Webhook and WebhookLog models, new COMPLAINED and AWAITING_WEBHOOK statuses, indexes, and relations; removed url field from Webhook.
apps/backend/src/app.ts Integrated webhookRouter and POST handler for /webhook/:webhookId; updated image route to handle AWAITING_WEBHOOK status.
apps/backend/src/campaign/mutation.ts Changed campaign deletion to a transaction deleting messages and campaign atomically.
apps/backend/src/cron/dailyMaintenance.ts Broadened message cleanup to exclude only pending/retrying messages.
apps/backend/src/cron/sendMessages.ts Used centralized message status constants; set message status to AWAITING_WEBHOOK if active webhooks exist.
apps/backend/src/cron/cleanupWebhookLogs.ts, apps/backend/src/cron/cron.ts Added cron job to clean up old webhook logs daily.
apps/backend/src/message/query.ts Added CANCELLED, COMPLAINED, and AWAITING_WEBHOOK to message status enums.
apps/backend/src/stats/query.ts Replaced hardcoded status arrays with centralized messageStatus constants including COMPLAINED.
apps/backend/src/subscriber/mutation.ts Refactored unsubscribe logic to cancel pending messages in a transaction; made campaign ID optional in public unsubscribe.
apps/backend/src/utils/message-status.ts Added utility categorizing message statuses into pending, delivered, opened, processed, and completed.
apps/backend/src/utils/logger.ts Added conditional debug method to logger.
apps/backend/src/utils/message-id.ts, apps/backend/src/utils/message-id.test.ts Added utility to strip angle brackets from message IDs with tests.
apps/backend/src/webhook/authorization.ts New module for running sandboxed authorization code via QuickJS.
apps/backend/src/webhook/handler.ts Added webhook handler for processing incoming webhook requests with auth and transform.
apps/backend/src/webhook/mutation.ts, apps/backend/src/webhook/query.ts Added tRPC mutations and queries for CRUD operations on webhooks with authorization checks.
apps/backend/src/webhook/processor.ts Added event processor for updating message status from webhook events.
apps/backend/src/webhook/router.ts Aggregated webhook operations into a router.
apps/backend/src/webhook/transformer.ts Added payload transformer supporting custom JS code execution in sandbox with timeout.
apps/backend/src/webhook/types.ts Defined types, schemas, and event/status mappings for webhook processing.
apps/backend/src/constants.ts Added environment variables for webhook transformer memory and stack size limits with defaults.
README.md, apps/docs/src/app/getting-started/configuration/page.mdx Documented environment variables including webhook transformer limits.
apps/docs/src/app/_meta.ts, apps/docs/src/app/api/_meta.ts, apps/docs/src/app/webhooks/_meta.ts Added metadata for new documentation sections.
apps/docs/src/app/webhooks/page.mdx Added webhook API documentation with authentication, transformation, and event types.
apps/docs/src/components/index.ts, apps/docs/src/components/webhook-events-reference.tsx Added and exported a React component for displaying webhook event types.
apps/docs/src/mdx-components.tsx Registered WebhookEventsReference as an MDX component.
packages/shared/index.ts, packages/shared/webhook-events-data.ts Added and exported shared webhook event constants and types.
apps/web/package.json Added Monaco Editor and syntax highlighter dependencies; added type-check script.
apps/web/src/components/alert-dialog-confirmation.tsx Made dialog trigger optional and added controlled open state props.
apps/web/src/components/copy-button.tsx Allowed copying arbitrary text or invoking a callback.
apps/web/src/components/index.ts, apps/web/src/components/monaco-editor.tsx Added and exported Monaco Editor component.
apps/web/src/components/webhook-events-reference.tsx Added a React component for listing webhook event types.
apps/web/src/pages/dashboard/messages/message-status-badge.tsx Added "AWAITING_WEBHOOK" and "COMPLAINED" statuses to message badge config.
apps/web/src/pages/dashboard/messages/message-status-filter.tsx Added "AWAITING_WEBHOOK", "CANCELLED", and "COMPLAINED" statuses to filter options.
apps/web/src/pages/dashboard/messages/columns.tsx, apps/web/src/pages/dashboard/messages/message-id-cell.tsx Added "Message ID" column with a dialog to display and copy full message ID.
apps/web/src/pages/dashboard/settings/page.tsx Enabled the "Webhooks" tab and rendered webhook settings.
apps/web/src/pages/dashboard/settings/webhook-form.tsx Added reusable form component for webhook configuration with Monaco code editor and validation.
apps/web/src/pages/dashboard/settings/webhook-settings.tsx Refactored settings page to use new form, dialogs, and updated API usage with improved UI.
apps/web/src/pages/dashboard/settings/webhook-details.tsx Added detailed webhook view with logs, pagination, and copyable webhook URL.
.github/workflows/docker.yaml, scripts/gen-container-img-tags.ts, tsconfig.json, package.json Added Bun support in CI workflow, container image tag generation script, new TS config, and updated package metadata.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant WebApp
    participant Backend
    participant DB

    User->>WebApp: Configure webhook (name, authCode, transformCode)
    WebApp->>Backend: Create/Update webhook via API
    Backend->>DB: Store webhook config
    DB-->>Backend: Ack
    Backend-->>WebApp: Success

    Note over User,Backend: Later, an SMTP provider triggers a webhook event

    participant SMTP
    SMTP->>Backend: POST /webhook/:webhookId with payload
    Backend->>DB: Lookup webhook config by webhookId
    DB-->>Backend: Webhook config
    Backend->>Backend: Run sandboxed authCode (if present)
    alt Auth fails
        Backend-->>SMTP: 401 Unauthorized
    else Auth succeeds
        Backend->>Backend: Run sandboxed transformCode (if present)
        Backend->>Backend: Validate event schema
        Backend->>DB: Find message by messageId and organizationId
        alt Message found
            Backend->>DB: Update message status and error message
            Backend-->>SMTP: 200 OK
        else Message not found
            Backend-->>SMTP: 404 Not Found
        end
    end
Loading

Poem

A bunny hops with code anew,
Webhooks now join the crew!
Sandboxed scripts and types galore,
Events tracked better than before.
Monaco shines, docs expand,
Real-time updates, all well planned.
🐇✨ Let’s celebrate this clever band!

✨ Finishing Touches
  • 📝 Generate Docstrings

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

❤️ Share
🪧 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 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

@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: 7

🧹 Nitpick comments (6)
todo.md (1)

1-1: Consider hyphenating "To-dos".
LanguageTool flags that the plural noun “to-dos” should include a hyphen. Update the header from # Todos to # To-dos for correct grammar.

apps/web/package.json (2)

10-10: Added check-types script
Great addition for enforcing type safety. Consider integrating this script into the CI pipeline to catch type errors automatically.


16-16: Monaco Editor dependencies
@monaco-editor/react, @types/react-syntax-highlighter, and monaco-editor are correctly added. To optimize bundle size, consider externalizing Monaco workers or lazy-loading the editor in your Vite config.

Also applies to: 24-24, 29-29

apps/backend/prisma/schema.prisma (1)

27-27: Added Webhooks relation to Organization
The one-to-many relation is correctly defined. Consider adding a unique constraint (e.g., on organizationId + url or name) to prevent duplicate webhooks per organization.

apps/backend/src/webhook/query.ts (1)

27-34: Consider adding pagination for scalability.

For organizations with many webhooks, returning all webhooks at once could impact performance. Consider implementing pagination with limit/offset or cursor-based pagination.

 const webhooks = await prisma.webhook.findMany({
   where: {
     organizationId: input.organizationId,
   },
   orderBy: {
     createdAt: "desc",
   },
+  take: input.limit || 20,
+  skip: input.offset || 0,
 })

Don't forget to add limit and offset to the input schema.

apps/docs/src/app/webhooks/page.mdx (1)

46-57: Enhance the transform function example with timestamp handling.

The example could better demonstrate timestamp handling, which is important for accurate event tracking.

 function transform(payload, headers, query) {
   // Transform the provider-specific payload into LetterSpace format
 
   return {
     messageId: payload.messageId, // Required: External message ID
     event: payload.event, // Required: Event type
-    timestamp: payload.timestamp, // Optional: Event timestamp
+    timestamp: payload.timestamp || new Date().toISOString(), // Optional: Event timestamp (use current time if not provided)
     reason: payload.reason, // Optional: Failure/bounce reason
   }
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5436a52 and 11a9f4d.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (38)
  • .cursor/rules/general.mdc (1 hunks)
  • RELEASE_NOTES.md (1 hunks)
  • apps/backend/package.json (1 hunks)
  • apps/backend/prisma/migrations/20250530060003_add_webhook_model/migration.sql (1 hunks)
  • apps/backend/prisma/schema.prisma (4 hunks)
  • apps/backend/src/app.ts (3 hunks)
  • apps/backend/src/campaign/mutation.ts (1 hunks)
  • apps/backend/src/cron/dailyMaintenance.ts (1 hunks)
  • apps/backend/src/cron/sendMessages.ts (2 hunks)
  • apps/backend/src/message/query.ts (1 hunks)
  • apps/backend/src/stats/query.ts (1 hunks)
  • apps/backend/src/subscriber/mutation.ts (3 hunks)
  • apps/backend/src/utils/message-status.ts (1 hunks)
  • apps/backend/src/webhook/handler.ts (1 hunks)
  • apps/backend/src/webhook/mutation.ts (1 hunks)
  • apps/backend/src/webhook/query.ts (1 hunks)
  • apps/backend/src/webhook/router.ts (1 hunks)
  • apps/docs/src/app/_meta.ts (1 hunks)
  • apps/docs/src/app/api/_meta.ts (1 hunks)
  • apps/docs/src/app/webhooks/_meta.ts (1 hunks)
  • apps/docs/src/app/webhooks/page.mdx (1 hunks)
  • apps/docs/src/components/index.ts (1 hunks)
  • apps/docs/src/components/webhook-events-reference.tsx (1 hunks)
  • apps/docs/src/mdx-components.tsx (2 hunks)
  • apps/web/package.json (1 hunks)
  • apps/web/src/components/alert-dialog-confirmation.tsx (3 hunks)
  • apps/web/src/components/copy-button.tsx (1 hunks)
  • apps/web/src/components/index.ts (1 hunks)
  • apps/web/src/components/monaco-editor.tsx (1 hunks)
  • apps/web/src/components/webhook-events-reference.tsx (1 hunks)
  • apps/web/src/pages/dashboard/messages/message-status-badge.tsx (1 hunks)
  • apps/web/src/pages/dashboard/messages/message-status-filter.tsx (1 hunks)
  • apps/web/src/pages/dashboard/settings/page.tsx (3 hunks)
  • apps/web/src/pages/dashboard/settings/webhook-form.tsx (1 hunks)
  • apps/web/src/pages/dashboard/settings/webhook-settings.tsx (2 hunks)
  • packages/shared/index.ts (1 hunks)
  • packages/shared/webhook-events-data.ts (1 hunks)
  • todo.md (1 hunks)
🧰 Additional context used
🪛 LanguageTool
todo.md

[grammar] ~1-~1: It appears that a hyphen is missing in the plural noun “to-dos”?
Context: # Todos - [x] I want the transform code and th...

(TO_DO_HYPHEN)

apps/docs/src/app/webhooks/page.mdx

[uncategorized] ~35-~35: Loose punctuation mark.
Context: ...``` The function receives: - headers: Request headers object - `body`: Reques...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~61-~61: Loose punctuation mark.
Context: ...``` The function receives: - payload: The raw webhook payload from your SMTP ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~69-~69: Loose punctuation mark.
Context: ...med payload must include: - messageId: The external message ID from your SMTP ...

(UNLIKELY_OPENING_PUNCTUATION)

🔇 Additional comments (53)
.cursor/rules/general.mdc (1)

4-4: LGTM! Configuration change promotes development consistency.

Enabling unconditional application of the development rules ensures consistent AI assistance behavior across the webhook implementation and future development work.

apps/backend/package.json (1)

42-42: Evaluate security implications of vm2 dependency.
Adding vm2 enables sandboxed JS execution for webhook scripts, but it has had security advisories in the past. Please verify that version ^3.9.19 has no known vulnerabilities (e.g., via npm audit or a vulnerability-scanning CI step) and ensure your usage restricts script capabilities to only what's necessary.

apps/docs/src/app/api/_meta.ts (1)

1-8: Metadata module looks good.
The new meta export correctly defines the API Overview section for Nextra. No changes needed.

apps/web/src/pages/dashboard/messages/message-status-badge.tsx (1)

46-50: New COMPLAINED status mapping is consistent.
The addition of COMPLAINED using the same yellow styling as RETRYING aligns with the backend enum changes and maintains UI consistency.

apps/backend/src/stats/query.ts (1)

24-31: Include COMPLAINED in processed statuses.
Adding "COMPLAINED" to processedMessageStatuses ensures it’s counted in overall stats, matching the updated enum and other query filters.

apps/backend/src/campaign/mutation.ts (1)

201-211: Excellent improvement to data integrity!

The change from a simple delete to a transactional operation ensures atomicity and prevents orphaned messages. This is a critical improvement that maintains referential integrity when campaigns are deleted.

apps/backend/src/message/query.ts (1)

16-17: Good addition of new message statuses.

These new status values align well with the webhook system implementation. "COMPLAINED" supports tracking spam complaints from email providers, while "CANCELLED" enables proper status tracking for cancelled messages.

packages/shared/index.ts (1)

5-5: Clean addition to shared package exports.

The new export follows the established pattern and makes webhook event data available across the monorepo. This enables proper code reuse for webhook-related functionality.

apps/web/src/components/index.ts (1)

16-17: Good additions to component exports.

The new component exports follow the established pattern and support the webhook functionality. These enable consistent usage of webhook-related UI components throughout the application.

apps/docs/src/app/webhooks/_meta.ts (1)

1-7: Proper documentation metadata setup.

The metadata configuration correctly follows the Nextra pattern and provides appropriate labeling for the webhook documentation section.

apps/docs/src/app/_meta.ts (1)

7-7: LGTM! Clean documentation metadata addition.

The webhooks entry is properly added to the navigation metadata, following the existing pattern and maintaining alphabetical-ish ordering.

apps/docs/src/mdx-components.tsx (2)

3-3: LGTM! Proper component import.

The WebhookEventsReference component is correctly imported from the local components module.


12-12: LGTM! Correct MDX component integration.

The WebhookEventsReference component is properly added to the MDX components object with the right precedence order.

apps/docs/src/components/index.ts (1)

2-2: LGTM! Standard component export.

The webhook-events-reference component is properly exported following the established pattern.

apps/web/src/pages/dashboard/messages/message-status-filter.tsx (1)

20-21: LGTM! Consistent status additions.

The new message statuses "CANCELLED" and "COMPLAINED" are correctly added to the array, maintaining consistency with the existing pattern and extending the MessageStatus union type appropriately.

apps/backend/src/cron/dailyMaintenance.ts (1)

27-27: Verify the behavioral change in cleanup logic.

This is a significant change from a whitelist to blacklist approach for message cleanup. The new logic will now include any message status not in ["QUEUED", "PENDING", "RETRYING"] for cleanup, including the newly added statuses like "CANCELLED" and "COMPLAINED".

While this aligns with treating these as completed states, please verify that this change doesn't inadvertently clean up messages that should be preserved, especially if there are other message statuses not explicitly handled.

#!/bin/bash
# Description: Verify all possible message statuses in the schema and codebase
# Expected: Confirm all statuses are properly categorized as pending vs completed

# Search for MessageStatus enum definition in Prisma schema
rg -A 20 "enum MessageStatus" 

# Search for any other message status references to ensure completeness
rg "MessageStatus|message.*status" --type ts -B 2 -A 2
apps/backend/src/app.ts (3)

17-17: LGTM: Clean import integration

The webhook imports are properly structured and follow the existing conventions in the file.

Also applies to: 23-23


34-34: LGTM: Proper tRPC router integration

The webhookRouter is correctly integrated into the main appRouter following the established pattern.


153-153: LGTM: Strategic webhook endpoint placement

The webhook POST route is correctly positioned to handle direct HTTP requests before tRPC processing, which is appropriate for webhook endpoints.

apps/backend/src/cron/sendMessages.ts (2)

36-36: LGTM: Appropriate rate limiting inclusion

Including "COMPLAINED" status in rate limiting is correct since these are successfully processed messages that should count against delivery limits.


103-110: LGTM: Logical campaign completion criteria

Adding "COMPLAINED" to the campaign completion status check is appropriate since it represents a final message state that should contribute to campaign completion determination.

apps/web/src/pages/dashboard/settings/page.tsx (3)

9-9: LGTM: Consistent import pattern

The WebhookSettings import follows the established pattern for other settings components.


52-52: LGTM: Proper tab trigger integration

The Webhooks tab trigger is correctly implemented following the existing TabsTrigger pattern.


78-80: LGTM: Consistent tab content structure

The webhooks TabsContent is properly structured and follows the established pattern for other settings tabs.

apps/docs/src/components/webhook-events-reference.tsx (4)

1-3: LGTM: Clean component setup

The import and component declaration follow React best practices with proper naming conventions.


5-20: LGTM: Well-structured documentation table

The table implementation uses proper semantic HTML with comprehensive styling including dark mode support and clear column headers.


22-30: LGTM: Proper React list rendering

The row rendering follows React best practices with proper key usage and clean alternating row styling for improved readability.


31-48: LGTM: Well-formatted technical documentation

The cell content uses appropriate styling with monospace fonts for technical elements and proper code formatting for aliases, enhancing readability for developers.

apps/backend/src/webhook/router.ts (2)

1-3: LGTM: Clean import organization

The imports follow the established pattern of separating tRPC router creation from operation implementations, promoting good code organization.


5-11: LGTM: Complete CRUD router implementation

The webhook router properly implements all standard CRUD operations (list, get, create, update, delete) following the established tRPC pattern with clear, consistent naming.

RELEASE_NOTES.md (3)

3-7: Well-documented feature additions
The new entries for Webhooks support, Complained Message Status, and Monaco Code Editor clearly summarize the enhancements.


11-11: Bug fix note is clear
The unsubscribe functionality fix is concisely noted under Bug Fixes.


15-16: Documentation link included
The link to the comprehensive webhook docs enhances discoverability.

apps/backend/src/utils/message-status.ts (1)

1-13: Clear categorization of message statuses
The separation into pendingMessages and completedMessages is straightforward and aligns with the updated enum.

apps/backend/prisma/schema.prisma (2)

203-203: COMPLAINED status added
Integrates the new enum value for tracking spam complaints. Ensure existing data migrations handle this addition gracefully.


230-230: Index on messageId
This index will improve lookup performance for message-related queries. Good catch.

packages/shared/webhook-events-data.ts (1)

1-39: Canonical webhook events defined
The WEBHOOK_EVENTS array provides a clear mapping of event names, aliases, and statuses. Great alignment with backend enums.

apps/backend/prisma/migrations/20250530060003_add_webhook_model/migration.sql (3)

1-2: LGTM! Clean enum extension.

The addition of 'COMPLAINED' to the MessageStatus enum is well-implemented and aligns with the webhook functionality described in the PR summary.


4-17: Well-structured webhook table design.

The table structure includes all necessary fields for webhook functionality:

  • Standard metadata fields (id, name, url, timestamps)
  • Business logic fields (isActive with sensible default, authCode, transformCode)
  • Proper organization scoping with foreign key relationship

The design supports both authentication and payload transformation, which is essential for webhook integrations.


19-20: Appropriate foreign key constraint with CASCADE operations.

The CASCADE operations for both DELETE and UPDATE ensure data integrity - when an organization is deleted or updated, all associated webhooks will be automatically handled. This prevents orphaned webhook records.

apps/web/src/components/alert-dialog-confirmation.tsx (2)

15-17: Good API enhancement for controlled state management.

Making trigger optional and adding open/onOpenChange props enables both controlled and uncontrolled usage patterns, increasing component flexibility.


38-39: Proper conditional rendering implementation.

The conditional rendering of AlertDialogTrigger prevents rendering issues when no trigger is provided, while the controlled props are correctly passed to the root AlertDialog component.

apps/web/src/components/webhook-events-reference.tsx (2)

6-18: Well-designed component interface with sensible defaults.

The props interface provides good flexibility while maintaining usability:

  • Optional customization for title, description, and event list
  • Sensible default values that work out of the box
  • Proper TypeScript typing with imported shared types

27-47: Clean and accessible event display implementation.

The event rendering logic is well-structured:

  • Proper key usage for React lists
  • Semantic HTML structure with appropriate spacing
  • Good visual hierarchy with badges for names/aliases
  • Informative status display with proper code formatting
apps/web/src/components/copy-button.tsx (2)

6-9: Good API enhancement for direct text copying.

Making onCopy optional and adding the text prop provides more flexibility for different use cases - direct text copying vs. custom copy logic.


14-22: Proper implementation of dual copy modes.

The logic correctly prioritizes direct text copying over callback execution, providing clear behavior when both options are available. The async handling and user feedback timing are appropriate.

apps/web/src/components/monaco-editor.tsx (4)

6-15: Comprehensive and well-typed component interface.

The props interface covers all essential Monaco editor features:

  • Standard editor props (value, onChange, language)
  • UI customization (placeholder, className, height)
  • State management (disabled)
  • Monaco-specific options for advanced configuration

29-31: Proper value normalization for controlled input.

The handleChange function correctly normalizes undefined values to empty strings, ensuring consistent behavior for controlled React components.


33-48: Excellent default editor configuration.

The default options provide a great out-of-the-box experience for code editing:

  • Disabled minimap saves space
  • Proper font size and line numbers
  • Word wrap and automatic layout for responsive behavior
  • Correct read-only mode based on disabled state
  • Sensible scroll behavior

54-66: Good theme integration and loading UX.

The theme switching based on the application theme and the loading placeholder with customizable text provide excellent user experience.

apps/backend/src/webhook/handler.ts (1)

101-108: Good security practice with organization-scoped message lookup.

The message lookup is properly scoped to the webhook's organization through the Campaign relationship, preventing cross-organization data access.

apps/backend/src/subscriber/mutation.ts (1)

369-403: Good implementation of transactional unsubscribe with message cancellation.

The transaction wrapper ensures atomicity between the unsubscribe operation and message cancellation. The query correctly identifies pending messages that should be cancelled based on the campaign lists.

apps/web/src/pages/dashboard/settings/webhook-settings.tsx (1)

1-285: Excellent refactor with improved maintainability and UX.

The refactor successfully:

  • Extracts form logic into a reusable WebhookForm component
  • Implements proper state management for CRUD operations
  • Adds comprehensive error handling with user feedback
  • Provides intuitive empty states and loading indicators
  • Uses controlled dialogs with proper key management for re-rendering

Copy link

@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: 4

🧹 Nitpick comments (8)
apps/backend/prisma/client/sql/index.edge.js (1)

4-4: Note: Redundant "use strict" directive in generated code.

The static analysis tool correctly identifies that the "use strict" directive is redundant in ES6 modules. However, since this is generated Prisma code (as indicated by the header comment), this should be addressed in the Prisma code generator configuration rather than manual editing.

Consider updating the Prisma client generation settings to remove redundant "use strict" directives from generated files.

apps/backend/prisma/client/sql/index.js (1)

4-4: Note: Redundant "use strict" directive in generated code.

Same issue as in index.edge.js - the "use strict" directive is redundant in ES6 modules. Since this is generated Prisma code, address this in the generator configuration rather than manual editing.

apps/web/src/pages/dashboard/messages/message-id-cell.tsx (1)

13-17: Consider adding error handling for clipboard operations.

The clipboard API call could fail in certain browsers or security contexts. Consider adding error handling:

  const copyToClipboard = () => {
    if (messageId) {
-     navigator.clipboard.writeText(messageId)
-     toast.success("Message ID copied to clipboard")
+     navigator.clipboard.writeText(messageId).then(() => {
+       toast.success("Message ID copied to clipboard")
+     }).catch(() => {
+       toast.error("Failed to copy message ID")
+     })
    }
  }
apps/backend/src/cron/cleanupWebhookLogs.ts (2)

40-43: Remove unnecessary continue statement.

The continue statement is unnecessary since it's the last statement in the loop iteration.

      } catch (error) {
        console.error(`Error deleting webhook logs for org ${org.id}: ${error}`)
-       continue
      }

17-20: Consider validating cleanup interval bounds.

While the default 90-day cleanup interval is reasonable, consider adding validation to prevent extremely short intervals that could cause excessive database operations or data loss.

-     const cleanupIntervalDays = org.GeneralSettings?.cleanupInterval ?? 90
+     const cleanupIntervalDays = Math.max(1, org.GeneralSettings?.cleanupInterval ?? 90)
apps/docs/src/app/webhooks/page.mdx (1)

29-29: Critical security consideration appropriately documented.

The security warning about plain text storage of authentication code and secrets is crucial for users to understand. Consider implementing encrypted storage for sensitive data in future versions.

apps/web/src/pages/dashboard/settings/webhook-settings.tsx (2)

28-30: Consider removing redundant date formatting library.

The component imports both date-fns and dayjs for date formatting. This creates unnecessary bundle bloat and potential confusion. Since dayjs is used for relative time formatting and date-fns for absolute dates, consider standardizing on one library.

Replace the date-fns import and usage with dayjs:

-import { format } from "date-fns"
-import dayjs from "dayjs"
-import relativeTime from "dayjs/plugin/relativeTime"
+import dayjs from "dayjs"
+import relativeTime from "dayjs/plugin/relativeTime"

Then update line 232:

-{format(new Date(webhook.createdAt), "MMM d, yyyy")}
+{dayjs(webhook.createdAt).format("MMM D, YYYY")}

310-318: Consider extracting large components for better maintainability.

This component handles multiple responsibilities (listing, creating, editing, deleting webhooks). While functional, it could benefit from being split into smaller, focused components.

Consider extracting:

  • WebhookList component for the table rendering
  • WebhookActions component for the action buttons
  • WebhookDeleteDialog as a separate component

This would improve testability and maintainability while keeping the logic centralized in the main component.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a2b193e and 2d9f8ec.

📒 Files selected for processing (49)
  • apps/backend/package.json (2 hunks)
  • apps/backend/prisma/client/sql/$DbEnums.d.ts (1 hunks)
  • apps/backend/prisma/client/sql/countDbSize.d.ts (1 hunks)
  • apps/backend/prisma/client/sql/countDbSize.edge.js (1 hunks)
  • apps/backend/prisma/client/sql/countDbSize.edge.mjs (1 hunks)
  • apps/backend/prisma/client/sql/countDbSize.js (1 hunks)
  • apps/backend/prisma/client/sql/countDbSize.mjs (1 hunks)
  • apps/backend/prisma/client/sql/countDistinctRecipients.d.ts (1 hunks)
  • apps/backend/prisma/client/sql/countDistinctRecipients.edge.js (1 hunks)
  • apps/backend/prisma/client/sql/countDistinctRecipients.edge.mjs (1 hunks)
  • apps/backend/prisma/client/sql/countDistinctRecipients.js (1 hunks)
  • apps/backend/prisma/client/sql/countDistinctRecipients.mjs (1 hunks)
  • apps/backend/prisma/client/sql/countDistinctRecipientsInTimeRange.d.ts (1 hunks)
  • apps/backend/prisma/client/sql/countDistinctRecipientsInTimeRange.edge.js (1 hunks)
  • apps/backend/prisma/client/sql/countDistinctRecipientsInTimeRange.edge.mjs (1 hunks)
  • apps/backend/prisma/client/sql/countDistinctRecipientsInTimeRange.js (1 hunks)
  • apps/backend/prisma/client/sql/countDistinctRecipientsInTimeRange.mjs (1 hunks)
  • apps/backend/prisma/client/sql/index.d.ts (1 hunks)
  • apps/backend/prisma/client/sql/index.edge.js (1 hunks)
  • apps/backend/prisma/client/sql/index.edge.mjs (1 hunks)
  • apps/backend/prisma/client/sql/index.js (1 hunks)
  • apps/backend/prisma/client/sql/index.mjs (1 hunks)
  • apps/backend/prisma/client/sql/subscriberGrowthQuery.d.ts (1 hunks)
  • apps/backend/prisma/client/sql/subscriberGrowthQuery.edge.js (1 hunks)
  • apps/backend/prisma/client/sql/subscriberGrowthQuery.edge.mjs (1 hunks)
  • apps/backend/prisma/client/sql/subscriberGrowthQuery.js (1 hunks)
  • apps/backend/prisma/client/sql/subscriberGrowthQuery.mjs (1 hunks)
  • apps/backend/prisma/migrations/20250621175427_add_transformed_payload_to_webhook_logs/migration.sql (1 hunks)
  • apps/backend/prisma/migrations/20250621191015_remove_webhook_url_field/migration.sql (1 hunks)
  • apps/backend/prisma/schema.prisma (4 hunks)
  • apps/backend/prisma/sql/countDbSize.sql (3 hunks)
  • apps/backend/src/cron/cleanupWebhookLogs.ts (1 hunks)
  • apps/backend/src/cron/cron.ts (2 hunks)
  • apps/backend/src/lib/Mailer.ts (2 hunks)
  • apps/backend/src/utils/message-id.test.ts (1 hunks)
  • apps/backend/src/utils/message-id.ts (1 hunks)
  • apps/backend/src/webhook/handler.ts (1 hunks)
  • apps/backend/src/webhook/mutation.ts (1 hunks)
  • apps/backend/src/webhook/processor.ts (1 hunks)
  • apps/backend/src/webhook/types.ts (1 hunks)
  • apps/docs/src/app/_meta.ts (1 hunks)
  • apps/docs/src/app/webhooks/page.mdx (1 hunks)
  • apps/web/src/pages/dashboard/messages/columns.tsx (2 hunks)
  • apps/web/src/pages/dashboard/messages/message-id-cell.tsx (1 hunks)
  • apps/web/src/pages/dashboard/settings/page.tsx (3 hunks)
  • apps/web/src/pages/dashboard/settings/webhook-details.tsx (1 hunks)
  • apps/web/src/pages/dashboard/settings/webhook-form.tsx (1 hunks)
  • apps/web/src/pages/dashboard/settings/webhook-settings.tsx (3 hunks)
  • package.json (2 hunks)
✅ Files skipped from review due to trivial changes (13)
  • apps/backend/prisma/client/sql/index.d.ts
  • apps/backend/prisma/client/sql/index.edge.mjs
  • apps/backend/prisma/client/sql/countDistinctRecipients.edge.mjs
  • apps/backend/prisma/migrations/20250621175427_add_transformed_payload_to_webhook_logs/migration.sql
  • apps/backend/prisma/client/sql/index.mjs
  • apps/docs/src/app/_meta.ts
  • apps/backend/prisma/client/sql/countDistinctRecipientsInTimeRange.edge.mjs
  • apps/backend/prisma/client/sql/subscriberGrowthQuery.mjs
  • apps/backend/prisma/client/sql/countDistinctRecipients.mjs
  • apps/backend/prisma/client/sql/subscriberGrowthQuery.edge.mjs
  • apps/backend/src/utils/message-id.ts
  • apps/backend/prisma/client/sql/countDistinctRecipientsInTimeRange.mjs
  • apps/web/src/pages/dashboard/settings/webhook-details.tsx
🚧 Files skipped from review as they are similar to previous changes (9)
  • apps/backend/package.json
  • package.json
  • apps/web/src/pages/dashboard/settings/page.tsx
  • apps/backend/src/webhook/mutation.ts
  • apps/backend/src/webhook/types.ts
  • apps/web/src/pages/dashboard/settings/webhook-form.tsx
  • apps/backend/src/webhook/processor.ts
  • apps/backend/src/webhook/handler.ts
  • apps/backend/prisma/schema.prisma
🧰 Additional context used
🪛 Biome (1.9.4)
apps/backend/src/cron/cleanupWebhookLogs.ts

[error] 42-42: Unnecessary continue statement

Unsafe fix: Delete the unnecessary continue statement

(lint/correctness/noUnnecessaryContinue)

apps/backend/prisma/client/sql/countDbSize.js

[error] 3-4: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

apps/backend/prisma/client/sql/countDbSize.edge.js

[error] 3-4: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

apps/backend/prisma/client/sql/countDistinctRecipients.edge.js

[error] 3-4: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

apps/backend/prisma/client/sql/countDistinctRecipients.js

[error] 3-4: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

apps/backend/prisma/client/sql/countDistinctRecipientsInTimeRange.d.ts

[error] 8-8: Duplicate parameter name.

The parameter overrides a preceding parameter by using the same name.

(lint/suspicious/noDuplicateParameters)

apps/backend/prisma/client/sql/countDistinctRecipientsInTimeRange.edge.js

[error] 3-4: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

apps/backend/prisma/client/sql/countDistinctRecipientsInTimeRange.js

[error] 3-4: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

apps/backend/prisma/client/sql/index.edge.js

[error] 3-4: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

apps/backend/prisma/client/sql/index.js

[error] 3-4: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

apps/backend/prisma/client/sql/subscriberGrowthQuery.d.ts

[error] 8-8: Duplicate parameter name.

The parameter overrides a preceding parameter by using the same name.

(lint/suspicious/noDuplicateParameters)

apps/backend/prisma/client/sql/subscriberGrowthQuery.edge.js

[error] 3-4: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

apps/backend/prisma/client/sql/subscriberGrowthQuery.js

[error] 3-4: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

🪛 LanguageTool
apps/docs/src/app/webhooks/page.mdx

[uncategorized] ~49-~49: Loose punctuation mark.
Context: ...``` The function receives: - headers: Request headers object - `body`: Reques...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~86-~86: Loose punctuation mark.
Context: ...``` The function receives: - payload: The raw webhook payload sent by your SM...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~94-~94: Loose punctuation mark.
Context: ...rm function must include: - messageId: The external message ID provided by you...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~99-~99: Possible missing comma found.
Context: ... webhook system works with popular SMTP providers including: - SendGrid: Configure t...

(AI_HYDRA_LEO_MISSING_COMMA)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Build and Push Bun Image
  • GitHub Check: Build and Push Node Image
🔇 Additional comments (42)
apps/backend/prisma/client/sql/countDistinctRecipientsInTimeRange.js (1)

1-7: Auto-generated Prisma client – no manual edits needed

This file is generated by Prisma; the only changes are stylistic. The SQL, function signature, and behavior are unchanged.

apps/backend/prisma/client/sql/countDistinctRecipientsInTimeRange.edge.js (1)

1-7: Skip review: Generated Prisma client file
This is an auto-generated file by Prisma (per the header). All formatting changes originate from the code generator, so manual edits are not needed or recommended.

apps/backend/prisma/client/sql/subscriberGrowthQuery.js (2)

4-4: Ignore redundant 'use strict' directive in generated file
This file is auto-generated by Prisma; manual edits here will be overwritten. Address this at the generator configuration level if needed.


5-6: Approve SQL formatting and factory call style
The refactored query string and factory invocation align with project conventions and introduce no functional changes.

apps/backend/prisma/client/sql/subscriberGrowthQuery.edge.js (4)

1-1: Remove extraneous leading newline
The leading blank line has been trimmed, which is purely cosmetic.


4-4: Retain use strict in generated code
Although modules are implicitly strict, this file is auto-generated by Prisma—avoid manual edits.


5-5: Single-line import invocation is fine
Converting the require call to a single line is a harmless stylistic change.


6-6: Single-line SQL string preserves logic
Switching from a multi-line to a single-line "\n"-delimited string doesn’t alter the query’s behavior.

apps/backend/prisma/client/sql/$DbEnums.d.ts (1)

5-6: LGTM! Enum extensions support webhook functionality well.

The additions to both CampaignStatus and MessageStatus enums are well-aligned with webhook event processing requirements. The new message statuses (AWAITING_WEBHOOK, CANCELLED, COMPLAINED) provide necessary granularity for tracking email delivery states in webhook scenarios.

apps/backend/prisma/migrations/20250621191015_remove_webhook_url_field/migration.sql (1)

7-11: LGTM! Migration follows proper sequence and aligns with architectural changes.

The migration correctly drops the unique index before removing the column, which is the proper order to avoid constraint violations. The change aligns with the architectural shift to dynamically constructed webhook URLs.

Ensure that any existing webhook data migration or cleanup is handled appropriately in the application code, since this migration will result in data loss for the url column.

apps/backend/src/lib/Mailer.ts (2)

4-4: Good addition of utility import for message ID normalization.

Importing stripAngleBrackets utility supports consistent message ID formatting across the webhook system.


92-94: LGTM! Proper message ID sanitization with null safety.

The conditional application of stripAngleBrackets ensures that message IDs are normalized while properly handling undefined values. This standardization is important for webhook event correlation and message tracking.

apps/backend/prisma/client/sql/countDistinctRecipients.edge.js (2)

4-4: Address the redundant "use strict" directive.

The static analysis tool correctly identified that the "use strict" directive is redundant in ES modules. However, since this is Prisma-generated code (as indicated by the comment on line 2), this should be addressed in the Prisma configuration or generator settings rather than manually editing this file.


5-6: LGTM - Formatting improvements in generated code.

The consolidation of the multi-line factory call and string formatting changes improve readability while maintaining the same functionality.

apps/web/src/pages/dashboard/messages/columns.tsx (2)

73-77: LGTM - Well-structured column addition.

The new Message ID column follows the established pattern and integrates cleanly with the existing column definitions. The use of a dedicated MessageIdCell component promotes reusability and separation of concerns.


7-7: Verify the MessageIdCell component exists.

Ensure that the MessageIdCell component is properly implemented and exported from the specified path.

#!/bin/bash
# Description: Verify MessageIdCell component exists and is properly exported

# Check if the MessageIdCell component file exists
fd "message-id-cell" --type f

# Verify the component is properly exported
if [ -f "apps/web/src/pages/dashboard/messages/message-id-cell.tsx" ]; then
  echo "Found MessageIdCell file, checking exports:"
  rg "export.*MessageIdCell" apps/web/src/pages/dashboard/messages/message-id-cell.tsx
fi
apps/backend/src/cron/cron.ts (3)

35-40: LGTM - Appropriate cron job configuration.

The webhook logs cleanup job is well-configured:

  • Daily execution at 1 AM is appropriate for maintenance tasks
  • Follows the established pattern for other cron jobs
  • Enabled by default is reasonable for log cleanup

46-46: LGTM - Proper integration with existing cron system.

The new job is correctly added to the cronJobs array and will be properly initialized by the existing cron management system.


5-5: Verify the cleanupWebhookLogsCron function exists.

Ensure that the imported cleanupWebhookLogsCron function is properly implemented and exported.

#!/bin/bash
# Description: Verify cleanupWebhookLogsCron function exists and is properly exported

# Check if the cleanupWebhookLogs file exists
fd "cleanupWebhookLogs" --type f

# Verify the function is properly exported
if [ -f "apps/backend/src/cron/cleanupWebhookLogs.ts" ]; then
  echo "Found cleanupWebhookLogs file, checking exports:"
  rg "export.*cleanupWebhookLogsCron" apps/backend/src/cron/cleanupWebhookLogs.ts
fi
apps/backend/prisma/client/sql/countDbSize.d.ts (2)

18-18: LGTM - Consistent type addition for webhook logs.

The new webhook_log_count field follows the same pattern as other count fields (nullable bigint), which is appropriate for aggregated count data that may be null when no records exist.


9-21: LGTM - Improved formatting consistency.

The removal of unnecessary parentheses and semicolons improves code consistency and readability while maintaining the same type definitions.

apps/backend/prisma/sql/countDbSize.sql (3)

82-82: LGTM - Consistent integration with existing size calculation.

The webhook log count and size calculations are properly integrated:

  • Count is included in the SELECT clause
  • Sizes are added to the total size calculation following the same pattern
  • All values are properly coalesced to handle null cases

Also applies to: 97-99


107-107: LGTM - Proper LEFT JOIN pattern.

The LEFT JOIN with webhook_log_storage follows the same pattern as other storage CTEs, ensuring organizations without webhook logs are still included in the results.


60-72: Verify webhook table schema and relationships.

The new CTE follows the established pattern, but ensure that:

  1. The WebhookLog and Webhook tables exist with the referenced fields
  2. The relationship between WebhookLog.webhookId and Webhook.id is properly defined
  3. The requestBody field casting to ::text is appropriate for its data type
#!/bin/bash
# Description: Verify webhook table schema in Prisma schema

# Check for Webhook and WebhookLog models in schema
rg -A 10 "model Webhook" apps/backend/prisma/schema.prisma
rg -A 10 "model WebhookLog" apps/backend/prisma/schema.prisma

# Check for the relationship fields
rg "webhookId.*Webhook" apps/backend/prisma/schema.prisma
apps/backend/prisma/client/sql/countDistinctRecipients.js (1)

1-6: LGTM: Formatting improvements in generated code.

The formatting changes improve code consistency by removing unnecessary whitespace and consolidating the export statement. While the static analysis tool flags the redundant "use strict" directive, this is generated code from Prisma, so direct modifications may be overwritten during regeneration.

apps/web/src/pages/dashboard/messages/message-id-cell.tsx (2)

12-18: Good component structure and error handling.

The component properly handles the null messageId case and implements clipboard functionality with user feedback. The TypeScript typing is correct and the null check prevents runtime errors.


24-54: Well-structured dialog implementation.

The dialog structure follows good accessibility patterns with proper header, content organization, and responsive design. The monospace font for message ID display and the copy button placement are user-friendly design choices.

apps/backend/prisma/client/sql/countDistinctRecipients.d.ts (1)

6-12: LGTM: Improved type declaration formatting.

The consolidation to a single-line arrow function type makes the declaration more concise while preserving all type information. The parameter and return types remain unchanged, maintaining API compatibility.

apps/backend/src/utils/message-id.test.ts (1)

4-78: Excellent test coverage with comprehensive edge cases.

The test suite thoroughly covers the stripAngleBrackets function with well-named test cases that include:

  • Normal cases with both brackets
  • Edge cases with single brackets
  • Empty strings and bracket-only strings
  • Complex message ID formats with timestamps and UUIDs
  • Multiple consecutive brackets

The test structure follows good practices with descriptive test names and clear assertions.

apps/backend/src/cron/cleanupWebhookLogs.ts (1)

5-54: Well-structured cron job with appropriate error handling.

The webhook log cleanup logic is sound with proper organization-specific cleanup intervals and comprehensive logging. The database query correctly filters by organization and creation date.

apps/backend/prisma/client/sql/countDbSize.js (1)

6-6: Well-structured webhook log storage calculation.

The SQL logic correctly adds webhook log metrics to the database size calculation. The CTE properly joins WebhookLog and Webhook tables, handles null values with COALESCE, and includes all relevant size calculations (request body, response body, error messages).

apps/backend/prisma/client/sql/countDbSize.mjs (1)

5-5: Consistent implementation across module formats.

The ESM version correctly mirrors the CommonJS implementation with identical SQL logic for webhook log storage calculation.

apps/backend/prisma/client/sql/countDbSize.edge.js (1)

6-6: Edge runtime implementation maintains consistency.

The edge runtime version correctly implements the same webhook log storage calculations with appropriate runtime-specific imports.

apps/backend/prisma/client/sql/countDbSize.edge.mjs (1)

5-5: Complete coverage across runtime and module formats.

All four generated client variants now consistently include webhook log storage calculations, ensuring proper database size metrics regardless of the runtime environment.

apps/docs/src/app/webhooks/page.mdx (4)

58-67: Well-documented runtime limits enhance security and stability.

The sandboxed execution environment with configurable limits (timeout, memory, stack size) provides good protection against resource exhaustion and malicious code execution.


70-82: Clear transform function specification.

The example provides a good template for users implementing transform functions. The required/optional field specification is helpful for proper integration.


99-107: Comprehensive SMTP provider coverage.

The documentation covers major SMTP providers and explains the necessity of transform functions due to varying payload formats. This will help users understand the integration requirements.


129-137: Complete HTTP status code reference.

The response codes are well-documented and cover all the expected scenarios, helping developers debug webhook integration issues.

apps/web/src/pages/dashboard/settings/webhook-settings.tsx (4)

42-49: Good implementation of conditional data fetching.

The webhook list query is properly disabled when organization ID is not available, preventing unnecessary API calls and potential errors.


53-84: Excellent mutation handling with proper error management.

The mutations include comprehensive success/error handling with user feedback through toast notifications and proper cache invalidation to keep the UI in sync.


171-192: Well-implemented loading and empty states.

The loading indicator and empty state provide excellent user experience with clear messaging about the webhook functionality and SMTP server integration.


245-292: Smart use of React keys for dialog re-rendering.

Using unique keys (edit-${webhook.id} and form-${webhook.id}) ensures proper component re-mounting when switching between different webhooks for editing, preventing stale form state.

@dcodesdev dcodesdev added the enhancement New feature or request label Jun 21, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
apps/backend/prisma/seed.ts (2)

177-177: Remove redundant fallback operator.

The || undefined is redundant since transformedPayload is already null when falsy.

-      transformedPayload: transformedPayload || undefined,
+      transformedPayload,

122-131: Consider extracting hardcoded test data to constants.

The hardcoded arrays for events, providers, and status codes could be extracted to constants for better maintainability and reusability.

+const TEST_WEBHOOK_EVENTS = [
+  "delivered",
+  "bounced", 
+  "complained",
+  "opened",
+  "clicked",
+  "failed",
+] as const
+
+const TEST_PROVIDERS = ["ses", "sendgrid", "postmark", "mailgun", "resend"] as const
+const TEST_STATUS_CODES = [200, 201, 400, 401, 404, 500, 502, 503] as const
+
-  const events = [
-    "delivered",
-    "bounced",
-    "complained", 
-    "opened",
-    "clicked",
-    "failed",
-  ]
-  const providers = ["ses", "sendgrid", "postmark", "mailgun", "resend"]
-  const statusCodes = [200, 201, 400, 401, 404, 500, 502, 503]
+  const events = TEST_WEBHOOK_EVENTS
+  const providers = TEST_PROVIDERS  
+  const statusCodes = TEST_STATUS_CODES
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2d9f8ec and b7e9c6a.

📒 Files selected for processing (1)
  • apps/backend/prisma/seed.ts (2 hunks)
🔇 Additional comments (3)
apps/backend/prisma/seed.ts (3)

3-3: LGTM: Type import addition is appropriate.

The addition of type Prisma import supports the new webhook log type annotations.


91-118: Webhook creation looks good with proper upsert pattern.

The webhook creation follows good practices with upsert to prevent duplicates and includes realistic test code for authorization and transformation logic.


207-213: LGTM: Batch insertion is a good performance optimization.

Using batch insertion with a reasonable batch size of 50 prevents potential memory issues and improves performance when creating large amounts of test data.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
todo.md (3)

1-1: Use consistent pluralization for to-dos heading.

Consider changing “# Todos” to “# To-dos” or “# TODOs” for grammatical accuracy and alignment with common conventions.


5-5: Clarify the instruction sentence.

The phrase “Anything in this list, do not touch them or do them.” is awkward. For clarity and readability, rephrase to something like:

  • “Items in this list are postponed—do not modify or implement them now.”

10-11: Add placeholder for empty Bugs section.

The “## Bugs” section is currently empty. If there are no known bugs yet, consider adding a placeholder like “- No bugs identified at this time” to indicate intent.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b7e9c6a and c0bd0af.

📒 Files selected for processing (11)
  • apps/docs/src/app/getting-started/configuration/page.mdx (1 hunks)
  • apps/docs/src/app/getting-started/page.mdx (1 hunks)
  • apps/web/src/components/index.ts (1 hunks)
  • apps/web/src/components/webhook-url-display.tsx (1 hunks)
  • apps/web/src/hooks/useSession.ts (1 hunks)
  • apps/web/src/pages/dashboard/settings/webhook-details.tsx (1 hunks)
  • apps/web/src/pages/dashboard/settings/webhook-settings.tsx (3 hunks)
  • docker-compose.node.yaml (1 hunks)
  • docker-compose.yaml (1 hunks)
  • package.json (2 hunks)
  • todo.md (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • apps/docs/src/app/getting-started/page.mdx
  • docker-compose.yaml
  • apps/web/src/pages/dashboard/settings/webhook-details.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • package.json
  • apps/docs/src/app/getting-started/configuration/page.mdx
  • apps/web/src/pages/dashboard/settings/webhook-settings.tsx
🧰 Additional context used
🪛 LanguageTool
todo.md

[grammar] ~1-~1: It appears that a hyphen is missing in the plural noun “to-dos”?
Context: # Todos ## For later Anything in this list, d...

(TO_DO_HYPHEN)

🔇 Additional comments (5)
docker-compose.node.yaml (1)

26-26: Explicitly set NODE_ENV to production
Adding NODE_ENV: production aligns the container behavior with best practices for a production environment and matches other compose files.

apps/web/src/hooks/useSession.ts (1)

9-12: Good performance optimization for user session data.

The addition of staleTime and disabling refetchOnWindowFocus are sensible optimizations for user session data that doesn't change frequently. This will reduce unnecessary network requests while maintaining data freshness.

apps/web/src/components/webhook-url-display.tsx (2)

18-21: Clever debounced copy confirmation logic.

The use of a counter with debounced value to show copy confirmation is an interesting approach. This works well to provide temporary visual feedback without additional timers or effects.


32-62: Well-structured variant handling.

The component properly separates the two variants with clear visual distinctions and appropriate sizing. The conditional rendering is clean and the styling is consistent between variants.

Also applies to: 64-93

apps/web/src/components/index.ts (1)

16-18: Consistent export additions for webhook components.

The new exports follow the established pattern and correctly expose the webhook-related components for use throughout the application.

Comment on lines +27 to +30
const handleCopyUrl = async () => {
await navigator.clipboard.writeText(url)
setCopyTriggered((prev) => prev + 1)
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for clipboard API.

The navigator.clipboard.writeText call should include error handling as the clipboard API can fail in certain contexts (e.g., non-HTTPS environments, permission denied).

  const handleCopyUrl = async () => {
-   await navigator.clipboard.writeText(url)
-   setCopyTriggered((prev) => prev + 1)
+   try {
+     await navigator.clipboard.writeText(url)
+     setCopyTriggered((prev) => prev + 1)
+   } catch (error) {
+     console.error('Failed to copy to clipboard:', error)
+     // Could show a toast notification or fallback behavior
+   }
  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleCopyUrl = async () => {
await navigator.clipboard.writeText(url)
setCopyTriggered((prev) => prev + 1)
}
const handleCopyUrl = async () => {
try {
await navigator.clipboard.writeText(url)
setCopyTriggered((prev) => prev + 1)
} catch (error) {
console.error('Failed to copy to clipboard:', error)
// Could show a toast notification or fallback behavior
}
}
🤖 Prompt for AI Agents
In apps/web/src/components/webhook-url-display.tsx around lines 27 to 30, the
clipboard writeText call lacks error handling, which can cause unhandled promise
rejections if the clipboard API fails. Wrap the await
navigator.clipboard.writeText(url) call in a try-catch block and handle errors
gracefully, such as logging the error or showing a user-friendly message, to
ensure the app remains stable in failure scenarios.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/shared/webhook-events-data.ts (1)

4-4: Consider using a union type for better type safety.

The status field could be more type-safe by using a union type instead of a generic string.

+export type WebhookEventStatus = 'PENDING' | 'SENT' | 'OPENED' | 'CLICKED' | 'FAILED' | 'COMPLAINED'

export interface WebhookEvent {
  name: string
  aliases: string[]
-  status: string
+  status: WebhookEventStatus
  description: string
}
apps/docs/src/app/webhooks/page.mdx (1)

99-106: Consider adding setup links for SMTP providers.

While the provider list is comprehensive, adding direct links to each provider's webhook configuration documentation would enhance user experience.

- **SendGrid**: Configure the webhook URL in your SendGrid Event Webhook settings
+ **SendGrid**: Configure the webhook URL in your [SendGrid Event Webhook settings](https://docs.sendgrid.com/for-developers/tracking-events/getting-started-event-webhook)
- **Mailgun**: Set up the webhook URL in your Mailgun webhook configuration  
+ **Mailgun**: Set up the webhook URL in your [Mailgun webhook configuration](https://documentation.mailgun.com/en/latest/user_manual.html#webhooks)

And similar for other providers.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 73d4386 and e589ef9.

📒 Files selected for processing (4)
  • apps/backend/src/webhook/types.ts (1 hunks)
  • apps/docs/src/app/webhooks/page.mdx (1 hunks)
  • apps/web/src/components/webhook-events-reference.tsx (1 hunks)
  • packages/shared/webhook-events-data.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/src/components/webhook-events-reference.tsx
  • apps/backend/src/webhook/types.ts
🧰 Additional context used
🪛 LanguageTool
apps/docs/src/app/webhooks/page.mdx

[uncategorized] ~49-~49: Loose punctuation mark.
Context: ...``` The function receives: - headers: Request headers object - `body`: Reques...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~86-~86: Loose punctuation mark.
Context: ...``` The function receives: - payload: The raw webhook payload sent by your SM...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~94-~94: Loose punctuation mark.
Context: ...rm function must include: - messageId: The external message ID provided by you...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~99-~99: Possible missing comma found.
Context: ... webhook system works with popular SMTP providers including: - SendGrid: Configure t...

(AI_HYDRA_LEO_MISSING_COMMA)

🔇 Additional comments (7)
packages/shared/webhook-events-data.ts (2)

1-6: Well-structured interface design.

The WebhookEvent interface is clean and covers all necessary fields for webhook event metadata.


8-45: Comprehensive webhook events coverage.

The webhook events array covers all essential email lifecycle states with appropriate aliases and clear descriptions. The status mappings are logical and consistent.

apps/docs/src/app/webhooks/page.mdx (5)

3-9: Excellent beta feature disclosure.

The prominent beta warning appropriately sets user expectations about potential API changes.


29-29: Critical security warning well-positioned.

The security warning about plain text storage of authentication code is appropriately prominent and helps users make informed decisions about sensitive data.


62-66: Well-documented runtime limits.

The runtime limits for the sandboxed environment are clearly specified with configurable environment variables, providing both security and flexibility.


119-127: Status mappings consistent with shared data.

The status table correctly reflects the webhook event mappings defined in packages/shared/webhook-events-data.ts, ensuring consistency across documentation and implementation.


134-174: Comprehensive transform function examples.

The examples effectively demonstrate real-world usage patterns for different SMTP providers, making the documentation actionable for users.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant