feat(backend): Implement email verification flow - Phase 2

Add complete email verification system with token-based verification.

Changes:
- Created EmailVerificationToken domain entity with expiration and verification tracking
- Created EmailVerifiedEvent domain event for audit trail
- Updated User entity with IsEmailVerified property and VerifyEmail method
- Created IEmailVerificationTokenRepository interface and implementation
- Created SecurityTokenService for secure token generation and SHA-256 hashing
- Created EmailVerificationTokenConfiguration for EF Core mapping
- Updated IdentityDbContext to include EmailVerificationTokens DbSet
- Created SendVerificationEmailCommand and handler for sending verification emails
- Created VerifyEmailCommand and handler for email verification
- Added POST /api/auth/verify-email endpoint to AuthController
- Integrated email verification into RegisterTenantCommandHandler
- Registered all new services in DependencyInjection
- Created and applied AddEmailVerification database migration
- Build successful with no compilation errors

Database Schema:
- email_verification_tokens table with indexes on token_hash and user_id
- 24-hour token expiration
- One-time use tokens with verification tracking

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Yaojia Wang
2025-11-03 21:30:40 +01:00
parent 921990a043
commit 3dcecc656f
20 changed files with 2823 additions and 3 deletions

View File

@@ -1,5 +1,6 @@
using ColaFlow.API.Models;
using ColaFlow.Modules.Identity.Application.Commands.Login;
using ColaFlow.Modules.Identity.Application.Commands.VerifyEmail;
using ColaFlow.Modules.Identity.Application.Services;
using MediatR;
using Microsoft.AspNetCore.Authorization;
@@ -148,6 +149,22 @@ public class AuthController(
return BadRequest(new { message = "Logout failed" });
}
}
/// <summary>
/// Verify email address using token
/// </summary>
[HttpPost("verify-email")]
[AllowAnonymous]
public async Task<IActionResult> VerifyEmail([FromBody] VerifyEmailRequest request)
{
var command = new VerifyEmailCommand(request.Token);
var success = await mediator.Send(command);
if (!success)
return BadRequest(new { message = "Invalid or expired verification token" });
return Ok(new { message = "Email verified successfully" });
}
}
public record LoginRequest(
@@ -155,3 +172,5 @@ public record LoginRequest(
string Email,
string Password
);
public record VerifyEmailRequest(string Token);