Files
cproudlock 6ed3da1b64
Some checks failed
CI / backend (push) Failing after 1m43s
CI / naming (push) Successful in 2s
CI / frontend (push) Successful in 8s
CI / migrations-mysql (push) Failing after 8s
printedparts stage 7: the kiosk - scan bin, scan badge, keypad, take
Two open endpoints: an item lookup by scanned code and the take POST -
the product's first unauthenticated write, held to the decision
record's bar (decrement-only, badge-attributed server-side, bounded,
physically rate-limited; justification in the plugin README). The
/parts-kiosk route is a full-screen no-auth view beside /shopfloor: a
hidden always-focused input consumes keyboard-wedge scans for
whichever step is active, TouchKeypad (net-new 3x4 grid) takes the
quantity, and a success screen resets after a few seconds. Manual
type-in fallbacks cover damaged labels. Kiosk test proves open access,
the over-take guard, the badge policy, and cache==ledger afterward.
2026-07-17 07:49:13 -04:00

60 lines
2.7 KiB
Markdown

# 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
```bash
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.