Page:
ADR 003 plugin distribution
Pages
ADR 001 asset as platform contract
ADR 002 plugin versioning
ADR 003 plugin distribution
ADR 004 deployment topology
ADR 005 equipment vs measuringtools
ADR 006 collector contract
ADR 007 product versioning and releases
ADR 008 plugin migration ownership
ADR 009 frontend plugin gating
ADR 010 frontend plugin hooks
ADR 011 machines rename
ADR 012 geenforce manifest ownership
BACKUP RESTORE
COLLECTOR INTEGRATION
CONFIG
CONTRACT STABILITY
DEPLOY WINDOWS IIS
DEPLOY
GE ENFORCE CLIENT
GE ENFORCE DEPLOY
GE ENFORCE
Home
IMPORT ADOPTION
IMPORT API
INSTALL WINDOWS IIS
PILOT DEPLOY
PLUGIN EXTERNAL REPO
PLUGIN GUIDE
PLUGIN HOOKS
PLUGIN QUICKSTART
PLUGINS
PROPOSAL ge enforce plugin
README
ROADMAP
UPGRADE
Clone
1
ADR 003 plugin distribution
Cameron Proudlock edited this page 2026-07-13 19:51:21 -04:00
ADR-003: Plugin distribution model
- Status: ACCEPTED
- Date: 2026-05-08
- Deciders: cproudlock
Context
Sister sites adopting shopdb-flask need a way to:
- Install the framework
- Pick which plugins they want
- Build their own plugins for site-specific equipment
- Receive updates to both framework and plugins
Today, every plugin lives in the plugins/ directory of the framework repo. There is no separation between framework code and plugin code, no install / uninstall, and no way for a site to develop a plugin without forking the whole repo.
Three viable distribution models:
| Model | How a site installs a plugin |
|---|---|
| In-tree only | Fork the framework repo, add plugin under plugins/, run their own deploy. No separation. |
| Pip-installable plugins | Each plugin published as a Python package. Site does pip install shopdb-printers shopdb-network etc. Discovery via Python entry points. Framework loads any installed plugin that registers itself. |
| Git-based plugins | Each plugin lives in its own git repo. Site clones / submodules into plugins/<name>/. Loader picks them up from the directory. |
Decision
PROPOSED: Use a hybrid model with two clearly-labeled paths.
- Bundled plugins: a small set of plugins ships with the framework, in-tree at
plugins/. These are the reference implementations and the default install (printers, computers, network, equipment, usb, notifications). A site that wants only what's bundled needs no extra work. - External plugins: sister sites or third parties build plugins in their own git repos. The site running the framework drops the plugin into
plugins/<name>/(clone, submodule, or symlink) and runsflask plugin install <name>. No pip packaging required for v1.
Pip-installable plugins (Python entry-point discovery) are deferred to v2. The complexity is not justified until at least two sites are running their own plugins.
Consequences
Positive
- v1 is simple: filesystem-based discovery (already implemented in
shopdb/plugins/loader.py), works for both bundled and external plugins. - Sites can develop plugins without changing the framework repo.
- The
plugins/directory is already the canonical location, so no architectural change is needed.
Negative / cost
- No automatic update path for external plugins. Sites must
git pullin each plugin directory manually. Acceptable for v1; revisit when plugin count grows. - Multiple plugin authors writing in parallel can collide on namespace (e.g., two plugins both registering an
AssetTypenamed "Equipment"). Need a naming policy: plugin names and asset-type names should be prefixed with the site or org if not in the bundled set.
Neutral
- The existing in-tree pattern keeps working. This decision just formalizes it and clarifies the path for outside-the-tree plugins.
Alternatives considered
- Pip-installable from day one. Cleaner for the long term but adds packaging, entry-point registration, and CI steps. Premature for current scale (one site running, no sister-site plugins yet).
- In-tree only forever. Forces every site to fork. Doesn't scale beyond two or three sites.
- Submodules only. Forces git-submodule discipline on every adopting site. Submodules are notoriously fiddly. Rejected.
Open questions
- For external plugins, should there be a manifest field (
source_url) declaring where the plugin can be cloned from, soflask plugin installcould pull it for the site? Defer; manual clone is fine for v1. - Naming convention for non-bundled plugin directory names: prefix with site? (
gea-wjsf-shipping)? Adopt if and when we hit a name collision.
References
shopdb/plugins/loader.py(filesystem discovery)shopdb/plugins/cli.py(plugin install / uninstall command)- ADR-001 (defines what plugins target)
- ADR-002 (defines plugin version compatibility)
Docs
Install and operate
Data import
Plugins
Integrations
Project
ADRs
- ADR-001-asset-as-platform-contract
- ADR-002-plugin-versioning
- ADR-003-plugin-distribution
- ADR-004-deployment-topology
- ADR-005-equipment-vs-measuringtools
- ADR-006-collector-contract
- ADR-007-product-versioning-and-releases
- ADR-008-plugin-migration-ownership
- ADR-009-frontend-plugin-gating
- ADR-010-frontend-plugin-hooks
- ADR-011-machines-rename
- ADR-012-geenforce-manifest-ownership
- README
Proposals