Browse the docs

LaraMES v1.2.0

Laraplate MES module: work orders, routings, shop-floor events, traceability, quality and KPIs.

Reference.

From the README.

Imported from larames/README.md

Table of Contents

Description

The MES Module provides the Manufacturing Execution System foundation for Laraplate. It is designed to host production workflows, work orders, shop-floor events, traceability, and manufacturing KPIs.

It depends on the ERP module (items, warehouses, stock, companies, sales orders); the dependency runs one way, ERP knows nothing of MES.

Installation

If you want to add this module to your project, you can use the joshbrw/laravel-module-installer package.

Add repository to your composer.json file:

"repositories": [
    {
        "type": "composer",
        "url": "https://github.com/getlaraplate/laracore.git"
    },
    {
        "type": "composer",
        "url": "https://github.com/getlaraplate/larames.git"
    }
]
composer require joshbrw/laravel-module-installer getlaraplate/laracore getlaraplate/larames

Then, you can install the module by running the following command:

php artisan module:install Core
php artisan module:install MES

Configuration

The module configuration is automatically mapped as mes.* when the module is active. Configuration file: Modules/MES/config/config.php.

# MES activation toggle (example)
MES_ENABLED=true

# Queue used by MES jobs and listeners (backflush, production-order auto-creation)
MES_QUEUE_CONNECTION=database
MES_QUEUE_NAME=mes

# Machine connectivity (see docs/MACHINE_CONNECTIVITY.md)
MES_MACHINE_QUEUE=mes-machine
MES_MACHINE_MAX_SAMPLES=5000
MES_MACHINE_MAX_BODY_KB=1024
MES_MACHINE_CLOCK_SKEW_SECONDS=30
MES_MACHINE_INBOX_RETENTION_DAYS=7
MES_MACHINE_RATE_LIMIT_PER_MINUTE=600
MES_MACHINE_CONFIG_RATE_LIMIT_PER_MINUTE=60
MES_MACHINE_RAW_RETENTION_DAYS=30
MES_MACHINE_MINUTE_AGGREGATE_RETENTION_DAYS=90
MES_MACHINE_PROCESS_STORE=database

# MQTT broker of the bridge (`php artisan mes:machine-bridge`), one per installation
MES_MACHINE_MQTT_HOST=127.0.0.1
MES_MACHINE_MQTT_PORT=1883
MES_MACHINE_MQTT_USERNAME=
MES_MACHINE_MQTT_PASSWORD=
MES_MACHINE_MQTT_TLS=false
MES_MACHINE_MQTT_CLIENT_ID=laraplate-mes-bridge
MES_MACHINE_MQTT_TOPIC_PREFIX=laraplate

The machine variables set the config keys mes.machine.queue, mes.machine.max_samples, mes.machine.max_body_kb, mes.machine.clock_skew_seconds, mes.machine.inbox_retention_days, mes.machine.rate_limit_per_minute, mes.machine.config_rate_limit_per_minute (configuration polls and apply reports of the edge agent, per source and minute), mes.machine.raw_retention_days, mes.machine.minute_aggregate_retention_days and mes.machine.process_store; the MQTT ones set mes.machine.mqtt.host, mes.machine.mqtt.port, mes.machine.mqtt.username, mes.machine.mqtt.password, mes.machine.mqtt.tls, mes.machine.mqtt.client_id and mes.machine.mqtt.topic_prefix. The machine queue (mes-machine) needs its own Horizon supervisor; incident notifications go to the roles under mes.notifications.machine_incident.

The receiving warehouse for auto-created production orders is resolved per company. Set it explicitly through the mes.production.default_warehouse config map ([company_id => warehouse_id]) when a company owns more than one warehouse; with a single warehouse the module picks it automatically.

Production planning tunables are Settings (module MES, group mes), edited like any other Setting and applied without a restart. The seeder (MESDatabaseSeeder) creates them with the defaults below and a re-seed keeps any value an operator changed. Both are floored where they are read, so a stored 0 behaves as 1.

Setting Default Purpose
production.daily_minutes 480 Working minutes per day used to turn the routing's standard minutes into a planned lead time.
production.default_lead_time_days 5 Planned lead time in working days when the item has no routing to estimate from.

The effective set of environment variables will be expanded as domain features are introduced.

Current Status

The manufacturing domain is implemented and covered by the module test suite:

  • Work centers with a weekly calendar, BOMs and routings with validity windows and DIFF versioning (lines and operations included)

  • Production orders numbered by ERP DocumentNumberAllocator, with immutable BOM/routing snapshots, release/complete/cancel. Starting the first operation moves a released order to in_progress; cancelling an order that has not completed ends its running and pending operations as skipped; an order cannot complete while an operation is in progress. Every transition emits a typed event (ProductionOrderReleased/Started/Completed/Cancelled, OperationStarted/Completed/Skipped, DowntimeOpened/Closed)

  • Automatic draft orders from confirmed ERP sales orders (SalesOrderConfirmed listener)

  • Operation execution (start/complete/skip) with efficiency, operator logs and non-blocking shift warnings

  • Backflush and manual material consumption through the StockMovementRecorder contract, with partial consumption and a shortage notification when stock is short

  • Completion receives the finished goods into stock, valued at the material cost consumed per unit produced (labour and machine time carry no cost rate yet)

  • Lot and serial generation with forward/backward lot genealogy

  • Quality plans, automatic quality checks, non-conformances with dispositions (rework spawns a linked order)

  • Downtime, OEE (A x P x Q, clamped to [0, 1]) and work-center capacity load, schedule and overload check (available minutes from the work center calendar, net of every downtime, planned maintenance included; operations get planned dates on release, forward and infinite-capacity, and estimateCompletionDate() plans what is left from now). A downtime is opened through the open_downtime action on its work center (one open downtime per work center). OEE and capacity are materialised per work center and day by mes:kpis:materialize (hourly, queued) into the cache and shown as an OEE column in the work-center list; starting an operation on a work center materialised as overloaded emits CapacityOverloadDetected, notified through mes.notifications.capacity_overload

  • No custom routes: entities go through Core's generic CRUD, domain verbs through the domain-action registry (MesDomainActionRegistrar, MesModelPolicy, permissions seeded by MESDatabaseSeeder)

  • Filament backoffice (Modules\MES\Filament\MESPlugin): resources for work centers (with calendar), BOMs (with lines), routings, production orders (read-only operations, consumptions, quality checks and lots, and Release/Complete/Cancel header actions), quality plans, quality checks, non-conformances, downtimes and shifts, plus a production dashboard widget with four cached counts

  • Machine connectivity foundation: machines and probes push laraplate-machine/1 messages over HTTP (POST api/v1/insert/mes/machine-messages; each source authenticates as its own service account, holding the api role mes-machine-agent) into a durable inbox processed by an idempotent, per-source serialised job (normalise, resolve, attribute, typed events); unmapped signals, incidents, a watchdog for silent devices, reprocessing, importable machine profiles, and a "Machine connectivity" backoffice; a long-running MQTT bridge (php artisan mes:machine-bridge, QoS 1, persistent session, topics from the sources, bridge_down incident) and a sparkplug_b normaliser with a persisted alias map; a state history per device with downtimes derived from it (micro-stop threshold, alarm codes, mes:machine-open-stops, synthetic Offline), manual downtimes refused on connected work centers, and ISO 22400 OEE availability with an incomplete-data flag; stored piece counts (rollover and reset aware) feeding operation machine quantities, a once-only OperationTargetReached notification, declared quantities with an audit trail, assignment of unattributed counts by time range, and ISO 22400 performance and quality; probe measurements that fill the quality check of their operation (required samples, immediate OutOfToleranceMeasured, waiting measurements attached when the check is created or assigned by hand); process values stored behind a ProcessValueStore contract (relational driver, minute and hour aggregates rebuilt by mes:machine-rollup, retention pruning) with permanent per-operation summaries and lot traceability. Guide: docs/MACHINE_CONNECTIVITY.md. The machine routes are /api routes: they answer 403 until Core's expose_api setting is on, they authenticate the bearer token of the source's service account through Core (the token is issued on the user page, optionally narrowed by allowed_cidrs), and they are limited per service account (mes.machine.rate_limit_per_minute for ingest, mes.machine.config_rate_limit_per_minute for the two configuration routes) on top of Core's per-token api limit. Edge agent backend: an optional losses[] in the envelope records data_dropped incidents; each source receives a versioned laraplate-edge-config/1 document (GET api/v1/detail/mes/machine-agent-configs, 304 on an unchanged version; versions only grow and activating an older one publishes it again as a new version; structural validation only) and reports the outcome of applying it (POST api/v1/insert/mes/machine-agent-config-reports; a rejected or rolled_back report opens a config_rejected incident); both are managed in two sections of the source page in the backoffice

Developer reference: docs/rag/MODULE.md. Operator guide (Italian): docs/MES_GUIDA_SEMPLICE.md.

Roadmap

Machine data acquisition (design: docs/superpowers/specs/2026-10-05-mes-machine-data-acquisition-design.md at the stack root). All six steps are built, each with its own plan: the foundation, the MQTT bridge, the machine states, the piece counts, the probe measurements and the process values. The backend side of the laraplate-edge agent (service accounts, configuration delivery, loss reports) is built too: docs/superpowers/plans/2026-10-15-mes-edge-agent-backend.md.

Scripts

The module has no Composer scripts of its own. Run tests and checks from the laraplate root:

# MES test suite
php artisan test --compact Modules/MES/tests

# Static analysis of the module with the root configuration
vendor/bin/phpstan analyse Modules/MES/app

# Formatting: always pass an explicit file list
vendor/bin/pint --format agent Modules/MES/app/Services/CapacityService.php

Contributing

If you want to contribute to this project, follow these steps:

  1. Fork the repository.
  2. Create a new branch for your feature or correction.
  3. Send a pull request.

License

MES Module is open-sourced software licensed under the GNU AGPL v3.

Copyright (c) 2025 Marco P. The full licence text is in LICENSE.

100%