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'); }