Files
framework-ignition-docker/CLAUDE.md
2026-03-17 13:23:56 -05:00

135 lines
5.2 KiB
Markdown

# Ignition + Docker Development Framework
## What This Is
Reusable scaffold for Ignition + Docker projects with Claude Code.
The PLC I/O Testing Platform is the first project built on this framework.
## Stack
- Ignition 8.3 (Git-native project storage, Perspective, WebDev, OPC-UA)
- Rockwell Allen-Bradley ControlLogix/CompactLogix, Studio 5000, PlantPAx
- Docker Compose on Ubuntu 24 (Ignition, PostgreSQL, Traefik, Modbus sims)
- Gitea at 192.168.3.59:3000 for source control
- Jython 2.7 inside Ignition; Python 3.10+ for external tooling
- Claude Code on the Linux host (VS Code Remote to Docker host)
- WikiJS at wikijs.primecontrols-dev.com for team documentation (`.md` files auto-sync on `git push` via `tools/publish_docs.py`)
## Gateway HTTP API
Ignition 8.3 exposes a full REST API. Use it for infrastructure-as-code configuration —
adding DB connections, OPC connections, importing tags, managing projects, etc.
- **Browse**: `http://<gateway-host>:8088/openapi`
- **Spec**: `http://<gateway-host>:8088/openapi.json`
- **Auth header**: `X-Ignition-API-Token: <name>:<token>`
- **Full reference**: `ignition/ignition-api.md`
- **Skill**: `/ignition-configure` — resolves token and walks through config tasks
## API Key / Secrets Policy
**Source of truth**: `~/.config/ignition-dev/secrets.env` (chmod 600, never committed)
**Template**: `.env.example` in repo root — update this when adding new secrets
- All secrets via environment variables — no hardcoded values in any file
- Docker Compose references host env vars: `VAR=${VAR}` pattern
- Python scripts use `python-dotenv` + `os.environ["KEY"]` (loud failure on missing)
- `.env` at project root is a symlink to secrets file — listed in .gitignore
- CI secrets live in Gitea repository secrets settings
Key variables: `IGNITION_API_TOKEN`, `POSTGRES_PASSWORD` — see `.env.example` for full list.
## Language Rules
### Jython 2.7 (Inside Ignition)
All scripts in `ignition/project/` run Jython 2.7. Top violations:
- NO f-strings → use `"text {}".format(val)`
- NO walrus operator `:=`
- NO type hints → no `def foo(x: int) -> str:`
Full constraint list: [ignition/CLAUDE.md](ignition/CLAUDE.md)
### Python 3.10+ (External Tooling)
All scripts outside Ignition use Python 3.10+. Add at top of every file:
```python
# env: python3.10+ (external tooling — NOT Ignition)
```
## Safety Rules (Non-Negotiable)
1. **Validate JSON** before writing to any Ignition resource directory.
2. **Back up files** before overwriting: `cp file file.bak`
3. **Sorted-key JSON** for all JSON files (Git-friendly diffs).
4. **Never restart Ignition gateway** without explicit user confirmation.
5. **Never `docker compose down`** without confirmation (destroys unnamed volumes).
6. **Every change needs a verification step** — scenario run, curl, tag read.
7. **Scan after file edits** — after editing `ignition/project/` run `POST /data/api/v1/scan/projects`; after editing `docker/gw-config/` run `POST /data/api/v1/scan/config`. Use `/ignition-configure`.
## Canonical Patterns (Do Not Change Without Discussion)
### UDT / Linking Pattern
Linking/Link sub-UDT with `LinkPath` + `LinkData` for PLC signal binding.
Decouples simulation from PLC I/O structure. All device test tags follow this.
### JSON Test Scenarios
Five required sections: `identity`, `device`, `initial_state`, `sequence`, `expected_outcomes`.
See `testing/CLAUDE.md` for full schema.
### WebDev API
All external I/O goes through WebDev endpoints — never direct tag file edits at runtime:
`tagWrite`, `tagRead`, `tagBrowse`, `health`. See `webdev/CLAUDE.md`.
### Ignition as I/O Orchestrator
Ignition writes to Modbus containers and PLC I/O tags.
PLC runs real logic. Test runner talks to Ignition only.
Never bypass Ignition to write directly to Modbus or PLC.
## Directory Layout
```
project-root/
├── CLAUDE.md
├── scripts/ ← setup.sh and utility scripts
├── docker/
│ ├── CLAUDE.md
│ ├── docker-compose.yml
│ ├── docker-compose.override.yml
│ ├── gw-build/ ← custom Ignition Dockerfile
│ ├── gw-init/ ← gateway env vars (no secrets)
│ ├── gw-commission/ ← commissioning.json
│ ├── gw-config/ ← gateway runtime config (bind-mounted; runtime dirs gitignored)
│ ├── gw-secret/ ← admin password file (gitignored)
│ └── config/
│ ├── postgres/ ← init.sql
│ └── traefik/ ← traefik.yml, dynamic/
├── ignition/
│ ├── CLAUDE.md
│ ├── ignition-api.md ← Gateway HTTP API reference
│ └── project/
│ ├── com.inductiveautomation.perspective/
│ ├── com.inductiveautomation.webdev/
│ └── ignition/
│ ├── named-query/
│ ├── script-python/
│ └── global-props/
├── testing/
│ ├── CLAUDE.md
│ ├── scenarios/
│ ├── runner/
│ └── results/
├── webdev/
│ ├── CLAUDE.md
│ └── endpoints/
├── tools/
│ └── (Python 3.10+ external utilities)
└── docs/
```