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

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

@@ -1,5 +1,19 @@
# 변경사항
## v4.0.12
### 이메일 인증 회원가입
새로 가입하는 사용자는 가입한 이메일로 전송된 링크를 눌러야 로그인할 수 있습니다. 인증 메일을 받지 못한 경우 인증 화면에서 다시 요청할 수 있습니다.
### 비밀번호 직접 재설정
로그인 화면의 `비밀번호를 잊으셨나요?`에서 가입 이메일로 재설정 링크를 받아 새 비밀번호를 설정할 수 있습니다.
### 중복 가입 검증 강화
이메일 형식을 서버에서도 확인하며, 사용자명은 영문 대소문자만 다른 경우에도 중복 가입을 차단합니다.
## v4.0.11
### 로그인 유지 선택

View File

@@ -29,6 +29,9 @@ JWT_SECRET=32자_이상의_랜덤_문자열
ADMIN_EMAIL=관리자_이메일
ADMIN_PASSWORD=8자_이상의_비밀번호
WEB_PORT=44082
APP_BASE_URL=http://localhost:44082
RESEND_API_KEY=Resend_API_Key
RESEND_FROM_EMAIL=UNIARE <인증된_발신주소>
```
랜덤 문자열은 `openssl rand -hex 32`로 만들 수 있다.
@@ -59,15 +62,27 @@ ADMIN_PASSWORD=8자_이상의_비밀번호
ADMIN_USERNAME=admin
WEB_PORT=44082
CORS_ORIGINS=https://uniare.sori.studio
APP_BASE_URL=https://uniare.sori.studio
RESEND_API_KEY=Resend_API_Key
RESEND_FROM_EMAIL=UNIARE <account@인증된_발신도메인>
```
Resend에서 소유한 도메인 또는 발신용 하위 도메인을 먼저 추가하고 DNS 인증을 완료해야 한다. API Key에는 메일 발송 권한이 필요하며 `.env` 외에는 기록하지 않는다.
Docker 실행: `docker compose -f docker-compose.prod.yml up -d --build`
상태 확인: `docker compose -f docker-compose.prod.yml ps`
API 확인: `curl -fsS http://localhost:44082/api/v1/health`
정상이면 `{"ok":true,"version":"4.0.11"}`이 표시된다.
정상이면 `{"ok":true,"version":"4.0.12"}`이 표시된다.
이메일 기능 확인:
1. 실제 수신 가능한 주소로 신규 가입한다.
2. 인증 메일 링크를 누르기 전 로그인이 차단되는지 확인한다.
3. 인증 후 로그인되는지 확인한다.
4. 로그인 화면의 `비밀번호를 잊으셨나요?`에서 재설정 메일과 새 비밀번호 로그인을 확인한다.
NAS 리버스 프록시는 `https://uniare.sori.studio`을 `http://<NAS_IP>:44082`로 연결한다.
@@ -142,6 +157,8 @@ curl -s http://127.0.0.1:44082/script/deck-favorites.js | tail -1
HTML·`style/`·`script/`만 바뀐 경우 API 컨테이너 재시작은 필요 없다.
이메일 기능은 API와 Compose 환경 변수가 함께 바뀌므로 `git pull`만으로 반영되지 않는다. 반드시 `.env` 설정 후 전체 스택을 다시 빌드한다.
## 4. 전체 업데이트
`api/`, `nginx/`, Dockerfile, Compose 설정을 변경했다면 NAS 프로젝트 폴더에서 다음 명령을 실행한다.

View File

@@ -1,5 +1,10 @@
# 의사결정 이력
## 2026-06-25 v4.0.12 — 신규 가입부터 이메일 소유 확인 적용
💡 기존 회원을 잠그지 않으면서 허위 이메일 가입과 관리자 의존 비밀번호 초기화를 막기 위함.
🔧 기존 회원은 인증 완료로 이관하고 신규 회원은 Resend 인증 후 로그인, 재설정 토큰은 해시·1회용·30분 만료로 저장.
## 2026-06-24 v4.0.11 — 로그인 유지와 실제 접속 시각을 분리 관리
💡 브라우저 종료 후 로그인 유지 여부는 사용자가 선택하고, 접속 기록은 재로그인 없이도 실제 이용을 반영해야 하기 때문.

View File

@@ -18,6 +18,15 @@ login.html
/signup.html
signup.html
/verify-email.html
verify-email.html
/forgot-password.html
forgot-password.html
/reset-password.html
reset-password.html
/profile.html
profile.html
@@ -110,9 +119,12 @@ api/src/db.js
JWT 인증·권한
api/src/middleware/auth.js
회원가입·로그인·프로필·인증 세션 접속 시각 갱신
회원가입·이메일 인증·비밀번호 재설정·로그인·프로필·인증 세션 접속 시각 갱신
api/src/routes/auth.js
Resend 인증·비밀번호 재설정 메일
api/src/services/emailService.js
덱 저장·조회·공개 목록
api/src/routes/decks.js

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에서 인증된 발신 도메인이 필요하다.

View File

@@ -5,6 +5,7 @@
- NAS에서 `uniare-web`, `uniare-api` 스택의 재기동과 헬스 체크를 최종 확인한다.
- SEO 메타데이터 배포 후 Google Search Console에서 메인 URL 재색인을 요청한다.
- 운영 `.env`의 `JWT_SECRET`, 관리자 계정, CORS 허용 도메인을 실제 환경 기준으로 점검한다.
- Resend에서 발신용 하위 도메인을 인증하고 운영 `.env`의 `RESEND_API_KEY`, `RESEND_FROM_EMAIL`, `APP_BASE_URL`을 설정한 뒤 실제 수신을 확인한다.
- DB와 업로드 이미지(`api/data/previews`, `api/data/avatars`)의 정기 백업·복구 절차를 검증한다.
- 원격 저장소의 Git LFS 업로드 상태와 용량 정책을 확인한다.
- Compose의 컨테이너명과 데이터 볼륨명을 환경 변수로 관리할지 결정하고, 적용 시 운영 마이그레이션 절차를 작성한다.

View File

@@ -1,5 +1,15 @@
# 업데이트 이력
## 2026-06-25 / v4.0.12 — 이메일 인증·비밀번호 재설정
### 수행 작업
- 신규 회원가입 시 Resend 이메일 인증 링크 발송, 인증 완료 전 로그인 차단
- 인증 메일 재전송과 24시간·1회용 인증 토큰 적용
- 비밀번호 찾기·30분 만료 재설정 링크·사용자 직접 비밀번호 변경 화면 추가
- 이메일 형식 서버 검증과 사용자명 대소문자 무시 중복 검사 적용
- 기존 회원은 배포 시 이메일 인증 완료 상태로 마이그레이션
- Resend 환경 변수와 운영 배포·확인 절차 문서화
## 2026-06-24 / v4.0.11 — 로그인 유지·마지막 접속 갱신 개선
### 수행 작업