feat(guild): invite state machine

Add surrogate PK (IDENTITY bigint) to GuildInvite for wire invite_id.
Implement InviteAsync, CancelInviteAsync, RejectInviteAsync,
ListOutgoingInvitesAsync, ListInvitedGuildsAsync in GuildService.
Wire 5 endpoints: invite_user_list, invited_guild_list, invite,
cancel_invite, reject_invite in GuildController.
Migration: AddGuildInviteSurrogatePk — drops composite PK, adds Id
IDENTITY column, adds unique index on (GuildId, InviteeViewerId).
6 integration tests in GuildInviteFlowTests all green.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-27 13:21:57 -04:00
parent c103ab6a87
commit 1b7fa2d525
12 changed files with 5574 additions and 22 deletions

View File

@@ -13,8 +13,12 @@ public sealed class GuildInviteRepository : IGuildInviteRepository
=> _db.GuildInvites.FirstOrDefaultAsync(
i => i.GuildId == guildId && i.InviteeViewerId == inviteeViewerId, ct);
public Task<GuildInvite?> GetByIdAsync(long inviteId, CancellationToken ct = default)
=> _db.GuildInvites.FirstOrDefaultAsync(i => i.Id == inviteId, ct);
public async Task<IReadOnlyList<GuildInvite>> ListPendingForInviteeAsync(long viewerId, CancellationToken ct = default)
=> await _db.GuildInvites
.Include(i => i.Guild)
.Where(i => i.InviteeViewerId == viewerId && i.Status == GuildInviteStatus.Pending)
.ToListAsync(ct);