using FastEndpoints; using KArtSell.BuildingBlocks.Time; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; namespace KArtSell.Modules.ModelOperations.Compliance; /// /// Submit GDPR right-to-be-forgotten request. /// POST /compliance/gdpr-request /// public class SubmitGdprRequestDto { public Guid CustomerId { get; set; } public string Reason { get; set; } = "Right to be forgotten (GDPR Article 17)"; } public class GdprRequestResponseDto { public Guid GdprTrackingId { get; set; } public string Status { get; set; } = "IN_PROGRESS"; public DateTime EstimatedCompletion { get; set; } public string Message { get; set; } = string.Empty; } public class SubmitGdprRequestEndpoint : Endpoint { private readonly ProcessGdprRequestHandler _handler; private readonly IClock _clock; private readonly ILogger _logger; public SubmitGdprRequestEndpoint(ProcessGdprRequestHandler handler, IClock clock, ILogger logger) { _handler = handler; _clock = clock; _logger = logger; } public override void Configure() { Post("/compliance/gdpr-request"); AllowAnonymous(); // RBAC enforced at handler level (Data Admin/Compliance Officer role) Summary(x => { x.Summary = "Submit GDPR Request"; x.Description = "Submit right-to-be-forgotten request for customer data redaction"; }); } public override async Task HandleAsync(SubmitGdprRequestDto req, CancellationToken ct) { try { var trackingId = Guid.NewGuid(); var now = _clock.UtcNow.UtcDateTime; var correlationId = HttpContext.Request.Headers.TryGetValue("X-Correlation-ID", out var header) ? Guid.Parse(header.ToString()) : Guid.NewGuid(); var command = new ProcessGdprRequestCommand { TrackingId = trackingId, CustomerId = req.CustomerId, RequestDate = now, Reason = req.Reason, CorrelationId = correlationId }; await _handler.Handle(command, ct); var response = new GdprRequestResponseDto { GdprTrackingId = trackingId, Status = "IN_PROGRESS", EstimatedCompletion = now.AddHours(24), Message = $"GDPR request {trackingId} submitted. Redaction will complete within 24 hours." }; await Send.ResponseAsync(response, StatusCodes.Status202Accepted, ct); _logger.LogInformation( "GDPR request {TrackingId} submitted for customer {CustomerId}", trackingId, req.CustomerId); } catch (Exception ex) { _logger.LogError(ex, "Failed to submit GDPR request for customer {CustomerId}", req.CustomerId); await Send.ResponseAsync( new GdprRequestResponseDto { Message = "Failed to submit request" }, StatusCodes.Status500InternalServerError, ct); } } }