Built via parallel Workflow (5 builders + adversarial verifiers), then live-rendered and fixed in a headless browser against the running gateway. Tabs (PrimeControls/Tabs/*): - Overview: priority cards, KPI status row, alarm-rate timeline, insights, top-5 - Analysis: hour x day heatmap, priority donut vs ISA 80/15/5, MTTA/MTTR, floods - BadActors: chattering/standing/fleeting tables, focus chip, AlarmDetail wiring - Journal: paginated getJournalPage table, CSV export, EventDetail wiring Popups (PrimeControls/Popups/*): HealthScore, ShiftReport, AlarmDetail, EventDetail Chart fixes (verified rendering in-browser): - Overview timeline: seeded dataSources.rate, switched to static fills, split flood bins into their own red stacked series (per-point deriveFieldsFromData fill was crashing render with React.cloneElement null). - BadActors: removed the dual-axis Pareto XY chart (scaling was unusable); replaced with a ranked "Top Sources" table (share-of-total progress bar + cumulative %). Same insight, no axis scaling to break. Structural / hygiene: - Relocated Header + FilterBar from Dashboard/ to Shell/ and updated the two embed paths. A Perspective view cannot resolve sub-views nested inside another view's folder, so both were rendering as "view does not exist" placeholders. - Set persistent:false on all view input params. persistent:true caused the gateway to bake the live bundle (with sim tag paths) into Tabs/Analysis on render; nulled that baked data and reset the session query range to 0. lint_project.py: 0 failures / 0 warnings. Verified in-browser: Overview, BadActors. NOT yet live-verified: Analysis, Journal, and the four popups (schema-verified only). Header content is next phase (renders now, but a benign cloneElement console warning remains). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Build-a-Thon — Alarm Analysis Dashboard (Ignition 8.3.7 + Perspective)
Local development environment for the Inductive Automation Build-a-Thon. Native Ignition features only — no third-party modules (contest rule).
Quickstart
docker compose up -d
- Gateway: http://localhost:8088 — login
admin/password - MariaDB:
localhost:3306— dbignition, userignition/ignition(root password:password)
First start takes a minute or two while the gateway commissions itself (EULA, edition, and admin credentials are seeded by env vars, so there is no commissioning wizard). Watch with:
docker compose logs -f ignition
The gateway is ready when curl http://localhost:8088/StatusPing returns {"state":"RUNNING"}.
Gateway state lives in this repo (gateway-as-files)
The gateway's durable state is bind-mounted from the repo (primebench/TestingPlatform pattern) — a container recreate can never wipe it, and the gateway never re-commissions:
| Repo path | In container (data/) |
What's in it |
|---|---|---|
ignition/gateway/commission/commissioning.json |
commissioning.json |
Commissioning marker (committed) |
ignition/gateway/config/ |
config/ |
All config resources: DB connection, journal, API token, tags, secrets |
ignition/gateway/projects/ |
projects/ |
Project files: Perspective views, scripts, timers |
Everything else (internal db, logs, certs) stays ephemeral in the container. The gateway
runs as your host uid/gid (IGNITION_UID/IGNITION_GID, default 1000), so files stay
owned by you.
Edit-files workflow: change files under ignition/gateway/, then tell the gateway to
reload — python3 tools/provision.py scan-config (config/tags) or scan-projects
(project resources). Changes made in the Designer/gateway UI land back in these files,
ready to diff.
Automated provisioning (REST API)
Gateway config is provisioned through the Ignition 8.3 HTTP API using tools/provision.py (stdlib only, no pip installs). On a fresh gateway:
python3 tools/provision.py mint-token # API token file-drops + gateway restart; updates .env
python3 tools/provision.py provision # secret provider + DB connection + alarm journal + sim tags
mint-tokenwrites anapi-tokenconfig resource underignition/gateway/config/, patches theAuthenticated > APIsecurity levels into gateway read/write permissions, restarts the gateway (if running; otherwise the token loads on next boot), and savesIGN_API=Buildathon:<secret>to.env(gitignored). Only the SHA-256 hash of the secret is stored in the config files.provisionis idempotent — it skips resources that already exist. It creates:- file secret provider
local(MariaDB password lives in the gitignored fileignition/gateway/config/secrets/mariadb_password, referenced by the connection — the 8.3 API only accepts encrypted or referenced secrets) - database connection
Buildathon_DB→jdbc:mariadb://db:3306/ignition - alarm journal
Journal→ tablesPrimeControls_alarm_events/PrimeControls_alarm_event_data - imports
test-data/simulation_tags.jsoninto thedefaulttag provider
- file secret provider
Ad-hoc API calls use one header: curl -H "X-Ignition-API-Token: $IGN_API" $GATEWAY_URL/openapi.json
(source .env first).
Two steps remain manual (Designer-only): creating the Buildathon Perspective project
(step 3 below) and installing the simulator timer script (test-data/README.md).
Manual setup reference (what provision.py does, plus the Designer steps)
1. Database connection (MariaDB) — automated
Gateway web UI → Config → Databases → Connections → Create new Database Connection
| Setting | Value |
|---|---|
| Name | Buildathon_DB |
| Driver | MariaDB |
| Connect URL | jdbc:mariadb://db:3306/ignition |
| Username | ignition |
| Password | ignition |
Note the host is db (the compose service name), not localhost — the gateway reaches
MariaDB over the compose network. Save and confirm the status shows Valid.
Ignition 8.3 ships the MariaDB JDBC driver, so no driver install is needed.
2. Alarm journal profile — automated
Gateway web UI → Config → Alarming → Journal → Create new Alarm Journal Profile
| Setting | Value |
|---|---|
| Name | Journal (any name works) |
| Type | Database |
| Datasource | Buildathon_DB |
| Table prefix | PrimeControls_ |
Leave the event filters at defaults (store everything) so the analytics have full data.
The journal auto-creates PrimeControls_alarm_events and PrimeControls_alarm_event_data
in MariaDB the first time an alarm event occurs.
3. Perspective project — manual
- Gateway web UI → Config → Projects → Create new Project (or Designer → File → New Project)
- Name:
Buildathon
- Name:
- Open it in the Designer (launch from http://localhost:8088 → Designer launcher),
then set the project default database: Project → Project Properties → General →
Default Database →
Buildathon_DB. Save the project.
Named queries and bindings that use the "default" database now hit MariaDB.
Test data
See test-data/README.md — imports simulation memory tags with alarm configs and a Jython script that generates realistic alarm activity (baseline alarms across 5 plant areas / 3 priorities, chattering, standing, fleeting, and flood-burst patterns).
Reset to a completely fresh gateway
Gateway state is repo files now, so docker compose down -v alone no longer wipes the
gateway — it only removes the containers and the MariaDB volume. To verify the project
export imports cleanly on a fresh install (the contest judging scenario), set the gateway
files aside and rebuild:
docker compose down -v # containers + MariaDB volume
mv ignition/gateway ignition/gateway.bak # keep your current state for rollback
mkdir -p ignition/gateway/commission ignition/gateway/config ignition/gateway/projects
cp ignition/gateway.bak/commission/commissioning.json ignition/gateway/commission/
docker compose up -d # boots factory-fresh, auto-commissions
python3 tools/provision.py mint-token # old token lived in gateway.bak
python3 tools/provision.py provision
Then import your project export to prove it stands alone. Roll back to your working
state with docker compose down && rm -rf ignition/gateway && mv ignition/gateway.bak ignition/gateway && docker compose up -d (MariaDB journal data is gone either way after
-v — the sim regenerates it).
A plain docker compose down / up -d restarts with everything intact.
Notes
- Max JVM heap is 2 GB (
-m 2048runtime arg in the composecommand). - The 8.3 image's data dir is
/usr/local/bin/ignition/data; onlycommissioning.json,config/, andprojects/are bind-mounted fromignition/gateway/(see the gateway-as-files section above). ignitionwaits on the MariaDB healthcheck before starting, so the datasource is reachable as soon as the gateway is up.