릴리스: v1.4.45 이메일 인증 및 비밀번호 재설정 추가
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
# 의사결정 이력
|
||||
|
||||
## 2026-04-03 v1.4.45
|
||||
- 실제 서비스에서는 남의 이메일 주소로 가입만 먼저 해두는 문제가 생길 수 있으므로, 일반 회원은 가입 직후 인증 메일을 거쳐야 로그인할 수 있게 하고 비밀번호 분실도 메일 토큰 기반으로 복구하는 구조가 필요하다고 판단했다.
|
||||
- 다만 초기 운영자가 바로 서비스를 띄울 수 있어야 하므로, 첫 번째 가입 계정만은 기존처럼 이메일 인증 없이 바로 최고 관리자 계정으로 활성화하는 예외를 유지하는 편이 맞다고 정리했다.
|
||||
- 발신 인프라는 우선 사용자가 준비한 Gmail 계정과 앱 비밀번호로 SMTP를 먼저 붙이고, 도메인 발신 주소와 SPF/DKIM/DMARC는 실제 발송 품질을 본 뒤 Cloudflare DNS에서 후속 정리하는 단계적 접근이 더 현실적이라고 판단했다.
|
||||
|
||||
## 2026-04-03 v1.4.44
|
||||
- 공통 카피라이트 링크 색을 고정 민트색으로 두면 다크 모드에서는 잘 보이지만 라이트 모드에서 대비가 부족해질 수 있으므로, 테마 텍스트 색을 따라가게 하고 굵기로 링크 인지를 보완하는 편이 더 안정적이라고 판단했다.
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
|
||||
## `/login`
|
||||
- 화면 파일: `frontend/src/views/LoginView.vue`
|
||||
- 역할: 로그인/회원가입 전환, 첫 가입 안내
|
||||
- 연동 API: `GET /api/auth/meta`, `POST /api/auth/login`, `POST /api/auth/signup`
|
||||
- 역할: 로그인/회원가입 전환, 첫 가입 안내, 일반 회원가입 후 이메일 인증 안내와 인증 메일 재전송, 비밀번호 재설정 메일 요청, `?verifyToken=...` 인증 링크 처리, `?resetToken=...` 새 비밀번호 설정 처리
|
||||
- 연동 API: `GET /api/auth/meta`, `POST /api/auth/login`, `POST /api/auth/signup`, `POST /api/auth/email/verify`, `POST /api/auth/email/resend`, `POST /api/auth/password-reset/request`, `POST /api/auth/password-reset/confirm`
|
||||
|
||||
## `/me`
|
||||
- 화면 파일: `frontend/src/views/MyTierListsView.vue`
|
||||
@@ -56,6 +56,7 @@
|
||||
- 로컬 DB 실행 설정: `docker-compose.yml`
|
||||
- 로컬 MariaDB 가이드: `docs/local-mariadb.md`
|
||||
- 인증 라우트: `backend/src/routes/auth.js`
|
||||
- 메일 발송 유틸: `backend/src/lib/mailer.js`
|
||||
- 주제 라우트: `backend/src/routes/topics.js`
|
||||
- 티어표 라우트: `backend/src/routes/tierlists.js`
|
||||
- 관리자 라우트: `backend/src/routes/admin.js`
|
||||
|
||||
39
docs/spec.md
39
docs/spec.md
@@ -64,9 +64,24 @@
|
||||
- `email`: string
|
||||
- `nickname`: string
|
||||
- `passwordHash`: string
|
||||
- `emailVerified`: boolean
|
||||
- `isAdmin`: boolean
|
||||
- `avatarSrc`: string
|
||||
- `createdAt`: number
|
||||
- `emailVerificationTokens`
|
||||
- `id`: string
|
||||
- `userId`: string
|
||||
- `tokenHash`: string
|
||||
- `expiresAt`: number
|
||||
- `consumedAt`: number
|
||||
- `createdAt`: number
|
||||
- `passwordResetTokens`
|
||||
- `id`: string
|
||||
- `userId`: string
|
||||
- `tokenHash`: string
|
||||
- `expiresAt`: number
|
||||
- `consumedAt`: number
|
||||
- `createdAt`: number
|
||||
- `games`
|
||||
- `id`: string
|
||||
- `name`: string
|
||||
@@ -110,11 +125,21 @@
|
||||
## 주요 API
|
||||
- 인증
|
||||
- `POST /api/auth/signup`
|
||||
- 첫 관리자 계정은 바로 로그인 세션을 만들고, 이후 일반 계정은 인증 메일 발송 후 `verificationRequired` 상태를 반환한다.
|
||||
- `POST /api/auth/login`
|
||||
- 이메일 인증이 끝나지 않은 계정은 `email_unverified`로 차단한다.
|
||||
- `POST /api/auth/logout`
|
||||
- `GET /api/auth/me`
|
||||
- `GET /api/auth/meta`
|
||||
- `POST /api/auth/profile`
|
||||
- `POST /api/auth/email/verify`
|
||||
- `login?verifyToken=...` 링크에서 받은 토큰으로 이메일 인증을 완료하고 바로 로그인 세션을 만든다.
|
||||
- `POST /api/auth/email/resend`
|
||||
- 미인증 계정의 인증 메일을 다시 발송한다.
|
||||
- `POST /api/auth/password-reset/request`
|
||||
- 입력한 이메일로 비밀번호 재설정 링크를 발송한다.
|
||||
- `POST /api/auth/password-reset/confirm`
|
||||
- `login?resetToken=...` 링크의 토큰과 새 비밀번호로 비밀번호를 재설정하고 바로 로그인 세션을 만든다.
|
||||
- 주제
|
||||
- `GET /api/topics`
|
||||
- `GET /api/topics/:topicId`
|
||||
@@ -245,6 +270,20 @@
|
||||
- `TRUST_PROXY`: 프록시 홉 수
|
||||
- `SESSION_COOKIE_SECURE`: `true`면 HTTPS 전용 쿠키
|
||||
- `SESSION_COOKIE_SAME_SITE`: 기본 `lax`
|
||||
- `APP_ORIGIN`: 이메일 인증/비밀번호 재설정 링크를 만들 때 사용할 서비스 기준 주소
|
||||
- `SMTP_HOST`: 메일 서버 호스트, Gmail SMTP 사용 시 보통 `smtp.gmail.com`
|
||||
- `SMTP_PORT`: 메일 서버 포트, Gmail SSL SMTP 기준 보통 `465`
|
||||
- `SMTP_SECURE`: `true`면 SMTP SSL/TLS 연결을 사용
|
||||
- `SMTP_USER`: 발신용 Gmail 계정
|
||||
- `SMTP_PASS`: Gmail 앱 비밀번호
|
||||
- `SMTP_FROM`: 실제 메일 From 주소, 비워두면 `SMTP_USER`를 기본값으로 사용한다
|
||||
|
||||
## 회원 인증 메모
|
||||
- 첫 번째 가입 계정은 운영 초기 부트스트랩을 위해 이메일 인증 없이 바로 최고 관리자 계정으로 활성화한다.
|
||||
- 두 번째 이후 일반 회원가입은 가입 직후 로그인 세션을 만들지 않고, 인증 메일 링크를 눌러 `email_verified=1`이 된 뒤에만 로그인할 수 있게 한다.
|
||||
- 인증 메일/비밀번호 재설정 메일 토큰은 원문을 DB에 저장하지 않고 SHA-256 해시만 저장하며, 새 토큰을 발급할 때는 같은 사용자의 이전 미사용 토큰을 먼저 만료 처리한다.
|
||||
- 이메일 인증 토큰은 24시간, 비밀번호 재설정 토큰은 1시간 유효 기간을 사용한다.
|
||||
- 비밀번호 재설정 링크로 새 비밀번호를 저장한 사용자는 같은 메일 주소를 확인한 것으로 보고, 기존에 미인증 상태였더라도 저장과 함께 이메일 인증을 완료 처리한다.
|
||||
|
||||
## 운영 배포 메모
|
||||
- 프로덕션 컴포즈 파일은 [docker-compose.prod.yml](/Users/bicute/Desktop/zenn.dev/tier-cursor/docker-compose.prod.yml)이다.
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
# 할 일 및 이슈
|
||||
|
||||
## 단기 확인
|
||||
- `v1.4.45`에서 이메일 인증/비밀번호 재설정 메일 발송을 Gmail SMTP로 붙였으므로, 운영 `.env`에 `SMTP_USER`, `SMTP_PASS`, `SMTP_HOST`, `SMTP_PORT`, `SMTP_SECURE`, `SMTP_FROM`, `APP_ORIGIN`을 넣은 뒤 실제 회원가입 인증 메일과 비밀번호 재설정 메일이 도착하는지 확인한다.
|
||||
- 일반 회원가입 직후에는 자동 로그인되지 않고 인증 안내 문구가 떠야 하며, 메일의 `login?verifyToken=...` 링크를 누르면 이메일 인증과 로그인 세션 생성이 함께 끝나는지 QA한다.
|
||||
- 미인증 계정으로 로그인하면 `email_unverified` 상태 안내가 뜨고, `인증 메일 재전송` 버튼으로 같은 메일 주소에 인증 링크를 다시 보낼 수 있는지 확인한다.
|
||||
- `비밀번호를 잊으셨나요?`에서 재설정 메일을 요청한 뒤 `login?resetToken=...` 링크로 들어가면 새 비밀번호 입력 화면이 열리고, 저장 후 바로 로그인 상태로 내 티어표 화면으로 이동하는지 확인한다.
|
||||
- Gmail 주소 그대로 발송하는 1차 단계에서는 도메인 DNS 인증을 당장 쓰지 않지만, 이후 `noreply@sori.studio` 같은 도메인 발신 주소로 바꿀 경우 Cloudflare DNS에 SPF/DKIM/DMARC를 설정하는 후속 작업이 필요하다.
|
||||
- `v1.4.44`에서 공통 카피라이트 `zenn` 링크를 테마 텍스트 색으로 바꿨으므로, 다크/라이트 모드 양쪽에서 하단 링크가 배경에 묻히지 않고 hover 상태도 자연스러운지 확인한다.
|
||||
- `v1.4.43`에서 같은 `TierEditorView` 라우트 안에서도 `topicId / tierListId / preview`가 바뀌면 상태를 다시 불러오게 했으므로, 타인 티어표 복사 직후 화면이 내 복사본으로 바뀌는지와 상단 원본 링크 클릭 시 실제 원본 티어표 내용으로 전환되는지 확인한다.
|
||||
- 편집 중 미저장 변경이 있는 상태에서 상단 원본 링크를 눌렀을 때는 경고 모달이 뜨고, `계속 편집`은 현재 화면 유지, `저장 없이 이동`은 원본으로 이동하면서 변경분을 버리는지 QA한다.
|
||||
@@ -120,6 +125,8 @@
|
||||
- 아이템 관리의 같은 이미지 참조 요약과 상세 모달은 붙였으므로, 실제 운영 데이터에서 카드 수치와 모달 목록이 기대한 참조 관계와 맞는지 한 번 더 QA한다.
|
||||
|
||||
## 중기 개선
|
||||
- 이메일 인증/비밀번호 재설정 1차 구현이 들어갔으므로, 다음 단계에서는 Gmail 발신 기반이 실제 운영에서 스팸함으로 얼마나 가는지 보고 필요하면 Cloudflare DNS의 SPF/DKIM/DMARC와 도메인 발신 주소 전환을 정리한다.
|
||||
- 구글 계정 로그인은 아직 붙이지 않았으므로, 이메일 인증 안정화 후 Google OAuth 클라이언트를 만들고 일반 이메일 계정과 같은 이메일의 구글 계정을 자동 연결할지 정책을 먼저 결정한다.
|
||||
- 신규 템플릿 요청은 현재 `첫 생성 1회 후 요청과 게임을 연결해 재사용` 단계까지 정리했으므로, 다음 단계에서는 정말로 게임을 DB에 만들기 전까지 임시 작업 상태로 유지할지 여부를 운영 흐름 기준으로 결정한다.
|
||||
- 관리자 템플릿 요청은 동일 `src` 중복 생성 방지와 `연결된 게임/이미 반영 n개` 표시까지 붙였으므로, 이후에는 요청별 반영 이력(예: 어떤 아이템을 언제 반영했는지)까지 별도로 남길지 검토한다.
|
||||
- 관리자 URL 분리는 시작했으므로, 다음 단계에서는 `AdminView.vue` 단일 대형 파일을 섹션별 뷰/컴포저블로 쪼개고 직접 진입 시 선택 게임/요청 작업 상태 복원 범위도 함께 정리한다.
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
# 업데이트 로그
|
||||
|
||||
## 2026-04-03 v1.4.45
|
||||
- Gmail SMTP를 사용하는 이메일 인증/비밀번호 재설정 1차 흐름을 추가했다. 첫 관리자 계정은 기존처럼 바로 활성화되지만, 일반 회원은 가입 직후 인증 메일을 받고 `login?verifyToken=...` 링크로 인증을 마쳐야 로그인할 수 있게 바꿨다.
|
||||
- 로그인 화면에 `인증 메일 재전송`, `비밀번호를 잊으셨나요?`, `login?resetToken=...` 기반 새 비밀번호 설정 UI를 추가해, 메일 링크를 받은 사용자가 같은 `/login` 화면에서 인증 완료와 비밀번호 재설정을 이어서 처리할 수 있게 했다.
|
||||
- 백엔드 `users`에 `email_verified`를 추가하고, 이메일 인증/비밀번호 재설정 토큰을 해시로 저장하는 전용 테이블과 API를 추가했다. 운영 배포용 `docker-compose.prod.yml`에는 `APP_ORIGIN`, `SMTP_*` 환경변수 자리를 열어 Gmail 앱 비밀번호를 코드에 넣지 않고 주입할 수 있게 정리했다.
|
||||
|
||||
## 2026-04-03 v1.4.44
|
||||
- 오른쪽 레일 공통 카피라이트의 `zenn` 링크가 민트 단색이라 라이트 모드에서 배경과 충분히 분리되지 않을 수 있었으므로, 테마 텍스트 색 기반의 굵은 링크 스타일로 바꿔 다크/라이트 양쪽에서 읽히도록 조정했다.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user