Files
shopdb-flask/plugins/printedparts
cproudlock 035419fa51 ADR-015: stop shipping one site's values, and make the rule a gate
The scanner has been reporting the same count for weeks, which is what a rule
that only prints becomes. It now FAILS the build, and it looks where the leaks
actually were: PowerShell, the installer, the seeds, generated JSON, the
frontend - case-insensitively, across plugins, shopdb, scripts, deploy, tools.
A line that is deliberate declares itself with an ADR-015-OK marker and a
reason, so the claim is visible in review instead of tolerated in silence.

What it found, fixed here:

- The shadow client wrote one site's ShopDB URL into HKLM whenever the registry
  disagreed. At the site it was written for that reads as healing drift;
  anywhere else it overwrites the site's own address on every enforce cycle,
  and the site cannot win because the cycle repeats. The bay's value now wins,
  an explicit -BaseUrl seeds it, and with neither there is nothing honest to
  write, so it says so and skips.
- The kiosk dispatcher fell back to one plant's host when HKLM was unset, so a
  kiosk elsewhere quietly opened a server it has no business reaching. The
  fallback is now this site's site_base_url, baked in at seed time, and the
  dispatcher refuses rather than guessing when neither is set. Its legacy
  shortcut matcher derives the host from that URL instead of naming one.
- The OpenAPI generator hardcoded a production hostname into every spec it
  generated, which then published to a public wiki. The relative mount is the
  only server it can honestly name; a site passes its own by environment.
- Placeholders and examples in the UI and the client help offered real internal
  subnets and a real production URL. They now use documentation ranges.

Both publication gates - the export scrub and the docs publishability test -
carry the site patterns, which neither did. One plant's hostname, FQDN and
internal networks are out of the documentation and the generated specs.

Comments naming the reference site are reworded rather than deleted: the
reasoning is worth keeping, the plant name is not what makes it true.
2026-08-14 13:47:39 -04:00
..

Printedparts plugin

3D-printed parts inventory + kiosk checkout

This plugin was generated by flask plugin new printedparts. It satisfies the framework contract out of the box. Replace the example model and routes with your domain.

What's here

  • plugin.py - the PrintedpartsPlugin class extending BasePlugin. Edit init_app for custom setup, on_install to seed reference data.
  • models/printedparts.py - example Asset extension table. Replace examplefield with your domain fields.
  • api/routes.py - example list and detail endpoints. Add CRUD as needed.
  • schemas/__init__.py - marshmallow schema stub for request/response validation.
  • tests/test_plugin.py - smoke tests asserting contract compliance.
  • manifest.json - plugin metadata. Bump version on changes; keep core_version range broad.

Common edits

You want to... Do this
Add a hook (search, navigation, dashboard widget) Override the method in PrintedpartsPlugin. See docs/PLUGIN-HOOKS.md.
Accept external collector data Override get_collector_schema() to return a JSON Schema. See ADR-006.
Add another model Create models/<other>.py, export it in models/__init__.py, return it in get_models().
Add a CLI command Override get_cli_commands() returning a list of Click commands.

Frontend

Vue components for this plugin live under frontend/src/views/printedparts/ (per project convention). Backend scaffolding does not generate frontend yet; copy from an existing plugin's view files (e.g., frontend/src/views/network/) as a starting point.

Install and run

flask plugin install printedparts
flask db migrate -m "Add printedparts plugin tables"
flask db upgrade
pytest plugins/printedparts/tests/

References

  • docs/PLUGIN-HOOKS.md - canonical hook reference
  • docs/PLUGIN-QUICKSTART.md - 30-minute walkthrough
  • migrations/adr/ADR-001-asset-as-platform-contract.md - the platform contract
  • migrations/adr/ADR-002-plugin-versioning.md - versioning rules

Why the kiosk take endpoint is unauthenticated

POST /api/printedparts/kiosk/take is the product's first open WRITE (every other kiosk endpoint is a read). Accepted deliberately, against the criteria in docs/proposals/printedparts-plugin.md:

  1. Decrement-only: it can reduce stock of an active item, nothing else.
  2. Fully attributed: it refuses to act without a badge that resolves under the site policy; every action lands in the ledger with SSO + name + time.
  3. Bounded blast radius: worst case is stock counts driven low - visible in the ledger and reversible with an adjust.
  4. Physically rate-limited: it serves a touch screen on the shop floor; nothing enumerable, nothing worth scraping.

Any future open-write endpoint must clear the same bar.