import { redirect } from 'next/navigation';
import Link from 'next/link';
import { createPrismaClient } from '@startover/database';
const prisma = createPrismaClient();
export default async function VerifyPage({
searchParams,
}: {
searchParams: Promise<{ token?: string }>;
}) {
const { token } = await searchParams;
if (!token) {
return (
);
}
const verificationToken = await prisma.verificationToken.findUnique({
where: { token },
});
if (!verificationToken) {
return (
유효하지 않은 토큰
이미 사용되었거나 존재하지 않는 인증 토큰입니다.
로그인으로 이동
);
}
if (verificationToken.expires < new Date()) {
await prisma.verificationToken.delete({
where: { identifier_token: { identifier: verificationToken.identifier, token } },
});
return (
토큰 만료
인증 토큰이 만료되었습니다. 다시 로그인하여 인증 메일을 재발송해주세요.
로그인으로 이동
);
}
const user = await prisma.user.findFirst({
where: { emailNormalized: verificationToken.identifier },
});
if (!user) {
// 토큰은 유효하지만 사용자가 삭제된 경우
await prisma.verificationToken.delete({
where: { identifier_token: { identifier: verificationToken.identifier, token } },
});
return (
사용자를 찾을 수 없습니다
해당 계정이 존재하지 않습니다.
회원가입으로 이동
);
}
// 이미 ACTIVE인 경우 중복 처리 방지
if (user.status !== 'PENDING_VERIFICATION') {
await prisma.verificationToken.delete({
where: { identifier_token: { identifier: verificationToken.identifier, token } },
});
redirect('/auth/login?verified=true');
}
// 인증 처리 (트랜잭션)
await prisma.$transaction(async (tx) => {
await tx.user.update({
where: { id: user.id },
data: { emailVerifiedAt: new Date(), status: 'ACTIVE' },
});
await tx.verificationToken.delete({
where: { identifier_token: { identifier: verificationToken.identifier, token } },
});
await tx.auditLog.create({
data: {
actorUserId: user.id,
resourceType: 'User',
resourceId: user.id.toString(),
actionType: 'EMAIL_VERIFIED',
},
});
});
redirect('/auth/login?verified=true');
}