Files
ColaFlow/colaflow-api/src/Modules/Mcp/ColaFlow.Modules.Mcp.Infrastructure/Services/McpNotificationService.cs
Yaojia Wang 1d6e732018
Some checks failed
Code Coverage / Generate Coverage Report (push) Has been cancelled
Tests / Run Tests (9.0.x) (push) Has been cancelled
Tests / Docker Build Test (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
fix(backend): Move McpNotificationHub to Infrastructure layer to fix dependency inversion violation
Fixed compilation error where Infrastructure layer was referencing API layer (ColaFlow.API.Hubs).
This violated the dependency inversion principle and Clean Architecture layering rules.

Changes:
- Moved McpNotificationHub from ColaFlow.API/Hubs to ColaFlow.Modules.Mcp.Infrastructure/Hubs
- Updated McpNotificationHub to inherit directly from Hub instead of BaseHub
- Copied necessary helper methods (GetCurrentUserId, GetCurrentTenantId, GetTenantGroupName) to avoid cross-layer dependency
- Updated McpNotificationService to use new namespace (ColaFlow.Modules.Mcp.Infrastructure.Hubs)
- Updated Program.cs to import new Hub namespace
- Updated McpNotificationServiceTests to use new namespace
- Kept BaseHub in API layer for ProjectHub and NotificationHub

Architecture Impact:
- Infrastructure layer no longer depends on API layer
- Proper dependency flow: API -> Infrastructure -> Application -> Domain
- McpNotificationHub is now properly encapsulated within the MCP module

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 18:37:08 +01:00

136 lines
5.6 KiB
C#

using ColaFlow.Modules.Mcp.Application.DTOs.Notifications;
using ColaFlow.Modules.Mcp.Application.Services;
using ColaFlow.Modules.Mcp.Infrastructure.Hubs;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
namespace ColaFlow.Modules.Mcp.Infrastructure.Services;
/// <summary>
/// Implementation of IMcpNotificationService using SignalR
/// </summary>
public class McpNotificationService : IMcpNotificationService
{
private readonly IHubContext<McpNotificationHub> _hubContext;
private readonly ILogger<McpNotificationService> _logger;
public McpNotificationService(
IHubContext<McpNotificationHub> hubContext,
ILogger<McpNotificationService> logger)
{
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task NotifyPendingChangeCreatedAsync(
PendingChangeCreatedNotification notification,
CancellationToken cancellationToken = default)
{
var groupName = GetPendingChangeGroupName(notification.PendingChangeId);
var tenantGroupName = GetTenantGroupName(notification.TenantId);
_logger.LogInformation(
"Sending PendingChangeCreated notification - PendingChangeId={PendingChangeId}, EntityType={EntityType}, Operation={Operation}",
notification.PendingChangeId, notification.EntityType, notification.Operation);
// Send to both: specific pending change subscribers AND all tenant members
await _hubContext.Clients
.Groups(groupName, tenantGroupName)
.SendAsync("PendingChangeCreated", notification, cancellationToken);
_logger.LogDebug(
"PendingChangeCreated notification sent - Groups=[{GroupName}, {TenantGroupName}]",
groupName, tenantGroupName);
}
public async Task NotifyPendingChangeApprovedAsync(
PendingChangeApprovedNotification notification,
CancellationToken cancellationToken = default)
{
var groupName = GetPendingChangeGroupName(notification.PendingChangeId);
var tenantGroupName = GetTenantGroupName(notification.TenantId);
_logger.LogInformation(
"Sending PendingChangeApproved notification - PendingChangeId={PendingChangeId}, EntityType={EntityType}, ApprovedBy={ApprovedBy}",
notification.PendingChangeId, notification.EntityType, notification.ApprovedBy);
await _hubContext.Clients
.Groups(groupName, tenantGroupName)
.SendAsync("PendingChangeApproved", notification, cancellationToken);
_logger.LogDebug(
"PendingChangeApproved notification sent - Groups=[{GroupName}, {TenantGroupName}]",
groupName, tenantGroupName);
}
public async Task NotifyPendingChangeRejectedAsync(
PendingChangeRejectedNotification notification,
CancellationToken cancellationToken = default)
{
var groupName = GetPendingChangeGroupName(notification.PendingChangeId);
var tenantGroupName = GetTenantGroupName(notification.TenantId);
_logger.LogInformation(
"Sending PendingChangeRejected notification - PendingChangeId={PendingChangeId}, Reason={Reason}, RejectedBy={RejectedBy}",
notification.PendingChangeId, notification.Reason, notification.RejectedBy);
await _hubContext.Clients
.Groups(groupName, tenantGroupName)
.SendAsync("PendingChangeRejected", notification, cancellationToken);
_logger.LogDebug(
"PendingChangeRejected notification sent - Groups=[{GroupName}, {TenantGroupName}]",
groupName, tenantGroupName);
}
public async Task NotifyPendingChangeAppliedAsync(
PendingChangeAppliedNotification notification,
CancellationToken cancellationToken = default)
{
var groupName = GetPendingChangeGroupName(notification.PendingChangeId);
var tenantGroupName = GetTenantGroupName(notification.TenantId);
_logger.LogInformation(
"Sending PendingChangeApplied notification - PendingChangeId={PendingChangeId}, Result={Result}",
notification.PendingChangeId, notification.Result);
await _hubContext.Clients
.Groups(groupName, tenantGroupName)
.SendAsync("PendingChangeApplied", notification, cancellationToken);
_logger.LogDebug(
"PendingChangeApplied notification sent - Groups=[{GroupName}, {TenantGroupName}]",
groupName, tenantGroupName);
}
public async Task NotifyPendingChangeExpiredAsync(
PendingChangeExpiredNotification notification,
CancellationToken cancellationToken = default)
{
var groupName = GetPendingChangeGroupName(notification.PendingChangeId);
var tenantGroupName = GetTenantGroupName(notification.TenantId);
_logger.LogInformation(
"Sending PendingChangeExpired notification - PendingChangeId={PendingChangeId}, ExpiredAt={ExpiredAt}",
notification.PendingChangeId, notification.ExpiredAt);
await _hubContext.Clients
.Groups(groupName, tenantGroupName)
.SendAsync("PendingChangeExpired", notification, cancellationToken);
_logger.LogDebug(
"PendingChangeExpired notification sent - Groups=[{GroupName}, {TenantGroupName}]",
groupName, tenantGroupName);
}
private static string GetPendingChangeGroupName(Guid pendingChangeId)
{
return $"pending-change-{pendingChangeId}";
}
private static string GetTenantGroupName(Guid tenantId)
{
return $"tenant-{tenantId}";
}
}