Skip to content

Architecture

openwcs-docs-agent edited this page Jun 11, 2026 · 4 revisions

Architecture

openWCS is a set of Java 21 / Spring Boot microservices behind a reactive API gateway, with Go device adapters, PostgreSQL 16 for state and Kafka as the event backbone. Full rationale: build.md.

Principles

  • Bounded contexts — each service owns its domain and its own database schema; no service reaches into another's tables. Cross-service references are UUIDs with no cross-schema foreign keys, so any schema can later move to its own database.
  • Event-sourced system of record — the transaction log (txlog) is an append-only event store; read models (e.g. inventory stock) are projections rebuilt from it.
  • Transactional outbox — services that must publish events write the event and an outbox row in one DB transaction; a relay publishes to Kafka in order (no dual-write loss).
  • Idempotent handlers — message/device delivery can repeat; consumers dedupe on eventId/correlationId.
  • Contract-first — REST (contracts/openapi/) and events are defined before implementation.
  • Toggleable security — gateway JWT validation + per-endpoint RBAC, off by default so the stack runs without a realm (see Security).
  • Horizontally scalable — the request path of every service is stateless; all durable state lives in Postgres or Kafka. Scheduled jobs (outbox relays, off-peak sweeps) are guarded by ShedLock so only one replica runs each job per tick. The conveyor-loop capacity check uses a pessimistic row lock so it stays correct under concurrent scans from multiple replicas. Starter Kubernetes manifests and HPAs live in deploy/k8s/. See Horizontal Scaling.

High-level shape

            ┌─────────── API Gateway (8080) ── JWT validate · forward X-Auth-* ───────────┐
            │                                                                              │
  master-data  inventory  order-management  allocation  flow-orchestrator  txlog  iam  ...
            │                                                                              │
            └── PostgreSQL 16 (schema-per-service) ─────────── Kafka (txlog.stream) ───────┘

  Host (WMS/ERP) ─► integration-host (canonical Host API) ─► order-management / master-data / txlog
                    integration-sap / integration-manhattan translate vendor formats into it

  flow-orchestrator ─► device adapters (Go: conveyor, asrs, amr-geekplus, autostore) ─► equipment

See Services for the full list and ports.

Data ownership (schema-per-service)

Schema Owner Holds
master_data master-data warehouses, SKUs (+profiles), UoMs, barcodes, locations, equipment, shippers, fulfillment config, shipping-services, routes, label-templates
transaction_log txlog append-only events (UPDATE/DELETE blocked) + outbox
inventory inventory durable stock, reservations, batch/serial, projection cursor
orders order-management orders (all types), lines, line transactions, outbox
allocation allocation order allocation + cube plan, pick batches
iam iam roles, role-permissions, users, user-roles
flow flow-orchestrator device tasks
host_integration integration-host idempotency keys, webhook subscriptions

Event backbone

txlog is the system of record. Movement events — GoodsReceived, PutawayCompleted / StockMoved, Picked, StockAdjusted, StockStatusChanged — are appended (via outbox → relay) to the Kafka topic txlog.stream. The inventory projection consumes them idempotently (an inbox keyed on eventId) to move stock.qty and advance a replay cursor, so the read model can be rebuilt from the log.

UI resilience — reconnecting overlay

When the API gateway is unreachable (HTTP 502/503/504, or a thrown fetch), the React UI replaces the normal screen with a calm full-screen "Reconnecting…" overlay rather than letting every panel flash its own error. The overlay clears itself automatically as soon as the gateway answers.

Internally: a tiny backendStatus.ts module holds a global up/down flag with a publish-subscribe interface. The existing authFetch.ts fetch interceptor flips the flag on every /api/** call — down on a gateway error or thrown fetch, up on any other response. BackendOverlay.tsx subscribes to the flag and, while down, also actively probes GET /api/system/services every 2.5 s so recovery does not depend on another screen still polling (see System Info).

Architecture Decision Records

Clone this wiki locally