Skip to main content

Service case study

Order Service

An order HTTP service demonstrating validation-driven boundaries today and a full lifecycle core — state machines, idempotency, optimistic concurrency and a transactional outbox — as the target.

In developmentBackend runtime: Local development onlyDemo data source: Mock

Scope
A backend engineering case study of order creation, lifecycle state and payment semantics for a technical demo environment.
Not in scope
  • Not a storefront or product catalog.
  • Not an inventory system.
  • Not a real acquiring/payment-provider integration.
Engineering focus
State machines, transactions, idempotency, optimistic concurrency, transactional outbox.

Engineering Focus

State machines, transactions, idempotency, optimistic concurrency, transactional outbox.

Current Implementation

  • Current

    POST /orders validates the product field (trim + non-empty) and calls the service layer; GET /orders/{id} validates a positive integer ID and an optional details flag. Handlers return demonstration text without persistence.

  • Current

    Independent domain models and transition methods exist in the module but are not yet connected to the HTTP flow.

    • Domain models and transition methods (separate from the HTTP flow)services/order-service/internal/orderhttps://github.com/Officialsayp/zolotoy-dev-backende36b1025reviewed 2026-09-17
  • Current

    No storage integration yet: created orders are not persisted and GET does not retrieve from storage.

  • Current

    No automated backend tests existed in the inspected inventory — handler/service/domain tests are part of the current milestone, not a completed fact.

    • Backend roadmap: Service Layer milestone in progressdocs/roadmap.mdzolotoy-dev-backende36b1025reviewed 2026-09-17

Target Architecture

  • Target

    Independent order and payment state machines with an explicit allowed-transition matrix, cancellation and refund paths, and versioned updates.

    • Order service specification (target contract)docs/backend-specs/01_order_service.mdzolotoy-dev-frontend (this repository)reviewed 2026-09-17
  • Target

    PostgreSQL persistence with migrations, durable create/read, and transactions that keep external payment calls outside open database transactions.

    • Order service specification (target contract)docs/backend-specs/01_order_service.mdzolotoy-dev-frontend (this repository)reviewed 2026-09-17
    • Persistence milestone: PostgreSQL repository and migrations (future)docs/roadmap.mdzolotoy-dev-backende36b1025reviewed 2026-09-17
  • Target

    Optimistic concurrency (version checks) and idempotency keys so repeated create/pay operations converge instead of duplicating side effects.

    • Order service specification (target contract)docs/backend-specs/01_order_service.mdzolotoy-dev-frontend (this repository)reviewed 2026-09-17
  • Target

    A transactional outbox records order events atomically with state changes; publication is at-least-once and consumers deduplicate.

    • Order service specification (target contract)docs/backend-specs/01_order_service.mdzolotoy-dev-frontend (this repository)reviewed 2026-09-17
    • Events milestone: outbox contract feeding Notification (future)docs/roadmap.mdzolotoy-dev-backende36b1025reviewed 2026-09-17

Architecture / Core Flow

Current
  • HTTP clientcurl / Bruno manual collection
  • Handler (net/http)POST /orders, GET /orders/{id}: trim, validate, delegate
  • Order serviceBusiness result construction (in development)
  • Domain modelsStatus/payment transitions — present but not connected
  • POST /orders {product}: client → handler
  • validated call: handler → service
  • not yet integrated: service → domain (planned)
Current order flow: HTTP boundary into the service layer, no storage.
Target
  • HTTP clientJSON API consumers
  • HandlerDTO validation and error envelopes
  • Order serviceTransition matrix, idempotency, version checks
  • PostgreSQLOrders, history, outbox records
  • Outbox publisherAt-least-once event delivery
  • JSON API: client → handler
  • application boundary: handler → service
  • transactional writes: service → db (planned)
  • atomic event records: db → outbox (planned)
Target order flow: state machines, persistence, outbox.

Engineering Decisions

Validation lives at the HTTP boundary, business rules in the service layer

Handlers trim and validate input shape (product, ID, flags) and delegate; the service layer owns the result. Keeping transport parsing out of the service keeps the boundary testable without HTTP.

Domain models are built separately before wiring the HTTP flow

Order/payment state machines and transition methods are developed as an independent domain package first, so lifecycle semantics can be designed and tested before they are coupled to handlers and storage.

Idempotency keys scope to operation + payload

Target design: a repeated idempotency key with the same payload returns the original result; the same key with a different payload is a client error. This prevents both duplicate side effects and silent payload substitution.

External payment calls stay outside open database transactions

Target design: reserve state in a short transaction, call the provider outside it, then apply the result in a guarded transition. A crash between the two steps is recovered by reconciliation, not by holding locks across network I/O.

Reliability / Failure Modes

Repeated idempotency key: same payload vs different payload
Same payload → return the recorded result (no second side effect). Different payload → 409-style client error instead of silently reprocessing. The stored key must bind to a request fingerprint.
Competing Pay/Cancel operations
Two concurrent transitions on one order must serialize through the version check: exactly one wins, the loser gets a concurrency conflict and re-reads current state.
External payment call vs process crash
If the process dies between charging and recording, reconciliation (not a live transaction) resolves the outcome; the order records an in-flight payment state rather than pretending nothing happened.
Outbox publication duplicates
Outbox delivery is at-least-once: consumers must deduplicate by event ID. Publishers do not promise exactly-once.

Evidence

  • HTTP handlers: POST /orders, GET /orders/{id} validation and service delegationservices/order-service/cmd/order-service/main.gohttps://github.com/Officialsayp/zolotoy-dev-backende36b1025reviewed 2026-09-17
  • Service layer producing the demonstration resultservices/order-service/internal/service/order_service.gohttps://github.com/Officialsayp/zolotoy-dev-backende36b1025reviewed 2026-09-17
  • Domain models and transition methods (separate from the HTTP flow)services/order-service/internal/orderhttps://github.com/Officialsayp/zolotoy-dev-backende36b1025reviewed 2026-09-17
  • Order service specification (target contract)docs/backend-specs/01_order_service.mdzolotoy-dev-frontend (this repository)reviewed 2026-09-17
  • Backend roadmap: Service Layer milestone in progressdocs/roadmap.mdzolotoy-dev-backende36b1025reviewed 2026-09-17
  • Persistence milestone: PostgreSQL repository and migrations (future)docs/roadmap.mdzolotoy-dev-backende36b1025reviewed 2026-09-17
  • Events milestone: outbox contract feeding Notification (future)docs/roadmap.mdzolotoy-dev-backende36b1025reviewed 2026-09-17

Interactive Demo

Next Milestone: Order persistence

Agree OpenAPI/DTOs, add repository/PostgreSQL/migrations and durable create/read flows.

Acceptance evidence (planned):

  • Migration set reproducibly bootstraps the schema
  • Created orders survive process restart