From 1047f8adf8e0fd5458b6f662b34bf039ccb88960 Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Wed, 11 Mar 2026 21:51:54 -0300 Subject: [PATCH 1/5] =?UTF-8?q?feature(#12):=20this=20commit=20adds=20the?= =?UTF-8?q?=20=E2=80=9CIdempwanna=E2=80=9D=20package=20in=20version=201.0.?= =?UTF-8?q?0,=20enabling=20the=20integration=20of=20idempotency=20into=20t?= =?UTF-8?q?he=20project.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Comanda.Orchestrator.WebApi.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Comanda.Orchestrator.WebApi.csproj b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Comanda.Orchestrator.WebApi.csproj index ac7827f..6431dc7 100644 --- a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Comanda.Orchestrator.WebApi.csproj +++ b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Comanda.Orchestrator.WebApi.csproj @@ -13,6 +13,7 @@ + From fdb75093a3696b0ee1a174e56c5886b9606ca431 Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Wed, 11 Mar 2026 21:56:01 -0300 Subject: [PATCH 2/5] =?UTF-8?q?featue(#12):=20this=20commit=20introduces?= =?UTF-8?q?=20global=20using=20to=20the=20=E2=80=9CIdempwanna=E2=80=9D=20n?= =?UTF-8?q?amespace,=20enabling=20references=20throughout=20the=20project.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/Comanda.Orchestrator.WebApi/Usings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Usings.cs b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Usings.cs index 11ce87d..01e0fda 100644 --- a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Usings.cs +++ b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Usings.cs @@ -41,4 +41,4 @@ global using Serilog; global using Serilog.Context; global using FluentValidation.AspNetCore; - +global using Idempwanna.Core.Configuration; From 848841b8ea6ac7e051ceabacd89d9be8d4223c3d Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Wed, 11 Mar 2026 21:57:30 -0300 Subject: [PATCH 3/5] feature(#12): this commit introduces configuration for idempotency services in memory --- .../Extensions/WebInfrastructureExtension.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Extensions/WebInfrastructureExtension.cs b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Extensions/WebInfrastructureExtension.cs index dff9168..0e5657e 100644 --- a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Extensions/WebInfrastructureExtension.cs +++ b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Extensions/WebInfrastructureExtension.cs @@ -27,5 +27,13 @@ public static void AddWebComposition(this IServiceCollection services) options.Realm = settings.Federation.Realm; options.ClientSecret = settings.Federation.ClientSecret; }); + + services.AddIdempotency() + .WithInMemoryCache(options => + { + options.DefaultCacheExpiration = TimeSpan.FromMinutes(1); + options.DefaultHeaderName = Headers.Idempotency; + options.ThrowOnMissingKey = false; + }); } } From d7fb8f4be720671bfa670c95e547efca58430f33 Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Wed, 11 Mar 2026 22:02:37 -0300 Subject: [PATCH 4/5] =?UTF-8?q?feature(#12):=20this=20commit=20adds=20a=20?= =?UTF-8?q?global=20usage=20directive=20to=20the=20=E2=80=9CIdempwanna.Cor?= =?UTF-8?q?e.Attributes=E2=80=9D=20namespace,=20enabling=20reuse=20through?= =?UTF-8?q?out=20the=20project?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/Comanda.Orchestrator.WebApi/Usings.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Usings.cs b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Usings.cs index 01e0fda..02b9c73 100644 --- a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Usings.cs +++ b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Usings.cs @@ -37,8 +37,11 @@ global using HttpsRichardy.Federation.Sdk.Extensions; global using HttpsRichardy.Federation.Sdk.Contracts.Errors; -global using Scalar.AspNetCore; global using Serilog; global using Serilog.Context; + +global using Scalar.AspNetCore; global using FluentValidation.AspNetCore; + global using Idempwanna.Core.Configuration; +global using Idempwanna.Core.Attributes; From 0e96d045fc74721d76aaf1d9897228e9c558e865 Mon Sep 17 00:00:00 2001 From: Richard Garcia Date: Wed, 11 Mar 2026 22:15:04 -0300 Subject: [PATCH 5/5] feature(#12): this commit adds attributes to endpoints that must support idempotency --- .../Controllers/OrdersController.cs | 1 + .../Controllers/PaymentsController.cs | 2 ++ .../Controllers/ProfilesController.cs | 3 +++ .../Controllers/StoresController.cs | 4 ++++ .../Controllers/SubscriptionsController.cs | 2 ++ 5 files changed, 12 insertions(+) diff --git a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/OrdersController.cs b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/OrdersController.cs index 371e163..c0632ce 100644 --- a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/OrdersController.cs +++ b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/OrdersController.cs @@ -32,6 +32,7 @@ public async Task GetOrdersAsync([FromQuery] OrdersFetchParameter } [HttpPost] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent [Authorize(Roles = Permissions.CreateOrder)] public async Task CreateOrderAsync([FromBody] OrderCreationScheme request, CancellationToken cancellation) { diff --git a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/PaymentsController.cs b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/PaymentsController.cs index 9468ac0..0d60b34 100644 --- a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/PaymentsController.cs +++ b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/PaymentsController.cs @@ -7,6 +7,7 @@ public sealed class PaymentsController(IDispatcher dispatcher, IEventDispatcher eventDispatcher) : ControllerBase { [HttpPost("online")] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent [Authorize(Roles = Permissions.MakePayment)] public async Task CreateOnlineChargeAsync( [FromBody] CheckoutSessionCreationScheme request, [FromHeader(Name = Headers.Credential)] string credential, CancellationToken cancellation) @@ -33,6 +34,7 @@ public async Task CreateOnlineChargeAsync( } [HttpPost("offline")] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent [Authorize(Roles = Permissions.MakePayment)] public async Task CreateOfflinePaymentAsync([FromBody] OfflinePaymentScheme request, CancellationToken cancellation) { diff --git a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/ProfilesController.cs b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/ProfilesController.cs index 740477d..8fd8bbb 100644 --- a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/ProfilesController.cs +++ b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/ProfilesController.cs @@ -32,6 +32,7 @@ public async Task GetCustomersAsync([FromQuery] FetchCustomersPar } [HttpPost("customers")] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent [Authorize] public async Task CreateCustomerAsync([FromBody] CustomerCreationScheme request, CancellationToken cancellation) { @@ -138,6 +139,7 @@ public async Task GetCustomerAddressesAsync( [HttpPost("customers/{customerId}/addresses")] [Authorize(Roles = Permissions.EditCustomers)] + [Idempotent] public async Task AssignCustomerAddressAsync( [FromBody] AssignCustomerAddressScheme request, [FromRoute] string customerId, CancellationToken cancellation) { @@ -232,6 +234,7 @@ public async Task GetOwnersAsync([FromQuery] FetchOwnersParameter } [HttpPost("owners")] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent [Authorize] public async Task CreateOwnerAsync([FromBody] OwnerCreationScheme request, CancellationToken cancellation) { diff --git a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/StoresController.cs b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/StoresController.cs index 87d5558..fb7fbde 100644 --- a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/StoresController.cs +++ b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/StoresController.cs @@ -35,6 +35,7 @@ public async Task GetEstablishmentsAsync( } [HttpPost] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent [Authorize(Roles = Permissions.CreateEstablishment)] public async Task CreateEstablishmentAsync( [FromBody] EstablishmentCreationScheme request, CancellationToken cancellation) @@ -111,6 +112,7 @@ public async Task DeleteEstablishmentAsync( [HttpPost("{establishmentId}/checkout")] [Authorize(Roles = Permissions.MakePayment)] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent public async Task CheckoutAsync( [FromBody] CreateCheckoutScheme request, [FromRoute] string establishmentId, CancellationToken cancellation) { @@ -162,6 +164,7 @@ public async Task GetProductsAsync( [HttpPost("{establishmentId}/products")] [Authorize(Roles = Permissions.CreateProduct)] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent public async Task CreateProductAsync( [FromBody] ProductCreationScheme request, [FromRoute] string establishmentId, CancellationToken cancellation) { @@ -292,6 +295,7 @@ public async Task GetCredentialsAsync( [HttpPost("{establishmentId}/integrations/credentials")] [Authorize(Roles = Permissions.CreateCredential)] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent public async Task AssignCredentialAsync( [FromBody] CredentialCreationScheme request, [FromRoute] string establishmentId, CancellationToken cancellation) { diff --git a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/SubscriptionsController.cs b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/SubscriptionsController.cs index eb026df..114942d 100644 --- a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/SubscriptionsController.cs +++ b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/SubscriptionsController.cs @@ -6,6 +6,7 @@ public sealed class SubscriptionsController(IDispatcher dispatcher) : Controller { [HttpPost] [Authorize(Roles = Permissions.Subscribe)] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent public async Task CreateCheckoutSessionAsync( [FromBody] SubscriptionCheckoutSessionCreationScheme request, CancellationToken cancellation) { @@ -29,6 +30,7 @@ public async Task CreateCheckoutSessionAsync( [HttpDelete("{id}")] [Authorize(Roles = Permissions.CancelSubscription)] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent public async Task CancelSubscriptionAsync( [FromQuery] SubscriptionCancelationScheme request, [FromRoute] string id, CancellationToken cancellation) {