Improve email verification flow and error handling

- Send verification email before creating user to prevent orphaned accounts
- Detect SMTP authentication errors and fail fast without retries
- Add field-level validation errors for better frontend UX
- Configure docker-compose with explicit environment variables
- Document dollar sign escaping in .env.example (use $$)
- Implement welcome email on successful verification
- Clean up unnecessary comments
This commit is contained in:
2025-11-28 11:32:51 +01:00
parent 00f6b51228
commit f37c1ac19b
24 changed files with 850 additions and 78 deletions
+8 -10
View File
@@ -31,6 +31,7 @@ type RegisterUserHandler struct {
emailService services.EmailService
appURL string
registrationMode string
sendWelcomeEmail bool
}
func NewRegisterUserHandler(
@@ -39,6 +40,7 @@ func NewRegisterUserHandler(
emailService services.EmailService,
appURL string,
registrationMode string,
sendWelcomeEmail bool,
) *RegisterUserHandler {
return &RegisterUserHandler{
userRepo: userRepo,
@@ -46,6 +48,7 @@ func NewRegisterUserHandler(
emailService: emailService,
appURL: appURL,
registrationMode: registrationMode,
sendWelcomeEmail: sendWelcomeEmail,
}
}
@@ -55,7 +58,7 @@ func (h *RegisterUserHandler) Handle(ctx context.Context, cmd RegisterUserComman
}
if err := validation.ValidateRegistration(cmd.Email, cmd.Password, cmd.Timezone); err != nil {
return nil, errors.ErrInvalidInput
return nil, fmt.Errorf("%w: %v", errors.ErrInvalidInput, err)
}
existing, _ := h.userRepo.FindByEmail(ctx, cmd.Email)
@@ -81,6 +84,10 @@ func (h *RegisterUserHandler) Handle(ctx context.Context, cmd RegisterUserComman
user.EmailVerificationToken = &token
user.EmailVerificationExpiry = &expiry
emailVerificationRequired = true
if err := h.sendVerificationEmail(user); err != nil {
return nil, fmt.Errorf("failed to send verification email: %w", err)
}
} else {
user.EmailVerified = true
}
@@ -89,15 +96,6 @@ func (h *RegisterUserHandler) Handle(ctx context.Context, cmd RegisterUserComman
return nil, err
}
if h.emailService != nil && user.EmailVerificationToken != nil {
if err := h.sendVerificationEmail(user); err != nil {
return &RegisterUserResult{
UserID: user.ID,
EmailVerificationRequired: emailVerificationRequired,
}, nil
}
}
return &RegisterUserResult{
UserID: user.ID,
EmailVerificationRequired: emailVerificationRequired,