feat(backend): Implement SignalR real-time communication infrastructure
Add complete SignalR infrastructure for real-time project collaboration and notifications with multi-tenant isolation and JWT authentication. Changes: - Created BaseHub with multi-tenant isolation and JWT authentication helpers - Created ProjectHub for real-time project collaboration (join/leave, typing indicators) - Created NotificationHub for user-level notifications - Implemented IRealtimeNotificationService for application layer integration - Configured SignalR in Program.cs with CORS and JWT query string support - Added SignalRTestController for connection testing - Documented hub endpoints, client events, and integration examples Features: - Multi-tenant isolation via automatic tenant group membership - JWT authentication (Bearer header + query string for WebSocket) - Hub endpoints: /hubs/project, /hubs/notification - Project-level events: IssueCreated, IssueUpdated, IssueStatusChanged, etc. - User-level notifications with tenant-wide broadcasting - Test endpoints for validation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using ColaFlow.API.Hubs;
|
||||
|
||||
namespace ColaFlow.API.Services;
|
||||
|
||||
public class RealtimeNotificationService : IRealtimeNotificationService
|
||||
{
|
||||
private readonly IHubContext<ProjectHub> _projectHubContext;
|
||||
private readonly IHubContext<NotificationHub> _notificationHubContext;
|
||||
private readonly ILogger<RealtimeNotificationService> _logger;
|
||||
|
||||
public RealtimeNotificationService(
|
||||
IHubContext<ProjectHub> projectHubContext,
|
||||
IHubContext<NotificationHub> notificationHubContext,
|
||||
ILogger<RealtimeNotificationService> logger)
|
||||
{
|
||||
_projectHubContext = projectHubContext;
|
||||
_notificationHubContext = notificationHubContext;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
});
|
||||
}
|
||||
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user