Skip to content

OpenMES v0.26.0

Choose a tag to compare

@github-actions github-actions released this 13 Oct 08:16
· 49 commits to main since this release
31cd776

OpenMES v0.26.0 is about two places where the application was quietly doing less than it claimed β€” installations running more than one module, and installations running more than one tenant β€” plus a set of industrial-connectivity fixes where a counter reading reached the database but never the screen.

OpenMES is an open-source Manufacturing Execution System (MES) built on Laravel and React: work orders, process routing, material lots and genealogy, quality control, OEE, downtime tracking and shop-floor terminals.


Fixed

Every enabled module boots, not just the last one

Laravel keys its service-provider list by class name, and each module was registered through its own ModuleProviderGuard β€” the same class every time β€” so each guard overwrote the previous one's entry. register() ran for every module and boot() only for the last one enabled.

With two or more modules installed, the others had no routes, no menus and no migrations, and nothing appeared in the log because nothing failed. Modules now register through a single provider that holds every module's guard and runs both phases for each in turn, each still inside its own guard so a module that throws costs only itself.

If you run more than one module, this is the line that matters in this release.

Workers are scoped to their tenant

Workers carried no tenant, so on a multi-tenant installation every tenant's users could see, open and change every other tenant's workers β€” contact and pay data included.

Worker now behaves like users, lines and work orders: queries are scoped to the signed-in user's tenant, a new worker is stamped with its creator's, and the live-sync snapshot scopes the collection on its own. The migration backfills existing workers from the strongest evidence first β€” the tenant of their user account, then of their schedule entries and pallet moves, and only then the oldest tenant. A worker whose own records point at different tenants is left without one rather than assigned to a guess.

MQTT credentials and TLS settings reach the broker

ConnectionSettings in the MQTT client is immutable β€” every setter returns a modified copy β€” and the results were being discarded, so the username, password and TLS options configured on a device were never sent. Against a broker with anonymous access disabled the listener was simply refused, with nothing on screen suggesting the credentials had not left the building.

Machine counts arriving over MQTT reach the browser live

The MQTT listener was pinned to the log broadcaster, so the deltas it produced went to a file instead of to Reverb: a counter reading landed in the database and the work order list only showed it after a manual reload. The same was true of the Modbus poller and the queue worker, which set no broadcaster at all and fell back to a default with no host configured. Every process that writes rows now broadcasts them.

And the rest

  • Inspection plans show how many criteria they hold β€” the column was missing from the collection's shape, so every plan read "Criteria: 0" however many were stored
  • Unhandled errors are written to the log again, and warnings and notices sent with a redirect are shown instead of silently dropped
  • A work order can be raised for a product whose bill of materials holds a material with no type
  • The installer refuses to run over an installation that is in use, generates a stable APP_KEY, and gives each fresh install a unique Docker Compose project name
  • A page from a compiled-in module gets its own styles, and WebP uploads work in the Docker image (GD was built without WebP support)
  • tenants:prune is scheduled only in demo mode β€” it was written for the public demo and had no business running elsewhere

Added

The bill of materials, one step at a time

A template's component list and its routing graph now drive the same filter: click a step on the graph and the list shows only what that step consumes, with a badge on each step for how many components it takes. The filter lives in the URL (?step_id=), so a link to one step's components survives a reload and can be sent to a colleague. Each component also states when it is consumed β€” at the start of the step, during it, or at the end.

The ionCube Loader ships in the Docker image

A module can be installed into a running OpenMES from the admin panel, and a module distributed as encoded PHP cannot run without the loader. Without it in the stock image, installing one would mean swapping the whole installation for a different image first β€” which defeats the point of installing through the panel at all. The loader is inert until something asks it to run an encoded file: a couple of megabytes, and no behaviour change for anyone not running such a module.

Two more extension points for modules

  • The sign-in page β€” display.auth.login.before and display.auth.login.after render above and below the form, which stays core's own. Previously a module with something to say before anybody is signed in had one option: replace the page entirely and then follow every change core made to signing in.
  • Every admin screen β€” display.admin.layout is resolved with the signed-in user and rendered above the page wherever AppLayout is used. A licence about to lapse or a maintenance window could previously only be announced on the module's own pages, which is where nobody is when it matters.

With no module listening, both are {} and render nothing.

Vietnamese translations for the mobile app

Plus the production screens' remaining hardcoded strings, now translatable.


Changed

Operator line selection: an operator assigned to a single line goes straight to it, keeping the bench they already picked.


Upgrade notes

Database migrations run automatically on container start. The worker tenant migration backfills existing rows β€” on a single-tenant installation every worker lands in the only tenant there is, and no action is needed.

Modules need no changes. If you have more than one installed, expect the ones that were silently inert to come back to life, with their routes, menus and pending migrations.


Installation

Web / self-hosted: download openmmes-v0.26.0.zip below β€” it is self-contained (PHP dependencies in vendor/ and the built frontend in backend/public/build/ are already bundled, so no composer install or npm run build is required).

Docker: unzip the web package and run docker compose up -d from the package root (or bash install.sh). To pull the published image instead of building, set OPENMES_PULL_POLICY=missing and OPENMES_VERSION=0.26.0 in .env β€” note the tag carries no v prefix:

docker pull ghcr.io/mes-open/openmes:0.26.0

Desktop: grab the installer for your OS β€” Windows *-setup.exe, macOS *.dmg, or Linux *.deb / *.rpm. They bundle PHP and the backend and run OpenMES as a local app or LAN server.

Mobile (Android): install openmes-mobile-v0.26.0.apk and point it at your OpenMES server.

Shared hosting (no terminal): unzip the web package, upload the folder, point the document root at the package root, then open the URL β€” the browser-based setup wizard handles environment, database and the admin account.


Full changelog: v0.25.0...v0.26.0