fix(backend): Fix database foreign key constraint bug (BUG-002)

Critical bug fix for tenant registration failure caused by incorrect EF Core migration.

## Problem
The AddUserTenantRoles migration generated duplicate columns:
- Application columns: user_id, tenant_id (used by code)
- Shadow FK columns: user_id1, tenant_id1 (incorrect EF Core generation)

Foreign key constraints referenced wrong columns (user_id1/tenant_id1), causing all
tenant registrations to fail with:
```
violates foreign key constraint "FK_user_tenant_roles_tenants_tenant_id1"
```

## Root Cause
UserTenantRoleConfiguration.cs used string column names in HasForeignKey(),
combined with Value Object properties (UserId/TenantId), causing EF Core to
create shadow properties with duplicate names (user_id1, tenant_id1).

## Solution
1. **Configuration Change**:
   - Keep Value Object properties (UserId, TenantId) for application use
   - Ignore navigation properties (User, Tenant) to prevent shadow property generation
   - Let EF Core use the converted Value Object columns for data storage

2. **Migration Change**:
   - Delete incorrect AddUserTenantRoles migration
   - Generate new FixUserTenantRolesIgnoreNavigation migration
   - Drop duplicate columns (user_id1, tenant_id1)
   - Recreate FK constraints referencing correct columns (user_id, tenant_id)

## Changes
- Modified: UserTenantRoleConfiguration.cs
  - Ignore navigation properties (User, Tenant)
  - Use Value Object conversion for UserId/TenantId columns
- Deleted: 20251103135644_AddUserTenantRoles migration (broken)
- Added: 20251103150353_FixUserTenantRolesIgnoreNavigation migration (fixed)
- Updated: IdentityDbContextModelSnapshot.cs (no duplicate columns)
- Added: test-bugfix.ps1 (regression test script)

## Test Results
- Tenant registration: SUCCESS
- JWT Token generation: SUCCESS
- Refresh Token generation: SUCCESS
- Foreign key constraints: CORRECT (user_id, tenant_id)

## Database Schema (After Fix)
```sql
CREATE TABLE identity.user_tenant_roles (
    id uuid PRIMARY KEY,
    user_id uuid NOT NULL,     -- Used by application & FK
    tenant_id uuid NOT NULL,   -- Used by application & FK
    role varchar(50) NOT NULL,
    assigned_at timestamptz NOT NULL,
    assigned_by_user_id uuid,
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);
```

Fixes: BUG-002 (CRITICAL)
Severity: CRITICAL - Blocked all tenant registrations
Impact: Day 5 RBAC feature now working

🤖 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 16:07:14 +01:00
parent aaab26ba6c
commit 738d32428a
6 changed files with 136 additions and 183 deletions

View File

@@ -0,0 +1,49 @@
# Test Bug Fix - Tenant Registration
$body = @{
tenantName = "BugFix Test Corp"
tenantSlug = "bugfix-test-$(Get-Random)"
subscriptionPlan = "Professional"
adminEmail = "admin@bugfix$(Get-Random).com"
adminPassword = "Admin@1234"
adminFullName = "Bug Fix Admin"
} | ConvertTo-Json
Write-Host "Testing Tenant Registration..."
Write-Host "Endpoint: http://localhost:5167/api/tenants/register"
try {
$response = Invoke-RestMethod -Uri "http://localhost:5167/api/tenants/register" `
-Method Post `
-ContentType "application/json" `
-Body $body `
-ErrorAction Stop
Write-Host ""
Write-Host "==================================" -ForegroundColor Green
Write-Host "SUCCESS - BUG FIXED!" -ForegroundColor Green
Write-Host "==================================" -ForegroundColor Green
Write-Host ""
Write-Host "Tenant Name: $($response.tenantName)" -ForegroundColor Cyan
Write-Host "Tenant Slug: $($response.tenantSlug)" -ForegroundColor Cyan
Write-Host "User Email: $($response.user.email)" -ForegroundColor Cyan
Write-Host "User Role: $($response.user.role)" -ForegroundColor Cyan
Write-Host "Access Token: $($response.accessToken.Substring(0, 50))..." -ForegroundColor Yellow
Write-Host "Refresh Token: $($response.refreshToken.Substring(0, 50))..." -ForegroundColor Yellow
Write-Host ""
Write-Host "The foreign key constraint bug has been successfully fixed!" -ForegroundColor Green
exit 0
} catch {
Write-Host ""
Write-Host "==================================" -ForegroundColor Red
Write-Host "FAILURE - Bug Still Exists" -ForegroundColor Red
Write-Host "==================================" -ForegroundColor Red
Write-Host ""
Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red
Write-Host ""
if ($_.Exception.Response) {
$reader = New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream())
$responseBody = $reader.ReadToEnd()
Write-Host "Response: $responseBody" -ForegroundColor Yellow
}
exit 1
}