# SignalR Real-time Communication Implementation

## Overview

This document describes the SignalR real-time communication infrastructure implemented for ColaFlow. The implementation provides real-time updates for project collaboration, issue tracking, and user notifications with multi-tenant isolation and JWT authentication.

## Implementation Date

2025-11-04

## Components Implemented

### 1. Hub Infrastructure

#### BaseHub (`src/ColaFlow.API/Hubs/BaseHub.cs`)

Base class for all SignalR hubs with:
- **JWT Authentication**: All hubs require authentication via `[Authorize]` attribute
- **Multi-tenant Isolation**: Automatically adds users to tenant-specific groups on connection
- **User/Tenant Extraction**: Helper methods to extract user ID and tenant ID from JWT claims
- **Connection Lifecycle**: Logging for connect/disconnect events

**Key Features:**
- `GetCurrentUserId()`: Extracts user ID from JWT token (sub or user_id claim)
- `GetCurrentTenantId()`: Extracts tenant ID from JWT token (tenant_id claim)
- `GetTenantGroupName(Guid tenantId)`: Returns standardized tenant group name
- Automatic group membership on connection
- Error handling with connection abort on authentication failures

#### ProjectHub (`src/ColaFlow.API/Hubs/ProjectHub.cs`)

Hub for project-level real-time collaboration:

**Methods:**
- `JoinProject(Guid projectId)`: Join a project room to receive updates
- `LeaveProject(Guid projectId)`: Leave a project room
- `SendTypingIndicator(Guid projectId, Guid issueId, bool isTyping)`: Send typing indicators

**Client Events:**
- `UserJoinedProject`: Notifies when a user joins a project
- `UserLeftProject`: Notifies when a user leaves a project
- `TypingIndicator`: Real-time typing indicators for issue editing
- `ProjectUpdated`: General project updates
- `IssueCreated`: New issue created
- `IssueUpdated`: Issue updated
- `IssueDeleted`: Issue deleted
- `IssueStatusChanged`: Issue status changed

#### NotificationHub (`src/ColaFlow.API/Hubs/NotificationHub.cs`)

Hub for user-level notifications:

**Methods:**
- `MarkAsRead(Guid notificationId)`: Mark a notification as read

**Client Events:**
- `Notification`: General notifications
- `NotificationRead`: Confirmation of read status

### 2. Realtime Notification Service

#### IRealtimeNotificationService (`src/ColaFlow.API/Services/IRealtimeNotificationService.cs`)

Service interface for sending real-time notifications from application layer.

**Project-level Methods:**
- `NotifyProjectUpdate(Guid tenantId, Guid projectId, object data)`
- `NotifyIssueCreated(Guid tenantId, Guid projectId, object issue)`
- `NotifyIssueUpdated(Guid tenantId, Guid projectId, object issue)`
- `NotifyIssueDeleted(Guid tenantId, Guid projectId, Guid issueId)`
- `NotifyIssueStatusChanged(Guid tenantId, Guid projectId, Guid issueId, string oldStatus, string newStatus)`

**User-level Methods:**
- `NotifyUser(Guid userId, string message, string type = "info")`
- `NotifyUsersInTenant(Guid tenantId, string message, string type = "info")`

#### RealtimeNotificationService (`src/ColaFlow.API/Services/RealtimeNotificationService.cs`)

Implementation of the notification service using `IHubContext<T>`.

### 3. Configuration

#### Program.cs Updates

**SignalR Configuration:**
```csharp
builder.Services.AddSignalR(options =>
{
    options.EnableDetailedErrors = builder.Environment.IsDevelopment();
    options.ClientTimeoutInterval = TimeSpan.FromSeconds(60);
    options.HandshakeTimeout = TimeSpan.FromSeconds(15);
    options.KeepAliveInterval = TimeSpan.FromSeconds(15);
});
```

**CORS Configuration (SignalR-compatible):**
```csharp
builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowFrontend", policy =>
    {
        policy.WithOrigins("http://localhost:3000", "https://localhost:3000")
              .AllowAnyHeader()
              .AllowAnyMethod()
              .AllowCredentials(); // Required for SignalR
    });
});
```

**JWT Authentication for SignalR (Query String Support):**
```csharp
options.Events = new JwtBearerEvents
{
    OnMessageReceived = context =>
    {
        var accessToken = context.Request.Query["access_token"];
        var path = context.HttpContext.Request.Path;
        if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/hubs"))
        {
            context.Token = accessToken;
        }
        return Task.CompletedTask;
    }
};
```

**Hub Endpoints:**
```csharp
app.MapHub<ProjectHub>("/hubs/project");
app.MapHub<NotificationHub>("/hubs/notification");
```

**Service Registration:**
```csharp
builder.Services.AddScoped<IRealtimeNotificationService, RealtimeNotificationService>();
```

### 4. Test Controller

#### SignalRTestController (`src/ColaFlow.API/Controllers/SignalRTestController.cs`)

Controller for testing SignalR functionality:

**Endpoints:**
- `POST /api/SignalRTest/test-user-notification`: Send notification to current user
- `POST /api/SignalRTest/test-tenant-notification`: Send notification to entire tenant
- `POST /api/SignalRTest/test-project-update`: Send project update notification
- `POST /api/SignalRTest/test-issue-status-change`: Send issue status change notification
- `GET /api/SignalRTest/connection-info`: Get connection information for debugging

## SignalR Hub Endpoints

| Hub | Endpoint | Description |
|-----|----------|-------------|
| ProjectHub | `/hubs/project` | Project-level real-time collaboration |
| NotificationHub | `/hubs/notification` | User-level notifications |

## Authentication

SignalR hubs use JWT authentication with two methods:

1. **Authorization Header**: Standard `Bearer {token}` in HTTP headers
2. **Query String**: `?access_token={token}` for WebSocket upgrade requests

All hubs are protected with `[Authorize]` attribute and require valid JWT tokens.

## Multi-Tenant Isolation

Users are automatically added to their tenant group (`tenant-{tenantId}`) on connection. This ensures:
- Notifications are only sent within tenant boundaries
- Cross-tenant data leakage is prevented
- Group-based broadcasting is efficient

## Client Connection Example

### JavaScript/TypeScript (SignalR Client)

```typescript
import * as signalR from "@microsoft/signalr";

const connection = new signalR.HubConnectionBuilder()
  .withUrl("https://localhost:5001/hubs/project", {
    accessTokenFactory: () => getAccessToken() // Your JWT token
  })
  .withAutomaticReconnect()
  .build();

// Listen for events
connection.on("IssueCreated", (issue) => {
  console.log("New issue:", issue);
});

connection.on("IssueStatusChanged", (data) => {
  console.log("Issue status changed:", data);
});

// Start connection
await connection.start();

// Join project
await connection.invoke("JoinProject", projectId);

// Send typing indicator
await connection.invoke("SendTypingIndicator", projectId, issueId, true);
```

## Integration with Domain Events

To send SignalR notifications from application layer:

```csharp
public class IssueCreatedEventHandler : INotificationHandler<IssueCreatedEvent>
{
    private readonly IRealtimeNotificationService _realtimeNotification;

    public async Task Handle(IssueCreatedEvent notification, CancellationToken cancellationToken)
    {
        await _realtimeNotification.NotifyIssueCreated(
            notification.TenantId,
            notification.ProjectId,
            new
            {
                Id = notification.IssueId,
                Title = notification.Title,
                Status = notification.Status
            }
        );
    }
}
```

## Testing

### Test Endpoints

1. **Get Connection Info**:
   ```bash
   curl -X GET https://localhost:5001/api/SignalRTest/connection-info \
     -H "Authorization: Bearer {your-jwt-token}"
   ```

2. **Test User Notification**:
   ```bash
   curl -X POST https://localhost:5001/api/SignalRTest/test-user-notification \
     -H "Authorization: Bearer {your-jwt-token}" \
     -H "Content-Type: application/json" \
     -d "\"Test notification message\""
   ```

3. **Test Tenant Notification**:
   ```bash
   curl -X POST https://localhost:5001/api/SignalRTest/test-tenant-notification \
     -H "Authorization: Bearer {your-jwt-token}" \
     -H "Content-Type: application/json" \
     -d "\"Test tenant message\""
   ```

4. **Test Project Update**:
   ```bash
   curl -X POST https://localhost:5001/api/SignalRTest/test-project-update \
     -H "Authorization: Bearer {your-jwt-token}" \
     -H "Content-Type: application/json" \
     -d '{"projectId":"00000000-0000-0000-0000-000000000000","message":"Test update"}'
   ```

### Build Status

✅ Build successful with no errors or warnings

```bash
cd colaflow-api
dotnet build src/ColaFlow.API/ColaFlow.API.csproj
```

## Success Criteria Checklist

- [x] SignalR infrastructure added (built-in .NET 9 SignalR)
- [x] Created BaseHub, ProjectHub, NotificationHub
- [x] Configured SignalR in Program.cs with CORS and JWT
- [x] Implemented IRealtimeNotificationService
- [x] Hub supports multi-tenant isolation (automatic tenant group membership)
- [x] Hub supports JWT authentication (Bearer + query string)
- [x] Created test controller (SignalRTestController)
- [x] Compilation successful with no errors

## Files Created/Modified

**Created:**
- `src/ColaFlow.API/Hubs/BaseHub.cs`
- `src/ColaFlow.API/Hubs/ProjectHub.cs`
- `src/ColaFlow.API/Hubs/NotificationHub.cs`
- `src/ColaFlow.API/Services/IRealtimeNotificationService.cs`
- `src/ColaFlow.API/Services/RealtimeNotificationService.cs`
- `src/ColaFlow.API/Controllers/SignalRTestController.cs`

**Modified:**
- `src/ColaFlow.API/Program.cs` (SignalR configuration, CORS, JWT, hub endpoints)

## Next Steps

1. **Frontend Integration**: Implement SignalR client in Next.js frontend
2. **Domain Event Integration**: Wire up notification service to domain events
3. **Permission Validation**: Add authorization checks in ProjectHub.JoinProject()
4. **User Connection Mapping**: Implement user-to-connection tracking for targeted notifications
5. **Scalability**: Consider Redis backplane for multi-server deployments
6. **Monitoring**: Add SignalR performance metrics and connection monitoring

## Notes

- SignalR is built-in to .NET 9.0 ASP.NET Core, no separate NuGet package required
- CORS policy updated to include `AllowCredentials()` for SignalR compatibility
- JWT authentication supports both HTTP Authorization header and query string for WebSocket upgrade
- All hubs automatically enforce tenant isolation via BaseHub
- Notification service can be injected into any application service or event handler
