v0.1.49 - 인증 재전송 버튼 노출 조건 조정

This commit is contained in:
2026-04-24 11:51:30 +09:00
parent 0013f03bb3
commit 39a731138b
5 changed files with 38 additions and 18 deletions

View File

@@ -4,7 +4,7 @@
- 프로젝트명: 10 Minute Planner 웹 UI
- 기술 스택: Vue 3 + Vite + TailwindCSS + JavaScript
- 현재 기준 버전: `v0.1.48` 준비 중
- 현재 기준 버전: `v0.1.49` 준비 중
- Git 원격 저장소: `https://git.sori.studio/zenn/planner.sori.studio.git`
## 기준 디자인
@@ -230,6 +230,7 @@
- 비밀번호 재설정/이메일 인증용 개발 링크는 `AUTH_PREVIEW_LINKS=true`여도 `APP_BASE_URL``localhost` 또는 `127.0.0.1`일 때만 응답에 포함한다. 상용 서버에서 링크가 그대로 보이면 이 조건부터 확인한다.
- 프론트는 `/verify-email?token=...` 진입 시 인증을 바로 확정하고 로그인 모달에 결과 메시지를 띄운다. `/reset-password?token=...`은 기존처럼 비밀번호 재설정 모달을 연다.
- 로그인 모달에는 `이메일 인증 메일 다시 보내기` 버튼이 추가되었다. 이메일 주소를 입력한 상태에서 바로 인증 메일 재전송을 요청할 수 있어, 가입 후 메일을 못 받은 사용자가 로그인 단계에서 막히지 않게 했다.
- 인증 메일 재전송 버튼은 항상 보이지 않는다. 로그인 모달에서 이메일 인증 관련 안내 메시지가 보일 때만 메시지 박스 오른쪽에 함께 노출한다.
- SETTINGS 화면에 일반 사용자 전용 `회원 탈퇴` 카드가 추가되었다. 현재 비밀번호 확인 후 계정, 플래너 기록, 목표, 세션, 인증 토큰이 함께 삭제된다. 기본 관리자 계정은 이 경로에서 삭제하지 못하게 막는다.
- `/api/auth/logout`이 추가되어 로그아웃 시 프론트 저장 토큰만 지우는 것이 아니라 서버 세션도 함께 폐기한다.
- SETTINGS 화면 왼쪽 카드에 현재 기기 로그인 유지 방식(`로그인 유지` 또는 브라우저 세션만 유지), 최근 로그인 시각, 이메일 인증 상태를 보여준다.

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "ten-minute-planner",
"version": "0.1.48",
"version": "0.1.49",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ten-minute-planner",
"version": "0.1.48",
"version": "0.1.49",
"dependencies": {
"vue": "^3.5.13"
},

View File

@@ -1,7 +1,7 @@
{
"name": "ten-minute-planner",
"private": true,
"version": "0.1.48",
"version": "0.1.49",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -644,6 +644,17 @@ const authSessionInfo = computed(() => ({
? '이메일 인증 완료'
: '이메일 인증 필요',
}))
const showVerificationResend = computed(() => {
if (authMode.value !== 'login') {
return false
}
if (!authForm.email.includes('@')) {
return false
}
return authMessage.value.includes('이메일 인증')
})
const filteredGoals = computed(() => {
const query = goalQuery.value.trim().toLowerCase()
return goals.value.filter((goal) => {
@@ -3277,6 +3288,7 @@ onBeforeUnmount(() => {
:form="authForm"
:busy="authBusy"
:message="authMessage"
:show-resend-verification="showVerificationResend"
@close="closeAuthDialog"
@submit="submitAuthForm"
@resend-verification="resendVerificationEmail"

View File

@@ -20,6 +20,10 @@ const props = defineProps({
type: String,
default: '',
},
showResendVerification: {
type: Boolean,
default: false,
},
})
const emit = defineEmits([
@@ -186,12 +190,25 @@ function getSubmitLabel(mode, busy) {
<span class="text-xs font-bold tracking-[0.08em] text-stone-700">로그인 상태 유지</span>
</label>
<p
<div
v-if="message"
class="rounded-2xl border border-stone-300 bg-white/80 px-4 py-3 text-sm font-semibold leading-6 text-stone-700"
class="rounded-2xl border border-stone-300 bg-white/80 px-4 py-3"
>
{{ message }}
</p>
<div class="flex items-start justify-between gap-4">
<p class="min-w-0 text-sm font-semibold leading-6 text-stone-700">
{{ message }}
</p>
<button
v-if="showResendVerification"
type="button"
class="shrink-0 rounded-full border border-stone-300 px-3 py-2 text-[10px] font-bold tracking-[0.14em] text-stone-600 transition hover:border-stone-500 hover:text-stone-900"
:disabled="busy"
@click="emit('resend-verification')"
>
재전송
</button>
</div>
</div>
<button
type="submit"
@@ -211,16 +228,6 @@ function getSubmitLabel(mode, busy) {
비밀번호를 잊으셨나요?
</button>
<button
v-if="mode === 'login'"
type="button"
class="mt-3 w-full text-center text-xs font-bold tracking-[0.14em] text-stone-500 underline underline-offset-4 transition hover:text-stone-900"
:disabled="busy"
@click="emit('resend-verification')"
>
이메일 인증 메일 다시 보내기
</button>
<div class="mt-5 flex items-center justify-center gap-2 border-t border-stone-300/70 pt-4">
<p class="text-sm font-semibold text-stone-600">
{{ mode === 'signup' ? '이미 계정이 있나요?' : '계정 화면으로 돌아갈까요?' }}