A point-of-sale looks like the easiest app in the world: a list of products, a cart, a "Charge" button. Then you put it in a real shop, with two tills, a flaky Wi-Fi router and a cashier who presses buttons twice, and you find out where the hard parts are.
I recently finished Tilly POS , a multi-branch retail POS built with ASP.NET Core 10, Entity Framework Core, SQL Server and Angular. These are the three failures I designed out first, with the actual code.
1. The double charge
The cashier presses Charge . The network drops before the response comes back. The customer is standing there, so the cashier presses it again. If your API treats that as a new request, the customer has now paid twice and your stock is down two units.
The fix is an idempotency key . The browser generates a key once per sale and sends it with every attempt:
// A retry of a sale that already went through returns the original sale. if ( await LoadExistingAsync ( idempotencyKey , ct ) is { } existing ) { return existing .…