-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Program owners pending payouts email notification #2456
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
WalkthroughA 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
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
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms (1)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this 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.jsonshows 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
📒 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
packages/ui/src/footer.tsx, the Footer component expectsstaticDomainandclassNameprops, not anLet 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.tsxthe<Footer />you’re using is the one defined inpackages/email/src/components/footer.tsx, which declares its own props (includingFooter. PassingLikely 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/remindersto/api/cron/payouts/reminders/partnersclearly 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
There was a problem hiding this 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
iconprop, 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
📒 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 tsLength 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`}
There was a problem hiding this 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
isEnterpriseFeatureis somewhat confusing since it'struewhen the feature should be restricted (for non-enterprise users). Consider a clearer name likeshouldRestrictFeatureorisNonEnterpriseUser.- const isEnterpriseFeature = plan !== "enterprise"; + const shouldRestrictFeature = plan !== "enterprise";
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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.
...eb/app/app.dub.co/(dashboard)/[slug]/(ee)/programs/[programId]/settings/rewards/settings.tsx
Outdated
Show resolved
Hide resolved
|
@CodeRabbit final review pls |
|
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: Length of output: 5671 🏁 Script executed: Length of output: 3897 🏁 Script executed: Length of output: 1101 🏁 Script executed: Length of output: 7359 🏁 Script executed: Length of output: 3969 🏁 Script executed: Length of output: 4698 🏁 Script executed: Length of output: 75 🏁 Script executed: Length of output: 329 Based on my comprehensive review of the PR, here's my final assessment: ✅ Excellent Implementation - Ready for MergeThis PR implements a robust system for program owner payout reminders with solid architecture and security practices. 🎯 Key Strengths:Security & Authentication:
Business Logic:
Technical Implementation:
User Experience:
Configuration:
📋 Code Quality Observations:
🚀 No Issues FoundThe 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: Length of output: 168 Perfect! The constant confirms the business logic:
This aligns perfectly with:
✅ Final Verdict: APPROVEDThe implementation is production-ready with:
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! |
There was a problem hiding this 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";
There was a problem hiding this 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 consistencyPrevious 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.lengthis 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 weeksThe 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.allSettledguards against single-email failuresIf one email send throws, the whole
Promise.allrejects and breaks the cron run.
Wrap withPromise.allSettled(or catch insidelimiter.schedule) to ensure all emails attempt to send and errors are logged individually.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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
Summary by CodeRabbit