Referral System with Referral Links
Referral system incentivizes users to attract new customers. Mechanics: unique link → registration → attribution → reward. Details in business logic: discount, account credit, percentage of payment.
Data Schema
model ReferralCode {
id String @id @default(cuid())
code String @unique // unique code: "JOHN2024"
userId String @unique // one code per user
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id])
referrals Referral[]
}
model Referral {
id String @id @default(cuid())
referralCodeId String
referredUserId String @unique // user can be referred once
status ReferralStatus @default(PENDING)
rewardAmount Int? // in kopeks/cents
rewardPaidAt DateTime?
createdAt DateTime @default(now())
referralCode ReferralCode @relation(fields: [referralCodeId], references: [id])
referredUser User @relation(fields: [referredUserId], references: [id])
}
enum ReferralStatus {
PENDING // registered but not paid
QUALIFIED // met condition (first payment)
REWARDED // reward paid
CANCELLED // cancelled (refund etc)
}
Code Generation and URL Building
// lib/referral.ts
import { customAlphabet } from 'nanoid';
const generateCode = customAlphabet('ABCDEFGHJKLMNPQRSTUVWXYZ23456789', 8);
export async function getOrCreateReferralCode(userId: string): Promise<string> {
const existing = await db.referralCode.findUnique({
where: { userId }
});
if (existing) return existing.code;
// Try to create unique code
for (let attempt = 0; attempt < 5; attempt++) {
const code = generateCode();
try {
const created = await db.referralCode.create({
data: { userId, code }
});
return created.code;
} catch (e) {
// Uniqueness violated — try again
}
}
throw new Error('Failed to generate unique referral code');
}
export function buildReferralUrl(code: string, baseUrl?: string): string {
const base = baseUrl ?? process.env.APP_URL!;
return `${base}/?ref=${code}`;
}
Referral Tracking on Registration
// Middleware: save ref in cookie
// middleware.ts
export function middleware(request: NextRequest) {
const response = NextResponse.next();
const ref = request.nextUrl.searchParams.get('ref');
if (ref && !request.cookies.get('referral_code')) {
// Cookie lives 30 days — even if user doesn't register immediately
response.cookies.set('referral_code', ref, {
maxAge: 60 * 60 * 24 * 30,
httpOnly: true,
sameSite: 'lax',
});
}
return response;
}
// On new user registration
export async function registerUser(email: string, password: string, referralCode?: string) {
const user = await createUser(email, password);
if (referralCode) {
const code = await db.referralCode.findUnique({
where: { code: referralCode },
});
if (code && code.userId !== user.id) { // can't refer self
await db.referral.create({
data: {
referralCodeId: code.id,
referredUserId: user.id,
status: 'PENDING',
}
});
}
}
return user;
}
Reward Accrual
// On first successful payment (webhook from Stripe)
export async function handleFirstPayment(userId: string, paymentAmount: number) {
const referral = await db.referral.findFirst({
where: {
referredUserId: userId,
status: 'PENDING',
},
include: { referralCode: true }
});
if (!referral) return;
// Reward: 20% of first payment
const rewardAmount = Math.floor(paymentAmount * 0.20);
await db.$transaction([
db.referral.update({
where: { id: referral.id },
data: {
status: 'QUALIFIED',
rewardAmount,
}
}),
// Accrue credit to referrer
db.userBalance.upsert({
where: { userId: referral.referralCode.userId },
create: {
userId: referral.referralCode.userId,
balance: rewardAmount,
},
update: {
balance: { increment: rewardAmount }
}
}),
]);
// Notify referrer
await sendReferralRewardEmail({
userId: referral.referralCode.userId,
amount: rewardAmount,
});
}
Referral Dashboard
// app/dashboard/referrals/page.tsx
export default async function ReferralsPage() {
const session = await auth();
const code = await getOrCreateReferralCode(session!.user.id);
const referralUrl = buildReferralUrl(code);
const stats = await db.referral.groupBy({
by: ['status'],
where: { referralCode: { userId: session!.user.id } },
_count: true,
_sum: { rewardAmount: true },
});
return (
<div>
<h1>Referral Program</h1>
<ReferralLinkCopy url={referralUrl} code={code} />
<ReferralStats stats={stats} />
<ReferralHistory userId={session!.user.id} />
</div>
);
}
Referral system development with tracking, attribution and reward accrual — 3–5 business days.







