Реферальна система з реферальними посиланнями
Реферальна система стимулює користувачів привлекати нових клієнтів. Механіка: унікальне посилання → реєстрація → атрибуція → вознаграждення. Деталі — в бізнес-логіці: скидка, кредит на рахунку, відсоток від оплати.
Схема даних
model ReferralCode {
id String @id @default(cuid())
code String @unique // унікальний код: "JOHN2024"
userId String @unique // один код на користувача
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 // користувач може бути реферален один раз
status ReferralStatus @default(PENDING)
rewardAmount Int? // у копійках/центах
rewardPaidAt DateTime?
createdAt DateTime @default(now())
referralCode ReferralCode @relation(fields: [referralCodeId], references: [id])
referredUser User @relation(fields: [referredUserId], references: [id])
}
enum ReferralStatus {
PENDING // зареєструвався, але не оплатив
QUALIFIED // виконав умову (перший платіж)
REWARDED // вознаграджен виплачено
CANCELLED // скасовано (повернення тощо)
}
Генерація коду і посилання
// 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;
// Пробуємо створити унікальний код
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) {
// Уникальність порушена — пробуємо знову
}
}
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}`;
}
Трекинг реферала при реєстрації
// Middleware: зберігаємо ref у 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 живе 30 днів — навіть якщо користувач не зареєструвався одразу
response.cookies.set('referral_code', ref, {
maxAge: 60 * 60 * 24 * 30,
httpOnly: true,
sameSite: 'lax',
});
}
return response;
}
// При реєстрації нового користувача
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) { // не можна ссилаться на себе
await db.referral.create({
data: {
referralCodeId: code.id,
referredUserId: user.id,
status: 'PENDING',
}
});
}
}
return user;
}
Начисление вознаграждения
// При першій успішній оплаті (webhook від 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;
// Вознаграждение: 20% від першого платежу
const rewardAmount = Math.floor(paymentAmount * 0.20);
await db.$transaction([
db.referral.update({
where: { id: referral.id },
data: {
status: 'QUALIFIED',
rewardAmount,
}
}),
// Нараховуємо кредит реферреру
db.userBalance.upsert({
where: { userId: referral.referralCode.userId },
create: {
userId: referral.referralCode.userId,
balance: rewardAmount,
},
update: {
balance: { increment: rewardAmount }
}
}),
]);
// Сповіщаємо реферрера
await sendReferralRewardEmail({
userId: referral.referralCode.userId,
amount: rewardAmount,
});
}
Дашборд реферальної програми
// 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>Реферальна програма</h1>
<ReferralLinkCopy url={referralUrl} code={code} />
<ReferralStats stats={stats} />
<ReferralHistory userId={session!.user.id} />
</div>
);
}
Розробка реферальної системи з трекингом, атрибуцією та начисленням вознаграджень — 3–5 робочих днів.







