feat: password reset flow and email verification

- Add forgot-password and reset-password pages and API routes
- Add email verification with token generation on registration
- Add resend-verification endpoint with 60s rate limit
- Add shared email utility (nodemailer, Migadu SMTP)
- Add VerificationBanner in dashboard layout
- Add PasswordResetToken and EmailVerificationToken models
- Add emailVerified field to User model
- Extend NextAuth session with isEmailVerified
- Add forgot-password link to login page
- Wire EMAIL_PASSWORD env var in docker-compose
This commit is contained in:
Vectry
2026-02-10 16:47:06 +00:00
parent 0e4ffce4fa
commit 539d35b649
16 changed files with 1026 additions and 6 deletions

View File

@@ -14,6 +14,7 @@ model User {
email String @unique
passwordHash String
name String?
emailVerified Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@ -21,10 +22,42 @@ model User {
subscription Subscription?
apiKeys ApiKey[]
traces Trace[]
passwordResetTokens PasswordResetToken[]
emailVerificationTokens EmailVerificationToken[]
@@index([email])
}
model PasswordResetToken {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
token String @unique // SHA-256 hash of the raw token
expiresAt DateTime
used Boolean @default(false)
createdAt DateTime @default(now())
@@index([token])
@@index([userId])
}
model EmailVerificationToken {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
token String @unique // SHA-256 hash of the raw token
expiresAt DateTime
used Boolean @default(false)
createdAt DateTime @default(now())
@@index([token])
@@index([userId])
}
model ApiKey {
id String @id @default(cuid())
userId String