Write down the plugin nobody documented, and stop pointing at a deleted branch

PLUGINS.md listed 14 of the 15 bundled plugins. `backups` had no row: the
per-asset configuration backups the collector takes off shopfloor machines,
kind-pluggable, with view and download as separate permissions because a .reg
is a restorable artifact. Added, with the pointer that separates it from
BACKUP-RESTORE.md, which is the database and a different subject.

PLUGIN-LAB-PRINTEDPARTS said the finished implementation lives on branch
feat/printedparts-plugin. That branch was deleted in the v0.8.0 cleanup; only
the 17 lab-stage tags survived, and they are enough. Says so now, and warns
that the tags are a record of contract 0.11-0.13 rather than today's
conventions. Its manifest example carried core_version >=0.12.0 against a
shipped >=0.16.0.

The printer-assignment proposal still said the client script is not built. It
shipped and released, across v0.11.3 and v0.12.0, and the collector half that
contradicted the assigned-vs-observed split was retired in adc7ef4.

PROJECT-MAP regenerated for the test count.
This commit is contained in:
cproudlock
2026-08-24 14:05:24 -04:00
parent 7b79a444b8
commit 90da0a1c09
4 changed files with 23 additions and 9 deletions

View File

@@ -2,11 +2,17 @@
This is the literal, type-along guide to building a complete shopdb plugin, This is the literal, type-along guide to building a complete shopdb plugin,
using the 3D-printed-parts storefront as the example. Every core stage shows using the 3D-printed-parts storefront as the example. Every core stage shows
the actual code; the finished implementation lives on branch the actual code; the finished implementation is merged into `main`, and each
`feat/printedparts-plugin` with one commit per stage, tagged `lab-stage-01` stage is tagged `lab-stage-01` .. `lab-stage-17` - so `git show lab-stage-05` or
.. `lab-stage-17` - so `git show lab-stage-05` or
`git diff lab-stage-04 lab-stage-05` always has the complete answer, `git diff lab-stage-04 lab-stage-05` always has the complete answer,
including the long Vue files this guide abridges. including the long Vue files this guide abridges. (The `feat/printedparts-plugin`
branch these tags were cut from has since been deleted; the tags are what
survive, and they are enough.)
Read the stage tags as a historical record, not as today's conventions. They
were cut against plugin contract 0.11-0.13 and the framework has moved on - the
`core_version` floor below, and the frontend layout in the later stages, are
both current-day values rather than what `git show` will hand you.
What you are building: a catalog of 3D-printed parts (photo, description, What you are building: a catalog of 3D-printed parts (photo, description,
quantity on hand), a stock LEDGER attributing every take/restock/adjust to a quantity on hand), a stock LEDGER attributing every take/restock/adjust to a
@@ -93,7 +99,7 @@ the edit (imports/meta boilerplate unchanged from the scaffold):
"description": "3D-printed parts inventory + kiosk checkout", "description": "3D-printed parts inventory + kiosk checkout",
"display_name": "3D Printed Parts", "display_name": "3D Printed Parts",
"dependencies": ["employees"], "dependencies": ["employees"],
"core_version": ">=0.12.0,<1.0.0", "core_version": ">=0.16.0,<1.0.0",
"api_prefix": "/api/printedparts", "api_prefix": "/api/printedparts",
"default_enabled": false "default_enabled": false
} }

View File

@@ -22,6 +22,7 @@ These plugins are in `plugins/` in this repo. Enable per site with `flask plugin
| `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. | | `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). | | `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. | | `warranty` | Asset warranty tracking | Manual entry now, Dell / Lenovo / HP provider lookups later. Derived coverage status with report buckets. |
| `backups` | Per-asset configuration backups with revision history: NTLARS/DNC registry, part marker, UDC, CMM | 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 ## Plugin permissions

View File

@@ -86,6 +86,6 @@ Manifest-less directories under `plugins/` are core frontend surface and always
## Size ## Size
- test functions defined: **1233** (parametrised cases collect higher) - test functions defined: **1236** (parametrised cases collect higher)
- documented API paths: **285** (`docs/openapi.json`, regenerate with `scripts/gen_openapi.py`) - documented API paths: **285** (`docs/openapi.json`, regenerate with `scripts/gen_openapi.py`)

View File

@@ -1,10 +1,17 @@
# Proposal: assign printers to a machine in ShopDB, let the PC install them # Proposal: assign printers to a machine in ShopDB, let the PC install them
Status: ACCEPTED. Server half being built 2026-08-18 (relationship types and Status: SHIPPED AND RELEASED. Built out 2026-08-18/19; the client script is
rails, resolution helper, two endpoints, PC form section, `drivername`). The built too. The feature itself released in v0.11.3, the observation half and
client script is not built. `seed-from-observed` adoption in v0.12.0.
Author: planning session 2026-08-18. Author: planning session 2026-08-18.
One thing this proposal did NOT anticipate, resolved 2026-08-24 in `adc7ef4`:
the computers collector carried a `_sync_printer_links` that wrote
`defaultprinter` / `connectedto` rows straight from a PC report, which is the
ASSIGNED-vs-OBSERVED split this proposal rests on, broken from the other end.
It is retired; `defaultprinter` and `printers` are now ignored (not rejected) on
the collector payload. See [COLLECTOR-INTEGRATION.md](../COLLECTOR-INTEGRATION.md).
## 1. What this is ## 1. What this is
Today a printer reaches a shop-floor PC because a person walks up to it, opens Today a printer reaches a shop-floor PC because a person walks up to it, opens