Architecture - Berufskolleg-Meschede/MESchede GitHub Wiki
Architecture
System overview
Browser ──HTTP──> Next.js frontend ──> FastAPI backend ──> PostgreSQL
├── OPC UA ──> Siemens S7 PLC
└── AMQP ────> RabbitMQ / ERP
The frontend calls the FastAPI backend through server-side Next.js proxy routes. The backend persists application data and runs the PLC order worker. Development Compose starts PostgreSQL and the backend; production Compose uses the separately published backend and frontend images behind Traefik.
Order worker
OrderWorkerHost owns the shared production and delivery dispatch loop. It acquires a database leadership lock before PLC dispatch so multiple backend instances do not run competing order workers. It observes both order slots, reconciles persisted state after restart, and delegates queue admission and PLC handshakes to the order services. Orders from both types share a durable FIFO and exclusive dispatch state.
Product catalog synchronization runs in a separate background task and uses a dedicated PLC read connection when configured. The live inventory endpoint uses another separate PlcStorageGateway; inventory reads therefore do not share the dispatch connection.
RabbitMQ flows
There are two independent stock flows:
- Inbound ERP to MES: the storage consumer reads snapshots and deltas from the configured
RABBITMQ_STORAGE_INBOUND_QUEUEand updates the database-backed legacy/storagedata. It remains disabled without a configured queue. - Outbound MES to ERP: the order worker publishes stock deltas for confirmed good units. Events are first stored in a PostgreSQL outbox and are marked published only after broker confirmation. Failed publishes remain pending for retry; consumers should deduplicate on the stable AMQP
message_id.
The frontend inventory page uses GET /plc-storage/ and reads current PLC values directly. It does not use the RabbitMQ-backed /storage endpoint.
Order state and recovery
Orders are durably admitted to PostgreSQL before the API returns 202 Accepted. A single active run is dispatched at a time. The state machine records queued, preparing, starting, running, completion, reset, interruption, and review-required states. On restart, the worker reconciles a persisted active run against current PLC observations before dispatching another order. When PLC evidence cannot establish an outcome, the run can require manual review.
See Data Model and API for routes and records, and OPC UA Integration for the handshake details.