@ericrisco/rsc 3.3.1 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/manifest.json +43 -22
- package/package.json +1 -1
- package/scripts/lib/default-skill-floor.js +5 -1
- package/scripts/lib/domains.js +2 -2
- package/scripts/lib/retired-skills.js +4 -0
- package/scripts/rsc.js +1 -1
- package/skills/design/SKILL.md +4 -3
- package/skills/design/evals/cases.yaml +2 -2
- package/skills/ftd/SKILL.md +1 -1
- package/skills/react/SKILL.md +2 -1
- package/skills/ux/SKILL.md +149 -0
- package/skills/ux/THIRD_PARTY.md +32 -0
- package/skills/ux/evals/cases.yaml +40 -0
- package/skills/ux/references/flows.md +124 -0
- package/skills/ux/upstream/UPSTREAM.json +59 -0
- package/skills/ux/upstream/ux-designer/GUIDE.md +180 -0
- package/skills/ux/upstream/ux-designer/LICENSE +21 -0
- package/skills/ux/upstream/ux-designer/references/01-core-principles.md +251 -0
- package/skills/ux/upstream/ux-designer/references/02-laws-of-ux.md +330 -0
- package/skills/ux/upstream/ux-designer/references/03-accessibility.md +411 -0
- package/skills/ux/upstream/ux-designer/references/04-visual-design.md +433 -0
- package/skills/ux/upstream/ux-designer/references/05-information-architecture.md +432 -0
- package/skills/ux/upstream/ux-designer/references/06-interaction-design.md +495 -0
- package/skills/ux/upstream/ux-designer/references/07-forms-and-inputs.md +491 -0
- package/skills/ux/upstream/ux-designer/references/08-mobile-ux.md +539 -0
- package/skills/ux/upstream/ux-designer/references/09-ux-writing.md +493 -0
- package/skills/ux/upstream/ux-designer/references/10-user-research.md +533 -0
- package/skills/ux/upstream/ux-designer/references/11-design-systems.md +618 -0
- package/skills/ux/upstream/ux-designer/references/12a-presence-awareness.md +395 -0
- package/skills/ux/upstream/ux-designer/references/12b-conflict-resolution-sync.md +420 -0
- package/skills/ux/upstream/ux-designer/references/13a-canvas-navigation.md +388 -0
- package/skills/ux/upstream/ux-designer/references/13b-canvas-objects-performance.md +559 -0
- package/skills/ux/upstream/ux-designer/references/14-ai-ux-patterns.md +511 -0
- package/skills/ux/upstream/ux-designer/references/15-ethical-design.md +419 -0
- package/skills/ux/upstream/ux-designer/references/16-onboarding.md +430 -0
- package/skills/ux/upstream/ux-designer/references/17-notifications.md +461 -0
- package/skills/ux/upstream/ux-designer/references/18-data-visualization.md +453 -0
- package/skills/ux/upstream/ux-designer/references/19-search-ux.md +479 -0
- package/skills/ux/upstream/ux-designer/references/20-emotional-design.md +382 -0
- package/skills/ux/upstream/ux-designer/references/21-data-tables.md +629 -0
- package/skills/ux/upstream/ux-designer/references/22-performance-ux.md +626 -0
- package/skills/ux/upstream/ux-designer/references/23-internationalization.md +347 -0
- package/skills/ux/upstream/ux-designer/references/24-voice-and-multimodal.md +308 -0
- package/skills/ux/upstream/ux-designer/references/25a-barcode-camera-scanning.md +342 -0
- package/skills/ux/upstream/ux-designer/references/25b-barcode-scanner-workflows.md +412 -0
- package/skills/ux/upstream/ux-designer/references/25c-barcode-display.md +277 -0
- package/skills/ux/upstream/ux-usability-foundations/GUIDE.md +285 -0
- package/skills/ux/upstream/ux-usability-foundations/LICENSE +21 -0
- package/skills/ux/upstream/ux-usability-foundations/references/anti-patterns.md +267 -0
- package/skills/ux/upstream/ux-usability-foundations/references/checklists.md +130 -0
- package/skills/ux/upstream/ux-usability-foundations/references/decision-prompts.md +340 -0
- package/skills/ux/upstream/ux-usability-foundations/references/principle-cards.md +449 -0
- package/skills/worktrees/SKILL.md +19 -5
- package/targets/branch-guard.mjs +59 -4
- package/targets/clone-bootstrap.mjs +1 -1
- package/targets/session-memory-adapter.mjs +2 -2
- package/targets/team-safe-start.mjs +1 -0
- package/targets/worktree-reaper.mjs +14 -1
- package/skills/ui-engineering/SKILL.md +0 -113
- package/skills/ui-engineering/evals/cases.yaml +0 -38
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
# Scanner-Driven Workflows
|
|
2
|
+
|
|
3
|
+
Warehouse, logistics, retail POS, field service, and healthcare apps where the **scan is
|
|
4
|
+
the primary input**. The devices are rugged handhelds, ring scanners, keyboard-wedge USB or
|
|
5
|
+
Bluetooth scanners, and fixed-mount or presentation scanners. The worker's eyes are on the
|
|
6
|
+
shelf, the parcel, or the patient, and their hands are busy, often gloved. Throughput is
|
|
7
|
+
high: GS1 targets 40–70 items per minute at POS. An unclear failure turns into a
|
|
8
|
+
workaround, and in healthcare workarounds hurt people.
|
|
9
|
+
|
|
10
|
+
This file also holds the **symbology and GS1 primer** that the other barcode files link to.
|
|
11
|
+
|
|
12
|
+
> Consumer camera scanning: [25a-barcode-camera-scanning.md](25a-barcode-camera-scanning.md).
|
|
13
|
+
> Showing codes for others to scan: [25c-barcode-display.md](25c-barcode-display.md).
|
|
14
|
+
> Offline and sync UI in general: [12b-conflict-resolution-sync.md](12b-conflict-resolution-sync.md).
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Contents
|
|
19
|
+
|
|
20
|
+
- Devices & What They Mean for UX
|
|
21
|
+
- Scan-First Design
|
|
22
|
+
- Input Capture: Wedge vs. Intent/SDK
|
|
23
|
+
- Scan Routing
|
|
24
|
+
- Eyes-Free Feedback
|
|
25
|
+
- Error Recovery
|
|
26
|
+
- Verification Patterns & Healthcare (BCMA)
|
|
27
|
+
- Batch, Counters & Undo
|
|
28
|
+
- Manual Entry Fallback & Audit
|
|
29
|
+
- Screen Design for the Floor
|
|
30
|
+
- Offline, Retries & Idempotency
|
|
31
|
+
- Training & Multilingual Crews
|
|
32
|
+
- Symbology & GS1 Primer
|
|
33
|
+
- Quick Checklist
|
|
34
|
+
- Common Mistakes
|
|
35
|
+
- Sources
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Devices & What They Mean for UX
|
|
40
|
+
|
|
41
|
+
| Device | How scans arrive | UX consequence |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| Rugged Android handheld (Zebra, Honeywell) | Vendor service: Zebra DataWedge, Honeywell Scan Wedge / Intent API / SDK | Prefer intent/SDK delivery; hardware trigger works on every screen |
|
|
44
|
+
| Ring / wearable scanner (Zebra RS5100, ProGlove) | Bluetooth to a host device | Eyes aren't on the host screen. Route feedback to the wearable (haptic, LED) |
|
|
45
|
+
| USB/BT keyboard-wedge scanner | Keystrokes, like a keyboard | Needs a focused field; the browser can't tell it from typing; keyboard-layout issues |
|
|
46
|
+
| Fixed-mount / POS presentation | Continuous or presentation mode | Dedupe the same code staying in view; dual-marked items |
|
|
47
|
+
| Phone camera inside an ops app | Camera SDK | Fallback only. Turn it off when the device has a scanner (D365 "Scan with camera") |
|
|
48
|
+
|
|
49
|
+
**NFC/RFID** complement barcodes rather than replacing them. HF/NFC suits a deliberate tap
|
|
50
|
+
(badges, patient or asset tags). UHF RFID reads many tags without line of sight. DataWedge
|
|
51
|
+
reports `source=rfid` through the same intent, so one handler can accept both.
|
|
52
|
+
|
|
53
|
+
## Scan-First Design
|
|
54
|
+
|
|
55
|
+
- **The scan is the navigation.** Each step asks for one thing, the scan answers it, and
|
|
56
|
+
the app moves on. Tapping is the exception.
|
|
57
|
+
- **Name the expected scan** in a large step prompt: "Scan location", "Scan item",
|
|
58
|
+
"Scan pallet LP". Not a generic "Scan or enter here". Microsoft replaced that
|
|
59
|
+
placeholder in the D365 warehouse app.
|
|
60
|
+
- **One scan, many fields.** A GS1 code carries GTIN, batch, expiry, and quantity together.
|
|
61
|
+
Parse it and fill every field it covers, and show the screen only when the worker needs
|
|
62
|
+
to act (D365 multi-field GS1 policy with auto-submit).
|
|
63
|
+
- Show the **current task context** (order, location, remaining qty) at a size readable
|
|
64
|
+
at arm's length. The worker glances at it; they don't read it.
|
|
65
|
+
|
|
66
|
+
## Input Capture: Wedge vs. Intent/SDK
|
|
67
|
+
|
|
68
|
+
| | Keyboard wedge (keystroke output) | Intent / SDK |
|
|
69
|
+
|---|---|---|
|
|
70
|
+
| Setup | None; works in any text field | App integration per vendor |
|
|
71
|
+
| Needs focus in a field | **Yes** | No; works over dialogs and on any screen |
|
|
72
|
+
| Symbology known | Only via a configured AIM prefix | Yes (`label_type`, `aimId`) |
|
|
73
|
+
| Control chars (GS 0x1D) | Often lost, especially in web apps | Raw bytes available (`decode_data`) |
|
|
74
|
+
| Keyboard-layout bugs | Yes | No |
|
|
75
|
+
|
|
76
|
+
**Prefer intent/SDK** on dedicated devices. Use a wedge when you must: web apps, desktop
|
|
77
|
+
POS, BYO scanners.
|
|
78
|
+
|
|
79
|
+
**Wedge rules:**
|
|
80
|
+
- **Suppress the soft keyboard** on scan fields with `inputmode="none"`. Don't use
|
|
81
|
+
`readonly`, because a readonly field ignores the scanner's keystrokes too.
|
|
82
|
+
- **Configure a suffix** (Enter or Tab) to end the scan. Microsoft recommends letting the
|
|
83
|
+
*device* send Enter instead of auto-submitting in the app, because vendors differ: the
|
|
84
|
+
same app auto-submits on Zebra but waits for confirmation on Honeywell.
|
|
85
|
+
- **Configure a prefix** (AIM symbology ID or a custom one). It identifies scans far more
|
|
86
|
+
reliably than timing, and it tells GS1 data apart from plain data.
|
|
87
|
+
- **Keyboard layout:** the scanner maps characters using its *own* keyboard-country
|
|
88
|
+
setting (US by default). On a German host, Y and Z swap and punctuation breaks. If
|
|
89
|
+
a scan fails format validation, say "Scanner keyboard layout may not match" instead
|
|
90
|
+
of "Item not found".
|
|
91
|
+
- Scanner keystrokes can trigger browser shortcuts. Capture and consume them during a scan burst.
|
|
92
|
+
- **Honeywell** opens URL barcodes in the browser by default (`DATA_PROCESSOR_LAUNCH_BROWSER`
|
|
93
|
+
= true), so no read event reaches your app. Turn it off for GS1 Digital Link or URL codes.
|
|
94
|
+
- **Zebra** keystroke output doesn't deliver control characters as key events to web
|
|
95
|
+
apps by default. GS1 separators vanish (see the primer).
|
|
96
|
+
|
|
97
|
+
**Telling a wedge scan from typing** (use only when you can't use a prefix or intent).
|
|
98
|
+
The thresholds are defaults from the widely used onScan.js library, not a standard.
|
|
99
|
+
Calibrate them per device. Timing breaks with configured inter-character delays (DataWedge allows
|
|
100
|
+
up to 1000 ms), slow Bluetooth HID, and remote-desktop sessions.
|
|
101
|
+
|
|
102
|
+
```js
|
|
103
|
+
// Timing heuristic: humans type ~100-200 ms/char, scanners burst in a few ms/char.
|
|
104
|
+
const MAX_GAP = 30, MIN_LEN = 6; // onScan.js defaults; calibrate per device
|
|
105
|
+
let buf = '', last = 0;
|
|
106
|
+
addEventListener('keydown', e => {
|
|
107
|
+
if (e.timeStamp - last > MAX_GAP * 3) buf = ''; // long gap -> new burst
|
|
108
|
+
last = e.timeStamp;
|
|
109
|
+
if (e.key === 'Enter' || e.key === 'Tab') {
|
|
110
|
+
if (buf.length >= MIN_LEN) { e.preventDefault(); onScan(buf); }
|
|
111
|
+
buf = ''; return;
|
|
112
|
+
}
|
|
113
|
+
if (e.key.length === 1) buf += e.key; // printable only; GS (0x1D) may not arrive
|
|
114
|
+
}, true); // capture phase: independent of focus
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
This doesn't stop the characters from also landing in a focused input. Route the scan
|
|
118
|
+
explicitly, or clear the field on detection.
|
|
119
|
+
|
|
120
|
+
## Scan Routing
|
|
121
|
+
|
|
122
|
+
- **Route by content, not only by focus.** Check the symbology or prefix, parse the payload,
|
|
123
|
+
then decide: SSCC → pallet, GTIN → item, location-label pattern → location. The focused
|
|
124
|
+
field is a hint, not the only rule.
|
|
125
|
+
- **Global listener.** A scan must work while an error, confirmation, or options dialog is
|
|
126
|
+
open. D365 added a dedicated global listener after dialogs were swallowing scans.
|
|
127
|
+
- **Transient UI never steals focus.** A success toast on iOS once left the D365 scanner
|
|
128
|
+
stuck in a non-ready state.
|
|
129
|
+
- **Unexpected type at this step** (e.g. a location scanned when the step wants an item):
|
|
130
|
+
say what was scanned and what's expected ("That's location A-12-03. Scan the item.").
|
|
131
|
+
If the intent is clear, offer the jump.
|
|
132
|
+
- **Unknown GS1 AIs:** skip the element rather than rejecting the whole scan (Microsoft's
|
|
133
|
+
recommended setting). Log it.
|
|
134
|
+
- Keep the scan button for scanning only. OCR, RFID, and other capture methods get their own
|
|
135
|
+
controls (SAP Fiori).
|
|
136
|
+
|
|
137
|
+
## Eyes-Free Feedback
|
|
138
|
+
|
|
139
|
+
Every scan produces **sound + haptic + visual** feedback, distinct for each outcome, and
|
|
140
|
+
readable without looking closely at the screen.
|
|
141
|
+
|
|
142
|
+
| Outcome | Sound | Haptic | Visual |
|
|
143
|
+
|---|---|---|---|
|
|
144
|
+
| Accepted | Short, high beep | Short single pulse | Full-screen green flash ~1 s + ✓ + value |
|
|
145
|
+
| Warning (accepted, check something) | Distinct mid tone | Two short pulses | Amber banner + text |
|
|
146
|
+
| Rejected / mismatch | Low, long, or repeated tones | Long or double pulse | Red full-screen state + ✕ + reason; stays until acknowledged or rescanned |
|
|
147
|
+
|
|
148
|
+
- The conventions come from Zebra's classic beeper codes (short high = good decode; long
|
|
149
|
+
low = error), D365/ProGlove wearable haptics (single crisp pulse = OK; double pulse =
|
|
150
|
+
"stop and check the screen"), and the DataWedge decode screen notification (green overlay,
|
|
151
|
+
1000 ms default, adjustable 500–1500 ms).
|
|
152
|
+
- **Never colour alone** (WCAG 1.4.1). Pair colour with an icon, text, and a sound and
|
|
153
|
+
haptic pattern that differ per outcome.
|
|
154
|
+
- **Too fast:** if the system can't keep up, say so with a distinct alert and "rescan"
|
|
155
|
+
(D365 added exactly this).
|
|
156
|
+
- Give **per-user volume and vibration settings** (D365: vibration 0–5, sound 0–10, separate
|
|
157
|
+
success/failure/warning sounds). Floors are loud, and hospital wards are quiet at night.
|
|
158
|
+
- **Meaningless beeps get muted.** In Koppel's BCMA study, staff disabling audio alarms was a
|
|
159
|
+
workaround, and confusing alert beeps and noise were listed as causes. Keep the sound
|
|
160
|
+
vocabulary small and distinct.
|
|
161
|
+
- Wearables: send the result to the ring or glove (LED + haptic). The host screen may be in a
|
|
162
|
+
pocket or on a cart.
|
|
163
|
+
|
|
164
|
+
## Error Recovery
|
|
165
|
+
|
|
166
|
+
| Situation | Handling |
|
|
167
|
+
|---|---|
|
|
168
|
+
| Wrong item for this pick | Block. Show expected vs scanned (name + image), error feedback, require a rescan. No "accept anyway" without a reasoned, audited override |
|
|
169
|
+
| Duplicate scan | Same code in view: same-symbol timeout. Same code via two channels (wedge + intent both on): dedupe (D365 duplicate-scan protection). Intentional repeat: count it and show the new total |
|
|
170
|
+
| Unknown code | Show the raw value and symbology, and offer manual lookup or "report label". Never add unknown barcodes to the master data on the spot (see ISMP below) |
|
|
171
|
+
| Over-scan (qty exceeded) | Stop at the limit, show "10 of 10 — this one is extra", and offer to put it back or report it |
|
|
172
|
+
| Invalid format / check digit | "Couldn't read that correctly — rescan", not "Not found". Possibly a short read or layout issue |
|
|
173
|
+
| Server error | Show the server's **specific** message. D365 had to fix a generic failure message that hid it |
|
|
174
|
+
|
|
175
|
+
- **No modal traps.** Error states clear with the next valid scan or a trigger press, not only
|
|
176
|
+
by tapping a small OK button with gloves on.
|
|
177
|
+
- **Crowded labels:** enable picklist mode (decode only what's under the crosshair) or ask
|
|
178
|
+
the user to cover the other codes.
|
|
179
|
+
- **Dual-marked retail items** (1D + 2D within 50 mm): count them once.
|
|
180
|
+
|
|
181
|
+
## Verification Patterns & Healthcare (BCMA)
|
|
182
|
+
|
|
183
|
+
**Warehouse:** location → item → quantity confirmation, where each scan verifies the
|
|
184
|
+
previous instruction. A confirmation scan (D365 "ProductConfirmation") is cheaper than
|
|
185
|
+
a mis-pick.
|
|
186
|
+
|
|
187
|
+
**Barcode medication administration** is the best-studied scanning workflow:
|
|
188
|
+
- **Poon et al., NEJM 2010** (14,041 administrations): with BCMA + eMAR, non-timing
|
|
189
|
+
administration errors fell 41.4%, potential ADEs from them fell 50.8%, timing errors fell
|
|
190
|
+
27.3%, and transcription errors were eliminated. Errors were reduced, not eliminated.
|
|
191
|
+
- **Koppel et al., JAMIA 2008:** 15 workaround types and 31 causes. Patient wristbands were
|
|
192
|
+
taped to carts, doorjambs, or belt rings; a single package was scanned for several doses;
|
|
193
|
+
documentation happened before administration; audio alarms were disabled. Causes included
|
|
194
|
+
unreadable or crinkled labels, chewed wristbands, non-barcoded meds, dying batteries, poor
|
|
195
|
+
Wi-Fi, and emergencies.
|
|
196
|
+
- **van der Veen et al., JAMIA 2018:** workarounds in 66% of administrations, with 3.06×
|
|
197
|
+
the odds of error. The most common were not scanning at all, and no wristband.
|
|
198
|
+
- **ISMP:** hard-stop product scanning; overrides only for real emergencies; track compliance
|
|
199
|
+
and override rates; fix the barriers behind workarounds. In an ISMP case, adding
|
|
200
|
+
unscannable barcodes on the fly let a strength mismatch (15 mg vs 5 mg) get overridden.
|
|
201
|
+
|
|
202
|
+
**Design takeaways:**
|
|
203
|
+
- Make **compliance easier than the workaround**: bedside wristband reprint, a flow that
|
|
204
|
+
works offline, and readable feedback in dim rooms.
|
|
205
|
+
- Scan the patient *and* the medication. A manual-key path must still run the same
|
|
206
|
+
verification.
|
|
207
|
+
- Overrides are visible, need a selected reason, and are audited.
|
|
208
|
+
- US drug barcodes are changing: the FDA's 2026 final rule moves to a 12-digit NDC and allows
|
|
209
|
+
2D barcodes (effective 2033, with a transition to 2036). Parsers must accept both NDC
|
|
210
|
+
lengths and 2D symbols.
|
|
211
|
+
|
|
212
|
+
## Batch, Counters & Undo
|
|
213
|
+
|
|
214
|
+
- **Continuous scanning:** show a running count and the **last scanned value** prominently.
|
|
215
|
+
Allow **one-tap undo of the last scan** in a non-modal way. (There's no published standard;
|
|
216
|
+
this is the common pattern.)
|
|
217
|
+
- **Batch round trips.** Sending a server request per scan doesn't scale at many scans per
|
|
218
|
+
second (Microsoft's multi-scan pages). Collect scans locally and submit them in one call
|
|
219
|
+
with per-item results.
|
|
220
|
+
- **Multi-barcode capture** (Zebra NG SimulScan) reads several codes per trigger. Show
|
|
221
|
+
which codes were read and which were missed on a visual of the label.
|
|
222
|
+
- **Quantity from the scan** can override the default ("PO for 10, scanned 5"), but only
|
|
223
|
+
when configured, and the difference is shown.
|
|
224
|
+
|
|
225
|
+
## Manual Entry Fallback & Audit
|
|
226
|
+
|
|
227
|
+
- **Every scan step has a manual path.** Labels get crinkled, smudged, torn, missing, or
|
|
228
|
+
printed on a curved surface (ISMP asked manufacturers to stop printing across round
|
|
229
|
+
surfaces).
|
|
230
|
+
- **Validate typed and scanned values the same way:** check digit, field ranges (month
|
|
231
|
+
01–12), length limits, numeric-only fields.
|
|
232
|
+
- Use a numeric keypad for numeric IDs (`inputmode="numeric"`), and support external numpads.
|
|
233
|
+
- **Record the input method** (scan vs manual vs override) with a reason. Track the manual
|
|
234
|
+
and override rate per user, site, and product. A rising rate points to a bad label or a
|
|
235
|
+
broken flow, not a bad worker.
|
|
236
|
+
|
|
237
|
+
## Screen Design for the Floor
|
|
238
|
+
|
|
239
|
+
- **Scalable UI.** D365 gives text scale 70–400% and button scale 50–200%, plus a
|
|
240
|
+
high-contrast theme. Offer comparable ranges.
|
|
241
|
+
- **Handedness.** Let the user put the primary button bottom-right or bottom-left (D365
|
|
242
|
+
"best button position").
|
|
243
|
+
- **Gloves.** Glove sensitivity is a *device* touch-panel mode (Zebra: glove, wet, finger).
|
|
244
|
+
The app's part is larger targets. The bare-hand baseline is ~9 mm (48dp; Parhi et al.
|
|
245
|
+
found 9.2–9.6 mm for one-handed thumb use). The "15–20 mm for gloves" figures are vendor
|
|
246
|
+
blog heuristics, so test with the real gloves.
|
|
247
|
+
- **Sunlight and freezers.** Reflections collapse contrast. Use a high-contrast theme,
|
|
248
|
+
heavy weights, no light-grey text, and never colour-only state.
|
|
249
|
+
- **Hardware trigger** scans from every screen, and a trigger press must never activate an
|
|
250
|
+
on-screen button by accident (D365 fixed a trigger submitting a summary step).
|
|
251
|
+
- **Product photo** on pick steps allows visual confirmation alongside the scan.
|
|
252
|
+
- **Shared devices:** make the signed-in worker obvious (name plus a per-user colour theme, as in D365).
|
|
253
|
+
- Small truck-mount and vehicle screens (~640 px) need their own layout.
|
|
254
|
+
|
|
255
|
+
## Offline, Retries & Idempotency
|
|
256
|
+
|
|
257
|
+
- **Every scan transaction gets a client ID, and the server dedupes it.** D365 once resent
|
|
258
|
+
a submitted page after a timeout without telling the worker, which could complete warehouse
|
|
259
|
+
work twice.
|
|
260
|
+
- **Tell the worker about retries**, and never silently resubmit.
|
|
261
|
+
- **Keep in-progress state** when the network drops. Don't bounce the worker to sign-in and
|
|
262
|
+
lose the task (another D365 fix).
|
|
263
|
+
- Wi-Fi dead zones cause workarounds (Koppel), so offline or degraded mode is a requirement.
|
|
264
|
+
Queue scans locally with a visible pending count, sync with per-item results, and show
|
|
265
|
+
conflicts (e.g. stock already moved) as a reviewable list. See
|
|
266
|
+
[12b](12b-conflict-resolution-sync.md).
|
|
267
|
+
|
|
268
|
+
## Training & Multilingual Crews
|
|
269
|
+
|
|
270
|
+
There's little research here; these are heuristics:
|
|
271
|
+
- Scan-driven steps need less reading. Short verbs plus icons, and sound and haptics that
|
|
272
|
+
carry meaning without language.
|
|
273
|
+
- **Language per user, not per device.** Shared devices change hands every shift.
|
|
274
|
+
- Step instructions that can be switched off once learned (D365 "Don't show again").
|
|
275
|
+
- Test RTL layouts for the crews you actually have.
|
|
276
|
+
- Inadequate training is a documented cause of workarounds (Koppel). Build a practice or
|
|
277
|
+
sandbox mode.
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Symbology & GS1 Primer
|
|
282
|
+
|
|
283
|
+
### Symbologies
|
|
284
|
+
|
|
285
|
+
| Symbology | AIM ID | Typical use |
|
|
286
|
+
|---|---|---|
|
|
287
|
+
| EAN-13 / UPC-A / UPC-E | `]E0` | Retail item at POS |
|
|
288
|
+
| EAN-8 | `]E4` | Small retail items |
|
|
289
|
+
| ITF-14 | `]I1` (scanner checked the check digit) / `]I0` | Outer cartons |
|
|
290
|
+
| GS1-128 | `]C1` | Logistics labels: SSCC, batch, expiry |
|
|
291
|
+
| Code 128 (non-GS1) | `]C0` | Internal IDs |
|
|
292
|
+
| Code 39 | `]A0` | Legacy internal |
|
|
293
|
+
| GS1 DataBar | `]e0` | Fresh food, coupons |
|
|
294
|
+
| GS1 DataMatrix | `]d2` | Healthcare UDI, pharma |
|
|
295
|
+
| Data Matrix with GS1 Digital Link | `]d1` | Retail 2D |
|
|
296
|
+
| QR with GS1 Digital Link / GS1 QR | `]Q1` / `]Q3` | Retail 2D, consumer links |
|
|
297
|
+
| PDF417 | — | IDs, tickets, boarding passes |
|
|
298
|
+
|
|
299
|
+
- AIM identifiers are **generated by the decoder**, not stored in the symbol, and they're
|
|
300
|
+
case-sensitive. Have the scanner prefix them so the app can tell `]C1` (GS1) from `]C0`
|
|
301
|
+
(plain) without guessing.
|
|
302
|
+
- **Enable only the symbologies the screen needs.** Zebra recommends disabling every
|
|
303
|
+
decoder the app doesn't need, to improve scanning performance. Honeywell likewise warns
|
|
304
|
+
that enabling everything degrades decoding. Use per-screen profiles (DataWedge profiles
|
|
305
|
+
bind to the app or activity).
|
|
306
|
+
- **Short reads:** ITF and Code 39 without a fixed length or check digit can decode a
|
|
307
|
+
fragment as a valid shorter number. If you must enable them, restrict lengths.
|
|
308
|
+
- 1D laser scanners can't read 2D codes or (reliably) screens. See [25c](25c-barcode-display.md).
|
|
309
|
+
|
|
310
|
+
### GS1 element strings
|
|
311
|
+
|
|
312
|
+
- Element strings look like `(01)09521101530001(17)210119(10)AB-123`. The parentheses
|
|
313
|
+
exist **only in the human-readable text**, never in the data.
|
|
314
|
+
- **FNC1 in the first position** marks a GS1 symbol. Variable-length fields are ended by a
|
|
315
|
+
separator, which **decodes as `<GS>` (ASCII 29, 0x1D)**. GS1 warns that receiving systems
|
|
316
|
+
often mangle it, and keyboard wedges often drop it. Configure the scanner to substitute a
|
|
317
|
+
printable character (e.g. `~`), or use intent or raw-byte delivery.
|
|
318
|
+
- **Predefined-length AIs** are recognised by their first two digits only: 00, 01, 02, 11–17,
|
|
319
|
+
20, 31–36, 41. Every other AI needs a separator unless it comes last, **even if its own
|
|
320
|
+
definition says "fixed length"**.
|
|
321
|
+
- Common AIs:
|
|
322
|
+
|
|
323
|
+
| AI | Meaning | Format |
|
|
324
|
+
|---|---|---|
|
|
325
|
+
| 00 | SSCC (logistic unit) | 18 digits |
|
|
326
|
+
| 01 | GTIN | 14 digits |
|
|
327
|
+
| 10 | Batch/lot | up to 20 alphanumeric |
|
|
328
|
+
| 17 | Expiry date | YYMMDD |
|
|
329
|
+
| 21 | Serial number | up to 20 alphanumeric |
|
|
330
|
+
| 30 | Variable count | up to 8 digits |
|
|
331
|
+
| 310n | Net weight, kg (n = decimals) | 6 digits |
|
|
332
|
+
|
|
333
|
+
- **Dates:** YYMMDD, with the century resolved within −49 to +50 years of today. **DD = 00
|
|
334
|
+
means the last day of the month** (`160200` = 2016-02-29). Show the resolved date, never
|
|
335
|
+
the raw "00".
|
|
336
|
+
|
|
337
|
+
### Check digits
|
|
338
|
+
|
|
339
|
+
- GS1 mod-10 algorithm for GTIN, GLN, and SSCC: weight the digits ×3, ×1 alternately,
|
|
340
|
+
**starting with ×3 at the rightmost data digit**, sum them, and subtract the sum from the
|
|
341
|
+
next multiple of 10. It catches all single-digit errors and most adjacent transpositions.
|
|
342
|
+
- **The scanner usually does not check it.** EAN/UPC readers verify the check digit, and
|
|
343
|
+
ITF-14 does only when the AIM ID is `]I1`. For GS1-128, DataBar, DataMatrix, QR, and
|
|
344
|
+
DotCode, the symbol's own error detection guarantees the *decode* but not the GTIN.
|
|
345
|
+
GS1 says the application **shall** verify it. Validate typed entries the same way.
|
|
346
|
+
|
|
347
|
+
### GS1 Digital Link
|
|
348
|
+
|
|
349
|
+
- A URI form of GS1 data, e.g. `https://id.gs1.org/01/09520123456788/10/ABC123?17=180426`.
|
|
350
|
+
The primary key (01 GTIN, 00 SSCC, 414 GLN) and its qualifiers (10, 21) go in the path,
|
|
351
|
+
and attributes (17 expiry) go in the query. The GTIN is always zero-padded to 14 digits.
|
|
352
|
+
- **Any domain** may host it. Parse by path syntax, not by the `id.gs1.org` domain.
|
|
353
|
+
- The same code serves the shopper's phone (opens a web page) and the POS (reads the GTIN).
|
|
354
|
+
The POS app must **not** open a browser (see the Honeywell default above).
|
|
355
|
+
|
|
356
|
+
### Sunrise 2027 (2D at retail POS)
|
|
357
|
+
|
|
358
|
+
- GS1's goal: retail POS globally able to read the GTIN from both linear and 2D codes by
|
|
359
|
+
the **end of 2027**. Accepted 2D forms are GS1 DataMatrix, and Data Matrix or QR carrying
|
|
360
|
+
GS1 Digital Link.
|
|
361
|
+
- It's a milestone, not a switch-off. Products keep the linear barcode until 90% of POS
|
|
362
|
+
systems are 2D-capable, so POS must **dedupe dual-marked items**.
|
|
363
|
+
- The opportunity is the extra data at the till: block sales of expired items, flag recalled
|
|
364
|
+
batches.
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## Quick Checklist
|
|
369
|
+
|
|
370
|
+
- [ ] Each step names the expected scan; one GS1 scan fills every field it covers
|
|
371
|
+
- [ ] Intent/SDK delivery on dedicated devices; wedge fields use `inputmode="none"` and a suffix
|
|
372
|
+
- [ ] Scanner prefix (AIM ID) configured; scans routed by content and type, not only focus
|
|
373
|
+
- [ ] Scans work over dialogs; toasts and transient UI never steal focus
|
|
374
|
+
- [ ] Distinct success/warning/error sound + haptic + full-screen visual; not colour-only
|
|
375
|
+
- [ ] Wrong / duplicate / unknown / over-scan each have a specific message and a rescan path; no modal traps
|
|
376
|
+
- [ ] Only needed symbologies enabled, per screen; ITF/Code 39 length-restricted
|
|
377
|
+
- [ ] App verifies check digits; GS separator survives the input path; DD=00 dates resolved
|
|
378
|
+
- [ ] Manual entry on every step, validated like scans, logged with method and reason
|
|
379
|
+
- [ ] Overrides reasoned, audited, and rate-tracked
|
|
380
|
+
- [ ] Client transaction IDs + server dedupe; no silent resubmits; offline queue with pending count
|
|
381
|
+
- [ ] Text/button scaling, handedness, high contrast, large targets tested with gloves
|
|
382
|
+
- [ ] Per-user language and sound/vibration settings on shared devices
|
|
383
|
+
|
|
384
|
+
## Common Mistakes
|
|
385
|
+
|
|
386
|
+
- A generic "Scan or enter" prompt on every step
|
|
387
|
+
- Scans lost because focus left the input, or a dialog was open
|
|
388
|
+
- Soft keyboard popping up over the screen on every scan field
|
|
389
|
+
- One beep for everything, or silence. Workers mute feedback that means nothing
|
|
390
|
+
- A red flash as the only sign of an error
|
|
391
|
+
- An error dialog that needs a precise tap to dismiss before the next scan
|
|
392
|
+
- Enabling every symbology "to be safe", which is slower and risks short reads
|
|
393
|
+
- Trusting the scanner to validate the GTIN check digit
|
|
394
|
+
- Hard-coding `id.gs1.org` or stripping GS characters in a GS1 parser
|
|
395
|
+
- Letting staff register unknown barcodes on the spot (the ISMP strength-mismatch case)
|
|
396
|
+
- A manual-entry path that skips the verification the scan would have done
|
|
397
|
+
- Silent retry after a timeout, completing the work twice
|
|
398
|
+
- Treating a high override rate as a training problem instead of a label or flow problem
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
## Sources
|
|
403
|
+
|
|
404
|
+
- [GS1 General Specifications](https://www.gs1.org/standards/barcodes-epcrfid-id-keys/gs1-general-specifications) (§5.1.3 symbology IDs, §7.2.7 check digit verification, §7.8 separators, §7.9 check digit) · [GS1 Digital Link URI syntax](https://ref.gs1.org/standards/digital-link/uri-syntax/) · [GS1 2D in retail](https://ref.gs1.org/guidelines/2d-in-retail/) · [GS1 US Sunrise 2027](https://www.gs1us.org/industries-and-insights/by-topic/sunrise-2027)
|
|
405
|
+
- [Zebra DataWedge — intent output](https://techdocs.zebra.com/datawedge/latest/guide/output/intent/) · [keystroke output](https://techdocs.zebra.com/datawedge/latest/guide/output/keystroke/) · [barcode input & feedback](https://techdocs.zebra.com/datawedge/latest/guide/input/barcode/) · [profiles](https://techdocs.zebra.com/datawedge/latest/guide/profiles/)
|
|
406
|
+
- [Honeywell Mobility SDK](https://sps.honeywell.com/us/en/software/productivity/development-tools/mobility-sdk-android) · [Honeywell — keyboard layout](https://sps-support.honeywell.com/s/article/Scanner-does-not-support-my-keyboard-layout-wrong-characters-are-displayed)
|
|
407
|
+
- [Microsoft D365 Warehouse Management — GS1 barcodes](https://learn.microsoft.com/en-us/dynamics365/supply-chain/warehousing/gs1-barcodes) · [auto-submit behavior](https://learn.microsoft.com/en-us/dynamics365/supply-chain/warehousing/warehouse-app-autosubmit-behavior) · [haptic feedback](https://learn.microsoft.com/en-us/dynamics365/supply-chain/warehousing/warehouse-app-haptic-feedback) · [user settings](https://learn.microsoft.com/en-us/dynamics365/supply-chain/warehousing/warehouse-app-user-settings-themes) · [what's new](https://learn.microsoft.com/en-us/dynamics365/supply-chain/warehousing/warehouse-app-whats-new) · [multi-scan pages](https://www.microsoft.com/en-us/dynamics-365/blog/it-professional/2018/12/20/customizing-the-warehouse-mobile-app-multi-scan-pages/)
|
|
408
|
+
- [MDN — inputmode](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/inputmode) · [onScan.js](https://github.com/axenox/onscan.js)
|
|
409
|
+
- [Poon et al., NEJM 2010 — BCMA and eMAR](https://www.nejm.org/doi/full/10.1056/NEJMsa0907115) · [Koppel et al., JAMIA 2008 — BCMA workarounds](https://pmc.ncbi.nlm.nih.gov/articles/PMC2442264) · [van der Veen et al., JAMIA 2018](https://academic.oup.com/jamia/article-abstract/25/4/385/4091349) · [ISMP workaround case (NABP)](https://nabp.pharmacy/news/blog/regulatory_news/ismp-common-workaround-contributes-to-override-of-barcode-alert/) · [ISMP — round surfaces](https://home.ecri.org/blogs/ismp-news/ismp-calls-for-manufacturers-to-stop-printing-medication-barcodes-across-round-surfaces)
|
|
410
|
+
- [FDA 2026 NDC format and barcode rule](https://www.federalregister.gov/documents/2026/03/05/2026-04368/revising-the-national-drug-code-format-and-drug-label-barcode-requirements) · [21 CFR 201.25](https://www.ecfr.gov/current/title-21/chapter-I/subchapter-C/part-201/subpart-A/section-201.25)
|
|
411
|
+
- [Parhi et al. 2006 — target size for one-handed thumb use](https://www.microsoft.com/en-us/research/wp-content/uploads/2006/01/parhi-mobileHCI06.pdf) · [Zebra touch panel modes](https://docs.zebra.com/us/en/mobile-computers/handheld/tc5-series/tc52-product-reference-guide/settings/display-settings/setting-touch-panel-mode.html)
|
|
412
|
+
- [RFID in healthcare scoping review](https://pmc.ncbi.nlm.nih.gov/articles/PMC9398041/)
|