using Microsoft.AspNetCore.SignalR; using ColaFlow.API.Hubs; namespace ColaFlow.API.Services; public class RealtimeNotificationService : IRealtimeNotificationService { private readonly IHubContext _projectHubContext; private readonly IHubContext _notificationHubContext; private readonly ILogger _logger; public RealtimeNotificationService( IHubContext projectHubContext, IHubContext notificationHubContext, ILogger logger) { _projectHubContext = projectHubContext; _notificationHubContext = notificationHubContext; _logger = logger; } public async Task NotifyProjectCreated(Guid tenantId, Guid projectId, object project) { var tenantGroupName = $"tenant-{tenantId}"; _logger.LogInformation("Notifying tenant {TenantId} of new project {ProjectId}", tenantId, projectId); await _projectHubContext.Clients.Group(tenantGroupName).SendAsync("ProjectCreated", project); } public async Task NotifyProjectUpdated(Guid tenantId, Guid projectId, object project) { var projectGroupName = $"project-{projectId}"; var tenantGroupName = $"tenant-{tenantId}"; _logger.LogInformation("Notifying project {ProjectId} updated", projectId); await _projectHubContext.Clients.Group(projectGroupName).SendAsync("ProjectUpdated", project); await _projectHubContext.Clients.Group(tenantGroupName).SendAsync("ProjectUpdated", project); } public async Task NotifyProjectArchived(Guid tenantId, Guid projectId) { var projectGroupName = $"project-{projectId}"; var tenantGroupName = $"tenant-{tenantId}"; _logger.LogInformation("Notifying project {ProjectId} archived", projectId); await _projectHubContext.Clients.Group(projectGroupName).SendAsync("ProjectArchived", new { ProjectId = projectId }); await _projectHubContext.Clients.Group(tenantGroupName).SendAsync("ProjectArchived", new { ProjectId = projectId }); } public async Task NotifyProjectUpdate(Guid tenantId, Guid projectId, object data) { var groupName = $"project-{projectId}"; _logger.LogInformation("Sending project update to group {GroupName}", groupName); 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}"; await _projectHubContext.Clients.Group(groupName).SendAsync("IssueCreated", issue); } public async Task NotifyIssueUpdated(Guid tenantId, Guid projectId, object issue) { var groupName = $"project-{projectId}"; await _projectHubContext.Clients.Group(groupName).SendAsync("IssueUpdated", issue); } public async Task NotifyIssueDeleted(Guid tenantId, Guid projectId, Guid issueId) { var groupName = $"project-{projectId}"; await _projectHubContext.Clients.Group(groupName).SendAsync("IssueDeleted", new { IssueId = issueId }); } public async Task NotifyIssueStatusChanged( Guid tenantId, Guid projectId, Guid issueId, string oldStatus, string newStatus) { var groupName = $"project-{projectId}"; await _projectHubContext.Clients.Group(groupName).SendAsync("IssueStatusChanged", new { IssueId = issueId, OldStatus = oldStatus, NewStatus = newStatus, ChangedAt = DateTime.UtcNow }); } // Sprint notifications public async Task NotifySprintCreated(Guid tenantId, Guid projectId, Guid sprintId, string sprintName) { var projectGroupName = $"project-{projectId}"; var tenantGroupName = $"tenant-{tenantId}"; _logger.LogInformation("Notifying sprint {SprintId} created in project {ProjectId}", sprintId, projectId); await _projectHubContext.Clients.Group(projectGroupName).SendAsync("SprintCreated", new { SprintId = sprintId, SprintName = sprintName, ProjectId = projectId, Timestamp = DateTime.UtcNow }); await _projectHubContext.Clients.Group(tenantGroupName).SendAsync("SprintCreated", new { SprintId = sprintId, SprintName = sprintName, ProjectId = projectId, Timestamp = DateTime.UtcNow }); } public async Task NotifySprintUpdated(Guid tenantId, Guid projectId, Guid sprintId, string sprintName) { var projectGroupName = $"project-{projectId}"; _logger.LogInformation("Notifying sprint {SprintId} updated", sprintId); await _projectHubContext.Clients.Group(projectGroupName).SendAsync("SprintUpdated", new { SprintId = sprintId, SprintName = sprintName, ProjectId = projectId, Timestamp = DateTime.UtcNow }); } public async Task NotifySprintStarted(Guid tenantId, Guid projectId, Guid sprintId, string sprintName) { var projectGroupName = $"project-{projectId}"; var tenantGroupName = $"tenant-{tenantId}"; _logger.LogInformation("Notifying sprint {SprintId} started", sprintId); await _projectHubContext.Clients.Group(projectGroupName).SendAsync("SprintStarted", new { SprintId = sprintId, SprintName = sprintName, ProjectId = projectId, Timestamp = DateTime.UtcNow }); await _projectHubContext.Clients.Group(tenantGroupName).SendAsync("SprintStarted", new { SprintId = sprintId, SprintName = sprintName, ProjectId = projectId, Timestamp = DateTime.UtcNow }); } public async Task NotifySprintCompleted(Guid tenantId, Guid projectId, Guid sprintId, string sprintName) { var projectGroupName = $"project-{projectId}"; var tenantGroupName = $"tenant-{tenantId}"; _logger.LogInformation("Notifying sprint {SprintId} completed", sprintId); await _projectHubContext.Clients.Group(projectGroupName).SendAsync("SprintCompleted", new { SprintId = sprintId, SprintName = sprintName, ProjectId = projectId, Timestamp = DateTime.UtcNow }); await _projectHubContext.Clients.Group(tenantGroupName).SendAsync("SprintCompleted", new { SprintId = sprintId, SprintName = sprintName, ProjectId = projectId, Timestamp = DateTime.UtcNow }); } public async Task NotifySprintDeleted(Guid tenantId, Guid projectId, Guid sprintId, string sprintName) { var projectGroupName = $"project-{projectId}"; var tenantGroupName = $"tenant-{tenantId}"; _logger.LogInformation("Notifying sprint {SprintId} deleted", sprintId); await _projectHubContext.Clients.Group(projectGroupName).SendAsync("SprintDeleted", new { SprintId = sprintId, SprintName = sprintName, ProjectId = projectId, Timestamp = DateTime.UtcNow }); await _projectHubContext.Clients.Group(tenantGroupName).SendAsync("SprintDeleted", new { SprintId = sprintId, SprintName = sprintName, ProjectId = projectId, Timestamp = DateTime.UtcNow }); } public async Task NotifyUser(Guid userId, string message, string type = "info") { var userConnectionId = $"user-{userId}"; await _notificationHubContext.Clients.User(userId.ToString()).SendAsync("Notification", new { Message = message, Type = type, Timestamp = DateTime.UtcNow }); } public async Task NotifyUsersInTenant(Guid tenantId, string message, string type = "info") { var groupName = $"tenant-{tenantId}"; await _notificationHubContext.Clients.Group(groupName).SendAsync("Notification", new { Message = message, Type = type, Timestamp = DateTime.UtcNow }); } }