Fix build and code structure improvements. New but essential UI functionality. CI improvements. Documentation improvements. AI module improvements.
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// UpdateOrderStatusEndpoint
|
||||
//
|
||||
// Demonstrates:
|
||||
// - PATCH operation for partial updates
|
||||
// - Path parameters with request body
|
||||
// - Write authorization claims
|
||||
// - State machine validation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using Examples.OrderService.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Microservice;
|
||||
|
||||
namespace Examples.OrderService.Endpoints;
|
||||
|
||||
/// <summary>
|
||||
/// Request to update order status.
|
||||
/// </summary>
|
||||
public sealed record UpdateOrderStatusRequest
|
||||
{
|
||||
public required string OrderId { get; init; }
|
||||
public required OrderStatus NewStatus { get; init; }
|
||||
public string? Reason { get; init; }
|
||||
public string? TrackingNumber { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response after status update.
|
||||
/// </summary>
|
||||
public sealed record UpdateOrderStatusResponse
|
||||
{
|
||||
public required string OrderId { get; init; }
|
||||
public required OrderStatus PreviousStatus { get; init; }
|
||||
public required OrderStatus CurrentStatus { get; init; }
|
||||
public required DateTimeOffset UpdatedAt { get; init; }
|
||||
public string? Message { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Endpoint for updating order status with state machine validation.
|
||||
/// </summary>
|
||||
[StellaEndpoint("PATCH", "/orders/{id}/status", TimeoutSeconds = 10, RequiredClaims = ["orders:write"])]
|
||||
[ValidateSchema(
|
||||
ValidateRequest = true,
|
||||
ValidateResponse = true,
|
||||
Summary = "Update order status",
|
||||
Description = "Updates the status of an order. Status transitions are validated against allowed state machine rules.",
|
||||
Tags = ["orders", "write", "status"])]
|
||||
public sealed class UpdateOrderStatusEndpoint : IStellaEndpoint<UpdateOrderStatusRequest, UpdateOrderStatusResponse>
|
||||
{
|
||||
private readonly ILogger<UpdateOrderStatusEndpoint> _logger;
|
||||
|
||||
// Valid state transitions
|
||||
private static readonly Dictionary<OrderStatus, OrderStatus[]> ValidTransitions = new()
|
||||
{
|
||||
[OrderStatus.Pending] = [OrderStatus.Confirmed, OrderStatus.Cancelled],
|
||||
[OrderStatus.Confirmed] = [OrderStatus.Processing, OrderStatus.Cancelled],
|
||||
[OrderStatus.Processing] = [OrderStatus.Shipped, OrderStatus.Cancelled],
|
||||
[OrderStatus.Shipped] = [OrderStatus.Delivered],
|
||||
[OrderStatus.Delivered] = [OrderStatus.Refunded],
|
||||
[OrderStatus.Cancelled] = [],
|
||||
[OrderStatus.Refunded] = []
|
||||
};
|
||||
|
||||
public UpdateOrderStatusEndpoint(ILogger<UpdateOrderStatusEndpoint> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Task<UpdateOrderStatusResponse> HandleAsync(
|
||||
UpdateOrderStatusRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// Simulate current status lookup
|
||||
var currentStatus = OrderStatus.Processing;
|
||||
|
||||
_logger.LogInformation(
|
||||
"Updating order {OrderId} status: {CurrentStatus} -> {NewStatus}",
|
||||
request.OrderId, currentStatus, request.NewStatus);
|
||||
|
||||
// Validate state transition
|
||||
if (!IsValidTransition(currentStatus, request.NewStatus))
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"Invalid status transition for order {OrderId}: {Current} -> {New}",
|
||||
request.OrderId, currentStatus, request.NewStatus);
|
||||
|
||||
// In real implementation, throw an exception that maps to 422
|
||||
return Task.FromResult(new UpdateOrderStatusResponse
|
||||
{
|
||||
OrderId = request.OrderId,
|
||||
PreviousStatus = currentStatus,
|
||||
CurrentStatus = currentStatus, // Unchanged
|
||||
UpdatedAt = DateTimeOffset.UtcNow,
|
||||
Message = $"Invalid transition: {currentStatus} cannot transition to {request.NewStatus}"
|
||||
});
|
||||
}
|
||||
|
||||
return Task.FromResult(new UpdateOrderStatusResponse
|
||||
{
|
||||
OrderId = request.OrderId,
|
||||
PreviousStatus = currentStatus,
|
||||
CurrentStatus = request.NewStatus,
|
||||
UpdatedAt = DateTimeOffset.UtcNow,
|
||||
Message = request.NewStatus == OrderStatus.Shipped
|
||||
? $"Shipped with tracking: {request.TrackingNumber}"
|
||||
: null
|
||||
});
|
||||
}
|
||||
|
||||
private static bool IsValidTransition(OrderStatus current, OrderStatus target)
|
||||
{
|
||||
return ValidTransitions.TryGetValue(current, out var allowed) && allowed.Contains(target);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user