diff --git a/colaflow-api/src/ColaFlow.API/Services/IRealtimeNotificationService.cs b/colaflow-api/src/ColaFlow.API/Services/IRealtimeNotificationService.cs
index d2b1011..c016422 100644
--- a/colaflow-api/src/ColaFlow.API/Services/IRealtimeNotificationService.cs
+++ b/colaflow-api/src/ColaFlow.API/Services/IRealtimeNotificationService.cs
@@ -8,6 +8,22 @@ public interface IRealtimeNotificationService
Task NotifyProjectArchived(Guid tenantId, Guid projectId);
Task NotifyProjectUpdate(Guid tenantId, Guid projectId, object data);
+ // Epic notifications
+ Task NotifyEpicCreated(Guid tenantId, Guid projectId, Guid epicId, object epic);
+ Task NotifyEpicUpdated(Guid tenantId, Guid projectId, Guid epicId, object epic);
+ Task NotifyEpicDeleted(Guid tenantId, Guid projectId, Guid epicId);
+
+ // Story notifications
+ Task NotifyStoryCreated(Guid tenantId, Guid projectId, Guid epicId, Guid storyId, object story);
+ Task NotifyStoryUpdated(Guid tenantId, Guid projectId, Guid epicId, Guid storyId, object story);
+ Task NotifyStoryDeleted(Guid tenantId, Guid projectId, Guid epicId, Guid storyId);
+
+ // Task notifications
+ Task NotifyTaskCreated(Guid tenantId, Guid projectId, Guid storyId, Guid taskId, object task);
+ Task NotifyTaskUpdated(Guid tenantId, Guid projectId, Guid storyId, Guid taskId, object task);
+ Task NotifyTaskDeleted(Guid tenantId, Guid projectId, Guid storyId, Guid taskId);
+ Task NotifyTaskAssigned(Guid tenantId, Guid projectId, Guid taskId, Guid assigneeId);
+
// Issue notifications
Task NotifyIssueCreated(Guid tenantId, Guid projectId, object issue);
Task NotifyIssueUpdated(Guid tenantId, Guid projectId, object issue);
diff --git a/colaflow-api/src/ColaFlow.API/Services/ProjectNotificationServiceAdapter.cs b/colaflow-api/src/ColaFlow.API/Services/ProjectNotificationServiceAdapter.cs
index 0ea74bf..fa8b92b 100644
--- a/colaflow-api/src/ColaFlow.API/Services/ProjectNotificationServiceAdapter.cs
+++ b/colaflow-api/src/ColaFlow.API/Services/ProjectNotificationServiceAdapter.cs
@@ -15,6 +15,7 @@ public class ProjectNotificationServiceAdapter : IProjectNotificationService
_realtimeService = realtimeService;
}
+ // Project notifications
public Task NotifyProjectCreated(Guid tenantId, Guid projectId, object project)
{
return _realtimeService.NotifyProjectCreated(tenantId, projectId, project);
@@ -29,4 +30,57 @@ public class ProjectNotificationServiceAdapter : IProjectNotificationService
{
return _realtimeService.NotifyProjectArchived(tenantId, projectId);
}
+
+ // Epic notifications
+ public Task NotifyEpicCreated(Guid tenantId, Guid projectId, Guid epicId, object epic)
+ {
+ return _realtimeService.NotifyEpicCreated(tenantId, projectId, epicId, epic);
+ }
+
+ public Task NotifyEpicUpdated(Guid tenantId, Guid projectId, Guid epicId, object epic)
+ {
+ return _realtimeService.NotifyEpicUpdated(tenantId, projectId, epicId, epic);
+ }
+
+ public Task NotifyEpicDeleted(Guid tenantId, Guid projectId, Guid epicId)
+ {
+ return _realtimeService.NotifyEpicDeleted(tenantId, projectId, epicId);
+ }
+
+ // Story notifications
+ public Task NotifyStoryCreated(Guid tenantId, Guid projectId, Guid epicId, Guid storyId, object story)
+ {
+ return _realtimeService.NotifyStoryCreated(tenantId, projectId, epicId, storyId, story);
+ }
+
+ public Task NotifyStoryUpdated(Guid tenantId, Guid projectId, Guid epicId, Guid storyId, object story)
+ {
+ return _realtimeService.NotifyStoryUpdated(tenantId, projectId, epicId, storyId, story);
+ }
+
+ public Task NotifyStoryDeleted(Guid tenantId, Guid projectId, Guid epicId, Guid storyId)
+ {
+ return _realtimeService.NotifyStoryDeleted(tenantId, projectId, epicId, storyId);
+ }
+
+ // Task notifications
+ public Task NotifyTaskCreated(Guid tenantId, Guid projectId, Guid storyId, Guid taskId, object task)
+ {
+ return _realtimeService.NotifyTaskCreated(tenantId, projectId, storyId, taskId, task);
+ }
+
+ public Task NotifyTaskUpdated(Guid tenantId, Guid projectId, Guid storyId, Guid taskId, object task)
+ {
+ return _realtimeService.NotifyTaskUpdated(tenantId, projectId, storyId, taskId, task);
+ }
+
+ public Task NotifyTaskDeleted(Guid tenantId, Guid projectId, Guid storyId, Guid taskId)
+ {
+ return _realtimeService.NotifyTaskDeleted(tenantId, projectId, storyId, taskId);
+ }
+
+ public Task NotifyTaskAssigned(Guid tenantId, Guid projectId, Guid taskId, Guid assigneeId)
+ {
+ return _realtimeService.NotifyTaskAssigned(tenantId, projectId, taskId, assigneeId);
+ }
}
diff --git a/colaflow-api/src/ColaFlow.API/Services/RealtimeNotificationService.cs b/colaflow-api/src/ColaFlow.API/Services/RealtimeNotificationService.cs
index e72dbaf..9a72106 100644
--- a/colaflow-api/src/ColaFlow.API/Services/RealtimeNotificationService.cs
+++ b/colaflow-api/src/ColaFlow.API/Services/RealtimeNotificationService.cs
@@ -59,6 +59,110 @@ public class RealtimeNotificationService : IRealtimeNotificationService
await _projectHubContext.Clients.Group(groupName).SendAsync("ProjectUpdated", data);
}
+ // Epic notifications
+ public async Task NotifyEpicCreated(Guid tenantId, Guid projectId, Guid epicId, object epic)
+ {
+ var projectGroupName = $"project-{projectId}";
+ var tenantGroupName = $"tenant-{tenantId}";
+
+ _logger.LogInformation("Notifying epic {EpicId} created in project {ProjectId}", epicId, projectId);
+
+ await _projectHubContext.Clients.Group(projectGroupName).SendAsync("EpicCreated", epic);
+ await _projectHubContext.Clients.Group(tenantGroupName).SendAsync("EpicCreated", epic);
+ }
+
+ public async Task NotifyEpicUpdated(Guid tenantId, Guid projectId, Guid epicId, object epic)
+ {
+ var projectGroupName = $"project-{projectId}";
+
+ _logger.LogInformation("Notifying epic {EpicId} updated", epicId);
+
+ await _projectHubContext.Clients.Group(projectGroupName).SendAsync("EpicUpdated", epic);
+ }
+
+ public async Task NotifyEpicDeleted(Guid tenantId, Guid projectId, Guid epicId)
+ {
+ var projectGroupName = $"project-{projectId}";
+
+ _logger.LogInformation("Notifying epic {EpicId} deleted", epicId);
+
+ await _projectHubContext.Clients.Group(projectGroupName).SendAsync("EpicDeleted", new { EpicId = epicId });
+ }
+
+ // Story notifications
+ public async Task NotifyStoryCreated(Guid tenantId, Guid projectId, Guid epicId, Guid storyId, object story)
+ {
+ var projectGroupName = $"project-{projectId}";
+ var tenantGroupName = $"tenant-{tenantId}";
+
+ _logger.LogInformation("Notifying story {StoryId} created in epic {EpicId}", storyId, epicId);
+
+ await _projectHubContext.Clients.Group(projectGroupName).SendAsync("StoryCreated", story);
+ await _projectHubContext.Clients.Group(tenantGroupName).SendAsync("StoryCreated", story);
+ }
+
+ public async Task NotifyStoryUpdated(Guid tenantId, Guid projectId, Guid epicId, Guid storyId, object story)
+ {
+ var projectGroupName = $"project-{projectId}";
+
+ _logger.LogInformation("Notifying story {StoryId} updated", storyId);
+
+ await _projectHubContext.Clients.Group(projectGroupName).SendAsync("StoryUpdated", story);
+ }
+
+ public async Task NotifyStoryDeleted(Guid tenantId, Guid projectId, Guid epicId, Guid storyId)
+ {
+ var projectGroupName = $"project-{projectId}";
+
+ _logger.LogInformation("Notifying story {StoryId} deleted", storyId);
+
+ await _projectHubContext.Clients.Group(projectGroupName).SendAsync("StoryDeleted", new { StoryId = storyId });
+ }
+
+ // Task notifications
+ public async Task NotifyTaskCreated(Guid tenantId, Guid projectId, Guid storyId, Guid taskId, object task)
+ {
+ var projectGroupName = $"project-{projectId}";
+ var tenantGroupName = $"tenant-{tenantId}";
+
+ _logger.LogInformation("Notifying task {TaskId} created in story {StoryId}", taskId, storyId);
+
+ await _projectHubContext.Clients.Group(projectGroupName).SendAsync("TaskCreated", task);
+ await _projectHubContext.Clients.Group(tenantGroupName).SendAsync("TaskCreated", task);
+ }
+
+ public async Task NotifyTaskUpdated(Guid tenantId, Guid projectId, Guid storyId, Guid taskId, object task)
+ {
+ var projectGroupName = $"project-{projectId}";
+
+ _logger.LogInformation("Notifying task {TaskId} updated", taskId);
+
+ await _projectHubContext.Clients.Group(projectGroupName).SendAsync("TaskUpdated", task);
+ }
+
+ public async Task NotifyTaskDeleted(Guid tenantId, Guid projectId, Guid storyId, Guid taskId)
+ {
+ var projectGroupName = $"project-{projectId}";
+
+ _logger.LogInformation("Notifying task {TaskId} deleted", taskId);
+
+ await _projectHubContext.Clients.Group(projectGroupName).SendAsync("TaskDeleted", new { TaskId = taskId });
+ }
+
+ public async Task NotifyTaskAssigned(Guid tenantId, Guid projectId, Guid taskId, Guid assigneeId)
+ {
+ var projectGroupName = $"project-{projectId}";
+
+ _logger.LogInformation("Notifying task {TaskId} assigned to {AssigneeId}", taskId, assigneeId);
+
+ await _projectHubContext.Clients.Group(projectGroupName).SendAsync("TaskAssigned", new
+ {
+ TaskId = taskId,
+ AssigneeId = assigneeId,
+ AssignedAt = DateTime.UtcNow
+ });
+ }
+
public async Task NotifyIssueCreated(Guid tenantId, Guid projectId, object issue)
{
var groupName = $"project-{projectId}";
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/EpicCreatedEventHandler.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/EpicCreatedEventHandler.cs
new file mode 100644
index 0000000..d75041a
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/EpicCreatedEventHandler.cs
@@ -0,0 +1,44 @@
+using MediatR;
+using Microsoft.Extensions.Logging;
+using ColaFlow.Modules.ProjectManagement.Domain.Events;
+using ColaFlow.Modules.ProjectManagement.Application.Services;
+
+namespace ColaFlow.Modules.ProjectManagement.Application.EventHandlers;
+
+///
+/// Handler for EpicCreatedEvent - sends SignalR notification
+///
+public class EpicCreatedEventHandler : INotificationHandler
+{
+ private readonly IProjectNotificationService _notificationService;
+ private readonly ILogger _logger;
+
+ public EpicCreatedEventHandler(
+ IProjectNotificationService notificationService,
+ ILogger logger)
+ {
+ _notificationService = notificationService;
+ _logger = logger;
+ }
+
+ public async Task Handle(EpicCreatedEvent notification, CancellationToken cancellationToken)
+ {
+ _logger.LogInformation("Handling EpicCreatedEvent for epic {EpicId}", notification.EpicId);
+
+ var epicData = new
+ {
+ Id = notification.EpicId.Value,
+ ProjectId = notification.ProjectId.Value,
+ Name = notification.EpicName,
+ CreatedAt = DateTime.UtcNow
+ };
+
+ await _notificationService.NotifyEpicCreated(
+ notification.TenantId.Value,
+ notification.ProjectId.Value,
+ notification.EpicId.Value,
+ epicData);
+
+ _logger.LogInformation("SignalR notification sent for epic {EpicId}", notification.EpicId);
+ }
+}
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/EpicDeletedEventHandler.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/EpicDeletedEventHandler.cs
new file mode 100644
index 0000000..9dfb0ff
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/EpicDeletedEventHandler.cs
@@ -0,0 +1,35 @@
+using MediatR;
+using Microsoft.Extensions.Logging;
+using ColaFlow.Modules.ProjectManagement.Domain.Events;
+using ColaFlow.Modules.ProjectManagement.Application.Services;
+
+namespace ColaFlow.Modules.ProjectManagement.Application.EventHandlers;
+
+///
+/// Handler for EpicDeletedEvent - sends SignalR notification
+///
+public class EpicDeletedEventHandler : INotificationHandler
+{
+ private readonly IProjectNotificationService _notificationService;
+ private readonly ILogger _logger;
+
+ public EpicDeletedEventHandler(
+ IProjectNotificationService notificationService,
+ ILogger logger)
+ {
+ _notificationService = notificationService;
+ _logger = logger;
+ }
+
+ public async Task Handle(EpicDeletedEvent notification, CancellationToken cancellationToken)
+ {
+ _logger.LogInformation("Handling EpicDeletedEvent for epic {EpicId}", notification.EpicId);
+
+ await _notificationService.NotifyEpicDeleted(
+ notification.TenantId.Value,
+ notification.ProjectId.Value,
+ notification.EpicId.Value);
+
+ _logger.LogInformation("SignalR notification sent for epic {EpicId}", notification.EpicId);
+ }
+}
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/EpicUpdatedEventHandler.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/EpicUpdatedEventHandler.cs
new file mode 100644
index 0000000..6ea94d4
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/EpicUpdatedEventHandler.cs
@@ -0,0 +1,44 @@
+using MediatR;
+using Microsoft.Extensions.Logging;
+using ColaFlow.Modules.ProjectManagement.Domain.Events;
+using ColaFlow.Modules.ProjectManagement.Application.Services;
+
+namespace ColaFlow.Modules.ProjectManagement.Application.EventHandlers;
+
+///
+/// Handler for EpicUpdatedEvent - sends SignalR notification
+///
+public class EpicUpdatedEventHandler : INotificationHandler
+{
+ private readonly IProjectNotificationService _notificationService;
+ private readonly ILogger _logger;
+
+ public EpicUpdatedEventHandler(
+ IProjectNotificationService notificationService,
+ ILogger logger)
+ {
+ _notificationService = notificationService;
+ _logger = logger;
+ }
+
+ public async Task Handle(EpicUpdatedEvent notification, CancellationToken cancellationToken)
+ {
+ _logger.LogInformation("Handling EpicUpdatedEvent for epic {EpicId}", notification.EpicId);
+
+ var epicData = new
+ {
+ Id = notification.EpicId.Value,
+ ProjectId = notification.ProjectId.Value,
+ Name = notification.EpicName,
+ UpdatedAt = DateTime.UtcNow
+ };
+
+ await _notificationService.NotifyEpicUpdated(
+ notification.TenantId.Value,
+ notification.ProjectId.Value,
+ notification.EpicId.Value,
+ epicData);
+
+ _logger.LogInformation("SignalR notification sent for epic {EpicId}", notification.EpicId);
+ }
+}
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/StoryCreatedEventHandler.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/StoryCreatedEventHandler.cs
new file mode 100644
index 0000000..8755643
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/StoryCreatedEventHandler.cs
@@ -0,0 +1,46 @@
+using MediatR;
+using Microsoft.Extensions.Logging;
+using ColaFlow.Modules.ProjectManagement.Domain.Events;
+using ColaFlow.Modules.ProjectManagement.Application.Services;
+
+namespace ColaFlow.Modules.ProjectManagement.Application.EventHandlers;
+
+///
+/// Handler for StoryCreatedEvent - sends SignalR notification
+///
+public class StoryCreatedEventHandler : INotificationHandler
+{
+ private readonly IProjectNotificationService _notificationService;
+ private readonly ILogger _logger;
+
+ public StoryCreatedEventHandler(
+ IProjectNotificationService notificationService,
+ ILogger logger)
+ {
+ _notificationService = notificationService;
+ _logger = logger;
+ }
+
+ public async Task Handle(StoryCreatedEvent notification, CancellationToken cancellationToken)
+ {
+ _logger.LogInformation("Handling StoryCreatedEvent for story {StoryId}", notification.StoryId);
+
+ var storyData = new
+ {
+ Id = notification.StoryId.Value,
+ ProjectId = notification.ProjectId.Value,
+ EpicId = notification.EpicId.Value,
+ Title = notification.StoryTitle,
+ CreatedAt = DateTime.UtcNow
+ };
+
+ await _notificationService.NotifyStoryCreated(
+ notification.TenantId.Value,
+ notification.ProjectId.Value,
+ notification.EpicId.Value,
+ notification.StoryId.Value,
+ storyData);
+
+ _logger.LogInformation("SignalR notification sent for story {StoryId}", notification.StoryId);
+ }
+}
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/StoryDeletedEventHandler.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/StoryDeletedEventHandler.cs
new file mode 100644
index 0000000..8130b3d
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/StoryDeletedEventHandler.cs
@@ -0,0 +1,36 @@
+using MediatR;
+using Microsoft.Extensions.Logging;
+using ColaFlow.Modules.ProjectManagement.Domain.Events;
+using ColaFlow.Modules.ProjectManagement.Application.Services;
+
+namespace ColaFlow.Modules.ProjectManagement.Application.EventHandlers;
+
+///
+/// Handler for StoryDeletedEvent - sends SignalR notification
+///
+public class StoryDeletedEventHandler : INotificationHandler
+{
+ private readonly IProjectNotificationService _notificationService;
+ private readonly ILogger _logger;
+
+ public StoryDeletedEventHandler(
+ IProjectNotificationService notificationService,
+ ILogger logger)
+ {
+ _notificationService = notificationService;
+ _logger = logger;
+ }
+
+ public async Task Handle(StoryDeletedEvent notification, CancellationToken cancellationToken)
+ {
+ _logger.LogInformation("Handling StoryDeletedEvent for story {StoryId}", notification.StoryId);
+
+ await _notificationService.NotifyStoryDeleted(
+ notification.TenantId.Value,
+ notification.ProjectId.Value,
+ notification.EpicId.Value,
+ notification.StoryId.Value);
+
+ _logger.LogInformation("SignalR notification sent for story {StoryId}", notification.StoryId);
+ }
+}
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/StoryUpdatedEventHandler.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/StoryUpdatedEventHandler.cs
new file mode 100644
index 0000000..f2317c6
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/StoryUpdatedEventHandler.cs
@@ -0,0 +1,46 @@
+using MediatR;
+using Microsoft.Extensions.Logging;
+using ColaFlow.Modules.ProjectManagement.Domain.Events;
+using ColaFlow.Modules.ProjectManagement.Application.Services;
+
+namespace ColaFlow.Modules.ProjectManagement.Application.EventHandlers;
+
+///
+/// Handler for StoryUpdatedEvent - sends SignalR notification
+///
+public class StoryUpdatedEventHandler : INotificationHandler
+{
+ private readonly IProjectNotificationService _notificationService;
+ private readonly ILogger _logger;
+
+ public StoryUpdatedEventHandler(
+ IProjectNotificationService notificationService,
+ ILogger logger)
+ {
+ _notificationService = notificationService;
+ _logger = logger;
+ }
+
+ public async Task Handle(StoryUpdatedEvent notification, CancellationToken cancellationToken)
+ {
+ _logger.LogInformation("Handling StoryUpdatedEvent for story {StoryId}", notification.StoryId);
+
+ var storyData = new
+ {
+ Id = notification.StoryId.Value,
+ ProjectId = notification.ProjectId.Value,
+ EpicId = notification.EpicId.Value,
+ Title = notification.StoryTitle,
+ UpdatedAt = DateTime.UtcNow
+ };
+
+ await _notificationService.NotifyStoryUpdated(
+ notification.TenantId.Value,
+ notification.ProjectId.Value,
+ notification.EpicId.Value,
+ notification.StoryId.Value,
+ storyData);
+
+ _logger.LogInformation("SignalR notification sent for story {StoryId}", notification.StoryId);
+ }
+}
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/TaskAssignedEventHandler.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/TaskAssignedEventHandler.cs
new file mode 100644
index 0000000..f670175
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/TaskAssignedEventHandler.cs
@@ -0,0 +1,37 @@
+using MediatR;
+using Microsoft.Extensions.Logging;
+using ColaFlow.Modules.ProjectManagement.Domain.Events;
+using ColaFlow.Modules.ProjectManagement.Application.Services;
+
+namespace ColaFlow.Modules.ProjectManagement.Application.EventHandlers;
+
+///
+/// Handler for TaskAssignedEvent - sends SignalR notification
+///
+public class TaskAssignedEventHandler : INotificationHandler
+{
+ private readonly IProjectNotificationService _notificationService;
+ private readonly ILogger _logger;
+
+ public TaskAssignedEventHandler(
+ IProjectNotificationService notificationService,
+ ILogger logger)
+ {
+ _notificationService = notificationService;
+ _logger = logger;
+ }
+
+ public async Task Handle(TaskAssignedEvent notification, CancellationToken cancellationToken)
+ {
+ _logger.LogInformation("Handling TaskAssignedEvent for task {TaskId}", notification.TaskId);
+
+ await _notificationService.NotifyTaskAssigned(
+ notification.TenantId.Value,
+ notification.ProjectId.Value,
+ notification.TaskId.Value,
+ notification.AssigneeId.Value);
+
+ _logger.LogInformation("SignalR notification sent for task {TaskId} assigned to {AssigneeId}",
+ notification.TaskId, notification.AssigneeId);
+ }
+}
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/TaskCreatedEventHandler.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/TaskCreatedEventHandler.cs
new file mode 100644
index 0000000..4694bee
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/TaskCreatedEventHandler.cs
@@ -0,0 +1,46 @@
+using MediatR;
+using Microsoft.Extensions.Logging;
+using ColaFlow.Modules.ProjectManagement.Domain.Events;
+using ColaFlow.Modules.ProjectManagement.Application.Services;
+
+namespace ColaFlow.Modules.ProjectManagement.Application.EventHandlers;
+
+///
+/// Handler for TaskCreatedEvent - sends SignalR notification
+///
+public class TaskCreatedEventHandler : INotificationHandler
+{
+ private readonly IProjectNotificationService _notificationService;
+ private readonly ILogger _logger;
+
+ public TaskCreatedEventHandler(
+ IProjectNotificationService notificationService,
+ ILogger logger)
+ {
+ _notificationService = notificationService;
+ _logger = logger;
+ }
+
+ public async Task Handle(TaskCreatedEvent notification, CancellationToken cancellationToken)
+ {
+ _logger.LogInformation("Handling TaskCreatedEvent for task {TaskId}", notification.TaskId);
+
+ var taskData = new
+ {
+ Id = notification.TaskId.Value,
+ ProjectId = notification.ProjectId.Value,
+ StoryId = notification.StoryId.Value,
+ Title = notification.TaskTitle,
+ CreatedAt = DateTime.UtcNow
+ };
+
+ await _notificationService.NotifyTaskCreated(
+ notification.TenantId.Value,
+ notification.ProjectId.Value,
+ notification.StoryId.Value,
+ notification.TaskId.Value,
+ taskData);
+
+ _logger.LogInformation("SignalR notification sent for task {TaskId}", notification.TaskId);
+ }
+}
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/TaskDeletedEventHandler.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/TaskDeletedEventHandler.cs
new file mode 100644
index 0000000..0a4be8d
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/TaskDeletedEventHandler.cs
@@ -0,0 +1,36 @@
+using MediatR;
+using Microsoft.Extensions.Logging;
+using ColaFlow.Modules.ProjectManagement.Domain.Events;
+using ColaFlow.Modules.ProjectManagement.Application.Services;
+
+namespace ColaFlow.Modules.ProjectManagement.Application.EventHandlers;
+
+///
+/// Handler for TaskDeletedEvent - sends SignalR notification
+///
+public class TaskDeletedEventHandler : INotificationHandler
+{
+ private readonly IProjectNotificationService _notificationService;
+ private readonly ILogger _logger;
+
+ public TaskDeletedEventHandler(
+ IProjectNotificationService notificationService,
+ ILogger logger)
+ {
+ _notificationService = notificationService;
+ _logger = logger;
+ }
+
+ public async Task Handle(TaskDeletedEvent notification, CancellationToken cancellationToken)
+ {
+ _logger.LogInformation("Handling TaskDeletedEvent for task {TaskId}", notification.TaskId);
+
+ await _notificationService.NotifyTaskDeleted(
+ notification.TenantId.Value,
+ notification.ProjectId.Value,
+ notification.StoryId.Value,
+ notification.TaskId.Value);
+
+ _logger.LogInformation("SignalR notification sent for task {TaskId}", notification.TaskId);
+ }
+}
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/TaskUpdatedEventHandler.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/TaskUpdatedEventHandler.cs
new file mode 100644
index 0000000..4b05cec
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/EventHandlers/TaskUpdatedEventHandler.cs
@@ -0,0 +1,46 @@
+using MediatR;
+using Microsoft.Extensions.Logging;
+using ColaFlow.Modules.ProjectManagement.Domain.Events;
+using ColaFlow.Modules.ProjectManagement.Application.Services;
+
+namespace ColaFlow.Modules.ProjectManagement.Application.EventHandlers;
+
+///
+/// Handler for TaskUpdatedEvent - sends SignalR notification
+///
+public class TaskUpdatedEventHandler : INotificationHandler
+{
+ private readonly IProjectNotificationService _notificationService;
+ private readonly ILogger _logger;
+
+ public TaskUpdatedEventHandler(
+ IProjectNotificationService notificationService,
+ ILogger logger)
+ {
+ _notificationService = notificationService;
+ _logger = logger;
+ }
+
+ public async Task Handle(TaskUpdatedEvent notification, CancellationToken cancellationToken)
+ {
+ _logger.LogInformation("Handling TaskUpdatedEvent for task {TaskId}", notification.TaskId);
+
+ var taskData = new
+ {
+ Id = notification.TaskId.Value,
+ ProjectId = notification.ProjectId.Value,
+ StoryId = notification.StoryId.Value,
+ Title = notification.TaskTitle,
+ UpdatedAt = DateTime.UtcNow
+ };
+
+ await _notificationService.NotifyTaskUpdated(
+ notification.TenantId.Value,
+ notification.ProjectId.Value,
+ notification.StoryId.Value,
+ notification.TaskId.Value,
+ taskData);
+
+ _logger.LogInformation("SignalR notification sent for task {TaskId}", notification.TaskId);
+ }
+}
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/Services/IProjectNotificationService.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/Services/IProjectNotificationService.cs
index 78cb719..c3fe685 100644
--- a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/Services/IProjectNotificationService.cs
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Application/Services/IProjectNotificationService.cs
@@ -5,7 +5,24 @@ namespace ColaFlow.Modules.ProjectManagement.Application.Services;
///
public interface IProjectNotificationService
{
+ // Project notifications
Task NotifyProjectCreated(Guid tenantId, Guid projectId, object project);
Task NotifyProjectUpdated(Guid tenantId, Guid projectId, object project);
Task NotifyProjectArchived(Guid tenantId, Guid projectId);
+
+ // Epic notifications
+ Task NotifyEpicCreated(Guid tenantId, Guid projectId, Guid epicId, object epic);
+ Task NotifyEpicUpdated(Guid tenantId, Guid projectId, Guid epicId, object epic);
+ Task NotifyEpicDeleted(Guid tenantId, Guid projectId, Guid epicId);
+
+ // Story notifications
+ Task NotifyStoryCreated(Guid tenantId, Guid projectId, Guid epicId, Guid storyId, object story);
+ Task NotifyStoryUpdated(Guid tenantId, Guid projectId, Guid epicId, Guid storyId, object story);
+ Task NotifyStoryDeleted(Guid tenantId, Guid projectId, Guid epicId, Guid storyId);
+
+ // Task notifications
+ Task NotifyTaskCreated(Guid tenantId, Guid projectId, Guid storyId, Guid taskId, object task);
+ Task NotifyTaskUpdated(Guid tenantId, Guid projectId, Guid storyId, Guid taskId, object task);
+ Task NotifyTaskDeleted(Guid tenantId, Guid projectId, Guid storyId, Guid taskId);
+ Task NotifyTaskAssigned(Guid tenantId, Guid projectId, Guid taskId, Guid assigneeId);
}
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Aggregates/ProjectAggregate/Project.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Aggregates/ProjectAggregate/Project.cs
index 98cfebe..fd3de75 100644
--- a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Aggregates/ProjectAggregate/Project.cs
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Aggregates/ProjectAggregate/Project.cs
@@ -90,11 +90,154 @@ public class Project : AggregateRoot
var epic = Epic.Create(this.TenantId, name, description, this.Id, createdBy);
_epics.Add(epic);
- AddDomainEvent(new EpicCreatedEvent(epic.Id, epic.Name, this.Id));
+ AddDomainEvent(new EpicCreatedEvent(epic.Id, this.TenantId, this.Id, epic.Name));
return epic;
}
+ public void UpdateEpic(EpicId epicId, string name, string description)
+ {
+ var epic = _epics.FirstOrDefault(e => e.Id == epicId);
+ if (epic == null)
+ throw new DomainException($"Epic with ID {epicId.Value} not found");
+
+ epic.UpdateDetails(name, description);
+ UpdatedAt = DateTime.UtcNow;
+
+ AddDomainEvent(new EpicUpdatedEvent(epic.Id, this.TenantId, this.Id, epic.Name));
+ }
+
+ public void DeleteEpic(EpicId epicId)
+ {
+ var epic = _epics.FirstOrDefault(e => e.Id == epicId);
+ if (epic == null)
+ throw new DomainException($"Epic with ID {epicId.Value} not found");
+
+ if (epic.Stories.Any())
+ throw new DomainException($"Cannot delete epic with ID {epicId.Value}. The epic has {epic.Stories.Count} associated story/stories. Please delete or reassign the stories first.");
+
+ _epics.Remove(epic);
+ UpdatedAt = DateTime.UtcNow;
+
+ AddDomainEvent(new EpicDeletedEvent(epicId, this.TenantId, this.Id));
+ }
+
+ public Story CreateStory(EpicId epicId, string title, string description, TaskPriority priority, UserId createdBy)
+ {
+ var epic = _epics.FirstOrDefault(e => e.Id == epicId);
+ if (epic == null)
+ throw new DomainException($"Epic with ID {epicId.Value} not found");
+
+ var story = epic.CreateStory(title, description, priority, createdBy);
+ UpdatedAt = DateTime.UtcNow;
+
+ AddDomainEvent(new StoryCreatedEvent(story.Id, this.TenantId, this.Id, epicId, story.Title));
+
+ return story;
+ }
+
+ public void UpdateStory(EpicId epicId, StoryId storyId, string title, string description)
+ {
+ var epic = _epics.FirstOrDefault(e => e.Id == epicId);
+ if (epic == null)
+ throw new DomainException($"Epic with ID {epicId.Value} not found");
+
+ var story = epic.Stories.FirstOrDefault(s => s.Id == storyId);
+ if (story == null)
+ throw new DomainException($"Story with ID {storyId.Value} not found in epic");
+
+ story.UpdateDetails(title, description);
+ UpdatedAt = DateTime.UtcNow;
+
+ AddDomainEvent(new StoryUpdatedEvent(storyId, this.TenantId, this.Id, epicId, story.Title));
+ }
+
+ public void DeleteStory(EpicId epicId, StoryId storyId)
+ {
+ var epic = _epics.FirstOrDefault(e => e.Id == epicId);
+ if (epic == null)
+ throw new DomainException($"Epic with ID {epicId.Value} not found");
+
+ epic.RemoveStory(storyId);
+ UpdatedAt = DateTime.UtcNow;
+
+ AddDomainEvent(new StoryDeletedEvent(storyId, this.TenantId, this.Id, epicId));
+ }
+
+ public WorkTask CreateTask(EpicId epicId, StoryId storyId, string title, string description, TaskPriority priority, UserId createdBy)
+ {
+ var epic = _epics.FirstOrDefault(e => e.Id == epicId);
+ if (epic == null)
+ throw new DomainException($"Epic with ID {epicId.Value} not found");
+
+ var story = epic.Stories.FirstOrDefault(s => s.Id == storyId);
+ if (story == null)
+ throw new DomainException($"Story with ID {storyId.Value} not found in epic");
+
+ var task = story.CreateTask(title, description, priority, createdBy);
+ UpdatedAt = DateTime.UtcNow;
+
+ AddDomainEvent(new TaskCreatedEvent(task.Id, this.TenantId, this.Id, storyId, task.Title));
+
+ return task;
+ }
+
+ public void UpdateTask(EpicId epicId, StoryId storyId, TaskId taskId, string title, string description)
+ {
+ var epic = _epics.FirstOrDefault(e => e.Id == epicId);
+ if (epic == null)
+ throw new DomainException($"Epic with ID {epicId.Value} not found");
+
+ var story = epic.Stories.FirstOrDefault(s => s.Id == storyId);
+ if (story == null)
+ throw new DomainException($"Story with ID {storyId.Value} not found in epic");
+
+ var task = story.Tasks.FirstOrDefault(t => t.Id == taskId);
+ if (task == null)
+ throw new DomainException($"Task with ID {taskId.Value} not found in story");
+
+ task.UpdateDetails(title, description);
+ UpdatedAt = DateTime.UtcNow;
+
+ AddDomainEvent(new TaskUpdatedEvent(taskId, this.TenantId, this.Id, storyId, task.Title));
+ }
+
+ public void DeleteTask(EpicId epicId, StoryId storyId, TaskId taskId)
+ {
+ var epic = _epics.FirstOrDefault(e => e.Id == epicId);
+ if (epic == null)
+ throw new DomainException($"Epic with ID {epicId.Value} not found");
+
+ var story = epic.Stories.FirstOrDefault(s => s.Id == storyId);
+ if (story == null)
+ throw new DomainException($"Story with ID {storyId.Value} not found in epic");
+
+ story.RemoveTask(taskId);
+ UpdatedAt = DateTime.UtcNow;
+
+ AddDomainEvent(new TaskDeletedEvent(taskId, this.TenantId, this.Id, storyId));
+ }
+
+ public void AssignTask(EpicId epicId, StoryId storyId, TaskId taskId, UserId assigneeId)
+ {
+ var epic = _epics.FirstOrDefault(e => e.Id == epicId);
+ if (epic == null)
+ throw new DomainException($"Epic with ID {epicId.Value} not found");
+
+ var story = epic.Stories.FirstOrDefault(s => s.Id == storyId);
+ if (story == null)
+ throw new DomainException($"Story with ID {storyId.Value} not found in epic");
+
+ var task = story.Tasks.FirstOrDefault(t => t.Id == taskId);
+ if (task == null)
+ throw new DomainException($"Task with ID {taskId.Value} not found in story");
+
+ task.AssignTo(assigneeId);
+ UpdatedAt = DateTime.UtcNow;
+
+ AddDomainEvent(new TaskAssignedEvent(taskId, this.TenantId, this.Id, storyId, assigneeId));
+ }
+
public void Archive()
{
if (Status == ProjectStatus.Archived)
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/EpicCreatedEvent.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/EpicCreatedEvent.cs
index 21bc67a..e7068f2 100644
--- a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/EpicCreatedEvent.cs
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/EpicCreatedEvent.cs
@@ -8,6 +8,7 @@ namespace ColaFlow.Modules.ProjectManagement.Domain.Events;
///
public sealed record EpicCreatedEvent(
EpicId EpicId,
- string EpicName,
- ProjectId ProjectId
+ TenantId TenantId,
+ ProjectId ProjectId,
+ string EpicName
) : DomainEvent;
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/EpicDeletedEvent.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/EpicDeletedEvent.cs
new file mode 100644
index 0000000..7c4edeb
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/EpicDeletedEvent.cs
@@ -0,0 +1,13 @@
+using ColaFlow.Shared.Kernel.Events;
+using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
+
+namespace ColaFlow.Modules.ProjectManagement.Domain.Events;
+
+///
+/// Event raised when an epic is deleted
+///
+public sealed record EpicDeletedEvent(
+ EpicId EpicId,
+ TenantId TenantId,
+ ProjectId ProjectId
+) : DomainEvent;
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/EpicUpdatedEvent.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/EpicUpdatedEvent.cs
new file mode 100644
index 0000000..a79e3aa
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/EpicUpdatedEvent.cs
@@ -0,0 +1,14 @@
+using ColaFlow.Shared.Kernel.Events;
+using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
+
+namespace ColaFlow.Modules.ProjectManagement.Domain.Events;
+
+///
+/// Event raised when an epic is updated
+///
+public sealed record EpicUpdatedEvent(
+ EpicId EpicId,
+ TenantId TenantId,
+ ProjectId ProjectId,
+ string EpicName
+) : DomainEvent;
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/StoryCreatedEvent.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/StoryCreatedEvent.cs
new file mode 100644
index 0000000..261f607
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/StoryCreatedEvent.cs
@@ -0,0 +1,15 @@
+using ColaFlow.Shared.Kernel.Events;
+using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
+
+namespace ColaFlow.Modules.ProjectManagement.Domain.Events;
+
+///
+/// Event raised when a story is created
+///
+public sealed record StoryCreatedEvent(
+ StoryId StoryId,
+ TenantId TenantId,
+ ProjectId ProjectId,
+ EpicId EpicId,
+ string StoryTitle
+) : DomainEvent;
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/StoryDeletedEvent.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/StoryDeletedEvent.cs
new file mode 100644
index 0000000..6378241
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/StoryDeletedEvent.cs
@@ -0,0 +1,14 @@
+using ColaFlow.Shared.Kernel.Events;
+using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
+
+namespace ColaFlow.Modules.ProjectManagement.Domain.Events;
+
+///
+/// Event raised when a story is deleted
+///
+public sealed record StoryDeletedEvent(
+ StoryId StoryId,
+ TenantId TenantId,
+ ProjectId ProjectId,
+ EpicId EpicId
+) : DomainEvent;
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/StoryUpdatedEvent.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/StoryUpdatedEvent.cs
new file mode 100644
index 0000000..1554bba
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/StoryUpdatedEvent.cs
@@ -0,0 +1,15 @@
+using ColaFlow.Shared.Kernel.Events;
+using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
+
+namespace ColaFlow.Modules.ProjectManagement.Domain.Events;
+
+///
+/// Event raised when a story is updated
+///
+public sealed record StoryUpdatedEvent(
+ StoryId StoryId,
+ TenantId TenantId,
+ ProjectId ProjectId,
+ EpicId EpicId,
+ string StoryTitle
+) : DomainEvent;
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/TaskAssignedEvent.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/TaskAssignedEvent.cs
new file mode 100644
index 0000000..7c166a6
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/TaskAssignedEvent.cs
@@ -0,0 +1,15 @@
+using ColaFlow.Shared.Kernel.Events;
+using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
+
+namespace ColaFlow.Modules.ProjectManagement.Domain.Events;
+
+///
+/// Event raised when a task is assigned to a user
+///
+public sealed record TaskAssignedEvent(
+ TaskId TaskId,
+ TenantId TenantId,
+ ProjectId ProjectId,
+ StoryId StoryId,
+ UserId AssigneeId
+) : DomainEvent;
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/TaskCreatedEvent.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/TaskCreatedEvent.cs
new file mode 100644
index 0000000..9ba4eb7
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/TaskCreatedEvent.cs
@@ -0,0 +1,15 @@
+using ColaFlow.Shared.Kernel.Events;
+using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
+
+namespace ColaFlow.Modules.ProjectManagement.Domain.Events;
+
+///
+/// Event raised when a task is created
+///
+public sealed record TaskCreatedEvent(
+ TaskId TaskId,
+ TenantId TenantId,
+ ProjectId ProjectId,
+ StoryId StoryId,
+ string TaskTitle
+) : DomainEvent;
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/TaskDeletedEvent.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/TaskDeletedEvent.cs
new file mode 100644
index 0000000..375477a
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/TaskDeletedEvent.cs
@@ -0,0 +1,14 @@
+using ColaFlow.Shared.Kernel.Events;
+using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
+
+namespace ColaFlow.Modules.ProjectManagement.Domain.Events;
+
+///
+/// Event raised when a task is deleted
+///
+public sealed record TaskDeletedEvent(
+ TaskId TaskId,
+ TenantId TenantId,
+ ProjectId ProjectId,
+ StoryId StoryId
+) : DomainEvent;
diff --git a/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/TaskUpdatedEvent.cs b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/TaskUpdatedEvent.cs
new file mode 100644
index 0000000..cf54be0
--- /dev/null
+++ b/colaflow-api/src/Modules/ProjectManagement/ColaFlow.Modules.ProjectManagement.Domain/Events/TaskUpdatedEvent.cs
@@ -0,0 +1,15 @@
+using ColaFlow.Shared.Kernel.Events;
+using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
+
+namespace ColaFlow.Modules.ProjectManagement.Domain.Events;
+
+///
+/// Event raised when a task is updated
+///
+public sealed record TaskUpdatedEvent(
+ TaskId TaskId,
+ TenantId TenantId,
+ ProjectId ProjectId,
+ StoryId StoryId,
+ string TaskTitle
+) : DomainEvent;
diff --git a/colaflow-api/tests/ColaFlow.Domain.Tests/Events/DomainEventsTests.cs b/colaflow-api/tests/ColaFlow.Domain.Tests/Events/DomainEventsTests.cs
index 3111930..d23cf86 100644
--- a/colaflow-api/tests/ColaFlow.Domain.Tests/Events/DomainEventsTests.cs
+++ b/colaflow-api/tests/ColaFlow.Domain.Tests/Events/DomainEventsTests.cs
@@ -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);