using Application.Abstractions.Data; using Application.Abstractions.Kyc; using Application.Abstractions.Messaging; using Domain.Entities.Developers.ValueObject; using Microsoft.EntityFrameworkCore; using SharedKernel.Results; namespace Application.Features.Api.Developers.Profile.CompleteKyc; internal sealed class Handler(IAppDbContext db, INiceAuthClient nice) : ICommandHandler { public async Task Handle(Command request, CancellationToken ct) { var session = await db.NiceAuthSession .AsTracking() .Include(c => c.Developer) .FirstOrDefaultAsync(c => c.SessionToken == request.SessionToken, ct); if (session is null) { return Result.Failure(Error.NotFound( "Nice.SessionNotFound", "본인인증 세션을 찾을 수 없습니다.")); } if (!session.CanProcessCallback()) { // 이미 Completed/Failed/Expired 처리된 세션 — 결과는 그대로 두고 안내 return session.Status == NiceAuthSessionStatus.Completed ? Result.Success() : Result.Failure(Error.Problem( "Nice.SessionFinalized", "본인인증 세션이 이미 종료되었습니다.")); } if (session.IsExpired(DateTime.UtcNow)) { session.MarkExpired(); await db.SaveChangesAsync(ct); return Result.Failure(Error.Problem( "Nice.AuthFailedOrExpired", "본인인증 유효시간이 만료되었습니다. 다시 시도해 주세요.")); } if (session.Developer is null) { session.MarkFailed("Developer 정보 누락"); await db.SaveChangesAsync(ct); return Result.Failure(Error.NotFound( "Developer.NotFound", "개발자 정보를 찾을 수 없습니다.")); } session.MarkWebTransactionReceived(request.WebTransactionID); var userResult = await nice.GetResultAsync( session.RequestNo, session.TransactionID, request.WebTransactionID, session.Ticket, session.Iterators, ct); if (userResult.IsFailure) { session.MarkFailed(userResult.Error.Code); await db.SaveChangesAsync(ct); return Result.Failure(userResult.Error); } var user = userResult.Value; // CI 가 다른 Developer 와 이미 묶여 있으면 중복가입 차단 var ciTaken = await db.Developer .AsNoTracking() .AnyAsync(c => c.ID != session.DeveloperID && c.KycCi == user.Ci, ct); if (ciTaken) { session.MarkFailed("CI 중복"); await db.SaveChangesAsync(ct); return Result.Failure(Error.Conflict( "Developer.KycCiTaken", "해당 명의로 이미 가입된 개발자 계정이 있습니다.")); } session.Developer.MarkKycVerified(user.Ci, user.Di); session.MarkCompleted(); await db.SaveChangesAsync(ct); return Result.Success(); } }