feat: 소셜 로그인(Google/Kakao) 및 회원가입 이메일 인증 추가
- User 엔티티 확장: passwordHash nullable, provider, emailVerified, 인증 토큰 해시/만료(select:false) - 회원가입: 자동 로그인 폐지 → 미인증 계정 생성 + 인증 메일 발송(MailService 플레이스홀더, 백엔드 로그로 링크 출력) - 이메일 인증: GET /auth/verify-email(해시 매칭+만료 검사) → 프론트로 리다이렉트, 재발송 엔드포인트 - 로그인 게이트: 미인증 로컬 403 차단, 소셜 전용 계정은 소셜 로그인 안내 - 소셜 OAuth: passport google/kakao 전략(키 미설정 시 자동 비활성), 이메일로 계정 매칭/생성 - 기존 로컬 계정 그랜드페더링(부팅 시 인증 완료 보정) - 프론트: 가입 후 인증 메일 안내 화면, 로그인 소셜 버튼 실연동 + 인증 결과 배너 - env(APP_API_URL/FRONTEND_URL/GOOGLE_*/KAKAO_*) 문서화, 문서·계약 갱신 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -265,8 +265,30 @@
|
||||
|
||||
> **알려진 한계**: ① 캐싱 대상은 현재 저장소 목록 1종(가장 트래픽 큰 랜딩) — 업무 목록 등은 세그먼트/검색/페이지 조합이 많아 추후 확장 후보. ② 업무 카운트 ≤60초 지연(위). ③ **의존성 추가(`@keyv/redis`)라 dev 컨테이너는 `up -d --build -V`(익명 node_modules 볼륨 갱신) 필요.**
|
||||
|
||||
#### 8-4. 그 외(미착수)
|
||||
- 소셜 로그인(Google/Kakao OAuth), 이메일 인증, AI 에이전트 패널 실연동.
|
||||
#### 8-4. 소셜 로그인 + 회원가입 이메일 인증 ✅ (2026-06-19)
|
||||
|
||||
**지시(2026-06-19)**: 소셜 키는 백엔드 env 에 등록됨 → 바로 연동. 회원가입은 인증 메일의 버튼 클릭 시 완료. **메일 전송은 우선 백엔드 로그로 대체.**
|
||||
|
||||
**백엔드**
|
||||
- **User 엔티티 확장**(`modules/user/entities/user.entity.ts`): `passwordHash` **nullable**(소셜 전용 계정=null), `provider`('local'|'google'|'kakao', default 'local'), `emailVerified`(bool, default false), `emailVerifyTokenHash`/`emailVerifyExpiresAt`(둘 다 select:false). 원문 인증 토큰은 메일 링크에만 담고 DB엔 **SHA-256 해시 + 만료(24h)** 만 저장.
|
||||
- **그랜드페더링**(`UserService.onApplicationBootstrap`): 인증 도입 이전 로컬 계정 락아웃 방지 — `provider='local' & 토큰 null & 미인증` 행을 인증완료로 보정(멱등 — 진행 중 미인증 계정은 토큰을 보유해 제외).
|
||||
- **메일 모듈**(신규 `modules/mail/`): `MailService.sendVerificationEmail()` 플레이스홀더 — **인증 링크를 백엔드 Logger 로 출력**(추후 SMTP 도입 시 이 서비스만 교체).
|
||||
- **AuthService**: `signup` **자동 로그인 폐지** → 미인증 계정 생성 + 인증 메일 발송, 응답 `{email, verificationPending}`. `verifyEmail(token)`(해시 매칭 + 만료 검사 → 인증 완료, 토큰 폐기), `resendVerification`(존재/상태 비노출), `validateUser` 에 **로그인 게이트**(미인증 로컬=`BIZ_001` 403, 비밀번호 없는 소셜 전용=소셜 안내), `validateOrCreateOAuthUser`(이메일로 매칭→없으면 생성 emailVerified=true, 미인증 로컬과 이메일 같으면 인증 보정).
|
||||
- **소셜 전략**(passport-google-oauth20·passport-kakao 신규 의존성, kakao 무타입→`auth/types/passport-kakao.d.ts` 앰비언트 선언): `GoogleStrategy`/`KakaoStrategy` 가 프로필 정규화 후 위임. **키(`*_CLIENT_ID`) 미설정 시 전략 미등록**(AuthModule `useFactory` 가드 — null 반환).
|
||||
- **AuthController**: `signup`(쿠키 미발급)·`resend-verification`·**`GET verify-email`**(`@SkipTransform`+`@Res` 302 → `FRONTEND_URL/login?verified=1|0`)·**`GET google|kakao` + `/callback`**(`@SkipTransform`, 콜백서 쿠키 발급 → `FRONTEND_URL/repos`). `loginWith` 헬퍼로 토큰 발급+쿠키 공통화.
|
||||
- **env**: `APP_API_URL`(메일 링크용 백엔드 주소, 폴백 `localhost:3100/api`)·`FRONTEND_URL`(리다이렉트, 폴백 CORS_ORIGIN→5273) + `GOOGLE_*`/`KAKAO_*`(콜백 URL 은 백엔드 포트 **3100**, `/api/auth/{provider}/callback`) → `backend/.env.development.example` 문서화.
|
||||
|
||||
**프론트**
|
||||
- `types/auth.ts` `SignupResult`, `useAuth`/`auth.store`: signup→대기(user 미갱신) + `resendVerification`.
|
||||
- **SignupPage**: 가입 성공 시 자동 로그인 대신 **인증 메일 안내(verify 단계)** 표시 + 재발송 버튼 연동.
|
||||
- **LoginPage**: 소셜 버튼 실연동(`window.location.href = ${VITE_API_BASE_URL}/auth/{provider}` 전체 페이지 이동) + `?verified=1|0` 결과 배너.
|
||||
|
||||
**검증**: 백엔드 build/lint 0 err·20 tests pass(MailService 가 AuthService 4번째 생성자 인자 — 영향 spec 없음), 프론트 type-check/lint/build 0 err.
|
||||
|
||||
> **알려진 한계**: ① **런타임 미검증** — DB + 소셜 콘솔에 콜백 URL 등록 필요(코드 레벨까지). ② 메일은 **로그 출력**(실발송 SMTP 미구현). ③ **의존성 추가(passport-google-oauth20/passport-kakao)라 dev 컨테이너 `up -d --build -V` 필요.** ④ 소셜 계정은 이메일 기준 매칭(별도 providerId 컬럼 없음) — 동일 이메일이면 동일인으로 연동.
|
||||
|
||||
#### 8-5. 그 외(미착수)
|
||||
- AI 에이전트 패널 실연동, 메일 실발송(SMTP).
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user