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
@@ -0,0 +1,40 @@
package entities
import (
"time"
"github.com/google/uuid"
)
type PasswordResetToken struct {
ID string
UserID string
Token string
ExpiresAt time.Time
UsedAt *time.Time
CreatedAt time.Time
}
func NewPasswordResetToken(userID, token string, expiresAt time.Time) *PasswordResetToken {
return &PasswordResetToken{
ID: uuid.NewString(),
UserID: userID,
Token: token,
ExpiresAt: expiresAt,
UsedAt: nil,
CreatedAt: time.Now(),
}
}
func (t *PasswordResetToken) IsExpired() bool {
return time.Now().After(t.ExpiresAt)
}
func (t *PasswordResetToken) IsUsed() bool {
return t.UsedAt != nil
}
func (t *PasswordResetToken) MarkAsUsed() {
now := time.Now()
t.UsedAt = &now
}
@@ -0,0 +1,14 @@
package repositories
import (
"context"
"apocapoc-api/internal/domain/entities"
)
type PasswordResetTokenRepository interface {
Create(ctx context.Context, token *entities.PasswordResetToken) error
FindByToken(ctx context.Context, token string) (*entities.PasswordResetToken, error)
Update(ctx context.Context, token *entities.PasswordResetToken) error
DeleteExpired(ctx context.Context) error
}
@@ -12,4 +12,5 @@ type UserRepository interface {
FindByEmail(ctx context.Context, email string) (*entities.User, error)
FindByVerificationToken(ctx context.Context, token string) (*entities.User, error)
Update(ctx context.Context, user *entities.User) error
Delete(ctx context.Context, id string) error
}