feat(signalr): Add real-time notifications for Epic/Story/Task operations

Extends SignalR notification system to cover all ProjectManagement CRUD operations:

Domain Events Created:
- EpicUpdatedEvent, EpicDeletedEvent
- StoryCreatedEvent, StoryUpdatedEvent, StoryDeletedEvent
- TaskCreatedEvent, TaskUpdatedEvent, TaskDeletedEvent, TaskAssignedEvent

Event Handlers Added (10 handlers):
- EpicCreatedEventHandler, EpicUpdatedEventHandler, EpicDeletedEventHandler
- StoryCreatedEventHandler, StoryUpdatedEventHandler, StoryDeletedEventHandler
- TaskCreatedEventHandler, TaskUpdatedEventHandler, TaskDeletedEventHandler
- TaskAssignedEventHandler

Infrastructure Extensions:
- Extended IProjectNotificationService with Epic/Story/Task methods
- Extended IRealtimeNotificationService with Epic/Story/Task methods
- Extended RealtimeNotificationService with implementations
- Extended ProjectNotificationServiceAdapter for delegation

Domain Changes:
- Updated EpicCreatedEvent to include TenantId (consistency with other events)
- Added Epic/Story/Task CRUD methods to Project aggregate root
- All operations raise appropriate domain events

Broadcasting Strategy:
- Created events: Broadcast to both project-{projectId} and tenant-{tenantId} groups
- Updated events: Broadcast to project-{projectId} group only
- Deleted events: Broadcast to project-{projectId} group only
- Assigned events: Broadcast to project-{projectId} group with assignment details

Test Results:
- All 192 domain tests passing
- Domain and Application layers compile successfully
- Event handlers auto-registered by MediatR

Files Changed:
- 9 new domain event files
- 10 new event handler files
- 3 service interfaces extended
- 2 service implementations extended
- 1 aggregate updated with event raising logic
- 1 test file updated for new event signature

Status: Complete real-time collaboration for ProjectManagement module

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Yaojia Wang
2025-11-04 20:56:08 +01:00
parent ec70455c7f
commit b53521775c
26 changed files with 896 additions and 11 deletions

View File

@@ -125,16 +125,18 @@ public class DomainEventsTests
{
// Arrange
var epicId = EpicId.Create();
var epicName = "Epic 1";
var tenantId = TenantId.Create(Guid.NewGuid());
var projectId = ProjectId.Create();
var epicName = "Epic 1";
// Act
var @event = new EpicCreatedEvent(epicId, epicName, projectId);
var @event = new EpicCreatedEvent(epicId, tenantId, projectId, epicName);
// Assert
@event.EpicId.Should().Be(epicId);
@event.EpicName.Should().Be(epicName);
@event.TenantId.Should().Be(tenantId);
@event.ProjectId.Should().Be(projectId);
@event.EpicName.Should().Be(epicName);
@event.OccurredOn.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(5));
}
@@ -143,17 +145,19 @@ public class DomainEventsTests
{
// Arrange
var epicId = EpicId.Create();
var epicName = "Epic 1";
var tenantId = TenantId.Create(Guid.NewGuid());
var projectId = ProjectId.Create();
var epicName = "Epic 1";
// Act
var event1 = new EpicCreatedEvent(epicId, epicName, projectId);
var event2 = new EpicCreatedEvent(epicId, epicName, projectId);
var event1 = new EpicCreatedEvent(epicId, tenantId, projectId, epicName);
var event2 = new EpicCreatedEvent(epicId, tenantId, projectId, epicName);
// Assert - Records with same values should be equal
event1.EpicId.Should().Be(event2.EpicId);
event1.EpicName.Should().Be(event2.EpicName);
event1.TenantId.Should().Be(event2.TenantId);
event1.ProjectId.Should().Be(event2.ProjectId);
event1.EpicName.Should().Be(event2.EpicName);
}
#endregion
@@ -167,7 +171,7 @@ public class DomainEventsTests
var projectCreatedEvent = new ProjectCreatedEvent(ProjectId.Create(), TenantId.Create(Guid.NewGuid()), "Test", UserId.Create());
var projectUpdatedEvent = new ProjectUpdatedEvent(ProjectId.Create(), "Test", "Desc");
var projectArchivedEvent = new ProjectArchivedEvent(ProjectId.Create());
var epicCreatedEvent = new EpicCreatedEvent(EpicId.Create(), "Epic", ProjectId.Create());
var epicCreatedEvent = new EpicCreatedEvent(EpicId.Create(), TenantId.Create(Guid.NewGuid()), ProjectId.Create(), "Epic");
// Assert
projectCreatedEvent.OccurredOn.Kind.Should().Be(DateTimeKind.Utc);