feat: Auth.js v5 인증 시스템 구현 - 카카오 소셜 + 이메일/비번 로그인
- Auth.js v5 (next-auth beta.30) + 커스텀 Prisma 어댑터 (BigInt PK 호환) - 카카오 OAuth2 소셜 로그인 (PKCE 비활성화, placeholder 이메일 처리) - 이메일/비밀번호 자격증명 로그인 (argon2 해시) - JWT 세션 전략 + 커스텀 클레임 (publicId, primaryRole, userStatus) - 역할 기반 미들웨어 (/admin 운영자 전용, /auth 비인증 전용) - Prisma 스키마: Account, VerificationToken, InviteToken 모델 추가 - ConsentType enum 7개로 업데이트 - 로그인/회원가입/프로필완성/403 페이지 구현 - 운영자 초대 시스템 (admin/settings/invite)
This commit is contained in:
@@ -64,11 +64,13 @@ enum ProfileType {
|
||||
}
|
||||
|
||||
enum ConsentType {
|
||||
PRIVACY_POLICY
|
||||
TERMS_OF_SERVICE
|
||||
MARKETING
|
||||
THIRD_PARTY_SHARING
|
||||
INFORMATION_DISCLOSURE
|
||||
PRIVACY_POLICY_REQUIRED
|
||||
PRIVACY_POLICY_MARKETING
|
||||
STORE_PUBLICATION_CONSENT
|
||||
MATCHED_INFO_DISCLOSURE
|
||||
THIRD_PARTY_MATCHED_PARTY
|
||||
NOTIFICATION_KAKAO
|
||||
|
||||
@@map("consent_type")
|
||||
}
|
||||
@@ -378,6 +380,8 @@ model User {
|
||||
phone String? @map("phone")
|
||||
phoneNormalized String? @map("phone_normalized")
|
||||
name String @map("name")
|
||||
passwordHash String? @map("password_hash")
|
||||
image String? @map("image")
|
||||
primaryRole UserRole @map("primary_role")
|
||||
status UserStatus @default(PENDING_VERIFICATION) @map("status")
|
||||
emailVerifiedAt DateTime? @map("email_verified_at") @db.Timestamptz(6)
|
||||
@@ -412,6 +416,8 @@ model User {
|
||||
disputesResolvedBy DisputeCase[] @relation("DisputeResolvedByUser")
|
||||
certificationReviewedBy VendorCertification[] @relation("CertificationReviewedByUser")
|
||||
auditLogs AuditLog[]
|
||||
accounts Account[]
|
||||
invitesCreated InviteToken[] @relation("InviteCreator")
|
||||
|
||||
@@index([primaryRole, status], map: "idx_user_role_status")
|
||||
@@map("users")
|
||||
@@ -452,6 +458,53 @@ model UserConsent {
|
||||
@@map("user_consents")
|
||||
}
|
||||
|
||||
/// Auth.js 소셜 로그인 계정 연동
|
||||
model Account {
|
||||
id BigInt @id @default(autoincrement()) @map("id")
|
||||
userId BigInt @map("user_id")
|
||||
type String @map("type")
|
||||
provider String @map("provider")
|
||||
providerAccountId String @map("provider_account_id")
|
||||
refresh_token String? @map("refresh_token") @db.Text
|
||||
access_token String? @map("access_token") @db.Text
|
||||
expires_at Int? @map("expires_at")
|
||||
token_type String? @map("token_type")
|
||||
scope String? @map("scope")
|
||||
id_token String? @map("id_token") @db.Text
|
||||
session_state String? @map("session_state")
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([provider, providerAccountId])
|
||||
@@map("accounts")
|
||||
}
|
||||
|
||||
/// 이메일 인증 토큰
|
||||
model VerificationToken {
|
||||
identifier String @map("identifier")
|
||||
token String @unique @map("token")
|
||||
expires DateTime @map("expires") @db.Timestamptz(6)
|
||||
|
||||
@@id([identifier, token])
|
||||
@@map("verification_tokens")
|
||||
}
|
||||
|
||||
/// 운영자 초대 토큰
|
||||
model InviteToken {
|
||||
id BigInt @id @default(autoincrement()) @map("id")
|
||||
email String @map("email")
|
||||
role UserRole @map("role")
|
||||
token String @unique @default(cuid()) @map("token")
|
||||
expires DateTime @map("expires") @db.Timestamptz(6)
|
||||
usedAt DateTime? @map("used_at") @db.Timestamptz(6)
|
||||
createdBy BigInt @map("created_by")
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
||||
|
||||
creator User @relation("InviteCreator", fields: [createdBy], references: [id])
|
||||
|
||||
@@map("invite_tokens")
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 2. 매장 공급 도메인
|
||||
// =============================================================================
|
||||
|
||||
Reference in New Issue
Block a user