main was 16 days and 259 commits behind the line the product is actually built on, at contract 0.30.0 against 0.35.0, with no per-PC credential code at all. It was neither current nor curated - just stale. This brings it forward and, at the same time, makes it mean something: main is what a receiving site installs, and nothing else. WHAT IT CARRIES. Twelve plugins - backups, computers, endpoints, guides, knowledgebase, machines, network, notifications, printers, slides, tools, warranty - plus applications, which is manifest-less core and always ships. The only manifest dependency inside that set is endpoints on computers, and both are in it, so the closure is self-contained. WHAT IT DOES NOT. employees, geenforce, measuringtools, printedparts and usb stay on the site line. So do the Windows installer tree, the VM rehearsal helpers, the agent tooling config, one site's data loader, the internal audit and findings records, and the planner spreadsheet. 1,135 tracked files against 1,438. A REMOVAL THAT BREAKS THE APP IS NOT A REMOVAL, and two nearly shipped: deploy/site-profile-universal.json still named all seventeen plugins. It is the file docs/DEPLOY.md tells a site to provision from, so a fresh install would have failed at `flask plugin apply-profile` with PluginError - the first thing a receiving site does, broken by the branch meant to serve them. It now names the twelve that exist, and its comment says the two must agree. agent/ was never refreshed. Whoever populated this branch copied shopdb/, plugins/, frontend/ and tests/ from the site line and left the agent tree at its September state: 22 C# and PowerShell sources missing, including AgentCredentials, EnrollmentService, AgentHttpFactory and the fleet-alert client, plus one file the site line had deleted still present. The old tree is internally consistent, so it compiles, and nothing in CI builds it - every gate was green over a server that speaks enrollment and per-PC credentials to a bundled agent source that cannot. Resynced whole. DECISIONS THIS ENCODES, rather than defers: - The plugin-authoring lab builds printedparts, whose manifest depends on employees, so it could not stay. The lab remains on the site line and main ships no build-along tutorial. That is a real loss for an adopting developer and is recorded here rather than discovered later. - Recognition, Training and Recertification notifications are no longer seeded. Each splits one notification into a card per employee and renders a photo, which needs a plugin this branch does not bundle. Seeding them would offer an author a type that cannot resolve anybody. A site that installs employees gets them from that plugin's own seed. - Windows/IIS is documented as the legacy path throughout, and the README leads with Docker, because that is what a receiving site gets. The API description is regenerated for THIS branch - 347 paths and 483 operations, down from 415 and 573 - so the published contract describes what is here rather than what the site line serves. docs/CONFIG.md lost the two measuring-tool label keys the code no longer declares, which two lanes had decided opposite ways. Suite: 3124 passed, 6 skipped. Naming and style gates pass. The docs gates run rather than skip, and every index line count is derived from the file it names.
135 lines
10 KiB
Markdown
135 lines
10 KiB
Markdown
<!-- docmeta
|
|
purpose: reference
|
|
audience: adopter, operator, developer
|
|
status: current
|
|
summary: What each bundled plugin tracks, how per-plugin migrations are owned, and how a site builds lean.
|
|
loadwith: none
|
|
-->
|
|
|
|
# Plugins
|
|
|
|
shopdb-flask is a framework. The plugins listed here are the pieces other GE Aerospace facilities can install, build, or skip per ADR-003. Bundled plugins ship in the framework repo. External plugins live in their own repos and drop into `<repo>/plugins/<name>/` at install time.
|
|
|
|
## Bundled (ship with the framework)
|
|
|
|
These plugins are in `plugins/` in this repo. Enable per site with `flask plugin
|
|
install <name>`. None of them ships `default_enabled: false`, so the shelf and
|
|
the catalog are the same list here: a site turns one on rather than fetching
|
|
it. [PROJECT-MAP](PROJECT-MAP.md) carries their versions and migration heads,
|
|
generated from the code.
|
|
|
|
| Plugin | Tracks | Notes |
|
|
|--------|--------|-------|
|
|
| `machines` | Manufacturing machinery: 5-axis mills, lathes, broachers, heat treatment ovens, and metrology instruments | Manually entered. Metrology instruments are machines here, not a class of their own - see [ADR-018](adr/ADR-018-metrology-instruments-are-machines.md). Subtype tables for FOCAS / CLM / MTConnect controller protocols (planned). |
|
|
| `computers` | Shop-floor PCs and engineering workstations | Fed by the PXE pipeline collector per [ADR-006](adr/ADR-006-collector-contract.md). |
|
|
| `printers` | Network and shop-floor printers | Public installer map page + fleet install contract (`/api/printers/install-list`, `/pc-default`, `/install-batch`; see [PRINTER-INSTALLER.md](PRINTER-INSTALLER.md)). Optional Zabbix integration for supply tracking. Legacy `PrinterData` retiring per ADR-001. |
|
|
| `network` | Switches, routers, access points, IDFs as locations | Asset-only; cleanest of the bundled set. |
|
|
| `notifications` | Shop-floor notifications, recognitions, kiosk feed | Used by `ShopfloorDashboard.vue`. |
|
|
| `knowledgebase` | Knowledge Base articles linking to external resources | Lightweight article store. |
|
|
| `slides` | Slides for the lobby display and shop-floor screensaver | Upload / reorder / delete per surface. Management gated on the `slides.manage` permission, grantable to non-admin curators; display routes are public. |
|
|
| `tools` | Technician utilities: barcode and QR label generation, unit conversions, Secure Send | Mostly browser-side by design, so an air-gapped bench gets them with no network. Secure Send is the exception and is why this plugin has a blueprint, a table and a migration chain: see [SECURE-SEND.md](SECURE-SEND.md). |
|
|
| `warranty` | Asset warranty tracking | Manual entry now, Dell / Lenovo / HP provider lookups later. Derived coverage status with report buckets. |
|
|
| `guides` | Step-by-step procedures written in ShopDB: typed blocks, pasted screenshots, live checkboxes, tags, drafts and revision history | Content is stored as typed blocks rather than markup, so the same guide renders to screen, dark mode and paper. Readers see the PUBLISHED revision only - a technician following a procedure must not have it change under them mid-task. Checkbox ticks are per-viewer and never edit the guide. See [GUIDES.md](GUIDES.md). |
|
|
| `endpoints` | Live endpoint telemetry for shop-floor PCs: liveness, services, processes, inventory, and curated Windows event records, reported by the ShopDB agent | Depends on `computers` - an endpoint is telemetry ABOUT a PC asset, never a second record of it. Adds the Fleet console plus the live panels on a PC's detail page. Four separate permissions: `endpoints.view` to read, `endpoints.fleet` for the fleet-wide console, `endpoints.command` to act on one endpoint, and `endpoints.restart` for a reboot. They are split because read access is grantable to guests and the command channel is not. Ingest is not a route in this plugin: agent reports arrive on the generic collector route and authorize on a service token scoped `collector.ingest.endpoints`, not a user JWT, per [ADR-006](adr/ADR-006-collector-contract.md). That scope doubles as the kill switch for the agent key. See [FLEET-ARCHITECTURE.md](FLEET-ARCHITECTURE.md). |
|
|
| `backups` | Per-asset configuration backups with revision history: NTLARS/DNC registry and part marker | Kind-pluggable per [BACKUP-KINDS.md](BACKUP-KINDS.md); a kind is one class in `services/registry.py`. Parseable kinds store a JSON projection and re-render to the native format on download; opaque vendor formats stay on the SFLD share with ShopDB holding metadata and the UNC pointer. Fed by the collector, so ingest authorizes on a `collector.ingest` service token, not a user JWT. `backups.view` and `backups.download` are separate permissions because a `.reg` is a restorable artifact. Not to be confused with [BACKUP-RESTORE.md](BACKUP-RESTORE.md), which is the ShopDB database itself. |
|
|
|
|
## Plugin permissions
|
|
|
|
Plugins may register their own permissions (for example `slides.manage`). Admins
|
|
implicitly hold them; grant them to specific roles or users to delegate curation
|
|
without admin. Each plugin's registered permissions appear in its `plugin.py`
|
|
`get_permissions()`.
|
|
|
|
## Building your own
|
|
|
|
Guides:
|
|
|
|
- [PLUGIN-HOOKS.md](PLUGIN-HOOKS.md) - **the contract**, and the only page that defines it: every hook, every manifest field, every importable name.
|
|
- [PLUGIN-QUICKSTART.md](PLUGIN-QUICKSTART.md) - start here: generate, customize, install and test a plugin in about 30 minutes.
|
|
- [PLUGIN-GUIDE.md](PLUGIN-GUIDE.md) - the conventions and traps of a real plugin, and the checklist to walk before calling one done.
|
|
- [PLUGIN-EXTERNAL-REPO.md](PLUGIN-EXTERNAL-REPO.md) - developing a plugin in its own repo per ADR-003: repo layout, symlink dev workflow, `core_version` pinning, and the CI harness.
|
|
- [PLUGIN-SIGNING.md](PLUGIN-SIGNING.md) - packaging a plugin as a signed artifact and trusting it at a site.
|
|
- [CONTRACT-STABILITY.md](CONTRACT-STABILITY.md) - how much of the contract is settled, and how tightly to pin.
|
|
|
|
The contract is locked in [ADR-001](adr/ADR-001-asset-as-platform-contract.md) and versioned per [ADR-002](adr/ADR-002-plugin-versioning.md).
|
|
|
|
Quick path:
|
|
|
|
```bash
|
|
flask plugin new cameras --description "Tracks shop-floor surveillance cameras"
|
|
# edit plugins/cameras/models/cameras.py with your fields
|
|
flask plugin install cameras
|
|
```
|
|
|
|
<a id="migrations"></a>
|
|
## Migrations (per-plugin chains)
|
|
|
|
This is the one place the anchor-vs-baseline rule is written down; other pages
|
|
link here.
|
|
|
|
Each plugin that owns tables carries its own Alembic chain under
|
|
`plugins/<name>/migrations/`, with a per-plugin version table
|
|
`alembic_version_<name>` independent of the core `alembic_version`. Ownership is
|
|
split at a fixed cutover (see [ADR-008](adr/ADR-008-plugin-migration-ownership.md)):
|
|
|
|
- The core chain (`flask db upgrade`) created every table that existed through
|
|
its head, including the bundled-plugin tables. Each bundled plugin's `0001`
|
|
migration is a stamp-only no-op anchor recording that fact.
|
|
- From the cutover forward, a change to a plugin's schema lands as
|
|
`plugins/<name>/migrations/versions/000N_*.py`, never in the core chain. The
|
|
core chain is reserved for core tables.
|
|
- A plugin built AFTER the cutover (`endpoints` and `guides` are the bundled
|
|
examples), and every plugin built from now on, is different: the core chain
|
|
never created its tables, so its `0001` is a REAL baseline that creates them,
|
|
not a no-op anchor.
|
|
|
|
Deploys and upgrades run `flask db upgrade` then `flask plugin upgrade-all`.
|
|
`upgrade-all` stamps every plugin anchor and applies any later plugin
|
|
migrations; it is idempotent. The registry (`instance/plugins.json`) records
|
|
which revisions each plugin has applied in `migrations_applied`.
|
|
|
|
## Distribution conventions
|
|
|
|
For sister-site plugins (per [ADR-003](adr/ADR-003-plugin-distribution.md)):
|
|
|
|
- Plugin lives in its own git repo: `<git-host>/<your-site>/<pluginname>`
|
|
- Adopting site clones or symlinks into their `<repo>/plugins/<name>/`
|
|
- Plugin manifest declares `core_version` range matching the framework version they target
|
|
- Plugin readme explains: what it tracks, who maintains it, where to file issues
|
|
|
|
<a id="lean-builds"></a>
|
|
## Lean per-site builds
|
|
|
|
A site ships only the plugins it chose; a site that never wants warranty /
|
|
guides / network never carries that code (see
|
|
[ADR-013](adr/ADR-013-plugin-catalog-and-lean-builds.md) and
|
|
[ADR-014](adr/ADR-014-schema-lean-per-site.md)). Three layers make a build lean:
|
|
|
|
- **Backend code** - `scripts/build-site.sh <profile>` stages `shopdb/core` plus
|
|
only the chosen plugins' directories (and their hard-dependency closure). A
|
|
plugin a site did not choose is absent from the backend tree.
|
|
- **Frontend code** - `SITE_PLUGINS=machines,printers npm run build` (via
|
|
`scripts/stage-frontend.mjs`) stages only those plugins' `frontend/` dirs and
|
|
codegens the route table. **Exception:** a `plugins/<name>/frontend/` dir with
|
|
**no `manifest.json`** is a CORE feature (e.g. `applications`), not a per-site
|
|
plugin, and is ALWAYS staged regardless of `SITE_PLUGINS` - otherwise a lean
|
|
build would lose a core page.
|
|
- **Database** - the shared core Alembic baseline creates every plugin's tables,
|
|
so a lean site provisions them and then drops the ones it does not use with
|
|
`flask plugin prune-schema` (ADR-014). Run it once at provisioning, after
|
|
`flask db upgrade` and `flask plugin upgrade-all`; see
|
|
[DEPLOY.md](DEPLOY.md).
|
|
|
|
**Menus follow the build, not a plugin flag.** The sidebar nav, the settings
|
|
rail, and the Displays links all gate on whether the target route was actually
|
|
staged into this build (the router's own route table), not on a registry
|
|
"enabled" flag. So a lean site never shows a menu entry that dead-ends on a
|
|
blank page - an omitted plugin's nav item, settings cards, and kiosk links all
|
|
disappear together. Shopfloor Dashboard is a core view but is gated on the
|
|
notifications plugin (its only data source), so it drops when notifications is
|
|
not in the build.
|
|
|
|
## Naming policy
|
|
|
|
Plugin names follow the framework's naming convention (lowercase concatenated, no underscores or dashes; full words preferred over acronyms). See [CONTRIBUTING.md](../CONTRIBUTING.md). Plugin name collisions across sites are not enforced; the convention recommends prefixing site-specific plugins with the site code (e.g. `sitecode-shippingstation`) when there is risk of overlap.
|