using MediatR; using ColaFlow.Modules.ProjectManagement.Application.DTOs; using ColaFlow.Modules.ProjectManagement.Application.Common.Interfaces; using ColaFlow.Modules.ProjectManagement.Domain.Repositories; using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects; using ColaFlow.Modules.ProjectManagement.Domain.Exceptions; namespace ColaFlow.Modules.ProjectManagement.Application.Queries.GetEpicsByProjectId; /// /// Handler for GetEpicsByProjectIdQuery /// public sealed class GetEpicsByProjectIdQueryHandler( IProjectRepository projectRepository, ITenantContext tenantContext) : IRequestHandler> { private readonly IProjectRepository _projectRepository = projectRepository ?? throw new ArgumentNullException(nameof(projectRepository)); private readonly ITenantContext _tenantContext = tenantContext ?? throw new ArgumentNullException(nameof(tenantContext)); public async Task> Handle(GetEpicsByProjectIdQuery request, CancellationToken cancellationToken) { // Get current tenant ID (Defense in Depth - Layer 2) var currentTenantId = _tenantContext.GetCurrentTenantId(); // CRITICAL SECURITY: Verify Project belongs to current tenant before querying epics var projectId = ProjectId.From(request.ProjectId); var project = await _projectRepository.GetByIdAsync(projectId, cancellationToken); if (project == null) throw new NotFoundException("Project", request.ProjectId); // Explicit TenantId validation (Defense in Depth) if (project.TenantId.Value != currentTenantId) throw new NotFoundException("Project", request.ProjectId); // Now fetch epics (already filtered by EF Core, but we verified project ownership) var epics = await _projectRepository.GetEpicsByProjectIdAsync(projectId, cancellationToken); return epics.Select(epic => new EpicDto { Id = epic.Id.Value, Name = epic.Name, Description = epic.Description, ProjectId = epic.ProjectId.Value, Status = epic.Status.Name, Priority = epic.Priority.Name, CreatedBy = epic.CreatedBy.Value, CreatedAt = epic.CreatedAt, UpdatedAt = epic.UpdatedAt, Stories = new List() // Don't include stories in list view }).ToList(); } }