From 2466cd4020b1dcdcc7b9efff46e54232b2fc3d9e Mon Sep 17 00:00:00 2001 From: Yaojia Wang Date: Tue, 4 Nov 2025 23:14:41 +0100 Subject: [PATCH] feat(backend): Add AuditLog repository interface and implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement repository pattern for AuditLog entity for Sprint 2 Story 1 Task 2. Changes: - Created IAuditLogRepository interface with 6 query methods - Implemented AuditLogRepository with efficient querying - Registered repository in DI container - All queries use AsNoTracking for read-only operations Query Methods: - GetByIdAsync: Get single audit log by ID - GetByEntityAsync: Get audit history for specific entity - GetByUserAsync: Get user activity with pagination - GetRecentAsync: Get recent audit logs - AddAsync: Add new audit log - GetCountAsync: Get total audit log count Performance: - All queries automatically filtered by TenantId (Global Query Filter) - Efficient use of composite indexes - AsNoTracking for read-only operations Testing: - All tests passing (192 domain + 113 identity + 8 arch + 32 app + 12 infra = 357 tests) - No compilation errors - Zero test failures 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../Extensions/ModuleExtensions.cs | 1 + .../Repositories/IAuditLogRepository.cs | 27 +++++++ .../Repositories/AuditLogRepository.cs | 72 +++++++++++++++++++ docs/plans/sprint_2_story_1_task_2.md | 3 +- 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Repositories/IAuditLogRepository.cs create mode 100644 colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Repositories/AuditLogRepository.cs diff --git a/colaflow-api/src/ColaFlow.API/Extensions/ModuleExtensions.cs b/colaflow-api/src/ColaFlow.API/Extensions/ModuleExtensions.cs index 7d38065..d42b5ce 100644 --- a/colaflow-api/src/ColaFlow.API/Extensions/ModuleExtensions.cs +++ b/colaflow-api/src/ColaFlow.API/Extensions/ModuleExtensions.cs @@ -45,6 +45,7 @@ public static class ModuleExtensions // Register repositories services.AddScoped(); + services.AddScoped(); services.AddScoped(); // Register services diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Repositories/IAuditLogRepository.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Repositories/IAuditLogRepository.cs new file mode 100644 index 0000000..ec35e1c --- /dev/null +++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Repositories/IAuditLogRepository.cs @@ -0,0 +1,27 @@ +using ColaFlow.Modules.ProjectManagement.Domain.Entities; + +namespace ColaFlow.Modules.ProjectManagement.Domain.Repositories; + +public interface IAuditLogRepository +{ + Task GetByIdAsync(Guid id, CancellationToken cancellationToken = default); + + Task> GetByEntityAsync( + string entityType, + Guid entityId, + CancellationToken cancellationToken = default); + + Task> GetByUserAsync( + Guid userId, + int pageNumber = 1, + int pageSize = 50, + CancellationToken cancellationToken = default); + + Task> GetRecentAsync( + int count = 100, + CancellationToken cancellationToken = default); + + Task AddAsync(AuditLog auditLog, CancellationToken cancellationToken = default); + + Task GetCountAsync(CancellationToken cancellationToken = default); +} diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Repositories/AuditLogRepository.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Repositories/AuditLogRepository.cs new file mode 100644 index 0000000..8f570ce --- /dev/null +++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Infrastructure/Repositories/AuditLogRepository.cs @@ -0,0 +1,72 @@ +using ColaFlow.Modules.ProjectManagement.Domain.Entities; +using ColaFlow.Modules.ProjectManagement.Domain.Repositories; +using ColaFlow.Modules.ProjectManagement.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; + +namespace ColaFlow.Modules.ProjectManagement.Infrastructure.Repositories; + +public class AuditLogRepository : IAuditLogRepository +{ + private readonly PMDbContext _context; + + public AuditLogRepository(PMDbContext context) + { + _context = context; + } + + public async Task GetByIdAsync(Guid id, CancellationToken cancellationToken = default) + { + return await _context.AuditLogs + .AsNoTracking() + .FirstOrDefaultAsync(a => a.Id == id, cancellationToken); + } + + public async Task> GetByEntityAsync( + string entityType, + Guid entityId, + CancellationToken cancellationToken = default) + { + return await _context.AuditLogs + .AsNoTracking() + .Where(a => a.EntityType == entityType && a.EntityId == entityId) + .OrderByDescending(a => a.Timestamp) + .ToListAsync(cancellationToken); + } + + public async Task> GetByUserAsync( + Guid userId, + int pageNumber = 1, + int pageSize = 50, + CancellationToken cancellationToken = default) + { + return await _context.AuditLogs + .AsNoTracking() + .Where(a => a.UserId == userId) + .OrderByDescending(a => a.Timestamp) + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .ToListAsync(cancellationToken); + } + + public async Task> GetRecentAsync( + int count = 100, + CancellationToken cancellationToken = default) + { + return await _context.AuditLogs + .AsNoTracking() + .OrderByDescending(a => a.Timestamp) + .Take(count) + .ToListAsync(cancellationToken); + } + + public async Task AddAsync(AuditLog auditLog, CancellationToken cancellationToken = default) + { + await _context.AuditLogs.AddAsync(auditLog, cancellationToken); + await _context.SaveChangesAsync(cancellationToken); + } + + public async Task GetCountAsync(CancellationToken cancellationToken = default) + { + return await _context.AuditLogs.CountAsync(cancellationToken); + } +} diff --git a/docs/plans/sprint_2_story_1_task_2.md b/docs/plans/sprint_2_story_1_task_2.md index 46a3e41..70f017e 100644 --- a/docs/plans/sprint_2_story_1_task_2.md +++ b/docs/plans/sprint_2_story_1_task_2.md @@ -1,9 +1,10 @@ --- task_id: sprint_2_story_1_task_2 story: sprint_2_story_1 -status: not_started +status: in_progress estimated_hours: 4 created_date: 2025-11-05 +start_date: 2025-11-05 assignee: Backend Team ---