PRD: Device registration, identity, activation & peripherals
| Module | Device | PRD ID | PRD-DEV-001 |
| Status | No item | FEAT | DEV |
| Epic | — | Plane | BANA-1539 |
| Date | 2026-07-21 | Version | v0.5 |
| Packages | @nx/commerce | URD | DEV |
| Surface | Client · Owner/MgrSale · POSBO · Ops | ||
| Owner | Device squad | ||
What Device does
The back office has a device fleet page - list, create, edit - and device search scoped to the merchants the user has joined. Every device is pinned to exactly one required merchant, carries an auto-generated Device Identifier, and has an operational Status field with a five-step lifecycle. The device type catalog covers 8 types today, including a Cash Drawer registered and selected exactly like any other device.
What's newly settled in this revision: identity, the login check, and activation
Revision v0.3 left a question open: what exactly does "auto-register on first login" mean, and how does "automatic activation" actually work? This v0.4 revision settles that business logic into three explicit rules, replacing the previously vague description:
- One device, one durable identifier. The Device Identifier cannot live only in the app's local memory (lost on uninstall) - it must be durable across reinstalls on the same hardware.
- Login is check-first, create-second. The app calls an API asking "does this identifier already belong to the current merchant?" - if yes, it operates normally, nothing is created; if no, the system creates a new device, in status NEW.
- Activation is a discrete action. A NEW device does not automatically become ACTIVATED. The system generates an Activation Code in two forms - a QR (camera scan) and a Barcode (scanner/manual entry, serving cameraless devices) - and someone must scan/enter that exact code and press "Activate." Each code is usable exactly once. This mechanism is chosen to not depend on browser storage, so it still works when ITP (Intelligent Tracking Prevention - a policy that blocks cookies or scripts tracking behavior across different websites) limits client-side storage duration and makes the automatic check in step 2 unreliable.
These three rules are forward-spec - no code exists today for the check-API, code generation, or single-use activation; the current flow is just the client creating/reusing a deviceId stored in local session state, with no guaranteed durability across reinstall and no explicit activation step.
Cash Drawer is a real device type
Cash Drawer (500_CASH_DRAWER) is registered and searched through the exact same flow as a POS terminal - not a stub, and not merely the cashDrawerEnabled flag on a POS terminal (a separate, also-real mechanism; see the Device URD for the distinction). The previous PRD revision under-documented the device type catalog entirely - it also omits the 300_BROWSER type, auto-registered by web sessions.
Fleet health has no visibility today
Nothing tracks whether a device is physically broken, under repair, or has been liquidated. The schema already carries lastMaintenanceAt / nextMaintenanceAt / vendor fields (Built), but nothing computes a due/overdue flag from them, nothing notifies anyone, and there is no "Faulty" or "Liquidated" concept anywhere - an owner finds out a POS terminal is broken only when a cashier can't ring up a sale and calls to complain.
1. Goals & Non-Goals
Goals
- (Built) A back-office device page - list, create, edit - with a sectioned form (general information, hardware config, software config, other settings), in both the client and BO apps.
- (Built) A required merchant assignment - every device belongs to exactly one merchant; there is no organizer ownership on the model.
- (Built) Device discoverability through the search index (including description-field matching), scoped to the merchants the user has joined.
- (Partial) A controlled operational Status field (new → active → deactivated → suspended → archived) with soft-delete and per-merchant code uniqueness. The values and soft-delete exist; transition validation is not enforced - status is a free CRUD field.
- (Planned, business logic settled in this revision) A durable device identifier - unchanged across app uninstall/reinstall on the same hardware.
- (Planned, business logic settled in this revision) Check-then-create on login - call an API checking whether the device already belongs to the current merchant; if yes, use it normally, if no, create a new device in status NEW.
- (Planned, business logic settled in this revision) Single-use Barcode/QR activation - a newly created device auto-generates an Activation Code (QR + Barcode); scanning/entering the code and pressing "Activate" moves it NEW → ACTIVATED; each code is usable once. Solves both the case of a browser failing to retain identity under ITP policy, and the case of a device with no QR-scan capability.
- (Planned) The peripheral & health stack: receipt printer, barcode scanner, SoundBox, and a heartbeat-driven health view with remote deactivation. None of these are wired on the backend - printing runs in the native POS client.
- (Built, previously undocumented) A Cash Drawer registered as its own device type, going through the same registration/lifecycle/search flow as any other device, and offered as a pick-list when opening a shift on a cash-drawer-enabled POS terminal.
- (Planned) Device Condition tracking (Working / Under Maintenance / Faulty), independent of the operational Status field.
- (Planned) Fault notification - marking a device Faulty pushes a real-time alert to the merchant's device/maintenance contact(s).
- (Planned) Maintenance due-date flagging - the fleet list flags a device as due/overdue based on the recorded next-maintenance date, with a reminder notification.
- (Planned) Retirement Reason on archive (Liquidated / Lost / Stolen / Replaced / Other).
Non-Goals
- VNPAY Terminal backend wiring (a data placeholder exists; backend not connected - QE finding).
- Label printer integration and Windows POS terminal support.
- SoftPOS / NFC contactless acceptance - Planned (P3).
- Physically triggering a cash drawer's kick-out signal - no such command exists in code today; staff open the drawer by hand. Registering and selecting a Cash Drawer device is in scope; driving it open is not.
- Who is authorized to press "Activate" (a specific role - owner, manager, or anyone with device-screen access) - proposed default is owner/manager, the exact rule belongs to the authorization design, not this PRD.
- A full maintenance-ticket / technician-dispatch workflow (assignment, SLA, repair-progress tracking) - routes through the Helpdesk module, independent of this PRD.
- An advanced peripheral driver-management UI.
- Kitchen display, waiter/service, and delivery apps.
2. Success Metrics
| Metric | Target / signal |
|---|---|
| Identity coverage | Every app session resolves to a device record via the request's device identity - no orphan sessions |
| Durable identity | Uninstalling and reinstalling the app on the same hardware always recovers the same identifier - no new identifier is generated |
| Correct check-then-create | Login on hardware already belonging to the merchant creates no new record; login on hardware not yet belonging to the merchant creates exactly one NEW record |
| Safe activation | Each Activation Code completes activation exactly once; every reuse attempt is rejected |
| Fleet visibility | Owners can list, search, and edit every registered device from the back office |
| Health accuracy | Online/offline status matches the 5-min heartbeat / 15-min offline threshold |
| Peripheral reliability | Print/scan/SoundBox failures surface a clear error; payment is never blocked by a disconnected SoundBox |
| Fault-to-notification latency | A device marked Faulty reaches the merchant's maintenance contact(s) in near real time |
| Maintenance overdue rate | Trend of devices flagged overdue for maintenance narrows over time, not just accumulates unacted-on |
| Retirement accounting | Every archived device carries a Retirement Reason |
3. Personas & Scenarios
| Persona | Goal |
|---|---|
| Owner | Register, manage, and monitor the device fleet; activate a new device via its code; remotely deactivate a compromised device; know which devices are broken, overdue for maintenance, or liquidated |
| Manager | View devices and health, activate a new device via its code, configure peripherals within scope |
| Cashier | Operate the POS on an activated device; pair and use printer / scanner / SoundBox |
| Technician / Maintenance staff | Receive a fault notification, physically repair or service the device, then clear its Condition back to Working |
Core flow (check - create - activate): a cashier logs in on a new POS terminal → the app calls the check API, finds no matching identifier under the merchant → the system creates a new device in status NEW and generates an Activation Code (QR + Barcode) → a manager scans that code with another device (or types it in) and presses "Activate" → the device moves NEW → ACTIVATED, the code is voided → the cashier starts selling. On the next login on that exact machine, even after uninstalling and reinstalling the app, the system recovers the same identifier and creates nothing new.
Browser scenario (ITP): an owner opens Web POS on Safari with ITP enabled - the browser can't retain the prior identifier across sessions (even from IndexedDB), so the check in step 2 treats it as a new device every time. Because code-based activation doesn't depend on browser storage, the owner still activates that session by scanning/entering the code shown on screen.
Fleet-health flow (forward-spec): a POS terminal stops working mid-shift → a cashier or manager marks it Faulty → the device is blocked from new sessions and a real-time alert reaches the maintenance contact → a technician repairs it and clears the Condition → the device serves sales again.
4. User Stories
- As an owner, I want a back-office page to list, create, and edit my devices, so I can manage the whole fleet in one place.
- As an owner, I want every device to carry a durable identifier unchanged across reinstalls, so the same machine is never mistaken for multiple different devices.
- As an owner, I want the system to automatically check on login whether a device already belongs to my merchant, so I don't have to re-register known hardware every time the app is reinstalled.
- As an owner, I want to activate a new device by scanning or entering a code, so I actively confirm which device is authorized to transact, instead of it being automatically granted.
- As an owner, I want the Activation Code to be single-use, so no one can reuse an old code to activate a different device.
- As an owner, I want to activate via either Barcode or QR, so machines without a camera can still connect.
- As an owner, I want to assign a device to a merchant, so I can scope it to a business unit.
- As an owner, I want to search devices by name, identifier, code, status, and type, so I can find a unit fast.
- As a cashier, I want printer, scanner, and SoundBox to pair to my device, so I can print receipts, scan products, and hear payment confirmations.
- As an administrator, I want to see device health and remotely deactivate a compromised device, so I can protect the fleet.
- As an owner, I want to register a cash drawer as its own device, so I can pick it when opening a shift instead of it being an invisible flag on the POS terminal.
- As an owner, I want to be notified the moment a device is marked Faulty, so a broken POS terminal gets fixed before it costs a shift's worth of sales.
- As an owner, I want the fleet list to flag a device overdue for maintenance, so I catch it before it breaks down unscheduled.
- As an owner, I want every archived device to record why it was retired, so I can tell at a glance which devices were liquidated versus lost, stolen, or replaced.
- As a technician, I want to clear a device's Condition back to Working once I've repaired it, so it can process sales again without anyone touching its underlying Status.
5. Functional Requirements
| # | Requirement | Status | URD ref |
|---|---|---|---|
FR-001 | A device is created with a bilingual name (English/Vietnamese), a device type, and is required to be assigned to a merchant. • The system auto-generates a stable Device Identifier from creation onward. | ✅ | URD-DEV-001..003 |
FR-002 | The operational Status field takes five ordered values: new → active → deactivated → suspended → archived, plus a soft-delete mechanism when a device is removed. • The values and soft-delete already exist, but transition validation is not enforced - status is currently a free CRUD field that can be set to any value regardless of the current one. | 🔶 | URD-DEV-004..009 |
FR-003 | Device code is optional; when provided, it must be unique within its merchant. | ✅ | URD-DEV-011 |
FR-004 | On login, the app calls an API checking whether the device identity already belongs to the current merchant. • Yes → the device operates normally, no new record is created. • No → the system creates a new device record in status NEW for that merchant. • Current state: the client already creates/reuses a deviceId stored in local session state, but this doesn't yet guarantee durability across reinstall (the correct check-belongs-to-merchant API isn't called as specified) and there is no explicit activation step (see FR-018). | 🔶 | URD-DEV-013 · URD-DEV-025..026 |
FR-005 | Devices are searchable by name, identifier, code, status, and type through the search index, scoped to the merchants the user has joined. | ✅ | URD-DEV-014 |
FR-006 | Every device created must be assigned to exactly one merchant from the start; the assignment can be changed via the edit screen. • No merchant-less device exists, and there is no organizer-level ownership concept on the device model. | ✅ | URD-DEV-016 |
FR-007 | Each device stores a hardware info set (manufacturer, model, serial, IMEI, MAC, processor, RAM, storage, screen, battery) and a software info set (OS, OS version, app version, firmware, last update time, peripheral drivers). | ✅ | URD-DEV-017..018 |
FR-008 | A device-identity header is carried on calls, but the resolver only works inside the POS shift-action flow today - a shift action resolves a device and derives its merchant from it. • There is no platform-wide per-request resolver yet, and no dedicated device-session entity. This gap is separate from FR-004/FR-018 - even once the check-create-activate flow is built to spec, the platform-wide resolver remains its own item. | 🔶 | URD-MON-001 |
FR-009 | Spec requirement: a device sends a heartbeat every 5 minutes, is considered offline after 15 minutes of silence; a health view shows online/offline, last seen, and app version; and a remote-deactivation action exists for a compromised device. • Current state: a last-seen field exists but nothing writes to it, and there is no heartbeat, health, or remote-action endpoint yet. | 🚧 | URD-MON-001..005 |
FR-010 | Spec requirement: receipt printer, barcode scanner, and SoundBox pair to a device and surface a clear error when pairing or use fails. • Current state: there is no backend wiring yet for scanner or SoundBox; printing today runs entirely in the POS client's native layer, not through a device backend. | 🚧 | URD-PRN · URD-SCN · URD-SBX |
FR-011 | Spec requirement (Planned, P3): accept contactless payment via SoftPOS/NFC on Android, authenticated through VNPAY KYC. None of this group has been built yet. | 🚧 | URD-NFC-001..004 |
FR-012 | Each device stores purchase date, warranty expiry, vendor, last maintenance date, next maintenance date, and free-text notes. • All are plain fields on the create/edit form today - the data persists and displays correctly. • Nothing yet computes a due/overdue state from the next-maintenance date (that's FR-014) and nothing yet notifies anyone (FR-016). | ✅ | URD-DEV-012 |
FR-013 | A cash drawer registers exactly like a POS terminal or a tablet - same form, same lifecycle, same search index - just with device type Cash Drawer. • When a cash-drawer-enabled POS terminal opens a shift, the shift-open flow offers a pick-list of ACTIVATED Cash Drawer devices to attach. • Distinct from the cashDrawerEnabled flag on the POS terminal itself and from the per-shift cash-reconciliation session (ShiftDrawer, owned by Sale's Multi-employee Shifts feature). | ✅ | URD-DEV-024 |
FR-014 | The fleet list computes, for each device, whether today's date has passed its recorded next-maintenance date; a device past that date is flagged due/overdue. • A reminder notification goes out as the date approaches (exact lead time proposed pending Design confirmation - see NFR). | 🚧 | URD-DEV-020 |
FR-015 | A new Condition attribute (Working / Under Maintenance / Faulty), orthogonal to the existing five-state operational Status lifecycle - a device can be ACTIVATED (authorized to transact) while Faulty (physically broken). • Proposed rule, pending confirmation of the exact enforcement point: marking an in-service device Faulty blocks it from opening new POS sessions or processing sales until a technician clears the Condition back to Working, without touching the device's underlying operational Status. | 🚧 | URD-DEV-021 |
FR-016 | Marking a device Faulty publishes an event that the platform's notification backbone (PRD-MON-001) fans out to the merchant's designated device/maintenance contact(s) in real time. • That backbone's pipeline (ingest → worker → persisted record → live push) is already built, but per PRD-MON-001 it currently has no producer feeding it - this FR would be among its first real producers. | 🚧 | URD-DEV-022 |
FR-017 | Archiving a device (URD-DEV-008) now requires picking a Retirement Reason - Liquidated, Lost, Stolen, Replaced, or Other. • The fleet list and CSV export (FR-005/URD-DEV-015) can filter/report by this reason. | 🚧 | URD-DEV-023 |
FR-018 | When the system creates a new device (per FR-004), it auto-generates a single unique Activation Code, represented in two parallel forms: a QR code and a Barcode. • Activation completes by scanning or entering that exact code and pressing "Activate," moving the device from NEW to ACTIVATED. • Every Activation Code is usable exactly once - reusing it (even on the same device) is rejected. • The Barcode form exists alongside the QR to serve devices without a camera; the whole mechanism does not depend on browser storage, so it works even when ITP policy limits client-side storage on Web POS. This is entirely new business logic - no code exists for it today. | 🚧 | URD-DEV-027..028 · URD-WEB-006 |
5.1 Acceptance Criteria
- Create a new device from the back office with a bilingual name, type, and a required merchant → a stable device identifier is auto-generated and unchanged across reloads (FR-001).
- Set a device's status to any of the 5 lifecycle values, including skipping intermediate steps → accepted, because transition validation is not enforced (FR-002 - 🔶).
- Create two devices with the same code under two different merchants → both succeed; create two devices with the same code under the same merchant → the second creation is rejected (FR-003).
- 🔶 Log in on new hardware → an API call checks whether the device already belongs to the merchant; if not, a NEW record is created - not fully testable to spec yet, since the current flow uses a locally stored
deviceIdwith no guaranteed durability across reinstall (FR-004). - Search by name, identifier, code, status, or type from the back office → only devices belonging to the merchants the user has joined are returned (FR-005).
- Create a device without selecting a merchant → blocked, since merchant is required; edit a device to reassign it to a different merchant → succeeds (FR-006).
- Save hardware info (serial, IMEI, MAC...) and software info (OS, app version...) for a device → the data persists and displays correctly on reloading the edit screen (FR-007).
- Call an API outside the POS shift-action flow with a device-identity header → no resolver picks up a device, since there is no platform-wide resolver (FR-008 - 🔶).
- 🚧 A device sends a heartbeat, displays online/offline status against the 5/15-minute threshold, and can be remotely deactivated - not yet testable, since the heartbeat/health/remote-action endpoints don't exist (FR-009).
- 🚧 Printer, scanner, and SoundBox pair and surface clear errors through a device backend - not yet testable, since backend wiring doesn't exist (FR-010).
- 🚧 SoftPOS/NFC accepts contactless payment on Android via VNPAY KYC - not yet testable, Planned P3 (FR-011).
- Save purchase date, warranty expiry, vendor, last and next maintenance dates, and notes for a device → the data persists and displays correctly on reloading the edit screen (FR-012).
- Register a device with type Cash Drawer → it goes through the same create/edit/search flow as any other device; open a shift on a cash-drawer-enabled POS terminal → only ACTIVATED Cash Drawer devices are offered to attach (FR-013).
- 🚧 A device's recorded next-maintenance date is today or earlier → it shows as due/overdue on the fleet list, and a reminder notification fires as the date approaches - not yet testable, the flagging/reminder logic doesn't exist (FR-014).
- 🚧 Mark an ACTIVATED device Faulty → it can no longer open a new POS session or process a sale, without its underlying Status changing; clear the Condition back to Working → it can process sales again - not yet testable, the Condition field doesn't exist (FR-015).
- 🚧 Mark a device Faulty → the merchant's designated maintenance contact(s) receive a real-time notification - not yet testable, blocked on both the Device-side trigger and the notification pipeline's first producer (FR-016).
- 🚧 Archive a device and pick Retirement Reason "Liquidated" → the reason is recorded; filter the fleet list by "Liquidated" → exactly that device is returned - not yet testable, the field doesn't exist (FR-017).
- 🚧 A new device is created (check-then-create returns "doesn't belong to merchant") → a single unique Activation Code is generated, shown as both QR and Barcode - not yet testable, the code-generation mechanism doesn't exist (FR-018).
- 🚧 Scan/enter the correct, still-valid Activation Code and press "Activate" → device moves NEW → ACTIVATED, code is voided; repeat the same action with the same code → rejected because the code was already used - not yet testable, the activation flow doesn't exist (FR-018).
6. Non-Functional Requirements
| Aspect | Requirement |
|---|---|
| Data integrity | A device is scoped to exactly one required merchant; identifiers are immutable; records use soft-delete |
| Identity | (Planned) the Device Identifier must be derivable/recoverable from the hardware, durable across reinstalls; every API call carries device identity - today only POS/shift actions resolve a device. There is no device-session entity |
| Activation security | (Planned) 🚧 proposed: the Activation Code is long enough to be unguessable (exact length/entropy pending Security confirmation), is voided immediately after its first valid use, and doesn't depend on browser storage for verification |
| Tenancy & authz | Operations are merchant-scoped; device search is limited to the merchants the user has joined; API access requires authentication |
| Performance / scale | Device search is index-backed; the 5-min heartbeat cadence bounds write load |
| Resilience | A disconnected SoundBox never blocks payment; print/scan failures surface, never silently drop |
| i18n | Device name and user-facing labels are bilingual (English & Vietnamese); receipts print Vietnamese characters correctly |
| Fault-notification latency | (Planned) A Faulty mark reaches the maintenance contact(s) in near real time, riding the same transport PRD-MON-001 already built for device activity |
| Maintenance reminder lead time | (Planned) 🚧 proposed: a reminder fires a configurable number of days before the recorded next-maintenance date (exact default pending Design confirmation) |
7. UX & Flows
Key screen: the back-office device page - list/table, create, edit, and a sectioned form (general, hardware config, software config, other settings) under the authenticated navigation; an activation screen shows/scans the Activation Code (QR + Barcode). POS peripheral flows (scanning, printing, SoundBox, SoftPOS) live in the POS app with its native device layer.
Fault reported → blocked → notified → resolved (forward-spec)
Scheduled maintenance due-date flagging (forward-spec)
8. Data & Domain
| Concept | Role |
|---|---|
| Device record | Bilingual name, type, operational Status, Device Identifier, required merchant relation (no organizer ownership), hardware/software info, cash-drawer flag |
| Device type | 8 values today: POS Terminal, POS Workstation, Mobile POS, Web Browser, Tablet, Barcode Scanner (standalone), Cash Drawer, Other - see Device URD for the full catalog |
| Hardware info | Manufacturer, model, serial, IMEI, MAC, processor, RAM, storage, screen, battery |
| Software info | OS, OS version, app version, firmware, last update, peripheral drivers |
| Maintenance info | Purchase date, warranty expiry, vendor, last maintenance date, next maintenance date, notes - all Built (FR-012); due/overdue flagging off the next-maintenance date is 🚧 (FR-014) |
| Activation Code (new, conceptual) | Single-use code generated when a new device is created, represented as QR and Barcode; moves device NEW → ACTIVATED on correct scan/entry plus "Activate" (FR-018) |
| Device Condition (new, conceptual) | Working / Under Maintenance / Faulty - orthogonal to operational Status; drives the fault-block and fault-notification behaviour (FR-015/016) |
| Retirement Reason (new, conceptual) | Liquidated / Lost / Stolen / Replaced / Other - recorded when a device is archived (FR-017) |
Cash Drawer (device) vs. ShiftDrawer (Sale) | The Cash Drawer device record is the physical hardware's fleet entry; ShiftDrawer is Sale's separate per-shift financial session that references the chosen Cash Drawer device - related, not the same entity |
| Device session | (Planned) an active session linked to a device, opened on login - no such entity exists today |
| Device search index | Indexes devices, including description fields |
Conceptual only - full schema and invariants in the commerce domain model.
9. Dependencies & Assumptions
Depends on
- Commerce domain - owns the device record, the required merchant assignment, hardware/software info, and the status field.
- Real-time signal backbone - real-time edge for device/payment events and the device search index.
- Client apps - the back office (fleet management), the POS app (POS UI), and its native device layer (USB/NFC/printer/scanner); the code scan/entry screen shares scanning infrastructure with
SCN, including the desktop scan/manual-entry mode shortcut (URD-SCN-008). - PRD-MON-001 - Device signal & notifications - the notification pipeline that fault alerts (FR-016) would ride on; Built end-to-end for its one live use case, but has no producer yet for a general activity feed.
- PRD-SHF-001 - Multi-employee shifts - owns
ShiftDrawer, the per-shift cash-reconciliation session that references a chosen Cash Drawer device.
Assumptions
- A merchant exists before a device is created - assignment is required, not optional.
- The hardware allows deriving or recovering a durable identifier (a machine identifier, OS-level secure storage, or an equivalent mechanism) - not every client platform has the same mechanism available, so the derivation approach may differ between POS/mobile and browsers. On the web app, the identity is stored in the browser's IndexedDB (not localStorage) - see URD-WEB-006.
- Whoever presses "Activate" holds device-management authorization within that merchant (proposed default owner/manager - the exact rule belongs to the authorization design).
- Certified hardware (VNPAY V-POS, Sunmi T2) is available for POS-terminal scenarios.
- A merchant has at least one designated device/maintenance contact to receive fault notifications; without one, Faulty marks are still recorded but nothing is delivered.
Risks & Open Questions
| Risk / question | Mitigation / status |
|---|---|
| Duplicate device records if the identifier isn't durable across reinstalls | Identifier must be derivable/recoverable from the hardware (URD-DEV-025), not just local storage; check-then-create reuses the existing record by that exact identifier |
| A browser with ITP enabled makes the automatic check treat the same machine as a new device every time | Activation via the Activation Code (QR/Barcode) doesn't depend on browser storage, so it still completes even when the automatic check is unreliable |
| An Activation Code leaked (screenshot, shared) could be used first by an unrelated party | Each code is usable exactly once - voided immediately after use; who is authorized to press "Activate" is settled in the authorization design (see Non-Goals) |
| VNPAY Terminal backend not wired (placeholder exists) | Out of scope - flagged QE finding; tracked for a later increment |
| SoftPOS / NFC depends on VNPAY KYC and Android hardware | Planned (P3); option hidden on iOS, blocked when NFC is unavailable |
| Heartbeat write load at fleet scale | Bounded by the 5-min cadence; revisit if load grows |
| Remote wipe when a device is offline | Queued and applied on next reconnect |
| Fault notification depends on a pipeline with no producer yet (PRD-MON-001) | Track as a joint dependency; this PRD's FR-016 doesn't ship in isolation |
| The Faulty-blocks-sessions rule (FR-015) isn't confirmed against exact POS login/shift-open enforcement points | Proposed rule pending Design/Engineering sign-off; flagged as such in the URD (C-14) |
| No designated device/maintenance contact configured for a merchant | Faulty marks still record; nothing is delivered until contact configuration is defined - open question |
FAQ
| Question | Answer |
|---|---|
| Do I have to register every device manually? | Not required - logging in on hardware that doesn't yet belong to the merchant auto-creates a NEW device; the back office still supports manual creation. This check-then-create flow is planned, not yet built to spec. |
| Does a device belong to a merchant or an organizer? | A required merchant - every device is created against exactly one merchant. There is no organizer ownership on the model. |
| Why doesn't a new device activate automatically? | Because activation is a deliberate decision, not a side effect of installing the app - someone must confirm the exact device authorized to transact by scanning/entering its Activation Code. |
| What happens if I reuse an already-used Activation Code? | Rejected. Each code completes activation exactly once, even when retried on the same device. |
| Why both a Barcode and a QR? | A QR needs a camera to scan; not every device has one. The Barcode serves exactly that group - scanned by a barcode scanner or typed by hand. |
| Does the device identifier get lost if I uninstall the app? | It shouldn't - that's this revision's core invariant. Reinstalling on the same hardware must recover the same identifier. |
| Will a disconnected SoundBox block a payment? | No - the payment still succeeds; the announcement is silently skipped. |
| Is SoftPOS available now? | No - SoftPOS / NFC is Planned (P3), Android-only, and requires VNPAY KYC. |
| Can I register a cash drawer as its own device? | Yes - today. Pick device type Cash Drawer; it goes through the same registration/lifecycle/search flow as any other device. |
| How do I know which devices are broken right now? | Not yet possible - device Condition (Working / Under Maintenance / Faulty) doesn't exist yet. |
| Will I be notified automatically if a POS terminal breaks down? | Not yet - fault notification (FR-016) depends on both new Device-side logic and the notification pipeline getting its first real producer. |
| Can I see which devices were liquidated vs. lost or replaced? | Not yet - Retirement Reason doesn't exist yet. |
Release Plan & Criteria
| Aspect | Plan |
|---|---|
| Phase | DEV / POS / PRN / SCN / MON = P2 (Partial); MOB / WEB / SBX = P1 (Built); NFC = P3 (Planned) - see URD feature catalog |
| Rollout | All organizers; no feature flag |
| Migration | Model cleanup - organizer ownership column removed, required merchant relation added, unique index corrected to per-merchant; add durable Device Identifier, Activation Code, Device Condition, Retirement Reason fields - no backfill required for existing data |
| Launch criteria | Acceptance criteria in §5.1 are ✅ met for back-office list/create/edit, merchant-scoped device search, maintenance-info capture, and Cash Drawer registration; items flagged 🚧/🔶 (durable identity, check-then-create, single-use Barcode/QR activation, heartbeat/health, peripherals, SoftPOS, maintenance due-date flagging, device Condition, fault notification, retirement reason) are still pending |
| Monitoring | (Planned) check-then-create accuracy rate, orphan-session count, rejected Activation Code reuse attempts, heartbeat online/offline accuracy, peripheral error rate, fault-to-notification latency, count of devices overdue for maintenance, Retirement Reason breakdown |
References
- URD: Device - DEV · MON · PRN · SCN · SBX · NFC · MOB · WEB · POS · DSX
- Related PRDs: PRD-MON-001 - Device signal & notifications · PRD-DSX-001 - Device shift context & printer binding · PRD-SHF-001 - Multi-employee shifts
- Module: Device - URD
- Developer: @nx/commerce · @nx/signal · domain model
- Apps: sale-renderer · sale-main · client