Skip to main content

Browser scanner inventory implementation plan

Strategy

Implement browser scanner support as a workflow-local deep module with one completed-scan interface. Keyboard-wedge input is the cross-browser baseline; Web Serial is a progressive enhancement for Chromium desktop and scanners configured as CDC or virtual COM devices. WebHID is excluded until a named scanner requires a vendor-specific HID report adapter.

A scan selects a product in the existing Receive Inventory dialog. It never receives or adjusts inventory automatically. The existing quantity field and Receive confirmation remain the only mutation path.

Status

Implemented on 2026-08-05 for the Receive Inventory workflow. Focused automated coverage and a browser smoke with real key events plus an injected Web Serial capability are complete. Receive and product lookup require both store.inventory.write and store.products.read; inventory-only callers do not issue product-list requests. Physical scanner enumeration, operating-system drivers, enterprise policy, and per-model settings remain external hardware-validation dependencies; WebHID and adjacent inventory workflows remain out of scope.

Scope

Deliver:

  • focused manual and USB HID keyboard-wedge barcode capture;
  • Enter-terminated scan submission with leading-zero and alphanumeric preservation;
  • optional Web Serial connection with user-controlled serial settings;
  • incremental bounded serial framing across arbitrary stream chunks;
  • explicit serial connection, denial, error, unplug, disconnect, and cleanup states;
  • exact selected-store lookup through api.products.byBarcode;
  • stale lookup protection across scans, dialog lifecycle, and store changes;
  • recoverable no-match UI;
  • a reusable capture interface that can later be mounted in transfers, purchase-order receiving, and serialized inventory;
  • privacy protection: raw scan values are never logged or sent to analytics.

Do not deliver:

  • scan-triggered inventory mutations;
  • offline queues, cycle-count sessions, or retryable bulk adjustments;
  • a global route-aware scanner listener;
  • WebHID or vendor-specific report parsing;
  • backend authorization or endpoint changes;
  • unvalidated vendor/product chooser filters.

Module seams

These are the TDD test seams. Tests exercise only their public interfaces.

  1. ScannerCapture interface
    • Props: label, optional disabled, and onScan({ value, source }).
    • Observable behavior: focused manual/wedge input, Enter submission, modifier/composition exclusion, feature-detected serial controls, accessible status/errors, duplicate suppression, and unmount cleanup.
  2. ScanFramer interface
    • Accepts timestamped Uint8Array chunks and returns zero or more complete strings.
    • Observable behavior: partial/multiple frames, CR/LF/CRLF/Tab delimiters, Unicode chunk boundaries, bounded overflow discard, partial timeout, empty-frame discard, and reset.
  3. connectSerialScanner interface
    • Accepts a serial-capability adapter, validated connection options, and frame/state callbacks; returns a disconnect handle.
    • Observable behavior: chooser/open/read lifecycle, arbitrary chunks, cancellation/denial, fatal read errors, EOF/unplug, reader-lock release, port close, and idempotent disconnect.
  4. Receive Inventory workflow seam
    • Observable behavior through InventoryPage: a completed scan performs exact barcode lookup for the active store, selects the result, reports no match, ignores stale responses, and does not call api.inventory.receive until the user presses Receive.

Invariants

  • Barcodes remain strings; never parse or coerce them numerically.
  • Scanner capture emits only non-empty completed values.
  • Buffered serial input is bounded and cleared after timeout, overflow, disconnect, or unmount.
  • Direct serial access is requested only from a user action.
  • Unsupported browsers retain the complete wedge/manual path and do not show unusable serial controls.
  • A duplicate from the other transport may be suppressed briefly; repeated scans from the same transport remain distinct.
  • Workflow context owns lookup, authorization, stale-response handling, staging, and mutation.

Implementation plan

Follow these slices in order. Each behavior uses a red → green TDD cycle before moving to the next slice.

Slice 1 — keyboard-wedge capture

  1. Add a failing interactive component test for manual/keyboard-wedge entry ending in Enter.
  2. Implement the minimal ScannerCapture interface and focused input.
  3. Add failing cases for leading zeros, alphanumeric values, modifiers, IME composition, empty values, and explicit manual submission; implement each case minimally.
  4. Run the focused scanner capture tests.

Slice 2 — bounded serial framing

  1. Add a failing framer test for one CR-terminated frame split across chunks.
  2. Implement the minimal incremental framer.
  3. Add one failing case at a time for multiple frames, CRLF, LF, Tab, empty frames, Unicode chunk boundaries, overflow, timeout, and reset; implement each minimally.
  4. Run the focused framer tests.

Slice 3 — Web Serial lifecycle

  1. Add a failing lifecycle test using a fake serial-capability adapter and fake readable stream.
  2. Implement chooser, open, read, frame delivery, and disconnect.
  3. Add one failing case at a time for chooser cancellation, permission/open failure, fatal read error, EOF/unplug, lock release, close, and idempotent cleanup; implement each minimally.
  4. Connect the adapter to ScannerCapture behind runtime feature detection.
  5. Add serial-setting controls for baud rate, data bits, stop bits, parity, and flow control. Use explicit conservative defaults and do not claim a device is supported without hardware validation.
  6. Add cross-transport duplicate coverage and implementation.
  7. Run scanner capture and serial tests.

Slice 4 — Receive Inventory integration

  1. Add products.byBarcode to the existing page API mock.
  2. Add a failing interactive workflow test: scan 00123ABC, resolve the active-store product, show it selected, and prove inventory.receive was not called.
  3. Mount ScannerCapture in the Receive Inventory dialog and implement exact lookup with request-sequence and store-scope guards.
  4. Add failing cases for 404/no-match, non-404 error, rapid scans with stale completion, store change, and dialog close; implement each minimally.
  5. Preserve the existing explicit Receive mutation test.
  6. Run inventory behavior and scanner tests.

Slice 5 — documentation and operational policy

  1. Add the contextual research report and this implementation plan to the documentation index.
  2. Document keyboard-wedge configuration, Chrome/Edge-only direct serial behavior, serial defaults/settings, permission recovery, privacy behavior, and the unsupported-hardware boundary in the implementation report.
  3. Confirm the deployment Permissions-Policy does not deny serial; change it only if validation proves necessary.

Slice 6 — self-validation

  1. Run focused Bazel tests after every slice.
  2. Run //apps/websites/portals/retail:test, :typecheck, and :lint.
  3. Start the retail portal through Bazel/local-validation and smoke the wedge path with real keyboard events. Inspect serial unsupported-state behavior in a browser; physical Web Serial enumeration remains a named hardware-validation dependency.
  4. Run broad relevant targets on BuildBuddy Remote Bazel, including the retail build and repository tests required by CI.

Slice 7 — review and delivery

  1. Commit only isolated scanner and documentation changes on feat/browser-scanner-inventory.
  2. Push with the kenobi1337 GitHub account and create an informative PR containing scope, architecture, screenshots/evidence, test commands, known hardware limits, and post-merge risks.
  3. Run the required two-axis code review against origin/main: Standards and Spec in parallel.
  4. Correct every actionable finding, rerun affected validation, and repeat review when behavior changes.
  5. Wait for PR checks, diagnose failures from their primary logs, and revise until all required checks are green.
  6. Assess post-merge readiness against merge-result-sensitive workflows, generated docs/build inclusion, deployment headers, and the current base branch. Report any external physical-hardware validation separately; do not present it as completed without a device.