Money is unforgiving
Totals, discounts, tax, and refunds have to agree across the storefront, the receipt, the payment provider, and the ledger.
The commerce package is not a plugin bolted to the side of the framework. It is 35-plus models with the same defineModel() shape as everything else, which is why a product page, the checkout, the fulfilment screen, and the nightly report all read the same rows without an integration layer between them.
The work that arrives whether you planned for it or not.
Totals, discounts, tax, and refunds have to agree across the storefront, the receipt, the payment provider, and the ledger.
Stock reservation, payment intents, webhook confirmation, and failure recovery all have to survive a browser closing mid-flow.
Orders get edited, refunded, and re-shipped by people who are not developers.
Variants, coupons, gift cards, and seasonal pricing arrive after launch, not before it.
All of it in the same install, typed against the rest of your application.
Products, variants, categories, collections, and reviews, each a model you can extend in app/Models/ rather than fork.
Carts, orders, coupons, gift cards, and Stripe payments including webhooks, refunds, and stored payment methods.
Zones, rates, methods, and tax rules live in config and models, so a quote at checkout and an invoice line come from the same calculation.
Order confirmation, shipping, and refund mail render from STX templates and go out through the queue.
STX views for the shop and a commerce dashboard for the people running it, both against the same models.
The useSearch trait indexes catalogue changes as they happen, through Meilisearch or Algolia.
Every one of these ships in the same install. Follow one to see what it covers.
Buddy scaffolds, runs, and ships this the same way it does the rest of the app.
Projects of this shape usually grow into one of these.