Skip to content

Comprehensive workflow reminder management for booking lifecycle events#6

Open
everettbu wants to merge 1 commit into
workflow-queue-basefrom
workflow-queue-enhanced
Open

Comprehensive workflow reminder management for booking lifecycle events#6
everettbu wants to merge 1 commit into
workflow-queue-basefrom
workflow-queue-enhanced

Conversation

@everettbu

@everettbu everettbu commented Jul 28, 2025

Copy link
Copy Markdown

Test 6

Summary by CodeRabbit

  • New Features

    • Added support for marking workflow reminders as cancelled without deleting them, including a new "cancelled" field in reminders.
    • Scheduled email reminders for cancelled or rescheduled bookings are now automatically cancelled if their send time is within the next hour.
  • Improvements

    • Enhanced cancellation logic for scheduled email and SMS reminders to ensure more reliable and flexible management.
    • Streamlined phone number verification UI for workflows, making the process clearer and more intuitive.
  • Bug Fixes

    • Fixed issues where reminders could be deleted from the database prematurely, improving reminder tracking and reliability.

…re still sent (#7232)

* small UI fix

* fix cancelling scheduled emails

* improve comments

* delete reminders for rescheduled bookings

* add migration file

* cancel rescheduled bookings immediately

* remove immediate delete for request reschedule

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
@coderabbitai

coderabbitai Bot commented Jul 28, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

This set of changes updates the handling of workflow reminders for bookings and workflows. Instead of deleting reminders from the database immediately, scheduled reminders are now cancelled via external APIs or marked as cancelled in the database. New logic is added for cancelling email reminders close to their scheduled time. The Prisma schema and migration are updated to support a new cancelled field on workflow reminders.

Changes

Cohort / File(s) Change Summary
Booking Cancellation & Rescheduling Logic
packages/features/bookings/lib/handleCancelBooking.ts, packages/features/bookings/lib/handleNewBooking.ts, packages/trpc/server/routers/viewer/bookings.tsx
Refactored cancellation of workflow reminders: now calls deletion/cancellation functions with reminder IDs and reference IDs, removes direct database deletion of reminders, and updates workflow reminder handling for rescheduling.
Workflow Reminder Deletion/Update Logic
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts, packages/features/ee/workflows/lib/reminders/smsReminderManager.ts, packages/trpc/server/routers/viewer/workflows.tsx
Updated reminder deletion functions to accept reminder IDs and reference IDs; email reminder logic now conditionally cancels via API or marks as cancelled in DB; SMS reminders are cancelled and deleted from DB. Viewer workflow router updated to use new deletion logic.
Email Reminder Scheduling & Cancellation
packages/features/ee/workflows/api/scheduleEmailReminders.ts
Added logic to cancel scheduled email reminders for bookings marked as cancelled/rescheduled within an hour of their scheduled time, including API cancellation and DB deletion.
Workflow Step UI
packages/features/ee/workflows/components/WorkflowStepContainer.tsx
Refactored phone number verification UI: consolidated logic, clarified conditional rendering, and improved error display.
Prisma Schema & Migration
packages/prisma/schema.prisma, packages/prisma/migrations/20230217230604_add_cancelled_to_workflow_reminder/migration.sql
Added nullable cancelled Boolean field to WorkflowReminder model and corresponding migration to update the database schema.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant App
    participant DB
    participant EmailAPI
    participant SMSAPI

    User->>App: Cancel booking or reschedule
    App->>DB: Fetch workflow reminders
    App->>EmailAPI: Cancel scheduled email (if referenceId)
    App->>SMSAPI: Cancel scheduled SMS (if referenceId)
    App->>DB: Mark reminder as cancelled or delete (based on type)
    App->>DB: Delete attendees, booking references
Loading
sequenceDiagram
    participant CronJob
    participant DB
    participant EmailAPI

    CronJob->>DB: Find reminders with cancelled=true, scheduledDate < 1h
    loop For each reminder
        CronJob->>EmailAPI: Cancel scheduled send (using referenceId)
        CronJob->>DB: Delete workflowReminder record
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~18 minutes

Poem

In the warren of reminders, a bunny takes care,
Cancelling emails and texts with a gentle, swift flair.
No more hasty deletions, just a mark—cancelled true,
While Prisma and APIs know just what to do.
🐇 The schema grows, the logic flows,
And bookings now hop with a smoother prose!

Note

⚡️ Unit Test Generation is now available in beta!

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

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch workflow-queue-enhanced

🪧 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.

@everettbu

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 28, 2025

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 235ec0e and 2ebfcf4.

📒 Files selected for processing (10)
  • packages/features/bookings/lib/handleCancelBooking.ts (1 hunks)
  • packages/features/bookings/lib/handleNewBooking.ts (4 hunks)
  • packages/features/ee/workflows/api/scheduleEmailReminders.ts (2 hunks)
  • packages/features/ee/workflows/components/WorkflowStepContainer.tsx (1 hunks)
  • packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (1 hunks)
  • packages/features/ee/workflows/lib/reminders/smsReminderManager.ts (1 hunks)
  • packages/prisma/migrations/20230217230604_add_cancelled_to_workflow_reminder/migration.sql (1 hunks)
  • packages/prisma/schema.prisma (1 hunks)
  • packages/trpc/server/routers/viewer/bookings.tsx (1 hunks)
  • packages/trpc/server/routers/viewer/workflows.tsx (6 hunks)
🔇 Additional comments (19)
packages/prisma/migrations/20230217230604_add_cancelled_to_workflow_reminder/migration.sql (1)

1-2: LGTM! Clean and safe migration.

The migration correctly adds a nullable boolean column for the cancelled state without affecting existing data.

packages/prisma/schema.prisma (1)

644-644: LGTM! Schema change aligns with migration.

The nullable boolean field correctly supports the new cancellation state management for workflow reminders.

packages/features/ee/workflows/lib/reminders/smsReminderManager.ts (1)

177-190: LGTM! Improved separation of concerns.

The updated function signature and logic properly separate external API cancellation (conditional on referenceId) from database deletion (using reminderId). This makes the cancellation process more robust and handles edge cases where external references might not exist.

packages/features/bookings/lib/handleNewBooking.ts (3)

1-41: LGTM! Import updates align with function signature changes.

The imports correctly include WorkflowMethods and the updated reminder deletion functions that now accept both id and referenceId parameters.


772-772: LGTM! Necessary relation added for reminder cancellation.

Adding workflowReminders: true to the query is required to access reminder data for the new cancellation logic.


964-975: LGTM! Proper reminder cancellation for rescheduled bookings.

The new logic correctly:

  • Iterates over workflow reminders from the original booking
  • Calls the appropriate deletion function based on reminder method
  • Passes both id and referenceId as required by the updated function signatures
  • Handles errors gracefully without disrupting the rescheduling process

The placement before existing rescheduling logic ensures reminders are cancelled before creating new ones.

packages/features/ee/workflows/api/scheduleEmailReminders.ts (1)

10-10: LGTM! Necessary import for new cancellation logic.

The additional imports are required for the new reminder cancellation functionality.

packages/features/ee/workflows/components/WorkflowStepContainer.tsx (1)

390-461: LGTM! Clean UI refactor for phone verification workflow.

The conditional rendering logic has been well-simplified to provide clearer states for phone number verification. The refactor eliminates duplication and provides a more intuitive user experience with explicit verified/unverified states.

packages/trpc/server/routers/viewer/bookings.tsx (2)

484-484: Accurate comment update for reschedule context.

The comment change from "delete scheduled jobs of cancelled bookings" to "delete scheduled jobs of previous booking" better reflects the reschedule scenario where we're handling the previous booking's scheduled jobs.


487-494: Improved workflow reminder cancellation approach.

The changes align well with the comprehensive workflow reminder management approach:

  • Removed conditional checks for scheduled and referenceId to ensure all reminders are processed
  • Now calling deletion functions with both id and referenceId parameters as required by the updated API
  • This supports the new pattern of cancelling scheduled reminders via external APIs rather than immediate database deletion

The approach provides better reliability by ensuring all workflow reminders are properly cancelled during reschedule operations.

packages/features/bookings/lib/handleCancelBooking.ts (2)

484-493: Consistent workflow reminder cancellation implementation.

The changes properly implement the new workflow reminder management approach:

  • Removed conditional checks to ensure all reminders are processed consistently
  • Updated to call deletion functions with both id and referenceId parameters
  • Eliminates immediate database deletion in favor of external API cancellation

This aligns well with the broader changes across the codebase for comprehensive workflow reminder management.


495-495: Simplified batch operations after reminder management changes.

The removal of remindersToDelete from the prismaPromises array correctly reflects that workflow reminders are no longer immediately deleted from the database during cancellation. The batch now focuses only on attendee and booking reference cleanup, which is appropriate for the new reminder cancellation approach.

packages/trpc/server/routers/viewer/workflows.tsx (6)

2-2: LGTM! Import organization improved.

The reordering of Prisma-related imports improves code organization by grouping related imports together.

Also applies to: 9-9


211-217: LGTM! Updated to use new cancellation strategy.

The code now properly cancels workflow reminders using the updated deletion functions with both reminder ID and reference ID parameters, aligning with the new cancellation approach instead of direct database deletion.


375-382: LGTM! Consistent cancellation logic for disabled event types.

The reminder cancellation logic for event types that are no longer active follows the same pattern as other cancellation scenarios, properly passing both reminder ID and reference ID to the cancellation functions.


517-525: LGTM! Proper immediate cancellation for deleted steps.

The reminder cancellation logic for deleted workflow steps correctly uses immediate cancellation (immediateDelete=true) for email reminders, which is appropriate when steps are permanently removed.


572-580: LGTM! Appropriate cancellation strategy for edited steps.

The reminder cancellation logic for edited workflow steps uses the database marking approach (without immediateDelete), which is suitable since new reminders will be created for the updated step configuration.


904-943: LGTM! Formatting improvements in commented test code.

The formatting changes in the commented test action code improve consistency and readability, even though this code is currently disabled.

packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (1)

197-236: deleteScheduledEmailReminder Implementation Approved

The function cleanly handles all three cancellation scenarios:

  • No referenceId: removes the reminder directly from the database
  • immediateDelete=true: issues a Sendgrid cancellation request
  • Default: flags the reminder as cancelled for deferred cleanup

Verification confirmed that the WorkflowReminder model in packages/prisma/schema.prisma includes the nullable cancelled Boolean field:

model WorkflowReminder {
  id             Int             @id @default(autoincrement())

  cancelled      Boolean?
}

No further changes are required—approving these updates.

Comment on lines +43 to +77
//cancel reminders for cancelled/rescheduled bookings that are scheduled within the next hour
const remindersToCancel = await prisma.workflowReminder.findMany({
where: {
cancelled: true,
scheduledDate: {
lte: dayjs().add(1, "hour").toISOString(),
},
},
});

try {
const workflowRemindersToDelete: Prisma.Prisma__WorkflowReminderClient<WorkflowReminder, never>[] = [];

for (const reminder of remindersToCancel) {
await client.request({
url: "/v3/user/scheduled_sends",
method: "POST",
body: {
batch_id: reminder.referenceId,
status: "cancel",
},
});

const workflowReminderToDelete = prisma.workflowReminder.delete({
where: {
id: reminder.id,
},
});

workflowRemindersToDelete.push(workflowReminderToDelete);
}
await Promise.all(workflowRemindersToDelete);
} catch (error) {
console.log(`Error cancelling scheduled Emails: ${error}`);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add null check for referenceId before API cancellation.

The cancellation logic is well-structured, but there's a potential issue: reminder.referenceId could be null, but it's used directly as batch_id in the SendGrid API call without validation.

Apply this diff to add proper null checking:

    for (const reminder of remindersToCancel) {
-     await client.request({
-       url: "/v3/user/scheduled_sends",
-       method: "POST",
-       body: {
-         batch_id: reminder.referenceId,
-         status: "cancel",
-       },
-     });
+     if (reminder.referenceId) {
+       await client.request({
+         url: "/v3/user/scheduled_sends",
+         method: "POST",
+         body: {
+           batch_id: reminder.referenceId,
+           status: "cancel",
+         },
+       });
+     }

This ensures we only attempt API cancellation when a referenceId exists, which aligns with the pattern used in the SMS reminder manager.

📝 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
//cancel reminders for cancelled/rescheduled bookings that are scheduled within the next hour
const remindersToCancel = await prisma.workflowReminder.findMany({
where: {
cancelled: true,
scheduledDate: {
lte: dayjs().add(1, "hour").toISOString(),
},
},
});
try {
const workflowRemindersToDelete: Prisma.Prisma__WorkflowReminderClient<WorkflowReminder, never>[] = [];
for (const reminder of remindersToCancel) {
await client.request({
url: "/v3/user/scheduled_sends",
method: "POST",
body: {
batch_id: reminder.referenceId,
status: "cancel",
},
});
const workflowReminderToDelete = prisma.workflowReminder.delete({
where: {
id: reminder.id,
},
});
workflowRemindersToDelete.push(workflowReminderToDelete);
}
await Promise.all(workflowRemindersToDelete);
} catch (error) {
console.log(`Error cancelling scheduled Emails: ${error}`);
}
//cancel reminders for cancelled/rescheduled bookings that are scheduled within the next hour
const remindersToCancel = await prisma.workflowReminder.findMany({
where: {
cancelled: true,
scheduledDate: {
lte: dayjs().add(1, "hour").toISOString(),
},
},
});
try {
const workflowRemindersToDelete: Prisma.Prisma__WorkflowReminderClient<WorkflowReminder, never>[] = [];
for (const reminder of remindersToCancel) {
if (reminder.referenceId) {
await client.request({
url: "/v3/user/scheduled_sends",
method: "POST",
body: {
batch_id: reminder.referenceId,
status: "cancel",
},
});
}
const workflowReminderToDelete = prisma.workflowReminder.delete({
where: {
id: reminder.id,
},
});
workflowRemindersToDelete.push(workflowReminderToDelete);
}
await Promise.all(workflowRemindersToDelete);
} catch (error) {
console.log(`Error cancelling scheduled Emails: ${error}`);
}
🤖 Prompt for AI Agents
In packages/features/ee/workflows/api/scheduleEmailReminders.ts between lines 43
and 77, the code uses reminder.referenceId directly in the API call without
checking if it is null. To fix this, add a null check for reminder.referenceId
before making the API request to cancel the scheduled send. Only proceed with
the cancellation API call and deletion if referenceId is not null, ensuring the
code does not attempt to cancel with an invalid batch_id.

@github-actions

Copy link
Copy Markdown
Contributor

This PR is being marked as stale due to inactivity.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants