관리자 레이아웃과 네비게이션 정리

This commit is contained in:
2026-05-13 10:23:18 +09:00
parent ec9f9ea57f
commit b490d5b90f
17 changed files with 484 additions and 164 deletions

View File

@@ -7,7 +7,9 @@ import {
countOtpSendsLastHour,
hasRecentOtpSend,
insertOtpChallenge,
invalidatePendingOtpChallenges
deleteOtpChallengeById,
invalidatePendingOtpChallenges,
invalidatePendingOtpChallengesExcept
} from '../../../repositories/email-otp-repository'
import { generateSixDigitOtp, hashOtpCode, normalizeOtpEmail } from '../../../utils/email-otp'
import { isResendConfigured, sendResendEmail } from '../../../utils/resend-mail'
@@ -129,8 +131,7 @@ export default defineEventHandler(async (event) => {
const expiresAt = new Date(Date.now() + OTP_TTL_MS)
const createdIp = String(getRequestIP(event) || '')
await invalidatePendingOtpChallenges(sql, email, purpose)
await insertOtpChallenge(sql, {
const challengeId = await insertOtpChallenge(sql, {
email,
purpose,
codeHash,
@@ -147,13 +148,20 @@ export default defineEventHandler(async (event) => {
? `<p>회원가입을 위한 인증번호입니다.</p><p style="font-size:24px;font-weight:700;letter-spacing:0.2em">${code}</p><p>15분 이내에 입력해 주세요.</p>`
: `<p>비밀번호 재설정을 위한 인증번호입니다.</p><p style="font-size:24px;font-weight:700;letter-spacing:0.2em">${code}</p><p>15분 이내에 입력해 주세요.</p>`
await sendResendEmail({
apiKey: String(config.resendApiKey).trim(),
from: String(config.resendFromEmail).trim(),
to: email,
subject,
html
})
try {
await sendResendEmail({
apiKey: String(config.resendApiKey).trim(),
from: String(config.resendFromEmail).trim(),
to: email,
subject,
html
})
} catch (error) {
await deleteOtpChallengeById(sql, challengeId)
throw error
}
await invalidatePendingOtpChallengesExcept(sql, email, purpose, challengeId)
return {
ok: true,