# ColaFlow Day 6 Planning Document

**Date**: 2025-11-03
**Prepared By**: Product Manager Agent
**Sprint**: M1 Sprint 2 - Enterprise-Grade Multi-Tenancy & SSO
**Status**: Planning Complete - Ready for Implementation

---

## Executive Summary

After analyzing the project's current state (Day 1-5 complete: JWT authentication, Refresh Token, RBAC with 5 roles, and integration tests), I recommend **Role Management API** as the Day 6 priority. This choice is strategically optimal because:

1. **Immediate Business Value**: Enables tenant administrators to invite and manage users (critical for multi-tenant SaaS)
2. **Technical Foundation**: Completes the authentication/authorization loop started in Days 4-5
3. **MCP Readiness**: Establishes role assignment patterns needed for AI agents in M2
4. **Realistic Scope**: Can be completed in 6-8 hours with full test coverage
5. **Low Risk**: Builds on existing RBAC system (no new architectural decisions)

**Recommended Scope for Day 6**: Role Management API (Option 1)

---

## Day 6 Priority Analysis

### Priority Matrix

| Option | Business Value | Technical Complexity | MCP Dependency | Risk Level | Time Estimate | Priority Ranking |
|--------|---------------|---------------------|----------------|-----------|---------------|------------------|
| **Option 1: Role Management API** | **HIGH** | **MEDIUM** | **MEDIUM** | **LOW** | **6-8 hours** | **1st (RECOMMENDED)** |
| Option 2: Email Verification | MEDIUM | MEDIUM | LOW | MEDIUM | 8-10 hours | 2nd |
| Option 3: Password Reset | MEDIUM | MEDIUM | LOW | MEDIUM | 6-8 hours | 3rd |
| Option 4: Project-Level Roles | HIGH | HIGH | HIGH | HIGH | 10-12 hours | 4th (Defer to Day 7) |
| Option 5: User Invitations | HIGH | HIGH | MEDIUM | MEDIUM | 10-12 hours | 5th (Combine with Option 1) |

---

### Option 1: Role Management API (RECOMMENDED)

**Priority**: P0 (Must have for Day 6)

#### Why This is the Best Choice

**1. Business Value (HIGH)**
- Completes the tenant management loop: Registration → Login → **User Management**
- Enables self-service user onboarding (critical for SaaS adoption)
- Reduces customer support burden (tenant admins manage their own users)
- Foundation for enterprise features (team management, access control)

**2. Technical Dependencies (Satisfied)**
- ✅ RBAC system already implemented (Day 5 Phase 2)
- ✅ JWT includes role claims
- ✅ Authorization policies configured
- ✅ `user_tenant_roles` table exists
- ✅ `IUserTenantRoleRepository` implemented
- **Zero new infrastructure needed** - just add API endpoints

**3. MCP Integration Readiness (MEDIUM)**
- Establishes pattern for AI agent role assignment
- Preview workflow for role changes (human approval)
- Audit logging for compliance
- Future: AI can suggest role assignments based on user activity

**4. Risk Assessment (LOW)**
- No database migrations required (schema already exists)
- No new architectural patterns (reuses existing RBAC)
- Clear acceptance criteria (CRUD operations)
- Well-understood domain (role assignment is standard functionality)

**5. Development Effort (6-8 hours)**
- Application Layer Commands: 3 hours
- API Controllers: 2 hours
- Integration Tests: 2-3 hours
- Documentation: 1 hour

#### What Gets Delivered

**API Endpoints**:
1. `POST /api/tenants/{tenantId}/users/{userId}/role` - Assign/Update role
2. `DELETE /api/tenants/{tenantId}/users/{userId}/role` - Remove user from tenant
3. `GET /api/tenants/{tenantId}/users` - List all users with roles
4. `GET /api/tenants/{tenantId}/roles` - Get available roles

**Security Features**:
- Only `TenantOwner` can assign `TenantOwner` role
- `TenantAdmin` can manage `TenantMember` and `TenantGuest` roles
- Users cannot modify their own roles
- Role changes logged for audit

**Test Coverage**:
- 15+ integration tests covering all scenarios
- Security test cases (unauthorized access, privilege escalation)
- Edge cases (invalid role, non-existent user, cross-tenant access)

---

### Option 2: Email Verification (2nd Priority)

**Priority**: P1 (Nice to have for Day 6, Can defer to Day 7)

#### Analysis

**Business Value (MEDIUM)**
- Reduces spam registrations
- Validates user email addresses
- Standard security practice
- Required for password reset flow

**Technical Complexity (MEDIUM)**
- Requires email service integration (SendGrid or SMTP)
- Verification token generation and storage
- Email template design
- Token expiration handling

**Why Defer to Day 7**:
- **Blocking dependency**: Needs email service setup (adds complexity)
- **Not critical for MVP**: Can launch with unverified emails initially
- **Better as Day 7**: Combine with Password Reset (both need email service)

**Time Estimate**: 8-10 hours
- Email service integration: 3 hours
- Token generation: 2 hours
- API endpoints: 2 hours
- Email templates: 2 hours
- Testing: 2-3 hours

---

### Option 3: Password Reset (3rd Priority)

**Priority**: P1 (Defer to Day 7)

#### Analysis

**Business Value (MEDIUM)**
- Essential user experience feature
- Reduces support tickets
- Security best practice

**Technical Complexity (MEDIUM)**
- Shares email infrastructure with Email Verification
- Password reset token generation
- Secure token validation
- Rate limiting to prevent abuse

**Why Defer to Day 7**:
- **Synergy with Option 2**: Both need email service
- **Day 7 recommendation**: Implement Email Verification + Password Reset together
- **Better user flow**: Users expect both features together

**Time Estimate**: 6-8 hours (if email service already configured)

---

### Option 4: Project-Level Roles (4th Priority)

**Priority**: P1 (Defer to Day 7-8)

#### Analysis

**Business Value (HIGH)**
- Critical for M1 core project module
- Enables fine-grained access control (per-project permissions)
- Foundation for collaborative project management
- Required before implementing Projects CRUD

**Technical Complexity (HIGH)**
- New database table: `user_project_roles`
- New enum: `ProjectRole` (4 roles)
- Role inheritance logic (TenantOwner → ProjectOwner)
- Multi-level authorization (tenant + project)
- Complex query logic (check both tenant and project roles)

**Why Defer to Day 7-8**:
- **High complexity**: Needs 10-12 hours for proper implementation
- **Architectural decisions**: Role inheritance rules need careful design
- **Dependency on M1**: Projects module implementation should come first
- **Better timing**: After user management is stable

**MCP Dependency (HIGH)**:
- AI agents need project-level permissions for MCP
- Preview workflow operates at project level
- Critical for M2 MCP Server

**Time Estimate**: 10-12 hours
- Design role inheritance: 2 hours
- Domain layer: 2 hours
- Infrastructure layer: 2 hours
- Authorization policies: 2 hours
- API endpoints: 2 hours
- Testing: 3-4 hours

---

### Option 5: User Invitation Management (5th Priority)

**Priority**: P1 (Combine with Option 1)

#### Analysis

**Business Value (HIGH)**
- Essential for team collaboration
- Reduces friction in user onboarding
- Allows users to invite colleagues
- Token-based secure invitation flow

**Technical Complexity (HIGH)**
- New database table: `user_invitations`
- Invitation token generation
- Email invitation (depends on email service)
- Invitation acceptance workflow
- Invitation expiration and resend

**Why This is Complex**:
- **Email dependency**: Needs email service (same as Option 2)
- **New workflow**: Invitation → Email → Accept → User created
- **State management**: Pending, Accepted, Expired, Revoked
- **Security**: Prevent invitation abuse (rate limiting)

**Recommendation**:
- **Day 6**: Implement basic role assignment (Option 1)
- **Day 8-9**: Add invitation system after email service is configured

**Time Estimate**: 10-12 hours (full invitation flow)

---

## Day 6 Recommended Scope

### Core Feature: Role Management API

**Goal**: Enable tenant administrators to manage user roles within their tenant.

**Deliverables**:
1. ✅ Application Layer: Commands for role management
2. ✅ API Layer: RESTful endpoints for role operations
3. ✅ Authorization: Policy-based role assignment rules
4. ✅ Integration Tests: Full test coverage (15+ tests)
5. ✅ Documentation: API documentation and usage examples

**Success Criteria**:
- TenantOwner can assign any role to any user in tenant
- TenantAdmin can assign Member/Guest roles (not Owner/Admin)
- Users cannot modify their own roles
- All operations logged for audit
- 100% test pass rate
- No security vulnerabilities (privilege escalation, cross-tenant access)

---

## Detailed Requirements: Role Management API

### User Stories

**US-1: Assign Role to User**
- **As a** TenantOwner
- **I want to** assign a role to a user in my tenant
- **So that** I can control their access level to resources

**US-2: Update User Role**
- **As a** TenantOwner
- **I want to** change a user's role
- **So that** I can adjust their permissions as their responsibilities change

**US-3: Remove User from Tenant**
- **As a** TenantOwner
- **I want to** remove a user from my tenant
- **So that** I can revoke their access when they leave the organization

**US-4: View All Users and Roles**
- **As a** TenantAdmin
- **I want to** see all users in my tenant and their assigned roles
- **So that** I can understand the current access control state

**US-5: Prevent Privilege Escalation**
- **As a** system
- **I want to** prevent users from elevating their own privileges
- **So that** security is maintained

---

### Acceptance Criteria

#### AC-RM-1: Assign Role to User (POST /api/tenants/{tenantId}/users/{userId}/role)

**Given**: I am authenticated as TenantOwner of "tenant-a"
**When**: I assign role "TenantMember" to user "user-123"
**Then**:
- User "user-123" is assigned "TenantMember" role in "tenant-a"
- Response returns 200 OK with user details and new role
- New JWT issued on next login includes the updated role
- Audit log entry created: "TenantOwner assigned TenantMember to user-123"

**Edge Cases**:
- ❌ Cannot assign role to user in different tenant (403 Forbidden)
- ❌ Cannot assign role if not TenantOwner or TenantAdmin (403 Forbidden)
- ❌ Cannot assign TenantOwner role unless requester is TenantOwner (403 Forbidden)
- ❌ Cannot assign invalid role (400 Bad Request)
- ❌ Cannot assign role to non-existent user (404 Not Found)

---

#### AC-RM-2: Update User Role (PUT /api/tenants/{tenantId}/users/{userId}/role)

**Given**: User "user-456" currently has role "TenantGuest"
**When**: TenantOwner updates their role to "TenantMember"
**Then**:
- User's role changes from "TenantGuest" to "TenantMember"
- Response returns 200 OK with updated role
- Audit log entry created: "TenantOwner changed user-456 role from TenantGuest to TenantMember"

**Edge Cases**:
- ❌ Cannot update own role (403 Forbidden)
- ❌ TenantAdmin cannot promote user to TenantOwner (403 Forbidden)
- ❌ Cannot downgrade last TenantOwner (400 Bad Request - "At least one TenantOwner required")

---

#### AC-RM-3: Remove User from Tenant (DELETE /api/tenants/{tenantId}/users/{userId}/role)

**Given**: User "user-789" exists in "tenant-a"
**When**: TenantOwner removes user "user-789"
**Then**:
- User's role entry deleted from `user_tenant_roles` table
- User can no longer access tenant resources
- Response returns 204 No Content
- Audit log entry created: "TenantOwner removed user-789 from tenant"

**Edge Cases**:
- ❌ Cannot remove last TenantOwner (400 Bad Request)
- ❌ Cannot remove self (403 Forbidden)
- ❌ TenantAdmin cannot remove TenantOwner (403 Forbidden)

---

#### AC-RM-4: List Tenant Users (GET /api/tenants/{tenantId}/users)

**Given**: I am authenticated as TenantAdmin
**When**: I request user list for my tenant
**Then**:
- Response returns 200 OK with array of users
- Each user includes: userId, email, fullName, role, status, createdAt
- Pagination supported: `?page=1&pageSize=20`
- Filtering supported: `?role=TenantMember&status=Active`

**Response Format**:
```json
{
  "users": [
    {
      "userId": "uuid",
      "email": "user@example.com",
      "fullName": "John Doe",
      "role": "TenantMember",
      "status": "Active",
      "authProvider": "Local",
      "createdAt": "2025-11-01T10:00:00Z",
      "assignedAt": "2025-11-01T10:00:00Z"
    }
  ],
  "totalCount": 15,
  "page": 1,
  "pageSize": 20
}
```

---

#### AC-RM-5: Get Available Roles (GET /api/tenants/{tenantId}/roles)

**Given**: I am authenticated as TenantAdmin
**When**: I request available roles
**Then**:
- Response returns 200 OK with array of roles
- Each role includes: name, description, permissions summary

**Response Format**:
```json
{
  "roles": [
    {
      "name": "TenantOwner",
      "description": "Full control over tenant",
      "canAssign": true
    },
    {
      "name": "TenantAdmin",
      "description": "Manage users and projects",
      "canAssign": true
    },
    {
      "name": "TenantMember",
      "description": "Create and manage own projects",
      "canAssign": true
    },
    {
      "name": "TenantGuest",
      "description": "Read-only access",
      "canAssign": true
    },
    {
      "name": "AIAgent",
      "description": "AI agent for MCP operations",
      "canAssign": false
    }
  ]
}
```

---

### Authorization Rules

| Requester Role | Can Assign Roles | Cannot Assign | Special Rules |
|---------------|-----------------|---------------|---------------|
| **TenantOwner** | All roles | - | Can assign TenantOwner |
| **TenantAdmin** | TenantMember, TenantGuest | TenantOwner, TenantAdmin | Cannot elevate privileges |
| **TenantMember** | None | All | No role management |
| **TenantGuest** | None | All | No role management |
| **AIAgent** | None | All | No role management |

**Global Rules**:
1. Cannot modify own role
2. Cannot remove last TenantOwner
3. Cannot assign role to user in different tenant
4. AIAgent role can only be assigned via API key generation (not this endpoint)

---

## API Design

### 1. Assign/Update Role

**Endpoint**: `POST /api/tenants/{tenantId}/users/{userId}/role`

**Request**:
```json
{
  "role": "TenantMember"
}
```

**Response** (200 OK):
```json
{
  "userId": "uuid",
  "email": "user@example.com",
  "fullName": "John Doe",
  "role": "TenantMember",
  "assignedAt": "2025-11-03T14:30:00Z",
  "assignedBy": "admin-uuid"
}
```

**Errors**:
- `400 Bad Request` - Invalid role or business rule violation
- `403 Forbidden` - Insufficient permissions
- `404 Not Found` - User or tenant not found

---

### 2. Remove User from Tenant

**Endpoint**: `DELETE /api/tenants/{tenantId}/users/{userId}/role`

**Response** (204 No Content)

**Errors**:
- `400 Bad Request` - Cannot remove last TenantOwner
- `403 Forbidden` - Insufficient permissions or self-removal
- `404 Not Found` - User or tenant not found

---

### 3. List Tenant Users

**Endpoint**: `GET /api/tenants/{tenantId}/users`

**Query Parameters**:
- `page` (default: 1)
- `pageSize` (default: 20, max: 100)
- `role` (filter by role: TenantOwner, TenantAdmin, TenantMember, TenantGuest)
- `status` (filter by status: Active, Inactive)
- `search` (search by email or full name)

**Response** (200 OK): See AC-RM-4 above

---

### 4. Get Available Roles

**Endpoint**: `GET /api/tenants/{tenantId}/roles`

**Response** (200 OK): See AC-RM-5 above

---

## Database Schema

**Table**: `identity.user_tenant_roles` (Already exists from Day 5)

**No new tables or migrations required**. Existing schema:

```sql
CREATE TABLE identity.user_tenant_roles (
    id UUID PRIMARY KEY,
    user_id UUID NOT NULL,
    tenant_id UUID NOT NULL,
    role VARCHAR(50) NOT NULL,
    assigned_at TIMESTAMP NOT NULL DEFAULT NOW(),
    assigned_by_user_id UUID NULL,

    CONSTRAINT FK_user_tenant_roles_users
        FOREIGN KEY (user_id) REFERENCES identity.users(id) ON DELETE CASCADE,
    CONSTRAINT FK_user_tenant_roles_tenants
        FOREIGN KEY (tenant_id) REFERENCES identity.tenants(id) ON DELETE CASCADE,
    CONSTRAINT UQ_user_tenant_role
        UNIQUE (user_id, tenant_id)
);

CREATE INDEX ix_user_tenant_roles_user_id ON identity.user_tenant_roles(user_id);
CREATE INDEX ix_user_tenant_roles_tenant_id ON identity.user_tenant_roles(tenant_id);
CREATE INDEX ix_user_tenant_roles_role ON identity.user_tenant_roles(role);
```

**Existing Repository Methods** (Already implemented):
- `GetByUserAndTenantAsync(userId, tenantId)` ✅
- `GetByTenantAsync(tenantId)` ✅
- `AddAsync()` ✅
- `UpdateAsync()` ✅
- `DeleteAsync()` ✅

**New Repository Method Needed** (Add to `IUserTenantRoleRepository`):
```csharp
Task<int> CountByTenantAndRoleAsync(Guid tenantId, TenantRole role, CancellationToken cancellationToken = default);
```
- **Purpose**: Check if at least one TenantOwner exists before removal

---

## Implementation Plan

### Phase 1: Application Layer (2-3 hours)

#### 1.1 Create Commands (1 hour)

**File**: `src/Modules/Identity/ColaFlow.Modules.Identity.Application/Commands/AssignRole/AssignRoleCommand.cs`
```csharp
public record AssignRoleCommand(
    Guid TenantId,
    Guid UserId,
    TenantRole Role,
    Guid AssignedByUserId
) : IRequest<AssignRoleResult>;

public record AssignRoleResult(
    Guid UserId,
    string Email,
    string FullName,
    TenantRole Role,
    DateTime AssignedAt,
    Guid AssignedBy
);
```

**File**: `src/Modules/Identity/ColaFlow.Modules.Identity.Application/Commands/RemoveUserFromTenant/RemoveUserFromTenantCommand.cs`
```csharp
public record RemoveUserFromTenantCommand(
    Guid TenantId,
    Guid UserId,
    Guid RemovedByUserId
) : IRequest<Unit>;
```

#### 1.2 Create Command Handlers (2 hours)

**File**: `AssignRoleCommandHandler.cs`
- Validate user exists in tenant
- Validate requester has permission to assign role
- Check business rules (cannot assign TenantOwner unless requester is TenantOwner)
- Create or update `UserTenantRole` entity
- Save to database
- Return result

**File**: `RemoveUserFromTenantCommandHandler.cs`
- Validate user exists in tenant
- Validate requester has permission to remove
- Check business rules (cannot remove last TenantOwner, cannot remove self)
- Delete `UserTenantRole` entity
- Save to database

#### 1.3 Create Queries (1 hour)

**File**: `GetTenantUsersQuery.cs`
```csharp
public record GetTenantUsersQuery(
    Guid TenantId,
    int Page = 1,
    int PageSize = 20,
    TenantRole? RoleFilter = null,
    UserStatus? StatusFilter = null,
    string? SearchTerm = null
) : IRequest<GetTenantUsersResult>;

public record GetTenantUsersResult(
    List<TenantUserDto> Users,
    int TotalCount,
    int Page,
    int PageSize
);

public record TenantUserDto(
    Guid UserId,
    string Email,
    string FullName,
    TenantRole Role,
    UserStatus Status,
    AuthenticationProvider AuthProvider,
    DateTime CreatedAt,
    DateTime AssignedAt
);
```

**File**: `GetTenantUsersQueryHandler.cs`
- Query users by tenant
- Include role information
- Apply filters (role, status, search)
- Paginate results
- Return DTO

---

### Phase 2: API Layer (2 hours)

**File**: `src/ColaFlow.API/Controllers/TenantManagementController.cs`

```csharp
[ApiController]
[Route("api/tenants")]
[Authorize]
public class TenantManagementController : ControllerBase
{
    private readonly IMediator _mediator;

    [HttpPost("{tenantId}/users/{userId}/role")]
    [Authorize(Policy = "RequireTenantAdmin")]
    public async Task<IActionResult> AssignRole(
        Guid tenantId,
        Guid userId,
        [FromBody] AssignRoleRequest request)
    {
        var currentUserId = Guid.Parse(User.FindFirst("user_id")!.Value);

        var command = new AssignRoleCommand(
            tenantId,
            userId,
            request.Role,
            currentUserId
        );

        var result = await _mediator.Send(command);
        return Ok(result);
    }

    [HttpDelete("{tenantId}/users/{userId}/role")]
    [Authorize(Policy = "RequireTenantAdmin")]
    public async Task<IActionResult> RemoveUserFromTenant(
        Guid tenantId,
        Guid userId)
    {
        var currentUserId = Guid.Parse(User.FindFirst("user_id")!.Value);

        var command = new RemoveUserFromTenantCommand(
            tenantId,
            userId,
            currentUserId
        );

        await _mediator.Send(command);
        return NoContent();
    }

    [HttpGet("{tenantId}/users")]
    [Authorize(Policy = "RequireTenantMember")]
    public async Task<IActionResult> GetTenantUsers(
        Guid tenantId,
        [FromQuery] int page = 1,
        [FromQuery] int pageSize = 20,
        [FromQuery] TenantRole? role = null,
        [FromQuery] UserStatus? status = null,
        [FromQuery] string? search = null)
    {
        var query = new GetTenantUsersQuery(
            tenantId,
            page,
            pageSize,
            role,
            status,
            search
        );

        var result = await _mediator.Send(query);
        return Ok(result);
    }

    [HttpGet("{tenantId}/roles")]
    [Authorize(Policy = "RequireTenantMember")]
    public IActionResult GetAvailableRoles(Guid tenantId)
    {
        var currentUserRole = User.FindFirst("tenant_role")?.Value;
        var canAssignOwner = currentUserRole == "TenantOwner";

        var roles = new[]
        {
            new { Name = "TenantOwner", Description = "Full control", CanAssign = canAssignOwner },
            new { Name = "TenantAdmin", Description = "Manage users", CanAssign = canAssignOwner },
            new { Name = "TenantMember", Description = "Manage own projects", CanAssign = true },
            new { Name = "TenantGuest", Description = "Read-only", CanAssign = true },
            new { Name = "AIAgent", Description = "AI operations", CanAssign = false }
        };

        return Ok(new { roles });
    }
}
```

**Request DTOs**:
```csharp
public record AssignRoleRequest(TenantRole Role);
```

---

### Phase 3: Integration Tests (2-3 hours)

**File**: `tests/ColaFlow.API.IntegrationTests/Controllers/TenantManagementControllerTests.cs`

**Test Cases** (15+ tests):
1. `AssignRole_AsTenantOwner_ReturnsSuccess`
2. `AssignRole_AsTenantAdmin_CanAssignMemberRole`
3. `AssignRole_AsTenantAdmin_CannotAssignOwnerRole`
4. `AssignRole_ToSelf_ReturnsForbidden`
5. `AssignRole_ToCrossTenantUser_ReturnsForbidden`
6. `AssignRole_WithInvalidRole_ReturnsBadRequest`
7. `AssignRole_ToNonExistentUser_ReturnsNotFound`
8. `UpdateRole_ChangesUserRole_ReturnsSuccess`
9. `RemoveUser_AsTenantOwner_ReturnsSuccess`
10. `RemoveUser_LastTenantOwner_ReturnsBadRequest`
11. `RemoveUser_Self_ReturnsForbidden`
12. `GetTenantUsers_ReturnsAllUsers`
13. `GetTenantUsers_WithRoleFilter_ReturnsFilteredUsers`
14. `GetTenantUsers_WithPagination_ReturnsCorrectPage`
15. `GetAvailableRoles_AsTenantOwner_ShowsAllRoles`
16. `GetAvailableRoles_AsTenantMember_HidesOwnerRole`

**Test Setup**:
- Use Testcontainers for PostgreSQL
- Seed test data (tenant, users, roles)
- Authenticate as different roles
- Cleanup after tests

---

## Security Considerations

### Authentication & Authorization

1. **All endpoints require authentication** (`[Authorize]` attribute)
2. **Role-based authorization** (`[Authorize(Policy = "RequireTenantAdmin")]`)
3. **Tenant isolation**: Validate requester belongs to target tenant
4. **Claims validation**: Extract `user_id` and `tenant_id` from JWT

### Business Rules Enforcement

1. **Privilege escalation prevention**:
   - TenantAdmin cannot assign TenantOwner role
   - Users cannot modify own roles

2. **Data integrity**:
   - At least one TenantOwner must exist per tenant
   - Cannot remove self

3. **Cross-tenant protection**:
   - Validate all operations within same tenant
   - Database-level tenant isolation via foreign keys

### Audit Logging (Future Enhancement)

**Recommendation**: Add audit logging to track:
- Who assigned role
- What role was assigned
- When assignment occurred
- Previous role (for updates)

**Implementation** (Can be added in Day 7):
```csharp
await _auditLogger.LogAsync(new AuditEntry
{
    Action = "AssignRole",
    UserId = currentUserId,
    TenantId = tenantId,
    TargetUserId = userId,
    OldValue = oldRole?.ToString(),
    NewValue = newRole.ToString(),
    Timestamp = DateTime.UtcNow
});
```

---

## Test Plan

### Unit Tests (Application Layer)

**File**: `tests/ColaFlow.Modules.Identity.Application.Tests/Commands/AssignRoleCommandHandlerTests.cs`

**Test Scenarios**:
1. ✅ Valid role assignment
2. ✅ Update existing role
3. ❌ Assign role to non-existent user
4. ❌ Assign role without permission
5. ❌ Self-assignment
6. ❌ Cross-tenant assignment

**Expected Coverage**: 85%+

---

### Integration Tests (API Layer)

**Test Strategy**: Use Testcontainers for full E2E testing

**Setup**:
```csharp
public class TenantManagementControllerTests : IAsyncLifetime
{
    private PostgreSqlContainer _dbContainer;
    private WebApplicationFactory<Program> _factory;

    public async Task InitializeAsync()
    {
        _dbContainer = new PostgreSqlBuilder().Build();
        await _dbContainer.StartAsync();

        _factory = new WebApplicationFactory<Program>()
            .WithWebHostBuilder(builder =>
            {
                builder.ConfigureServices(services =>
                {
                    // Replace DbContext with test container
                });
            });
    }
}
```

**Test Cases**: See Phase 3 above (15+ tests)

---

### Manual Testing

**Scenario 1: Happy Path - Assign Role**

```powershell
# 1. Register tenant and get TenantOwner token
$registerBody = @{
    tenantName = "Test Corp"
    tenantSlug = "test-corp"
    subscriptionPlan = "Professional"
    adminEmail = "owner@test.com"
    adminPassword = "Owner@1234"
    adminFullName = "Tenant Owner"
} | ConvertTo-Json

$response = Invoke-RestMethod -Uri "http://localhost:5167/api/tenants/register" `
    -Method Post -ContentType "application/json" -Body $registerBody

$ownerToken = $response.accessToken
$tenantId = $response.tenantId

# 2. Create another user (TenantMember by default)
$createUserBody = @{
    email = "member@test.com"
    password = "Member@1234"
    fullName = "Test Member"
} | ConvertTo-Json

$headers = @{ "Authorization" = "Bearer $ownerToken" }
$newUser = Invoke-RestMethod -Uri "http://localhost:5167/api/tenants/$tenantId/users" `
    -Method Post -ContentType "application/json" -Headers $headers -Body $createUserBody

$newUserId = $newUser.userId

# 3. Assign TenantAdmin role to new user
$assignRoleBody = @{ role = "TenantAdmin" } | ConvertTo-Json

$result = Invoke-RestMethod -Uri "http://localhost:5167/api/tenants/$tenantId/users/$newUserId/role" `
    -Method Post -ContentType "application/json" -Headers $headers -Body $assignRoleBody

Write-Host "Role assigned: $($result.role)"  # Should output: TenantAdmin
```

**Scenario 2: Security Test - Prevent Privilege Escalation**

```powershell
# 1. Login as TenantAdmin
$loginBody = @{
    tenantSlug = "test-corp"
    email = "admin@test.com"
    password = "Admin@1234"
} | ConvertTo-Json

$loginResponse = Invoke-RestMethod -Uri "http://localhost:5167/api/auth/login" `
    -Method Post -ContentType "application/json" -Body $loginBody

$adminToken = $loginResponse.accessToken

# 2. Try to assign TenantOwner role (should fail)
$headers = @{ "Authorization" = "Bearer $adminToken" }
$assignOwnerBody = @{ role = "TenantOwner" } | ConvertTo-Json

try {
    Invoke-RestMethod -Uri "http://localhost:5167/api/tenants/$tenantId/users/$newUserId/role" `
        -Method Post -ContentType "application/json" -Headers $headers -Body $assignOwnerBody
} catch {
    Write-Host "Correctly blocked: $($_.Exception.Response.StatusCode)"  # Should be 403 Forbidden
}
```

**Scenario 3: List Users**

```powershell
$headers = @{ "Authorization" = "Bearer $ownerToken" }
$users = Invoke-RestMethod -Uri "http://localhost:5167/api/tenants/$tenantId/users" `
    -Headers $headers

$users.users | Format-Table email, role, status
```

---

## Performance Considerations

### Database Queries

**Optimizations**:
1. **Index usage**: Queries use existing indexes on `user_id` and `tenant_id`
2. **Pagination**: Limit result sets with `LIMIT` and `OFFSET`
3. **Projection**: Return only needed fields (avoid `SELECT *`)
4. **Eager loading**: Use `Include()` for user details

**Expected Performance**:
- Assign role: < 50ms (1 INSERT or UPDATE)
- Remove role: < 30ms (1 DELETE)
- List users: < 100ms (1 SELECT with JOIN, up to 100 rows)

### Caching Strategy (Future)

**Recommendation** (Day 8+):
- Cache user roles in Redis (5-minute expiration)
- Invalidate cache on role change
- Reduces database queries for JWT validation

---

## Day 6 Timeline

**Total Estimated Time**: 6-8 hours

### Morning Session (4 hours)

- **09:00 - 10:00**: Design review and repository method addition
- **10:00 - 12:00**: Application layer implementation (commands, queries, handlers)
- **12:00 - 13:00**: Lunch break

### Afternoon Session (4 hours)

- **13:00 - 15:00**: API controller implementation and manual testing
- **15:00 - 17:00**: Integration tests (15+ tests)
- **17:00 - 18:00**: Documentation and code review

### End of Day Deliverables

- ✅ 4 API endpoints working
- ✅ 15+ integration tests passing
- ✅ Manual testing complete
- ✅ Documentation updated
- ✅ Code reviewed and merged

---

## Day 7-10 Roadmap

### Day 7: Email Service + Verification + Password Reset (8 hours)

**Why**: Combine email-related features in one day

**Deliverables**:
1. Email service integration (SendGrid or SMTP)
2. Email verification flow
3. Password reset flow
4. Email templates (verification, reset, welcome)
5. Integration tests

**Blockers**: None (independent feature)

---

### Day 8: Project-Level Roles + Audit Logging (8 hours)

**Why**: Foundation for M1 core project module

**Deliverables**:
1. `user_project_roles` table
2. `ProjectRole` enum (ProjectOwner, ProjectManager, ProjectMember, ProjectGuest)
3. Role inheritance logic (TenantOwner → ProjectOwner)
4. Authorization policies for project-level operations
5. Audit logging infrastructure

**Blockers**: None (builds on Day 6 role system)

---

### Day 9: M1 Core Project Module - Projects CRUD (8 hours)

**Why**: Complete M1.1 core features

**Deliverables**:
1. Projects CRUD API (already exists, needs multi-tenant update)
2. Add `tenant_id` to Projects table
3. Update EF Core global query filter for Projects
4. Project-level authorization (using Day 8 project roles)
5. Integration tests

**Blockers**: Depends on Day 8 (project-level roles)

---

### Day 10: Kanban Workflow + Sprint Management (8 hours)

**Why**: Complete M1 sprint management

**Deliverables**:
1. Sprint CRUD API
2. Kanban board state management
3. Drag-and-drop task status updates
4. Sprint burndown chart data
5. Integration tests

**Blockers**: Depends on Day 9 (Projects)

---

### Days 11-12: M2 MCP Server Foundation (16 hours)

**Why**: Begin M2 milestone - MCP integration

**Deliverables**:
1. MCP token generation API
2. MCP authentication middleware
3. Preview storage and approval workflow
4. Basic MCP resources (`projects.search`, `tasks.list`)
5. Basic MCP tools (`create_task`, `update_status`)

**Blockers**: Depends on Days 6-10 (complete RBAC and Projects)

---

## Risk Assessment

### Day 6 Risks

| Risk | Probability | Impact | Mitigation |
|------|------------|--------|------------|
| Complex authorization logic | MEDIUM | MEDIUM | Reuse existing policies from Day 5 |
| Edge case bugs | MEDIUM | LOW | Comprehensive test coverage (15+ tests) |
| Performance issues | LOW | LOW | Use existing indexes, no N+1 queries |
| Security vulnerabilities | LOW | HIGH | Thorough security testing, code review |

**Overall Risk**: **LOW** (well-understood requirements, existing infrastructure)

---

### Days 7-10 Risks

| Risk | Probability | Impact | Mitigation |
|------|------------|--------|------------|
| Email service integration delays | MEDIUM | MEDIUM | Use SMTP fallback if SendGrid fails |
| Project-level roles complexity | HIGH | HIGH | Start with simple design, iterate later |
| Scope creep (Days 11-12) | HIGH | HIGH | Strictly time-box Day 10, defer MCP to sprint 3 |

---

## Success Metrics

### Day 6 Success Criteria

- ✅ All 4 API endpoints functional
- ✅ 100% integration test pass rate (15+ tests)
- ✅ Zero security vulnerabilities found
- ✅ Manual testing complete
- ✅ Documentation updated
- ✅ Code reviewed by architect agent
- ✅ Deployed to development environment
- ✅ Ready for frontend integration

### KPIs (Key Performance Indicators)

- **Development Time**: ≤ 8 hours
- **Test Coverage**: ≥ 85%
- **API Response Time**: < 200ms (p95)
- **Bug Count**: 0 critical, ≤ 2 minor
- **Code Quality**: No SonarQube violations

---

## Alternative Approaches Considered

### Alternative 1: User Invitation System First

**Pros**:
- More complete user onboarding flow
- Better user experience

**Cons**:
- Requires email service (adds complexity)
- 10-12 hours implementation time (exceeds Day 6 budget)
- Cannot test without email

**Decision**: Defer to Day 8-9 after email service is ready

---

### Alternative 2: Combine Role Management + Email Verification

**Pros**:
- More complete feature set in Day 6

**Cons**:
- 14-16 hours total (too much for one day)
- Email service setup adds risk
- Testing complexity increases

**Decision**: Split into Day 6 (roles) + Day 7 (email)

---

### Alternative 3: Project-Level Roles First

**Pros**:
- More aligned with M1 core project module
- Needed for MCP integration

**Cons**:
- High complexity (10-12 hours)
- Requires architectural decisions (role inheritance)
- No immediate business value without Projects module

**Decision**: Defer to Day 8 after tenant-level roles are stable

---

## Conclusion

**Day 6 Recommendation**: Implement **Role Management API** (Option 1)

**Rationale**:
1. ✅ **Feasible**: Can be completed in 6-8 hours
2. ✅ **High value**: Completes tenant management loop
3. ✅ **Low risk**: Builds on existing RBAC infrastructure
4. ✅ **Well-defined**: Clear acceptance criteria and test cases
5. ✅ **Foundation**: Prepares for project-level roles (Day 8) and MCP (M2)

**Next Steps**:
1. Review and approve this planning document
2. Assign to backend agent for implementation
3. Track progress with hourly check-ins
4. Code review before end of day
5. Deploy to development environment

---

**Document Status**: ✅ Planning Complete - Ready for Implementation

**Prepared By**: Product Manager Agent
**Date**: 2025-11-03
**Version**: 1.0
