Files
ColaFlow/colaflow-api/src/Modules/IssueManagement/ColaFlow.Modules.IssueManagement.Application/Commands/ChangeIssueStatus/ChangeIssueStatusCommandHandler.cs
Yaojia Wang 6b11af9bea feat(backend): Implement complete Issue Management Module
Implemented full-featured Issue Management module following Clean Architecture,
DDD, CQRS and Event Sourcing patterns to support Kanban board functionality.

## Domain Layer
- Issue aggregate root with business logic
- IssueType, IssueStatus, IssuePriority enums
- Domain events: IssueCreated, IssueUpdated, IssueStatusChanged, IssueAssigned, IssueDeleted
- IIssueRepository and IUnitOfWork interfaces
- Domain exceptions (DomainException, NotFoundException)

## Application Layer
- **Commands**: CreateIssue, UpdateIssue, ChangeIssueStatus, AssignIssue, DeleteIssue
- **Queries**: GetIssueById, ListIssues, ListIssuesByStatus
- Command/Query handlers with validation
- FluentValidation validators for all commands
- Event handlers for domain events
- IssueDto for data transfer
- ValidationBehavior pipeline

## Infrastructure Layer
- IssueManagementDbContext with EF Core 9.0
- IssueConfiguration for entity mapping
- IssueRepository implementation
- UnitOfWork implementation
- Multi-tenant support with TenantId filtering
- Optimized indexes for query performance

## API Layer
- IssuesController with full REST API
  - GET /api/v1/projects/{projectId}/issues (list with optional status filter)
  - GET /api/v1/projects/{projectId}/issues/{id} (get by id)
  - POST /api/v1/projects/{projectId}/issues (create)
  - PUT /api/v1/projects/{projectId}/issues/{id} (update)
  - PUT /api/v1/projects/{projectId}/issues/{id}/status (change status for Kanban)
  - PUT /api/v1/projects/{projectId}/issues/{id}/assign (assign to user)
  - DELETE /api/v1/projects/{projectId}/issues/{id} (delete)
- Request models: CreateIssueRequest, UpdateIssueRequest, ChangeStatusRequest, AssignIssueRequest
- JWT authentication required
- Real-time SignalR notifications integrated

## Module Registration
- Added AddIssueManagementModule extension method
- Registered in Program.cs
- Added IMDatabase connection string
- Added project references to ColaFlow.API.csproj

## Architecture Patterns
-  Clean Architecture (Domain, Application, Infrastructure, API layers)
-  DDD (Aggregate roots, value objects, domain events)
-  CQRS (Command/Query separation)
-  Event Sourcing (Domain events with MediatR)
-  Repository Pattern (IIssueRepository)
-  Unit of Work (Transactional consistency)
-  Dependency Injection
-  FluentValidation
-  Multi-tenancy support

## Real-time Features
- SignalR integration via IRealtimeNotificationService
- NotifyIssueCreated, NotifyIssueUpdated, NotifyIssueStatusChanged, NotifyIssueAssigned, NotifyIssueDeleted
- Project-level broadcasting for collaborative editing

## Next Steps
1. Stop running API process if exists
2. Run: dotnet ef migrations add InitialIssueModule --context IssueManagementDbContext --startup-project ../../../ColaFlow.API
3. Run: dotnet ef database update --context IssueManagementDbContext --startup-project ../../../ColaFlow.API
4. Create test scripts
5. Verify all CRUD operations and real-time notifications

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 11:38:04 +01:00

44 lines
1.5 KiB
C#

using MediatR;
using ColaFlow.Modules.IssueManagement.Domain.Entities;
using ColaFlow.Modules.IssueManagement.Domain.Repositories;
using ColaFlow.Modules.IssueManagement.Domain.Exceptions;
namespace ColaFlow.Modules.IssueManagement.Application.Commands.ChangeIssueStatus;
public sealed class ChangeIssueStatusCommandHandler : IRequestHandler<ChangeIssueStatusCommand, Unit>
{
private readonly IIssueRepository _issueRepository;
private readonly IUnitOfWork _unitOfWork;
private readonly IPublisher _publisher;
public ChangeIssueStatusCommandHandler(
IIssueRepository issueRepository,
IUnitOfWork unitOfWork,
IPublisher publisher)
{
_issueRepository = issueRepository;
_unitOfWork = unitOfWork;
_publisher = publisher;
}
public async Task<Unit> Handle(ChangeIssueStatusCommand request, CancellationToken cancellationToken)
{
var issue = await _issueRepository.GetByIdAsync(request.IssueId, cancellationToken);
if (issue == null)
throw new NotFoundException(nameof(Issue), request.IssueId);
issue.ChangeStatus(request.NewStatus);
await _issueRepository.UpdateAsync(issue, cancellationToken);
await _unitOfWork.SaveChangesAsync(cancellationToken);
foreach (var domainEvent in issue.DomainEvents)
{
await _publisher.Publish(domainEvent, cancellationToken);
}
issue.ClearDomainEvents();
return Unit.Value;
}
}