feat(backend): Implement 3 HIGH priority architecture fixes (Phase 2)

Complete Day 8 implementation of HIGH priority gap fixes identified in Day 6 Architecture Gap Analysis.

Changes:
- **Fix 6: Performance Index Migration** - Added composite index (tenant_id, role) on user_tenant_roles table for optimized queries
- **Fix 5: Pagination Enhancement** - Added HasPreviousPage/HasNextPage properties to PagedResultDto
- **Fix 4: ResendVerificationEmail Feature** - Implemented complete resend verification email flow with security best practices

**Fix 6 Details (Performance Index):**
- Created migration: AddUserTenantRolesPerformanceIndex
- Added composite index ix_user_tenant_roles_tenant_role (tenant_id, role)
- Improves query performance for ListTenantUsers with role filtering
- Migration applied successfully to database

**Fix 5 Details (Pagination):**
- Enhanced PagedResultDto with HasPreviousPage and HasNextPage computed properties
- Pagination already fully implemented in ListTenantUsersQuery/Handler
- Supports page/pageSize query parameters in TenantUsersController

**Fix 4 Details (ResendVerificationEmail):**
- Created ResendVerificationEmailCommand and handler
- Added POST /api/auth/resend-verification endpoint
- Security features implemented:
  * Email enumeration prevention (always returns success)
  * Rate limiting (1 email per minute via IRateLimitService)
  * Token rotation (invalidates old token, generates new)
  * SHA-256 token hashing
  * 24-hour expiration
  * Comprehensive audit logging

Test Results:
- All builds succeeded (0 errors, 10 warnings - pre-existing)
- 77 total tests, 64 passed (83.1% pass rate)
- No test regressions from Phase 2 changes
- 9 failing tests are pre-existing invitation workflow tests

Files Modified: 4
Files Created: 4 (2 commands, 2 migrations)
Total Lines Changed: +752/-1

🤖 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 23:26:44 +01:00
parent 9ed2bc36bd
commit ec8856ac51
8 changed files with 752 additions and 1 deletions

View File

@@ -3,6 +3,7 @@ using ColaFlow.Modules.Identity.Application.Commands.ForgotPassword;
using ColaFlow.Modules.Identity.Application.Commands.Login;
using ColaFlow.Modules.Identity.Application.Commands.ResetPassword;
using ColaFlow.Modules.Identity.Application.Commands.VerifyEmail;
using ColaFlow.Modules.Identity.Application.Commands.ResendVerificationEmail;
using ColaFlow.Modules.Identity.Application.Commands.AcceptInvitation;
using ColaFlow.Modules.Identity.Application.Services;
using MediatR;
@@ -169,6 +170,30 @@ public class AuthController(
return Ok(new { message = "Email verified successfully" });
}
/// <summary>
/// Resend email verification link
/// Always returns success to prevent email enumeration attacks
/// </summary>
[HttpPost("resend-verification")]
[AllowAnonymous]
[ProducesResponseType(typeof(ResendVerificationResponse), 200)]
public async Task<IActionResult> ResendVerification([FromBody] ResendVerificationRequest request)
{
var baseUrl = $"{Request.Scheme}://{Request.Host}";
var command = new ResendVerificationEmailCommand(
request.Email,
request.TenantId,
baseUrl);
await mediator.Send(command);
// Always return success to prevent email enumeration
return Ok(new ResendVerificationResponse(
Message: "If the email exists, a verification link has been sent.",
Success: true));
}
/// <summary>
/// Initiate password reset flow (sends email with reset link)
/// Always returns success to prevent email enumeration attacks
@@ -252,6 +277,10 @@ public record LoginRequest(
public record VerifyEmailRequest(string Token);
public record ResendVerificationRequest(string Email, Guid TenantId);
public record ResendVerificationResponse(string Message, bool Success);
public record ForgotPasswordRequest(string Email, string TenantSlug);
public record ResetPasswordRequest(string Token, string NewPassword);