using System.Security.Claims; using MediatR; using Web.Api.Common; using Web.Api.Extensions; namespace Web.Api.Endpoints.V1.Purchases; internal sealed class List : IEndpoint { public void MapEndpoint(IEndpointRouteBuilder app) { app.MapGet("v1/purchases", async ( ClaimsPrincipal user, ISender sender, CancellationToken ct, string? status = null, DateTime? from = null, DateTime? to = null, int page = 1, int size = 50 ) => { var query = new Application.Features.Api.V1.Purchases.List.Query( user.GetApplicationID(), user.GetPatOwnerMemberID(), status, from, to, page, size ); var result = await sender.Send(query, ct); return result.Match( data => ApiResponse.Ok(data), CustomResults.Problem ); }) .WithTags("결제 보고") .WithGroupName("public") .WithName("ListPurchases") .WithSummary("결제 목록 조회") .WithDescription(""" 등록한 결제 내역을 페이지네이션해 반환합니다 (정산 대사용). - OAuth2 앱 토큰: 해당 앱이 등록한 건만 - PAT: 본인 소유 앱 전체 ### 필수 scope - `read:purchases` ### 쿼리 파라미터 | 이름 | 타입 | 기본 | 설명 | |---|---|---|---| | `status` | string? | 전체 | `pending` / `confirmed` / `canceled` | | `from` | datetime? | — | 등록 시각(UTC) 시작 | | `to` | datetime? | — | 등록 시각(UTC) 끝 | | `page` | int | 1 | 1부터 시작 | | `size` | int | 50 | 1~100 | ### 사용 예 ``` GET /v1/purchases?status=pending GET /v1/purchases?from=2026-06-01&to=2026-06-30&page=1&size=100 ``` """) .Produces(StatusCodes.Status200OK) .ProducesProblem(StatusCodes.Status400BadRequest) .ProducesProblem(StatusCodes.Status401Unauthorized) .ProducesProblem(StatusCodes.Status403Forbidden) .RequireAuthorization(policy => policy .AddAuthenticationSchemes("ApiKey", "OAuth2Bearer") .RequireAuthenticatedUser()) .RequireScope("read:purchases"); } }