Email marketing V2

This commit is contained in:
2026-07-29 10:42:21 +02:00
parent 11fdec610f
commit 6fd0ed8522
9 changed files with 256 additions and 53 deletions

View File

@@ -1,13 +1,12 @@
import { NextRequest, NextResponse } from 'next/server';
import bcrypt from 'bcryptjs';
import { NextRequest, NextResponse } from 'next/server';
import bcrypt from 'bcryptjs';
import crypto from 'crypto';
import { db } from '@/lib/db';
import { z } from 'zod';
import { csrfProtection } from '@/lib/csrf';
import { rateLimit, getClientIdentifier, RateLimits } from '@/lib/rateLimit';
import { getAuthCookieOptions } from '@/lib/cookieConfig';
import { signUserId } from '@/lib/session';
import { signupSchema, validateRequest } from '@/lib/validationSchemas';
import { sendWelcomeEmail } from '@/lib/email';
import { sendEmailVerificationEmail } from '@/lib/email';
import { sendConversionEvent } from '@/lib/metaConversions';
import {
ATTRIBUTION_COOKIE_NAME,
@@ -95,13 +94,29 @@ export async function POST(request: NextRequest) {
},
});
triggerLifecycleScoring(user.id, 'signup');
// Send welcome email (fire-and-forget - never block signup)
try {
await sendWelcomeEmail(user.email, user.name ?? 'there');
} catch (emailError) {
console.error('Welcome email failed:', emailError);
triggerLifecycleScoring(user.id, 'signup');
const verificationToken = crypto.randomBytes(32).toString('base64url');
const verificationUrl = new URL('/api/auth/verify-email', process.env.NEXT_PUBLIC_APP_URL || 'https://www.qrmaster.net');
verificationUrl.searchParams.set('token', verificationToken);
await db.verificationToken.deleteMany({ where: { identifier: user.email } });
await db.verificationToken.create({
data: {
identifier: user.email,
token: verificationToken,
expires: new Date(Date.now() + 24 * 60 * 60 * 1000),
},
});
// A confirmed address is required before the account can be used or receive campaigns.
try {
await sendEmailVerificationEmail(user.email, user.name ?? 'there', verificationUrl.toString());
} catch (emailError) {
console.error('Email verification message failed:', emailError);
await db.verificationToken.deleteMany({ where: { token: verificationToken } });
await db.user.delete({ where: { id: user.id } });
return NextResponse.json({ error: 'We could not send the confirmation email. Please try again.' }, { status: 503 });
}
// Meta Conversions API - CompleteRegistration event
@@ -119,19 +134,12 @@ export async function POST(request: NextRequest) {
// Create response
const response = NextResponse.json({
success: true,
needsOnboarding: true,
user: {
id: user.id,
name: user.name,
email: user.email,
plan: 'FREE',
},
success: true,
requiresEmailVerification: true,
email: user.email,
});
// Set cookie for auto-login after signup
response.cookies.set('userId', signUserId(user.id), getAuthCookieOptions());
response.cookies.delete(ATTRIBUTION_COOKIE_NAME);
response.cookies.delete(ATTRIBUTION_COOKIE_NAME);
return response;
} catch (error) {