---
task_id: sprint_2_story_2_task_2
story: sprint_2_story_2
status: not_started
estimated_hours: 3
created_date: 2025-11-05
assignee: Backend Team
---

# Task 2: Integrate User Context Tracking

**Story**: Story 2 - Audit Log Core Features (Phase 2)
**Estimated**: 3 hours

## Description

Enhance audit logging to automatically capture the current user (UserId) from HTTP context for every operation. This provides accountability and traceability.

## Acceptance Criteria

- [ ] UserId automatically captured from JWT token
- [ ] System operations (null user) handled correctly
- [ ] User information enriched in audit logs
- [ ] Integration tests verify user tracking
- [ ] Performance not impacted

## Implementation Details

**Already Implemented in Story 1!**

The `AuditLogInterceptor` already captures UserId from HTTP context:

```csharp
private Guid? GetCurrentUserId()
{
    var userIdClaim = _httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier);
    return userIdClaim != null ? Guid.Parse(userIdClaim.Value) : null;
}
```

**This Task: Add User Information Enrichment**

1. **Add User Navigation Property**: `colaflow-api/src/ColaFlow.Domain/Entities/AuditLog.cs`
```csharp
public class AuditLog
{
    // ... existing properties ...
    public Guid? UserId { get; set; }

    // Navigation property
    public User? User { get; set; }
}
```

2. **Update EF Configuration**: `colaflow-api/src/ColaFlow.Infrastructure/Data/Configurations/AuditLogConfiguration.cs`
```csharp
public void Configure(EntityTypeBuilder<AuditLog> builder)
{
    // ... existing configuration ...

    // User relationship (optional foreign key)
    builder.HasOne(a => a.User)
        .WithMany()
        .HasForeignKey(a => a.UserId)
        .OnDelete(DeleteBehavior.SetNull); // Don't delete audit logs when user is deleted
}
```

3. **Enrich Query Results**: `colaflow-api/src/ColaFlow.Infrastructure/Repositories/AuditLogRepository.cs`
```csharp
public async Task<List<AuditLog>> GetByEntityAsync(string entityType, Guid entityId)
{
    var tenantId = _tenantContext.TenantId;
    return await _context.AuditLogs
        .Include(a => a.User) // Include user info
        .Where(a => a.TenantId == tenantId && a.EntityType == entityType && a.EntityId == entityId)
        .OrderByDescending(a => a.Timestamp)
        .ToListAsync();
}
```

4. **Handle System Operations**: Update `AuditLogInterceptor` to handle null users gracefully:
```csharp
private Guid? GetCurrentUserId()
{
    try
    {
        var userIdClaim = _httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier);
        if (userIdClaim != null && Guid.TryParse(userIdClaim.Value, out var userId))
        {
            return userId;
        }
    }
    catch (Exception ex)
    {
        _logger.LogWarning(ex, "Failed to get current user ID for audit log");
    }

    return null; // System operation or anonymous
}
```

**Example Audit Log with User Info**:
```json
{
  "Id": "abc-123",
  "EntityType": "Project",
  "Action": "Update",
  "UserId": "user-456",
  "User": {
    "Id": "user-456",
    "UserName": "john.doe@example.com",
    "DisplayName": "John Doe"
  },
  "Timestamp": "2025-11-05T10:30:00Z",
  "ChangedFields": {
    "Title": { "OldValue": "Old", "NewValue": "New" }
  }
}
```

## Technical Notes

- Use `OnDelete(DeleteBehavior.SetNull)` to preserve audit logs when users are deleted
- Handle null users gracefully (system operations, background jobs)
- Use `Include(a => a.User)` for enriched query results
- Consider caching user info for performance (future optimization)

## Testing

**Integration Tests**:
```csharp
[Fact]
public async Task CreateProject_ShouldCaptureCurrentUser()
{
    // Arrange
    var userId = Guid.NewGuid();
    SetCurrentUser(userId); // Helper to set HTTP context user

    // Act
    var projectId = await Mediator.Send(new CreateProjectCommand { /* ... */ });

    // Assert
    var auditLog = await Context.AuditLogs
        .Include(a => a.User)
        .FirstAsync(a => a.EntityId == projectId);

    Assert.Equal(userId, auditLog.UserId);
    Assert.NotNull(auditLog.User);
}

[Fact]
public async Task SystemOperation_ShouldHaveNullUser()
{
    // Test background job or system operation
    // ...
}
```

---

**Created**: 2025-11-05 by Backend Agent
