using Application.Abstractions.Hub;
using Application.Abstractions.Notification;
using Domain.Entities.Notifications.ValueObject;
using Infrastructure.Hubs;
using Web.Api.Common;
using MediatR;
using Microsoft.AspNetCore.SignalR;
namespace Web.Api.Endpoints.Donation;
/// 크루 방송 시작 — 세션 생성 + 크루원에게 초대 알림
internal sealed class CrewSessionStart : IEndpoint
{
public void MapEndpoint(IEndpointRouteBuilder app)
{
app.MapPost("api/crew/session/start", async (
Application.Features.Api.Crew.StartSession.Command body,
ISender sender,
IHubContext appHub,
INotificationService notificationService,
Application.Abstractions.Data.IAppDbContext db,
CancellationToken ct
) => {
var data = await sender.Send(body, ct);
// 크루원들에게 초대 알림 발송
var consents = await Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions
.ToListAsync(
Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions
.AsNoTracking(db.CrewSessionConsent)
.Where(c => c.CrewSessionID == data.CrewSessionID)
.Join(db.CrewMember, c => c.CrewMemberID, m => m.ID, (c, m) => new { m.MemberID, m.Nickname }),
ct
);
foreach (var member in consents)
{
await notificationService.SendAsync(
member.MemberID,
NotificationType.CrewInvitation,
"크루 방송 초대",
$"크루 방송 '{body.Title}'에 초대되었습니다. 참여 동의를 해주세요.",
$"/crew/consent/{data.CrewSessionID}",
"CrewSession", data.CrewSessionID, null, ct
);
// AppHub 실시간 푸시
await appHub.Clients.Group($"member:{member.MemberID}").ReceiveCrewInvitation(new
{
CrewSessionID = data.CrewSessionID,
Title = body.Title,
CrewID = body.CrewID
});
}
return ApiResponse.Ok(data);
})
.WithTags("Crew")
.RequireAuthorization();
}
}