Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 39a731138b |
@@ -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
4
package-lock.json
generated
@@ -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"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ten-minute-planner",
|
||||
"private": true,
|
||||
"version": "0.1.48",
|
||||
"version": "0.1.49",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
12
src/App.vue
12
src/App.vue
@@ -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"
|
||||
|
||||
@@ -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' ? '이미 계정이 있나요?' : '계정 화면으로 돌아갈까요?' }}
|
||||
|
||||
Reference in New Issue
Block a user