Setup: manage multiple device instances per category (add/remove)
The data model was already multi-instance (lane_devices = one row per instance; assign always inserts) -- the limitation was UI-only. Make the whole flow support more than one of every category: - Backend: add DELETE /api/setup/assign/:id (unassign by id). /state now redacts secrets (pushPassword/webPassword/relayPassword) via a shared redactSecrets() also used by /assign -- it was returning raw config rows. - Web: SetupWizard reworked from one fixed slot per category into a list of assigned instances (driver/role/host + Remove) plus an "Add another" form. select-type config fields (e.g. printer role) now render as dropdowns. - api.ts: add fetchState(), unassignDevice(), Assignment/SetupState types. Verified via Fastify inject: two printers assigned to one lane both list, no secret leak, delete -> 204, delete unknown -> 404, count drops to 1. Full repo typechecks. Wiki: first-run-setup documents multi-instance + delete + redaction.
This commit is contained in:
@@ -27,17 +27,33 @@ each device's connection config.
|
||||
authenticated input push ([[device-input-flow]]) — the admin never touches the device's own web
|
||||
UI. **Fails the save** (no DB row) if the device can't be configured, so there are no
|
||||
orphan/half-configured rows. On success persists to `lane_devices`.
|
||||
4. **Complete** — `POST /api/setup/complete` marks the single-row `setup_state`.
|
||||
4. **Remove** — `DELETE /api/setup/assign/:id` (admin-only) drops one instance's row. Only our
|
||||
row is removed; the device itself is not un-hardened/un-configured (a stale push from an
|
||||
unknown device id is already rejected, and re-assigning reconfigures it).
|
||||
5. **Complete** — `POST /api/setup/complete` marks the single-row `setup_state`.
|
||||
|
||||
## Config granularity
|
||||
## Config granularity — multi-instance per category
|
||||
|
||||
Organized **per lane** — each lane gets an access controller, reader(s), and camera(s), each with
|
||||
its own connection settings. Matches the architecture's "mixable per lane" reality (a lane can
|
||||
serve permit holders via [[wiegand]] and casual via host-side reads on one relay — see
|
||||
[[entry-exit-readers]]).
|
||||
The data model is **multi-instance**: `lane_devices` holds **one row per instance**, keyed by a
|
||||
generated `id`, with no one-per-(lane, category) constraint. So a lane can have **more than one of
|
||||
every category** — e.g. two printers (an entry dispenser + a booth printer; see
|
||||
[[printer-roles-failover]]), multiple readers, multiple cameras. `assign` always inserts a new row
|
||||
(never an upsert), and `state` returns the full list.
|
||||
|
||||
The `SetupWizard` reflects this: each category shows the **list of assigned instances** for the
|
||||
current lane (with **Remove**) plus an **Add another** form — not a single fixed slot. `select`-type
|
||||
config fields (e.g. a printer's role) render as dropdowns.
|
||||
|
||||
Organized **per lane** — each lane gets its access controller(s), reader(s), camera(s), and
|
||||
printer(s), each with its own connection settings. Matches the architecture's "mixable per lane"
|
||||
reality (a lane can serve permit holders via [[wiegand]] and casual via host-side reads on one
|
||||
relay — see [[entry-exit-readers]]).
|
||||
|
||||
## Security notes
|
||||
|
||||
- The assign/state/complete endpoints require the **admin** role ([[local-jwt-auth]]).
|
||||
- The assign/state/delete/complete endpoints require the **admin** role ([[local-jwt-auth]]).
|
||||
- Device **credentials are stored in `lane_devices.config`** — protect at rest
|
||||
([[disk-os-hardening]]); device hosts belong on the isolated VLAN ([[network-isolation]]).
|
||||
- **Secrets are stripped on the way out**: `assign` and `state` both redact `pushPassword`,
|
||||
`webPassword`, and `relayPassword` from the returned config (the UI lists devices; it never
|
||||
needs the stored secrets).
|
||||
|
||||
+11
@@ -227,3 +227,14 @@ guarantee. Recorded in [[dingtian-relay]] (new Hardening section).
|
||||
- New page: [[printer-status-monitoring]]. Updated [[rongta-printer]], [[index]].
|
||||
- Open: capture the page's actual text for an ACTIVE fault (pull paper / open cover) to confirm
|
||||
the Yes flip; wire degraded/offline into failover + entry-flow all-down policy.
|
||||
|
||||
## [2026-06-15] ingest | Multi-instance device setup (add/remove per category)
|
||||
- Confirmed the data model was already multi-instance (lane_devices = one row per instance,
|
||||
assign always inserts); the limitation was UI-only (one slot per category).
|
||||
- Backend: added DELETE /api/setup/assign/:id (unassign); /state now redacts secrets
|
||||
(pushPassword/webPassword/relayPassword) via a shared redactSecrets() also used by /assign.
|
||||
- Web: SetupWizard reworked — each category lists assigned instances (with Remove) + "Add
|
||||
another" form; select-type config fields now render as dropdowns (fixes printer role input).
|
||||
- Verified via Fastify inject: 2 printers assigned to one lane -> both listed, no secret leak,
|
||||
delete -> 204, delete unknown -> 404, count drops to 1. Full repo typechecks (8/8).
|
||||
- Updated [[first-run-setup]].
|
||||
|
||||
Reference in New Issue
Block a user