이메일 인증과 비밀번호 재설정 추가

This commit is contained in:
2026-06-25 12:02:44 +09:00
parent edf48e53a5
commit 35a2976182
26 changed files with 770 additions and 43 deletions

View File

@@ -3,7 +3,7 @@
## 프로젝트 개요
- 서비스명: `UNIARE - Union Arena Deck Builder`
- 현재 버전: `v4.0.11`
- 현재 버전: `v4.0.12`
- 프론트: 정적 HTML, CSS, JavaScript
- 백엔드: Express, SQLite(`better-sqlite3`)
- 운영: Docker Compose 기반 Nginx + API
@@ -20,6 +20,9 @@
| `/result.html` | 덱 미리보기, PNG 다운로드, 회원 덱 저장 |
| `/login.html` | 로그인 |
| `/signup.html` | 회원가입 |
| `/verify-email.html` | 가입 이메일 인증·인증 메일 재전송 |
| `/forgot-password.html` | 비밀번호 재설정 메일 요청 |
| `/reset-password.html?token=<token>` | 1회용 토큰으로 비밀번호 재설정 |
| `/profile.html` | 이메일·사용자명·아바타·비밀번호·덱 공개 기본값 관리 |
| `/deckHistory.html` | 내 덱 검색·필터·이름 변경·공개 설정·삭제·불러오기 |
| `/preset.html` | 공개 사용자 덱 검색·필터·즐겨찾기·불러오기 |
@@ -85,6 +88,12 @@
## 인증 및 권한
- 비밀번호는 bcrypt 비용 12로 해시한다.
- 신규 회원은 Resend 인증 링크로 이메일 소유 확인을 완료해야 로그인할 수 있다.
- 기존 회원은 이메일 인증 기능 배포 시 인증 완료 상태로 마이그레이션한다.
- 인증 링크는 24시간, 비밀번호 재설정 링크는 30분 동안 한 번만 사용할 수 있다.
- 인증·재설정 원문 토큰은 DB에 저장하지 않고 SHA-256 해시만 저장한다.
- 사용자명은 대소문자를 구분하지 않고 중복을 차단한다.
- 인증된 이메일은 프로필에서 직접 변경할 수 없다.
- JWT 기본 만료는 7일이며 `JWT_EXPIRES`로 변경할 수 있다.
- 로그인 유지 선택 시 브라우저를 닫아도 인증 정보를 유지하고, 미선택 시 현재 브라우저 세션에서만 유지한다.
- 인증된 화면 진입 시 `/auth/me` 검증과 함께 `last_login_at`을 갱신한다.
@@ -123,8 +132,19 @@
| `default_deck_public` | 덱 저장 기본 공개 여부 |
| `skip_deck_public_prompt` | 저장 시 공개 확인 생략 여부 |
| `last_login_at` | 마지막 로그인 또는 인증 세션 확인 시각 |
| `email_verified_at` | 이메일 인증 완료 시각. 기존 회원은 마이그레이션 시 채움 |
| `created_at`, `updated_at` | 생성·수정 시각 |
### `auth_tokens`
| 컬럼 | 설명 |
|---|---|
| `user_id` | 인증 대상 사용자 |
| `type` | `verify_email` 또는 `reset_password` |
| `token_hash` | 원문 토큰의 SHA-256 해시 |
| `expires_at`, `used_at` | 만료·사용 시각 |
| `created_at` | 발급 시각 |
### `decks`
| 컬럼 | 설명 |
@@ -162,8 +182,12 @@
| Method | Path | 권한 | 기능 |
|---|---|---|---|
| POST | `/api/v1/auth/register` | 공개 | 회원가입 |
| POST | `/api/v1/auth/register` | 공개 | 미인증 회원 생성·가입 인증 메일 발송 |
| POST | `/api/v1/auth/resend-verification` | 공개 | 가입 인증 메일 재전송 |
| POST | `/api/v1/auth/verify-email` | 공개 | 이메일 인증 토큰 확인 |
| POST | `/api/v1/auth/login` | 공개 | 로그인과 JWT 발급, `last_login_at` 갱신 |
| POST | `/api/v1/auth/forgot-password` | 공개 | 비밀번호 재설정 메일 요청 |
| POST | `/api/v1/auth/reset-password` | 공개 | 1회용 토큰으로 비밀번호 변경 |
| GET | `/api/v1/auth/me` | 회원 | 내 정보와 인증 세션 확인, `last_login_at` 갱신 |
| PUT | `/api/v1/auth/me` | 회원 | 프로필·덱 저장 설정 변경 |
| POST | `/api/v1/auth/me/password` | 회원 | 비밀번호 변경 |
@@ -216,3 +240,4 @@
- `admin.html`은 3개 언어 번역 적용이 완료되지 않았다.
- Homepage 전용 `GET /api/homepage` 엔드포인트는 아직 구현되지 않았다.
- 현재 Compose의 컨테이너명(`uniare-api`, `uniare-web`)과 데이터 볼륨명(`uniare-data`)은 고정값이며 환경 변수화되지 않았다.
- Resend 발송은 운영 `.env`의 API 키·발신 주소와 Resend에서 인증된 발신 도메인이 필요하다.