Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@devkiran
Copy link
Collaborator

@devkiran devkiran commented May 30, 2025

Summary by CodeRabbit

  • New Features
    • Introduced a new monthly email reminder for program owners about pending payouts, including a tailored email template with payout details and a direct link for confirmation.
  • Improvements
    • Clarified the partner payout reminder endpoint to specifically target partners.
    • Updated scheduling for cron jobs to reflect the new and renamed endpoints.
    • Added feature gating to minimum payout settings and save actions, restricting customization to enterprise plan users with upgrade prompts.
    • Enforced minimum payout amount constraints for non-enterprise plans during program updates.

@vercel
Copy link
Contributor

vercel bot commented May 30, 2025

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

Name Status Preview Updated (UTC)
dub ✅ Ready (Inspect) Visit Preview Jun 4, 2025 5:05pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 30, 2025

Walkthrough

A new API route for sending program owner payout reminders was added, along with a corresponding React email template. The existing partner payout reminder route and its cron schedule were updated to use a more specific path. The Vercel cron configuration now includes both routes with distinct schedules. Additionally, UI and backend logic enforce enterprise-only customization of minimum payout amounts.

Changes

File(s) Change Summary
apps/web/app/(ee)/api/cron/payouts/reminders/partners/route.ts Updated route path and comment to specify "partners" payout reminders.
apps/web/app/(ee)/api/cron/payouts/reminders/program-owners/route.ts Added new GET API route for sending program owner payout reminders with email scheduling logic.
apps/web/vercel.json Renamed existing cron job path for partners and added a new cron job for program owners.
packages/email/src/templates/program-payout-reminder.tsx Introduced new React email template for program payout reminders, including stats and CTA.
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/programs/[programId]/settings/rewards/settings.tsx Added UI feature gating for minimum payout amount input and save button based on workspace plan.
apps/web/lib/actions/partners/update-program.ts Enforced minimum payout amount override for non-enterprise plans during program updates.

Sequence Diagram(s)

sequenceDiagram
    participant Cron as Vercel Cron
    participant API as /api/cron/payouts/reminders/program-owners
    participant DB as Database
    participant Email as Email Service

    Cron->>API: Trigger GET /program-owners
    API->>API: Verify Vercel signature
    API->>DB: Query pending payouts grouped by program
    alt No pending payouts
        API-->>Cron: Respond with "no action needed"
    else Pending payouts exist
        API->>DB: Fetch program and owner details
        loop For each program owner
            API->>Email: Send payout reminder email
        end
        API-->>Cron: Respond with count of reminders sent
    end
Loading

Suggested reviewers

  • devkiran

Poem

A new reminder hops along,
To program owners, swift and strong.
Partners’ path now clear and bright,
Cron jobs scheduled, emails in flight.
With stats and links, the message is sent—
Another payout nudge, well-spent!
🐇💌


📜 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 086218f and b17df72.

📒 Files selected for processing (1)
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/programs/[programId]/settings/rewards/settings.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/programs/[programId]/settings/rewards/settings.tsx
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
✨ Finishing Touches
  • 📝 Generate Docstrings

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

@devkiran devkiran marked this pull request as ready for review May 30, 2025 09:56
@devkiran devkiran requested a review from steven-tey May 30, 2025 09:57
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (5)
packages/email/src/templates/program-payout-reminder.tsx (3)

19-21: Address the TODO comment about missing icons.

The TODO comment indicates that icons for the Stats component need to be fixed. Currently, empty strings are passed as icon props, which will result in broken image elements.

Would you like me to suggest appropriate icons for "Pending payouts" and "Partners" stats, or help implement a fallback mechanism when icons are not provided?


22-48: Consider using more production-appropriate default values.

The default values contain potentially sensitive information like email addresses and specific IDs that appear to be from a development environment.

Consider using more generic or clearly placeholder default values:

-  email = "[email protected]",
+  email = "[email protected]",
-  workspace = {
-    slug: "acme",
-  },
+  workspace = {
+    slug: "example-workspace",
+  },
-  program = {
-    id: "prog_CYCu7IMAapjkRpTnr8F1azjN",
-    name: "Acme",
-  },
+  program = {
+    id: "prog_example_id",
+    name: "Example Program",
+  },

65-67: Fix grammatical error in the email text.

There's a grammatical error in the descriptive text.

Apply this fix:

-              There are payouts ready to be paid out. Completing these on time
-              keep your program running smooth and your partners happy.
+              There are payouts ready to be paid out. Completing these on time
+              keeps your program running smoothly and your partners happy.
apps/web/app/(ee)/api/cron/payouts/reminders/program-owners/route.ts (2)

11-13: Fix misleading comment about schedule timing.

The comment states the route "Runs a week before the end of the month", but the corresponding cron job in vercel.json shows it runs daily at 09:00.

Update the comment to match the actual schedule:

-// This route is used to send reminders to program owners about pending payouts
-// Runs a week before the end of the month
-// GET /api/cron/payouts/reminders/program-owners
+// This route is used to send reminders to program owners about pending payouts
+// Runs daily at 09:00
+// GET /api/cron/payouts/reminders/program-owners

111-111: Consider improving the return message for better observability.

The current return message only shows the count of programs but doesn't indicate how many individual emails were sent (since programs can have multiple owners).

Consider returning more detailed information:

-    return NextResponse.json(`Sent reminders for ${programs.length} programs.`);
+    return NextResponse.json(`Sent reminders for ${programs.length} programs to ${programsWithPayouts.length} program owners.`);
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 67b1fdc and fd13686.

📒 Files selected for processing (4)
  • apps/web/app/(ee)/api/cron/payouts/reminders/partners/route.ts (1 hunks)
  • apps/web/app/(ee)/api/cron/payouts/reminders/program-owners/route.ts (1 hunks)
  • apps/web/vercel.json (1 hunks)
  • packages/email/src/templates/program-payout-reminder.tsx (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
apps/web/app/(ee)/api/cron/payouts/reminders/program-owners/route.ts (2)
apps/web/app/(ee)/api/cron/payouts/reminders/partners/route.ts (2)
  • dynamic (9-9)
  • GET (15-138)
packages/email/src/templates/program-payout-reminder.tsx (1)
  • ProgramPayoutReminder (22-106)
packages/email/src/templates/program-payout-reminder.tsx (2)
packages/utils/src/constants/main.ts (1)
  • DUB_WORDMARK (68-68)
packages/ui/src/footer.tsx (1)
  • Footer (85-310)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (7)
packages/email/src/templates/program-payout-reminder.tsx (1)

100-100:

Details

❌ Incorrect review comment

Verify Footer component prop compatibility.

The Footer component is receiving an email prop, but based on the relevant code snippet from packages/ui/src/footer.tsx, the Footer component expects staticDomain and className props, not an email prop.

Let me verify the Footer component interface to ensure compatibility:


🏁 Script executed:

#!/bin/bash
# Description: Check the Footer component interface in the email package

# Find the Footer component in the email package
fd -t f "footer" packages/email/src/components/

# Look for the Footer component implementation
ast-grep --pattern 'export $_ Footer($_) {
  $$$
}'

Length of output: 142


#!/bin/bash
set -e

echo "=== Email Package: Footer Component ==="
echo ""
echo "-- Searching for FooterProps interface in packages/email/src/components/footer.tsx --"
rg -n "interface FooterProps" packages/email/src/components/footer.tsx || true

echo ""
echo "-- Searching for Footer definition in packages/email/src/components/footer.tsx --"
rg -n -C3 "export (const|function) Footer" packages/email/src/components/footer.tsx || true

echo ""
echo "=== UI Package: Footer Component ==="
echo ""
echo "-- Searching for FooterProps interface in packages/ui/src/footer.tsx --"
rg -n "interface FooterProps" packages/ui/src/footer.tsx || true

echo ""
echo "-- Searching for Footer definition in packages/ui/src/footer.tsx --"
rg -n -C3 "export (const|function) Footer" packages/ui/src/footer.tsx || true

#!/bin/bash
set -e

echo "=== Checking Footer import in the email template ==="
rg -n "import.*Footer" packages/email/src/templates/program-payout-reminder.tsx || true

echo ""
echo "=== Inspecting Footer component in email package ==="
rg -n -C3 "export (const|function) Footer" packages/email/src/components/footer.tsx || true
rg -n -C3 "interface FooterProps" packages/email/src/components/footer.tsx || true

#!/bin/bash
set -e

echo "=== Email Package: Footer Component ==="
rg -n -C3 "export (const|function) Footer" packages/email/src/components/footer.tsx || true
rg -n "interface FooterProps" packages/email/src/components/footer.tsx || true

echo ""
echo "=== UI Package: Footer Component ==="
rg -n -C3 "export (const|function) Footer" packages/ui/src/footer.tsx || true
rg -n "interface FooterProps" packages/ui/src/footer.tsx || true
rg -n "staticDomain" packages/ui/src/footer.tsx || true
rg -n "className" packages/ui/src/footer.tsx || true

#!/bin/bash
set -e

echo "=== Email package: Footer component details ==="
rg -n "interface FooterProps" packages/email/src/components/footer.tsx || true
rg -n -C3 "export (const|function) Footer" packages/email/src/components/footer.tsx || true

echo ""
echo "=== UI package: Footer component details ==="
rg -n "interface FooterProps" packages/ui/src/footer.tsx || true
rg -n -C3 "export (const|function) Footer" packages/ui/src/footer.tsx || true

Ignore incorrect Footer prop comment

It looks like in packages/email/src/templates/program-payout-reminder.tsx the <Footer /> you’re using is the one defined in packages/email/src/components/footer.tsx, which declares its own props (including email), not the UI package’s Footer. Passing email here is valid—no changes needed.

Likely an incorrect or invalid review comment.

apps/web/vercel.json (1)

36-42: LGTM! Cron job organization improves clarity.

The separation of partner and program owner reminder jobs with distinct paths and schedules is well-structured:

  • Partners: 14:00 (2 PM) daily
  • Program owners: 09:00 (9 AM) daily

This allows for different timing strategies and better organization of reminder functionality.

apps/web/app/(ee)/api/cron/payouts/reminders/partners/route.ts (1)

11-14: LGTM! Path update improves API organization.

The route path update from /api/cron/payouts/reminders to /api/cron/payouts/reminders/partners clearly indicates this endpoint's specific purpose for partner reminders, distinguishing it from the new program owner reminders.

apps/web/app/(ee)/api/cron/payouts/reminders/program-owners/route.ts (4)

18-33: LGTM! Query logic is efficient and correct.

The database query appropriately:

  • Groups payouts by program ID
  • Filters for pending status only
  • Aggregates total amount and count
  • Returns early if no pending payouts exist

35-65: LGTM! Program and workspace data fetching is well-structured.

The query efficiently:

  • Fetches only required programs
  • Includes workspace and owner user data in a single query
  • Filters for owner role users only
  • Returns early if no programs found

69-91: LGTM! Data transformation logic is clean and efficient.

The mapping logic effectively:

  • Creates a lookup map for payouts
  • Flattens the structure to handle multiple owners per workspace
  • Combines all necessary data for email sending
  • Handles optional payout data with fallbacks

93-109: LGTM! Email sending implementation follows established patterns.

The email sending logic:

  • Uses rate limiting for API protection
  • Follows the same pattern as the partner reminders route
  • Passes all required props to the email template
  • Uses appropriate subject line and variant

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

♻️ Duplicate comments (1)
packages/email/src/templates/program-payout-reminder.tsx (1)

74-74: Empty icon strings will cause broken image requests.

The Stats components are being passed empty strings for the icon prop, which will result in broken image requests in the rendered email.

This is the same issue previously identified in the past review comments about handling empty icons gracefully in the Stats component.

Also applies to: 85-85

🧹 Nitpick comments (2)
packages/email/src/templates/program-payout-reminder.tsx (2)

19-21: Address the TODO comment for icons.

The TODO comment indicates incomplete work regarding icon implementation for the Stats component.

Would you like me to help implement appropriate icons for the "Pending payouts" and "Partners" statistics, or should this be tracked in a separate issue?


65-67: Fix grammatical error in the description text.

There's a subject-verb agreement error in the text.

Apply this diff to fix the grammatical error:

-              There are payouts ready to be paid out. Completing these on time
-              keep your program running smooth and your partners happy.
+              There are payouts ready to be paid out. Completing these on time
+              keeps your program running smooth and your partners happy.
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 28fa02e and 64c55dc.

📒 Files selected for processing (2)
  • apps/web/app/(ee)/api/cron/payouts/reminders/program-owners/route.ts (1 hunks)
  • packages/email/src/templates/program-payout-reminder.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/app/(ee)/api/cron/payouts/reminders/program-owners/route.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/email/src/templates/program-payout-reminder.tsx (2)
packages/utils/src/constants/main.ts (1)
  • DUB_WORDMARK (68-68)
packages/ui/src/footer.tsx (1)
  • Footer (85-310)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (2)
packages/email/src/templates/program-payout-reminder.tsx (2)

22-48: LGTM! Well-structured component props and defaults.

The component props are well-typed with clear documentation, and the default values provide a good example for development and testing purposes. The payout amount being documented as "in cents" is particularly helpful.


93-93:

Details

❓ Verification inconclusive

Verify the app URL construction for the payout confirmation page.

The hardcoded URL construction should be validated to ensure it matches the actual routing structure in the application.


🏁 Script executed:

#!/bin/bash
# Description: Verify the app routing structure matches the URL pattern used in the email template
# Expected: Find routes that match /programs/:id/payouts pattern

# Search for program payout routes
rg -A 5 -B 5 "programs.*payouts" --type tsx --type ts

# Search for the specific query parameters used
rg "status=pending.*sortBy=amount.*confirmPayouts" --type tsx --type ts

Length of output: 185


Verify the email template URL against client routes

Ensure that the hardcoded link in the email matches the actual routing path and query parameters in your application’s router.

• File: packages/email/src/templates/program-payout-reminder.tsx
• Line: 93
• Snippet:

href={`https://app.dub.co/${workspace.slug}/programs/${program.id}/payouts?status=pending&sortBy=amount&confirmPayouts=true`}

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/programs/[programId]/settings/rewards/settings.tsx (1)

59-59: Consider renaming the boolean variable for clarity.

The variable name isEnterpriseFeature is somewhat confusing since it's true when the feature should be restricted (for non-enterprise users). Consider a clearer name like shouldRestrictFeature or isNonEnterpriseUser.

-  const isEnterpriseFeature = plan !== "enterprise";
+  const shouldRestrictFeature = plan !== "enterprise";
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5c68bc7 and 0e0cfff.

📒 Files selected for processing (3)
  • apps/web/app/(ee)/api/cron/payouts/reminders/program-owners/route.ts (1 hunks)
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/programs/[programId]/settings/rewards/settings.tsx (5 hunks)
  • apps/web/lib/actions/partners/update-program.ts (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/web/app/(ee)/api/cron/payouts/reminders/program-owners/route.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (5)
apps/web/lib/actions/partners/update-program.ts (2)

5-5: Good addition of the constant import.

The import is correctly placed and will be used for the conditional logic below.


93-96: Excellent server-side enforcement of enterprise-only feature.

The conditional logic properly ensures that only enterprise users can customize the minimum payout amount, while non-enterprise users are restricted to the default constant. This provides defense-in-depth security even if frontend restrictions are bypassed.

apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/programs/[programId]/settings/rewards/settings.tsx (3)

10-10: Good addition of tooltip components.

The import is correctly structured for the enterprise feature gating implementation.


21-21: Proper extraction of workspace plan.

Extracting the plan from the workspace context is correct for the conditional logic.


167-177: Excellent UX implementation for enterprise restrictions.

The button disabling with tooltip provides clear feedback to users about why the feature is restricted and how to upgrade. The conditional props pattern is well-implemented.

@steven-tey steven-tey changed the base branch from main to fix-customer-discount June 4, 2025 05:02
Base automatically changed from fix-customer-discount to main June 4, 2025 05:29
@steven-tey
Copy link
Collaborator

@CodeRabbit final review pls

@steven-tey steven-tey requested a review from Copilot June 4, 2025 16:56
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 4, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

@steven-tey I'll conduct a comprehensive final review of this PR. Let me examine the key implementation files to ensure everything looks good.


🏁 Script executed:

#!/bin/bash
# Examine the new program owners route implementation
cat "apps/web/app/(ee)/api/cron/payouts/reminders/program-owners/route.ts"

Length of output: 5671


🏁 Script executed:

#!/bin/bash
# Check the email template implementation
cat "packages/email/src/templates/program-payout-reminder.tsx"

Length of output: 3897


🏁 Script executed:

#!/bin/bash
# Review the vercel.json cron configuration
cat "apps/web/vercel.json"

Length of output: 1101


🏁 Script executed:

#!/bin/bash
# Examine the UI changes for enterprise feature gating
cat "apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/programs/[programId]/settings/rewards/settings.tsx"

Length of output: 7359


🏁 Script executed:

#!/bin/bash
# Check the backend action changes
cat "apps/web/lib/actions/partners/update-program.ts"

Length of output: 3969


🏁 Script executed:

#!/bin/bash
# Look for any potential imports or constants being used
rg "DUB_MIN_PAYOUT_AMOUNT_CENTS" -A 2 -B 2

Length of output: 4698


🏁 Script executed:

#!/bin/bash
# Check if there are any TODO comments or potential issues
rg "TODO|FIXME|XXX|HACK" --type ts --type tsx

Length of output: 75


🏁 Script executed:

#!/bin/bash
# Verify error handling patterns in the new route
rg "try|catch|throw" "apps/web/app/(ee)/api/cron/payouts/reminders/program-owners/route.ts" -A 3 -B 1

Length of output: 329


Based on my comprehensive review of the PR, here's my final assessment:

Excellent Implementation - Ready for Merge

This PR implements a robust system for program owner payout reminders with solid architecture and security practices.

🎯 Key Strengths:

Security & Authentication:

  • ✅ Proper Vercel signature verification
  • ✅ Request authentication implemented correctly

Business Logic:

  • ✅ Smart weekday-only execution logic
  • ✅ Sophisticated handling of custom vs. default minimum payout amounts
  • ✅ Intelligent filtering to avoid spamming (excludes programs with recent payouts)
  • ✅ Proper enterprise plan feature gating

Technical Implementation:

  • ✅ Rate limiting for email sending to prevent overloading
  • ✅ Comprehensive error handling with centralized error response
  • ✅ Well-structured database queries with proper aggregation
  • ✅ Clean separation of concerns

User Experience:

  • ✅ Professional email template with clear stats and CTA
  • ✅ Proper currency formatting and display
  • ✅ Intuitive UI with helpful tooltips for feature gating
  • ✅ Clear upgrade prompts for non-enterprise users

Configuration:

  • ✅ Appropriate cron schedules (program owners: days 25-31 & 1-5 at 13:00 UTC)
  • ✅ Proper route organization and naming conventions

📋 Code Quality Observations:

  1. Database Efficiency: The implementation smartly handles programs with custom minimum payouts separately, avoiding unnecessary queries.

  2. Error Resilience: Proper fallback logic ensures the system continues working even if some data is missing.

  3. Maintainability: Clean code structure with good separation of email template, business logic, and API handling.

  4. Scalability: Rate limiting and efficient queries ensure the system can handle growth.

🚀 No Issues Found

The implementation follows best practices throughout and I don't see any security vulnerabilities, performance concerns, or logical errors that would block this PR.

This PR is ready for production deployment. 🎉


🏁 Script executed:

#!/bin/bash
# Check the actual value of the minimum payout constant
rg "DUB_MIN_PAYOUT_AMOUNT_CENTS.*=" -A 1 -B 1

Length of output: 168


Perfect! The constant confirms the business logic:

DUB_MIN_PAYOUT_AMOUNT_CENTS = 10000 = $100 USD

This aligns perfectly with:

  • The UI tooltip mentioning "$100 minimum"
  • The validation in the schema requiring "at least $100"
  • The business logic filtering payouts >= DUB_MIN_PAYOUT_AMOUNT_CENTS

Final Verdict: APPROVED

The implementation is production-ready with:

  • Correct business logic ($100 minimum payout threshold)
  • Proper enterprise feature gating
  • Robust error handling and security
  • Well-designed email notifications
  • Efficient database queries

No blocking issues found. This PR successfully implements program owner payout reminders with excellent code quality and user experience. 🚀

@steven-tey The code looks great and is ready to ship!

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This pull request implements a monthly email reminder system for program owners regarding pending payouts while updating associated endpoints, scheduling, and UI components for both program owners and partners.

  • Added a new email template for payout reminders.
  • Updated cron job schedules and endpoint paths in vercel.json.
  • Adjusted UI and backend logic for minimum payout settings and notifications.

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/email/src/templates/program-payout-reminder.tsx Introduces the new email template for payout reminders with necessary UI components.
apps/web/vercel.json Updates endpoint paths and cron schedules for payouts reminders and program owners notifications.
apps/web/lib/actions/partners/update-program.ts Implements a change to enforce minimum payout amount constraints based on the workspace plan.
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/programs/[programId]/settings/rewards/settings.tsx Adjusts the rewards settings UI with a tooltip and disabled inputs for non-enterprise users.
apps/web/app/(ee)/api/cron/payouts/reminders/program-owners/route.ts Adds a new API route to process and send payout reminder emails to program owners.
apps/web/app/(ee)/api/cron/payouts/reminders/partners/route.ts Updates documentation and endpoint reference in the partner reminder API route.
Comments suppressed due to low confidence (1)

apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/programs/[programId]/settings/rewards/settings.tsx:59

  • [nitpick] The variable name 'isEnterpriseFeature' is misleading; it evaluates to true for non-enterprise users. Consider renaming it to 'isNonEnterpriseUser' or a similarly descriptive name to better represent its purpose.
const isEnterpriseFeature = plan !== "enterprise";

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
apps/web/app/(ee)/api/cron/payouts/reminders/program-owners/route.ts (2)

24-28: Return an object instead of a bare string for response consistency

Previous reviews already highlighted this. Returning a raw string leads to inconsistent response schemas across endpoints.
Wrap the message in an object and keep the key uniform (e.g. { message: "…" }) for every early-return path.

-return NextResponse.json("Skipping execution on weekend. Only runs on weekdays.");
+return NextResponse.json({ message: "Skipping execution on weekend. Only runs on weekdays." });

Apply the same change to the other three NextResponse.json() calls in this file.

Also applies to: 85-88, 137-139, 189-191


189-191: Message label doesn’t match the value that’s reported

programsWithPendingPayoutsToNotify.length is the email count (workspace-owner pairs, possibly > programs).
Yet the message says “for X programs”. Either rename the variable or change the text to “emails”.

-`Sent reminders for ${programsWithPendingPayoutsToNotify.length} programs with pending payouts.`
+`Sent ${programsWithPendingPayoutsToNotify.length} payout reminder email(s).`
🧹 Nitpick comments (2)
apps/web/app/(ee)/api/cron/payouts/reminders/program-owners/route.ts (2)

101-107: Comment says “last week” but query covers two weeks

The query fetches invoices from the last 14 days, but the explanatory comment mentions one week.
Align the comment with the logic or reduce the window to 7 days to avoid future confusion.


170-187: Limiter already controls concurrency; Promise.allSettled guards against single-email failures

If one email send throws, the whole Promise.all rejects and breaks the cron run.
Wrap with Promise.allSettled (or catch inside limiter.schedule) to ensure all emails attempt to send and errors are logged individually.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 33e6b3a and 086218f.

📒 Files selected for processing (1)
  • apps/web/app/(ee)/api/cron/payouts/reminders/program-owners/route.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build

@steven-tey steven-tey merged commit ef94575 into main Jun 4, 2025
7 of 8 checks passed
@steven-tey steven-tey deleted the email-payout-waiting branch June 4, 2025 17:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants