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.Commands.CreateEpic; /// /// Handler for CreateEpicCommand /// public sealed class CreateEpicCommandHandler( IProjectRepository projectRepository, IUnitOfWork unitOfWork) : IRequestHandler { private readonly IProjectRepository _projectRepository = projectRepository ?? throw new ArgumentNullException(nameof(projectRepository)); private readonly IUnitOfWork _unitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork)); public async Task Handle(CreateEpicCommand request, CancellationToken cancellationToken) { // Get the project (Global Query Filter ensures tenant isolation) var projectId = ProjectId.From(request.ProjectId); var project = await _projectRepository.GetByIdAsync(projectId, cancellationToken); if (project == null) throw new NotFoundException("Project", request.ProjectId); // Create epic through aggregate root (Project passes its TenantId) var createdById = UserId.From(request.CreatedBy); var epic = project.CreateEpic(request.Name, request.Description, createdById); // Update project (epic is part of aggregate) _projectRepository.Update(project); await _unitOfWork.SaveChangesAsync(cancellationToken); // Map to DTO return 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() }; } }