Production-minded demo of an order lifecycle service built with Go, Temporal, Postgres, and Ent. The service exposes a small HTTP API, orchestrates order state transitions as a Temporal workflow, and persists state in Postgres.
- API: Go + Chi (
POST /orders,GET /orders/{id}), JSON responses. - Workflow: Temporal workflow drives order creation → payment pending → payment confirmed → shipping → completed (or failed).
- Persistence: Postgres with Ent schema for strongly-typed access.
- Workers: Temporal worker registered in the app process (single binary).
- Docs: Redoc served from
/docs, OpenAPI at/openapi.yaml.
- Docker and Docker Compose
- Open ports:
3000(API/Redoc),7233(Temporal),8080(Temporal UI),5432(Postgres)
docker compose up -dAfter startup:
- API & Redoc: http://localhost:3000/docs
- Temporal UI: http://localhost:8080
- Temporal Frontend: localhost:7233
- Postgres: localhost:5432 (user/pass/db
temporal/temporal/app)
Stop the stack:
docker compose downEnvironment variables (see defaults in internal/config/config.go):
APP_HTTP_ADDR– HTTP listen address (default:3000)DATABASE_URL– Postgres DSN (defaultpostgres://temporal:temporal@localhost:5432/app?sslmode=disable)TEMPORAL_HOSTPORT– Temporal Frontend address (defaultlocalhost:7233)TEMPORAL_NAMESPACE– Temporal namespace (defaultdefault)TASK_QUEUE– Temporal task queue (defaultorders)PAYMENT_DELAY_SECONDS– Simulated payment delay (default3)SHIPPING_DELAY_SECONDS– Simulated shipping delay (default3)
POST /orders– create an order- body:
{"amount": 100, "customer_id": "c-123"}
- body:
GET /orders/{id}– fetch order by ID
curl -X POST http://localhost:3000/orders \
-H 'Content-Type: application/json' \
-d '{"amount":150,"customer_id":"cust-1"}'
curl http://localhost:3000/orders/<order-id>go test ./...
go run ./cmd/appEnt schema lives in ent/schema. If you change it, regenerate with:
go generate ./ent- Redoc is served from the running app; ensure the
appcontainer is healthy. - Temporal worker runs inside the app process; if Temporal is not yet healthy, restart the
appcontainer after Temporal is up.