From 5e279f20f85a440a2ff9e93fc4ed771005f8df91 Mon Sep 17 00:00:00 2001 From: Arsen Bekirov Date: Fri, 29 May 2026 19:41:47 +0300 Subject: [PATCH] fix: send invite emails before inserting DB records to avoid partial-state bugs Reversed the order of operations in POST /api/referrals: - Emails are now sent FIRST - DB records are only created for successfully delivered emails - Previously, DB records were created even if emails failed to send. - Also returns 502 if all emails fail instead of a misleading 200. --- src/app/api/referrals/route.ts | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/app/api/referrals/route.ts b/src/app/api/referrals/route.ts index 865997f7..53d52005 100644 --- a/src/app/api/referrals/route.ts +++ b/src/app/api/referrals/route.ts @@ -154,7 +154,26 @@ export async function POST(request: NextRequest) { ); } - const referralRows = newValidEmails.map((email: string) => ({ + // Send emails BEFORE inserting into DB to avoid partial-state issues + const emailContent = referralInviteEmail({ inviterName, referralCode }); + const emailResults = await Promise.all( + newValidEmails.map((email: string) => + sendEmail({ to: email, ...emailContent }) + ) + ); + + const successfulEmails = newValidEmails.filter((_, i) => emailResults[i]?.success); + const failedEmailCount = emailResults.filter((r) => !r.success).length; + + if (successfulEmails.length === 0) { + return NextResponse.json( + { error: "Failed to send invitation emails. Please try again." }, + { status: 502 } + ); + } + + // Only insert DB records for successfully delivered emails + const referralRows = successfulEmails.map((email: string) => ({ referrer_id: user.id, referred_email: email.trim().toLowerCase(), referral_code: referralCode, @@ -170,18 +189,10 @@ export async function POST(request: NextRequest) { return NextResponse.json({ error: error.message }, { status: 400 }); } - const emailContent = referralInviteEmail({ inviterName, referralCode }); - const emailResults = await Promise.all( - newValidEmails.map((email: string) => - sendEmail({ to: email, ...emailContent }) - ) - ); - const failedEmailCount = emailResults.filter((result) => !result.success).length; - return NextResponse.json({ message: failedEmailCount > 0 - ? `${newValidEmails.length} invite(s) created; ${failedEmailCount} email(s) failed to send` - : `${newValidEmails.length} invite(s) created and sent`, + ? `${successfulEmails.length} invite(s) sent successfully; ${failedEmailCount} email(s) failed` + : `${successfulEmails.length} invite(s) sent successfully`, data: referrals, email_delivery_failed: failedEmailCount, });