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
@@ -5,7 +5,9 @@ import (
"fmt"
"time"
"apocapoc-api/internal/domain/entities"
"apocapoc-api/internal/domain/repositories"
"apocapoc-api/internal/domain/services"
"apocapoc-api/internal/shared/errors"
)
@@ -14,12 +16,20 @@ type VerifyEmailCommand struct {
}
type VerifyEmailHandler struct {
userRepo repositories.UserRepository
userRepo repositories.UserRepository
emailService services.EmailService
sendWelcomeEmail bool
}
func NewVerifyEmailHandler(userRepo repositories.UserRepository) *VerifyEmailHandler {
func NewVerifyEmailHandler(
userRepo repositories.UserRepository,
emailService services.EmailService,
sendWelcomeEmail bool,
) *VerifyEmailHandler {
return &VerifyEmailHandler{
userRepo: userRepo,
userRepo: userRepo,
emailService: emailService,
sendWelcomeEmail: sendWelcomeEmail,
}
}
@@ -50,5 +60,27 @@ func (h *VerifyEmailHandler) Handle(ctx context.Context, cmd VerifyEmailCommand)
return fmt.Errorf("failed to verify email: %w", err)
}
if h.sendWelcomeEmail && h.emailService != nil {
h.sendWelcomeEmailToUser(user)
}
return nil
}
func (h *VerifyEmailHandler) sendWelcomeEmailToUser(user *entities.User) error {
emailBody := fmt.Sprintf(`
<h2>Welcome to Apocapoc!</h2>
<p>Your email has been successfully verified.</p>
<p>You can now start tracking your habits and building better routines.</p>
<p>If you have any questions or need help, please don't hesitate to contact us.</p>
`)
message := services.EmailMessage{
To: user.Email,
Subject: "Welcome to Apocapoc!",
Body: emailBody,
IsHTML: true,
}
return h.emailService.Send(message)
}