# Spice Commerce reference application

Unified documentation: [spiceframework.dev/examples/commerce](https://spiceframework.dev/examples/commerce/).

Commerce is Spice's standalone production-shaped reference application. It
uses six explicit application modules:

- `inventory` owns stock and compensated reservations;
- `payments` owns authorization policy and records approvals;
- `notifications` owns typed receipt composition and its selected mail
  transport;
- `orders` declares and uses explicit inventory, notification, payment, and
  storage APIs;
- `storage` owns typed order persistence and module-owned migrations;
- `platform` owns the safely configured HTTP server lifecycle and depends on
  storage readiness.

The ordinary `main.go` is the compile-time application marker. Its direct blank
imports name the same-module source packages that belong to the application;
the imports are valid Go, visible to tools and reviewers, and replace repeated
CLI package lists or compiler package scanning. Its explicit
`@management.Enable` allowlist exposes health, liveness, readiness, info, and
metrics plus redacted configuration and generated module reports;
`@observability.Logging` installs structured lifecycle and HTTP observers. The
inventory module's `@schedule.FixedDelay` audit demonstrates direct generated,
lifecycle-owned scheduled work. Its `@async.Execute` inventory verification
demonstrates a readiness-gated typed generated submit method, bounded
admission, and graceful drain before provider cleanup. The placement route's
`@data.Transactional` boundary passes the generated transaction-owned
`data.Executor` directly into the repository. Generated `@security.Authorize`
guards require exact `orders:write`, `orders:read`, and `orders:notify` scopes
on order routes and fail closed with safe 401/403 problems. The read route also
proves the compiler-validated restricted expression contract through explicit
`authenticated` and `hasScope` symbols. The public catalog
route's `@cache.Cacheable` boundary demonstrates configured, bounded, typed
response caching without putting principal-specific data in a shared cache.
Every successful persisted-order lookup publishes a typed `OrderViewed` event
to the provider-owned `ViewAudit` listener. Spice generates ordinary direct
construction, command, lifecycle, scheduling, asynchronous, cache, event,
migration, repository, transaction, authorization, and HTTP code under the
owned generated target package. Source-mirror files retain a deterministic
one-source-file-to-one-generated-file relationship; no runtime scan,
reflection, service locator, repeated CLI source list, or marker execution is
used.

The payment module exposes two explicit `payments.Processor` candidates.
`Service` is named, qualified as `stripe`, and primary; `OfflineProcessor` is
qualified separately and marked fallback. Both use `@Implements(Processor)`
and Spice emits source-owned Go assertions. The orders constructor requests
`@Qualifier("stripe")`, and the generated file passes the already constructed
Stripe service directly as the interface—there is no runtime lookup.
Notifications applies the same rule to an external framework interface:
`Delivery` uses `@Implements(mail.Sender)` and a generated Go assertion, while
`Notifier` requests the exact interface. Generated code constructs and passes
the concrete delivery directly. `SystemClock` is a second explicit interface
binding, keeping message dates caller-owned and deterministic in tests.

Commerce is a real consuming Go module. Its `go.mod` authorizes the standalone
Spice annotation and CLI tools, pins immutable core, toolchain, PostgreSQL, and
SMTP starter pseudo-versions without local replacements, and owns its
generated target, manifest, acceptance tests, and vendor tree. From this
directory:

```text
go tool github.com/spice-framework/toolchain/cmd/spice generate --check --target Commerce .
go tool github.com/spice-framework/toolchain/cmd/spice build --target Commerce .
go tool github.com/spice-framework/toolchain/cmd/spice run --target Commerce . -- -check
go tool github.com/spice-framework/toolchain/cmd/spice run --target Commerce .
```

The committed direct Spice core and toolchain requirements form Commerce's
provisional minimum compatibility pair. [`spice-compatibility.json`](https://github.com/spice-framework/commerce/blob/ae773cbef0927061d53679dbce590bdd23ef51a6/spice-compatibility.json)
also pins a current pair without implying that one module versions the other.
`make compatibility` resolves both modules through normal Go integrity,
asserts the exact MVS-selected core and toolchain plus both authorized tool
packages, then runs vet, shuffled race tests, `spice verify`, generation
freshness, and a Spice build against each paired boundary. It uses isolated
alternate modfiles and fails if any handwritten, generated, module, manifest,
artifact, or vendor byte changes. See
[`docs/compatibility.md`](/examples/commerce/compatibility/) for the complete contract.

Go 1.26.5 is exact. `make verify` (or
`go run ./internal/qualitygate` on every platform) runs the complete local
quality gate, including deterministic generation, offline vendor execution,
security analysis, race tests, and the executable zero-network workflow.
The definitive local gate always includes both paired core/toolchain
boundaries; CI publishes the same minimum/current evidence as parallel jobs.

The server binds `127.0.0.1:8081` by default. Set
`SPICE_COMMERCE_ADDRESS=127.0.0.1:0` for an ephemeral test listener. The command
uses the conventional `SPICE_` environment source. Set
`SPICE_SHUTDOWN_TIMEOUT` to override the typed `10s` shutdown default. Reusable
generated constructors read no environment, files, or process signals on their
own. Public catalog caching defaults to 256 entries and a five-minute TTL;
`SPICE_CACHE_COMMERCE_CATALOG_CAPACITY` and
`SPICE_CACHE_COMMERCE_CATALOG_TTL` override those generated typed
properties. Asynchronous execution defaults to 16 concurrent tasks;
`SPICE_ASYNC_MAX_CONCURRENCY` overrides that positive bound.

Database configuration is typed and secret-redacted. The default
`memory://commerce` URL selects an instance-owned transaction-aware
`database/sql` connector so `spice dev` needs no external service. Set
`SPICE_COMMERCE_DATABASE_URL` to a complete PostgreSQL URL to use the reviewed
pgx starter; local `sslmode=disable` additionally requires the explicit
`SPICE_COMMERCE_DATABASE_ALLOW_INSECURE=true` opt-in. The database opens without
network I/O during construction. Its module-owned migration runs as the first
lifecycle hook, and the HTTP server has an explicit dependency on the database
bean, so traffic cannot start against an unreconciled schema. The
`integration`-tagged storage test proves a committed order survives closing and
reopening the PostgreSQL pool:

```text
SPICE_TEST_POSTGRES_URL=postgres://... go test -tags=integration -run PostgreSQLPersistence ./storage
```

Mail configuration is typed and instance-owned. `test` is the default
transport: it performs no network I/O and retains a bounded decoded snapshot
for tests. `POST /orders/{id}/receipt` runs only after the order transaction has
committed, creates deterministic plain-text MIME plus a receipt attachment,
and returns only the message ID. Set
`SPICE_COMMERCE_MAIL_TRANSPORT=smtp` with
`SPICE_COMMERCE_MAIL_SMTP_ADDRESS`, optional server name, and paired username
and password to use the secure SMTP starter. SMTP requires verified STARTTLS
by default (or explicit `implicit-tls`), authenticates only after TLS, observes
caller cancellation and a typed timeout, retries only safe pre-DATA transient
failures, and never replays ambiguous delivery. Recipient and credential
configuration is secret-redacted.

For the local `spice dev` walkthrough only, set
`SPICE_COMMERCE_DEVELOPER_TOKEN` to a 16-byte-or-longer bearer token. The
reference platform accepts that token only while the server binds a loopback
address and attaches a fixed developer principal with the three documented
order scopes. The token is disabled by default, compared in constant time, and
secret-redacted. It is not a production authentication mechanism; production
applications compose the OAuth2/OIDC authentication starter ahead of the same
generated authorization guards.

The generated public API is:

- `GET /catalog`, the public cache-safe product;
- `POST /orders` with a strict `{"quantity": 2}` JSON body and
  `orders:write`;
- `GET /orders/{id}` with `orders:read`;
- `POST /orders/{id}/receipt` with `orders:notify`;
- deterministic RFC 9457 errors for invalid, unavailable, declined, and missing
  orders;
- `/actuator/health`, `/actuator/health/liveness`,
  `/actuator/health/readiness`, `/actuator/info`, and `/actuator/metrics`.
- `/actuator/configprops`, with generated key/type/module/provenance metadata
  and mandatory secret redaction.
- `/actuator/modules`, with the generated module/API/dependency canvas and
  unassigned-package report.

The generated OpenAPI 3.1 contract is
`internal/spicegen/commerce/artifacts/openapi.json`. Route metrics use compiler-owned
method, pattern, symbol, and module labels rather than raw request paths.

The handwritten `main.go` explicitly imports the generated commerce target and
only calls `os.Exit(spiceapp.Main(os.Args[1:]))`. Generated `Main` returns the
exit code and owns signals; it never exits the process itself. Tests and
embedded processes can instead use `RunCommand`, `NewApplication`,
`NewApplicationWithOptions`, `Start`, `Stop`, `Run`, or the typed `Components`
snapshot with caller-owned writers, loggers, sources, contexts, observers,
middleware, error mapping, and shutdown policy. The ready application exposes
`SubmitServiceVerifySKU(admissionContext, sku)` and `AsyncSnapshot()` as its
typed asynchronous boundary.

`TestCommerceDeveloperProof` in `main_test.go` is the executable vertical
proof. It uses
`spicetest.NewHTTP` to construct the real generated application, authenticates
verified principals in caller middleware, proves allowed/unauthenticated/
insufficient-scope decisions, places an order transactionally, retrieves the
persisted record, delivers its test receipt, exercises public caching, and
inspects management metadata through a bounded loopback-only slice. The
notifications tests inspect the exact decoded message, attachment, envelope,
cancellation, and sanitized delivery failures.

The complete edit/save/restart/HTTP walkthrough and its automated evidence map
are documented in the
[Spice developer proof](https://github.com/spice-framework/spice/blob/main/docs/developer-proof.md).
