Shoppr Jobs, Webhooks, And Background Work
Shoppr is not the scheduler showcase app. It is the best public example of why background work matters to a real store.
Use it to learn:
- how checkout hands work off to webhook and queue-driven follow-up
- what the operator needs to inspect after browser return
- where the customer app ends and the platform jobs surface begins
Start With The Live Runtime Contract
Shoppr’s development config already says the important part out loud:
[jobs]
backend = "redis"
[modules."commerce-payments-stripe"]
provider = "stripe"
checkout_mode = "hosted-checkout"
webhook_secret = { kind = "env", var = "STRIPE_WEBHOOK_SECRET" }
That gives you the real product boundary:
- requests are not the whole payment flow
- settlement depends on webhook handling
- background work must be operationally visible
What Developers Can Actually Exercise Locally
Without real Stripe credentials, Shoppr still runs through the built-in local hosted-checkout stub.
With real Stripe test credentials, use:
stripe listen --forward-to http://uk.localhost:8080/webhooks/commerce/payment-provider
That is the shortest honest path to see:
- request-path checkout
- provider return
- webhook callback
- resulting order/operator state
The Product-Side Operator Story
The admin orders screen is the main product surface to study:
<p>
This queue is store-wide. Use it to confirm payment state, review checkout email and totals,
and move into the per-order support detail view before escalating a checkout case.
</p>
And the same template teaches the real support boundary:
<p>
After a Stripe return, compare the customer account view and provider callback window before
treating Pending Payment as a failed checkout.
</p>
That is why Shoppr matters here. It does not just say “jobs exist.” It shows the operator consequence of async settlement in the product itself.
Where The Customer Binary Stops
The Shoppr customer binary owns:
validatemigrate applyassets publishup
The customer binary does not own queue control. Jobs remain an operator/platform concern.
Use the platform CLI for that:
cargo run -p coil-cli -- jobs status --config apps/shoppr/platform.dev.toml
cargo run -p coil-cli -- jobs ready --config apps/shoppr/platform.dev.toml --queue jobs.work --limit 25
cargo run -p coil-cli -- jobs dead-letters --config apps/shoppr/platform.dev.toml --queue jobs.dead-letter --limit 25
cargo run -p coil-cli -- jobs run --config apps/shoppr/platform.dev.toml --worker-id worker-a --limit 25
That split is intentional:
- customer binaries compose the product
- the platform CLI operates the shared job system
Linked Customer Hooks In This Flow
Shoppr’s linked backend is relevant because webhook handling is not purely native module code.
The checked-in backend demonstrates:
- checkout review hooks
- verified webhook hooks
- customer-owned logic running through the stable runtime boundary
Read those after you understand the product flow:
apps/shoppr/crates/shoppr-backend/src/lib.rsapps/shoppr/backend/shoppr-loyalty-backend/src/lib.rs
But start with the product pages and config above. That is where the behavior becomes real for a new developer.
What Shoppr Teaches Better Than Gitly
Gitly is the clearer scheduler-slot demo.
Shoppr is the clearer example for:
- webhook-driven follow-up
- customer-visible payment state
- order-support consequences of async work
- audit/operator traces around privileged actions
So if you are building commerce, learn the operator meaning of async work from Shoppr first.
Honest Limits
Shoppr is still not a public “queue tutorial app.” It does not ship a polished in-app worker dashboard or a demo page dedicated to ready/dead-letter queue internals.
That is why the public jobs operator learning path still spans:
- Shoppr for product and webhook consequences
- the platform CLI for queue control
- Gitly for a bounded scheduled-job extension example