Orders and payments bounded context for ordered-system, extracted from the ordered-backend monolith via the Strangler Fig pattern. Owns its own PostgreSQL database — no other service touches order_db directly.
- Order placement, orchestrated by
OrderPlacementOrchestrator: reserves stock onproduct-service(via a synchronous checkout-reservation call), charges the card through Stripe, and persists the order — with the database transaction and the external Stripe call deliberately kept in separate steps, so a slow/failed payment provider can never hold a DB transaction open. - Payments via Stripe, wrapped in Resilience4j
@CircuitBreaker+@Retry(the fallback fires on the@Retryannotation, not the circuit breaker, due to how Resilience4j orders its aspects — worth knowing if you're debugging why a fallback isn't triggering when you expect). Failed payments are picked up byPaymentRetryScheduler, which polls every 5 minutes for up to 5 attempts before cancelling the order. - Delivery address snapshotting — the address on an
Orderis a point-in-time copy (DeliveryAddress), not a live reference to the buyer's address book, so a later address edit never rewrites history on an already-placed order. - Outbox pattern for Kafka: state changes (e.g.
order-delivered) are written to anOutboxEventtable in the same transaction as the business change, then published to Kafka by a scheduled poller (@EnableSchedulingis required here — its absence was an early bug that silently stopped events from ever going out) — giving at-least-once delivery without a distributed transaction.
Base path /api/v1/orders and /api/v1/payments, reached through ordered-gateway in the full system. OpenAPI docs at /v3/api-docs (or via the gateway's aggregated Swagger UI).
Java 21 · Spring Boot 4.1.0 · PostgreSQL + Flyway (ddl-auto: validate — schema changes only happen through migrations, never Hibernate auto-DDL) · Kafka (outbox pattern) · Stripe + Resilience4j · Eureka Client · Spring Cloud Config Client · Micrometer / Prometheus / OpenTelemetry tracing · ordered-commons for JWT claims auth and shared exception handling
Needs ordered-eureka, ordered-config-server, Kafka, and its own Postgres. The easiest path is running the whole system via ordered-infra — but to run just this service in isolation:
git clone https://github.com/ordered-system/ordered-commons.git
(cd ordered-commons && make install) # ordered-commons isn't on Maven Central
git clone https://github.com/ordered-system/ordered-order-service.git
cd ordered-order-service
make up # starts this service's own Postgres on :5433
STRIPE_SECRET_KEY=sk_test_... make run # spring-boot:run, needs a real Stripe test key for payments to workRuns on port 9091.
The Dockerfile expects ordered-commons as an additional build context (see that repo's README) — building this service standalone with plain docker build . will fail on the ordered-commons dependency. Use ordered-infra's compose files, which wire the context correctly, or add --build-context commons=../ordered-commons yourself.
make test-unit # unit tests only
make test-integration # unit + integration tests (needs Docker — Testcontainers spins up real Postgres)Integration tests use Testcontainers inline (@ServiceConnection on a static PostgreSQLContainer, no shared base class) and live in the parent package (e.g. pl.dybcio.ordered.payment), while unit tests sit in .service subpackages — StripePaymentIntegrationTest and PaymentRetrySchedulerTest are good starting points for seeing the payment flow end-to-end.
| Service | Database | Role |
|---|---|---|
| ordered-order-service | PostgreSQL | Orders, cart checkout, payments (Stripe) |
| ordered-product-service | PostgreSQL + Redis | Product catalog, stock reservation |
| ordered-user-service | PostgreSQL | Users, auth, JWT issuance |
| ordered-engagement-service | MongoDB | Reviews, browsing history |
Part of the ordered-system organization — decomposed from ordered-backend, load-tested in ordered-load-tests.
MIT — see LICENSE.