Chapter 16: Mobile Raptag Application

RFID Inventory Management

The Raptag mobile application enables rapid inventory counting using RFID technology. Associates can scan entire racks of merchandise in seconds, dramatically reducing inventory count time and improving accuracy.

Configuration Note: RFID settings and device management are configured in the Tenant Admin Portal (Chapter 15), not in the mobile app itself. The mobile app downloads its configuration from the central API on startup. See Chapter 15: Settings > RFID for device registration, printer setup, and tag configuration.


16.1 Technology Stack

ComponentTechnologyRationale
Framework.NET MAUICross-platform, native RFID SDK access
RFID SDKZebra RFID SDKEnterprise-grade, widely deployed
Local DatabaseSQLiteOffline-capable, lightweight
SyncREST API + Background ServiceReliable batch uploads
Tag PrintingZebra ZPLIndustry standard label format

16.2 Architecture Overview

┌─────────────────────────────────────────────────────────────────────┐
│                    RAPTAG MOBILE APPLICATION                         │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  ┌─────────────────────────────────────────────────────────────────┐│
│  │                         UI LAYER                                 ││
│  │  Login  │ Dashboard │ Session │ Scanning │ Summary │ Sync       ││
│  └─────────────────────────────────────────────────────────────────┘│
│                              │                                       │
│  ┌─────────────────────────────────────────────────────────────────┐│
│  │                      VIEW MODELS                                 ││
│  │  LoginVM  │  SessionVM  │  ScanVM  │  SummaryVM  │  SyncVM      ││
│  └─────────────────────────────────────────────────────────────────┘│
│                              │                                       │
│  ┌───────────────┬───────────────┬───────────────┬─────────────────┐│
│  │ RFID Service  │ Sync Service  │ Print Service │ Session Service ││
│  │ (Zebra SDK)   │ (HTTP/Queue)  │ (ZPL/BT)      │ (State Mgmt)    ││
│  └───────────────┴───────────────┴───────────────┴─────────────────┘│
│                              │                                       │
│  ┌─────────────────────────────────────────────────────────────────┐│
│  │                    LOCAL SQLITE DATABASE                         ││
│  │  - Sessions          - Tags                                      ││
│  │  - Scan Records      - Product Cache                             ││
│  │  - Sync Queue        - Settings                                  ││
│  └─────────────────────────────────────────────────────────────────┘│
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘
                                 │
                        ┌────────▼────────┐
                        │   Central API   │
                        │  (When Online)  │
                        └─────────────────┘

16.3 Screen Specifications

Screen 1: Login

Purpose: Authenticate user and select operational context.

Route: /login

╔════════════════════════════════════════════════════════════════════╗
║                                                                    ║
║                                                                    ║
║                    ┌──────────────────────────┐                    ║
║                    │                          │                    ║
║                    │    ████████████████      │                    ║
║                    │    ██  RAPTAG   ██       │                    ║
║                    │    ████████████████      │                    ║
║                    │                          │                    ║
║                    └──────────────────────────┘                    ║
║                                                                    ║
║                      RFID Inventory System                         ║
║                                                                    ║
║                                                                    ║
║    ┌────────────────────────────────────────────────────────────┐ ║
║    │                                                            │ ║
║    │  Employee PIN                                              │ ║
║    │  ┌────────────────────────────────────────────────────┐   │ ║
║    │  │ ● ● ● ● ○ ○                                        │   │ ║
║    │  └────────────────────────────────────────────────────┘   │ ║
║    │                                                            │ ║
║    │  ┌───────┐  ┌───────┐  ┌───────┐                          │ ║
║    │  │   1   │  │   2   │  │   3   │                          │ ║
║    │  └───────┘  └───────┘  └───────┘                          │ ║
║    │  ┌───────┐  ┌───────┐  ┌───────┐                          │ ║
║    │  │   4   │  │   5   │  │   6   │                          │ ║
║    │  └───────┘  └───────┘  └───────┘                          │ ║
║    │  ┌───────┐  ┌───────┐  ┌───────┐                          │ ║
║    │  │   7   │  │   8   │  │   9   │                          │ ║
║    │  └───────┘  └───────┘  └───────┘                          │ ║
║    │  ┌───────┐  ┌───────┐  ┌───────┐                          │ ║
║    │  │  CLR  │  │   0   │  │  GO   │                          │ ║
║    │  └───────┘  └───────┘  └───────┘                          │ ║
║    │                                                            │ ║
║    └────────────────────────────────────────────────────────────┘ ║
║                                                                    ║
║                                                                    ║
║  ────────────────────────────────────────────────────────────────  ║
║  Reader: MC3390R  |  Battery: 85%  |  ● Offline                    ║
╚════════════════════════════════════════════════════════════════════╝

Components:

ComponentSpecification
LogoRaptag brand, centered
PIN Display6 digits with masked/filled indicators
NumpadLarge touch targets (64x64px min)
Clear (CLR)Reset PIN entry
GoSubmit PIN for validation
Status BarReader model, battery, connection

Behavior:

  • PIN validated against local cache (for offline)
  • Sync user list on startup when online
  • Auto-login from last session option
  • Lock screen after 5 minutes of inactivity

Screen 2: Home Dashboard

Purpose: At-a-glance overview of assigned counts, recent activity, sync health, and device status.

Route: /home

╔════════════════════════════════════════════════════════════════════╗
║ RAPTAG                                               [⚙] [Logout] ║
╠════════════════════════════════════════════════════════════════════╣
║                                                                    ║
║    Welcome, Sarah Miller                                           ║
║    📍 GM - Greenbrier Mall         Today: December 29, 2024        ║
║                                                                    ║
║  MY ASSIGNED COUNTS                                                ║
║  ┌────────────────────────────────────────────────────────────────╢
║  │                                                                ║
║  │  ▶ Full Inventory - Section A        Due: Today 5:00 PM       ║
║  │    Expected: 505 items               Assigned by: Manager      ║
║  │                                                                ║
║  │  ▶ Cycle Count - Section C           Due: Tomorrow 10:00 AM   ║
║  │    Expected: 312 items               Assigned by: Manager      ║
║  │                                                                ║
║  └────────────────────────────────────────────────────────────────╢
║                                                                    ║
║  RECENT SESSIONS                                                   ║
║  ┌────────────────────────────────────────────────────────────────╢
║  │  ✓ #GM-1228-003  Spot Check      156 items    Synced          ║
║  │  ✓ #GM-1228-001  Cycle Count     289 items    Synced          ║
║  │  ● #GM-1227-002  Full Inventory  2,847 items  Pending Upload  ║
║  └────────────────────────────────────────────────────────────────╢
║                                                                    ║
║  ┌─────────────────────────┐  ┌─────────────────────────────────╢
║  │  SYNC STATUS            │  │  DEVICE HEALTH                  ║
║  │  ● 1 session pending    │  │  Battery: 85% ●                 ║
║  │  Last sync: 5 min ago   │  │  Reader: MC3390R Connected      ║
║  │                         │  │  Storage: 2.1 GB free           ║
║  └─────────────────────────┘  └─────────────────────────────────╢
║                                                                    ║
║  ┌──────────────┐ ┌──────────────┐ ┌────────────┐ ┌────────────┐║
║  │ NEW SESSION  │ │ JOIN SESSION │ │ PRINT TAGS │ │  SYNC NOW  │║
║  └──────────────┘ └──────────────┘ └────────────┘ └────────────┘║
║                                                                    ║
║  ────────────────────────────────────────────────────────────────  ║
║  Reader: MC3390R  |  ● Battery: 85%  |  ● Online                  ║
╚════════════════════════════════════════════════════════════════════╝

Dashboard Components:

ComponentData SourceRefresh
Assigned CountsGET /api/rfid/sessions?assigned_to={operator}&status=pendingOn screen load
Recent SessionsLocal SQLite sessions table, last 5Real-time
Sync StatusLocal sync_queue pending countReal-time
Device HealthSystem APIs (battery, storage, Bluetooth)Every 30s

Quick Actions:

ButtonAction
New SessionNavigate to Screen 3 (Session Start)
Join SessionNavigate to Screen 3, scroll to “Join Existing Session”
Print TagsNavigate to Tag Printing screen (18.5)
Sync NowTrigger immediate sync of pending sessions

Screen 3: Session Start

Purpose: Configure a new inventory counting session or join an existing one.

Route: /session/new

╔════════════════════════════════════════════════════════════════════╗
║ NEW INVENTORY SESSION                                   [< Back]   ║
╠════════════════════════════════════════════════════════════════════╣
║                                                                    ║
║  ──────────────────────────────────────────────────────────────    ║
║                                                                    ║
║    LOCATION *                                                      ║
║    ┌────────────────────────────────────────────────────────────┐ ║
║    │ GM - Greenbrier Mall                                    ▼ │ ║
║    └────────────────────────────────────────────────────────────┘ ║
║                                                                    ║
║    COUNT TYPE *                                                    ║
║    ┌────────────────────────────────────────────────────────────┐ ║
║    │  ○  Full Inventory                                         │ ║
║    │      Complete inventory of entire location                 │ ║
║    │                                                            │ ║
║    │  ●  Cycle Count                                            │ ║
║    │      Count specific section/department                     │ ║
║    │                                                            │ ║
║    │  ○  Spot Check                                             │ ║
║    │      Quick verification of selected items                  │ ║
║    │                                                            │ ║
║    │  ○  Find Item                                              │ ║
║    │      Locate specific product by EPC/SKU                    │ ║
║    └────────────────────────────────────────────────────────────┘ ║
║                                                                    ║
║    SECTION (Required for Cycle Count)                              ║
║    ┌────────────────────────────────────────────────────────────┐ ║
║    │ Section A - Men's Tops                                  ▼ │ ║
║    └────────────────────────────────────────────────────────────┘ ║
║                                                                    ║
║    NOTES (Optional)                                                ║
║    ┌────────────────────────────────────────────────────────────┐ ║
║    │ Pre-inventory count for Q4 audit                           │ ║
║    │                                                            │ ║
║    └────────────────────────────────────────────────────────────┘ ║
║                                                                    ║
║    ┌────────────────────────────────────────────────────────────┐ ║
║    │                   START NEW SESSION                        │ ║
║    └────────────────────────────────────────────────────────────┘ ║
║                                                                    ║
║  ──────── OR ────────                                              ║
║                                                                    ║
║    JOIN EXISTING SESSION                                           ║
║    ┌────────────────────────────────────────────────────────────┐ ║
║    │  ● #GM-2024-1229-001   Full Inventory   3 operators        │ ║
║    │    Started: 1:30 PM    Sections: B, D available             │ ║
║    │                                                            │ ║
║    │  ○ #GM-2024-1229-002   Cycle Count      1 operator         │ ║
║    │    Started: 2:15 PM    Section: E (Accessories)             │ ║
║    └────────────────────────────────────────────────────────────┘ ║
║                                                                    ║
║    ┌────────────────────────────────────────────────────────────┐ ║
║    │                   JOIN SELECTED SESSION                    │ ║
║    └────────────────────────────────────────────────────────────┘ ║
║                                                                    ║
║  ────────────────────────────────────────────────────────────────  ║
║  Reader: Ready  |  ● Battery: 85%  |  ● Online                    ║
╚════════════════════════════════════════════════════════════════════╝

Count Types (RFID counting only — no receiving; see BRD Section 5.16.4):

TypeUse CaseExpected Items
Full InventoryAnnual/semi-annual full count2,000-100,000+
Cycle CountSection/department audits200-1,000
Spot CheckDiscrepancy verification10-50
Find ItemLocate specific product by EPC1

Note: “Receiving” is handled by the barcode Scanner in the POS Client (Ch 14), not RFID. See BRD Section 5.16.6 for the Scanner vs RFID distinction.

Sections (Configurable per location in Admin Portal):

  • Section A - Men’s Tops
  • Section B - Men’s Bottoms
  • Section C - Women’s Tops
  • Section D - Women’s Bottoms
  • Section E - Accessories
  • Backroom
  • Display Window

Join Session Flow:

  1. App queries GET /api/rfid/sessions?location={code}&status=active for active sessions at operator’s location
  2. Operator selects a session and picks an available section
  3. App calls POST /api/rfid/sessions/{id}/join with operator details
  4. Server adds row to session_operators table
  5. Scanning screen opens with session context pre-loaded
  6. Deduplication: If multiple operators scan the same EPC, server keeps highest RSSI reading (see Chapter 05 Section 4.6.8 for RSSI-based dedup rules)

Business Rules:

  • Maximum 10 operators per session (see Chapter 05 Section 5.16.4)
  • One active session per operator (must complete or leave current session before joining another)
  • Section assignment is advisory (not enforced by reader hardware)
  • Session creator is automatically the first operator

Screen 4: Scanning (Main Interface)

Purpose: The primary RFID scanning interface during an active session.

Route: /session/scan

╔════════════════════════════════════════════════════════════════════╗
║ SCANNING - Cycle Count                              [Pause] [End]  ║
╠════════════════════════════════════════════════════════════════════╣
║                                                                    ║
║  Location: GM - Greenbrier Mall   Section: A - Men's Tops          ║
║  Started: 2:45 PM                 Duration: 00:12:34               ║
║  Operator: Sarah Miller           Session: #GM-2024-1229-001       ║
║                                                                    ║
║  PROGRESS                                                          ║
║  ████████████████████░░░░░░░░░░  62%    312 of 505 items           ║
║  Est. remaining: ~8 min                                            ║
║                                                                    ║
║  ┌────────────────────────────────────────────────────────────────╢
║  │                                                                ║
║  │                      LIVE SCAN                                 ║
║  │                                                                ║
║  │         ┌──────────────────────────────────────────┐          ║
║  │         │                                          │          ║
║  │         │            ████  SCANNING  ████          │          ║
║  │         │                                          │          ║
║  │         │             Tags Read: 847               │          ║
║  │         │             Unique Items: 312            │          ║
║  │         │             Read Rate: 42/sec            │          ║
║  │         │                                          │          ║
║  │         └──────────────────────────────────────────┘          ║
║  │                                                                ║
║  │                   [HOLD TRIGGER TO SCAN]                       ║
║  │                                                                ║
║  └────────────────────────────────────────────────────────────────╢
║                                                                    ║
║  RECENT SCANS                                                      ║
║  ┌────────────────────────────────────────────────────────────────╢
║  │                                                                ║
║  │  ✓ NXJ1078-NAV-M    Galaxy V-Neck (M, Navy)         x3        ║
║  │  ✓ NXJ1078-NAV-L    Galaxy V-Neck (L, Navy)         x2        ║
║  │  ✓ NXP0892-KHK-32   Slim Fit Chinos (32, Khaki)     x1        ║
║  │  ! UNKNOWN TAG      E280116060000...                x1        ║
║  │  ✓ NXA0234-BLK-M    Leather Belt (M, Black)         x4        ║
║  │                                                                ║
║  │  [View All 312 Items]                                          ║
║  │                                                                ║
║  └────────────────────────────────────────────────────────────────╢
║                                                                    ║
║  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐    ║
║  │  [MANUAL ADD]   │  │  [FIND ITEM]    │  │  [SETTINGS]     │    ║
║  └─────────────────┘  └─────────────────┘  └─────────────────┘    ║
║                                                                    ║
║  ────────────────────────────────────────────────────────────────  ║
║  Reader: Scanning  |  ● Battery: 82%  |  Signal: Strong            ║
║  Auto-save: 30s ago  |  Checkpoint: 847 reads                     ║
╚════════════════════════════════════════════════════════════════════╝

Progress Tracking:

MetricSourceDisplay
Progress %unique_items / expected_count × 100Progress bar + percentage
Items count"312 of 505 items"Current unique vs expected
Time estimate(elapsed / progress%) × remaining%"~8 min remaining"
Auto-savelast_checkpoint_at vs now"Auto-save: 30s ago"

Note: expected_count comes from the server when the session is created (based on last known inventory at that location/section). If unavailable (offline session start), the progress bar is hidden and only raw counts are shown.

Scanning States:

IDLE STATE                          SCANNING STATE
┌────────────────────────┐          ┌────────────────────────┐
│                        │          │                        │
│    ○ ○ ○ ○ ○ ○ ○ ○     │          │    ████████████████    │
│                        │          │    ████ ACTIVE ████    │
│    Ready to Scan       │          │    ████████████████    │
│                        │          │                        │
│    Tags: 0             │          │    Tags: 847           │
│                        │          │    Rate: 42/sec        │
│                        │          │                        │
└────────────────────────┘          └────────────────────────┘

PAUSED STATE                        COMPLETED STATE
┌────────────────────────┐          ┌────────────────────────┐
│                        │          │                        │
│    ║ ║  PAUSED  ║ ║    │          │    ✓ COMPLETE ✓        │
│                        │          │                        │
│    Session paused      │          │    Session ended       │
│    Tap to resume       │          │                        │
│                        │          │    Total: 847 tags     │
│    Tags: 312           │          │    312 unique items    │
│                        │          │                        │
└────────────────────────┘          └────────────────────────┘

Reader Signal Strength:

LevelIconRead Rate
Strong4 bars40+ tags/sec
Good3 bars20-40 tags/sec
Fair2 bars10-20 tags/sec
Weak1 bar< 10 tags/sec
NoneXNo connection

Quick Actions:

ActionPurpose
Manual AddBarcode scan for untagged items
Find ItemLocate specific SKU using reader
SettingsAdjust power, beep, vibration

Screen 5: Session Summary

Purpose: Review results and submit completed count session.

Route: /session/summary

╔════════════════════════════════════════════════════════════════════╗
║ SESSION SUMMARY                                         [< Back]   ║
╠════════════════════════════════════════════════════════════════════╣
║                                                                    ║
║  ┌────────────────────────────────────────────────────────────────╢
║  │  SESSION #GM-2024-1229-001                                     ║
║  │  Cycle Count - Section A (Men's Tops)                          ║
║  │  Location: GM - Greenbrier Mall                                ║
║  │  Operator: Sarah Miller                                        ║
║  │  Date: December 29, 2024                                       ║
║  │  Duration: 00:23:45                                            ║
║  └────────────────────────────────────────────────────────────────╢
║                                                                    ║
║  SCAN RESULTS                                                      ║
║  ┌─────────────────────────────────────────────────────────────┐  ║
║  │                                                             │  ║
║  │   ┌─────────────────────┐    ┌─────────────────────┐       │  ║
║  │   │  TOTAL TAGS         │    │  UNIQUE ITEMS       │       │  ║
║  │   │       847           │    │       312           │       │  ║
║  │   └─────────────────────┘    └─────────────────────┘       │  ║
║  │                                                             │  ║
║  │   ┌─────────────────────┐    ┌─────────────────────┐       │  ║
║  │   │  EXPECTED           │    │  VARIANCE           │       │  ║
║  │   │       305           │    │       +7 (2.3%)     │       │  ║
║  │   └─────────────────────┘    └─────────────────────┘       │  ║
║  │                                                             │  ║
║  └─────────────────────────────────────────────────────────────┘  ║
║                                                                    ║
║  DISCREPANCIES                                          View All   ║
║  ┌─────────────────────────────────────────────────────────────┐  ║
║  │                                                             │  ║
║  │  ▲ OVER (5 items)                                           │  ║
║  │    NXJ1078-NAV-M    Expected: 12   Counted: 15   (+3)       │  ║
║  │    NXP0892-KHK-32   Expected:  8   Counted: 10   (+2)       │  ║
║  │                                                             │  ║
║  │  ▼ SHORT (3 items)                                          │  ║
║  │    NXJ2156-WHT-L    Expected:  6   Counted:  4   (-2)       │  ║
║  │    NXA0234-BRN-M    Expected:  5   Counted:  4   (-1)       │  ║
║  │                                                             │  ║
║  │  ? UNKNOWN (2 tags)                                         │  ║
║  │    E280116060000207523456789                                │  ║
║  │    E280116060000207523456790                                │  ║
║  │                                                             │  ║
║  └─────────────────────────────────────────────────────────────┘  ║
║                                                                    ║
║  ┌─────────────────────┐  ┌─────────────────────────────────────┐ ║
║  │                     │  │                                     │ ║
║  │  [RECOUNT SECTION]  │  │         SUBMIT SESSION              │ ║
║  │                     │  │                                     │ ║
║  └─────────────────────┘  └─────────────────────────────────────┘ ║
║                                                                    ║
║  ────────────────────────────────────────────────────────────────  ║
║  Reader: Idle  |  Battery: 78%  |  ● Online                        ║
╚════════════════════════════════════════════════════════════════════╝

Variance Thresholds (Configurable):

VarianceColorAction
0%GreenAuto-approve
1-2%YellowReview recommended
3-5%OrangeManager review required
> 5%RedRecount required

Screen 6: Sync Status

Purpose: Monitor data synchronization with central server.

Route: /sync

╔════════════════════════════════════════════════════════════════════╗
║ SYNC STATUS                                             [< Menu]   ║
╠════════════════════════════════════════════════════════════════════╣
║                                                                    ║
║  CONNECTION                                                        ║
║  ┌────────────────────────────────────────────────────────────────╢
║  │                                                                ║
║  │    ●  Connected to Central Server                              ║
║  │       Server: api.nexuspos.com                                 ║
║  │       Latency: 45ms                                            ║
║  │       Last Sync: 2 minutes ago                                 ║
║  │                                                                ║
║  └────────────────────────────────────────────────────────────────╢
║                                                                    ║
║  PENDING UPLOADS                                                   ║
║  ┌────────────────────────────────────────────────────────────────╢
║  │                                                                ║
║  │    ┌─────────────────────────────────────────────────────────┐║
║  │    │ Session #GM-2024-1229-001                    Uploading  │║
║  │    │ 312 items, 847 tag reads                                │║
║  │    │ Progress: ████████████░░░░░░░░  62%                     │║
║  │    └─────────────────────────────────────────────────────────┘║
║  │                                                                ║
║  │    ┌─────────────────────────────────────────────────────────┐║
║  │    │ Session #GM-2024-1228-003                    Pending    │║
║  │    │ 156 items, 423 tag reads                                │║
║  │    │ Waiting...                                              │║
║  │    └─────────────────────────────────────────────────────────┘║
║  │                                                                ║
║  └────────────────────────────────────────────────────────────────╢
║                                                                    ║
║  RECENT SYNCS                                                      ║
║  ┌────────────────────────────────────────────────────────────────╢
║  │                                                                ║
║  │    ✓  Product Catalog     Updated 10 min ago     1,245 items  ║
║  │    ✓  Tag Mappings        Updated 10 min ago     8,432 tags   ║
║  │    ✓  User List           Updated 1 hour ago     24 users     ║
║  │    ✓  Location Config     Updated 1 hour ago     5 locations  ║
║  │                                                                ║
║  └────────────────────────────────────────────────────────────────╢
║                                                                    ║
║  ┌─────────────────────────────────────────────────────────────┐  ║
║  │                                                             │  ║
║  │                     [SYNC NOW]                              │  ║
║  │                                                             │  ║
║  └─────────────────────────────────────────────────────────────┘  ║
║                                                                    ║
║  Storage: 245 MB used of 2 GB  |  Last Full Sync: 12/29 9:00 AM   ║
║                                                                    ║
║  ────────────────────────────────────────────────────────────────  ║
║  Reader: Idle  |  Battery: 78%  |  ● Online                        ║
╚════════════════════════════════════════════════════════════════════╝

16.4 Zebra RFID Reader Integration

Supported Devices

ModelForm FactorRangeUse Case
MC3390RHandheld20 ftStore counts
RFD40Sled12 ftAttaches to phone
FX9600Fixed30 ftDock door receiving

SDK Integration

public interface IRfidService
{
    event EventHandler<TagReadEventArgs> TagRead;
    event EventHandler<BatteryEventArgs> BatteryChanged;
    event EventHandler<ReaderEventArgs> ReaderConnected;
    event EventHandler<ReaderEventArgs> ReaderDisconnected;

    Task<bool> ConnectAsync();
    Task DisconnectAsync();
    Task StartInventoryAsync();
    Task StopInventoryAsync();
    Task<ReaderStatus> GetStatusAsync();
    Task SetPowerLevelAsync(int dbm);
}

public class ZebraRfidService : IRfidService
{
    private readonly RFIDReader _reader;
    private readonly EventHandler _eventHandler;

    public async Task<bool> ConnectAsync()
    {
        var readers = RFIDReader.GetAvailableReaders();
        if (readers.Count == 0) return false;

        _reader = readers[0];
        _reader.Events.TagReadEvent += OnTagRead;
        _reader.Events.ReaderAppearEvent += OnReaderAppear;
        _reader.Events.ReaderDisappearEvent += OnReaderDisappear;
        _reader.Events.BatteryEvent += OnBatteryChanged;

        return await _reader.ConnectAsync();
    }

    public async Task StartInventoryAsync()
    {
        var config = new InventoryConfig
        {
            MemoryBank = MEMORY_BANK.MEMORY_BANK_EPC,
            ReportUnique = true,
            StopTrigger = new StopTrigger
            {
                StopTriggerType = STOP_TRIGGER_TYPE.STOP_TRIGGER_TYPE_TAG_OBSERVATION
            }
        };

        await _reader.Inventory.PerformAsync(config);
    }

    private void OnTagRead(object sender, TagDataEventArgs e)
    {
        foreach (var tag in e.ReadEventData.TagData)
        {
            var epc = tag.TagID;
            var rssi = tag.PeakRSSI;

            TagRead?.Invoke(this, new TagReadEventArgs(epc, rssi));
        }
    }
}

Power Level Settings

Power (dBm)RangeBattery ImpactUse Case
30 (Max)20+ ftHighFull store
2515 ftMediumZone count
2010 ftLowSpot check
155 ftMinimalSingle rack

16.5 Tag Printing Workflow

Encoding New Tags

╔════════════════════════════════════════════════════════════════════╗
║ PRINT RFID TAGS                                         [< Back]   ║
╠════════════════════════════════════════════════════════════════════╣
║                                                                    ║
║  PRODUCT                                                           ║
║  ┌────────────────────────────────────────────────────────────────╢
║  │  NXJ1078-NAV-M                                                 ║
║  │  Galaxy V-Neck Tee - Navy, Medium                              ║
║  │  Price: $29.00                                                 ║
║  │  Current Stock: 15 (GM)                                        ║
║  └────────────────────────────────────────────────────────────────╢
║                                                                    ║
║  PRINT SETTINGS                                                    ║
║  ┌────────────────────────────────────────────────────────────────╢
║  │                                                                ║
║  │  Quantity:    [    5    ]  tags                                ║
║  │                                                                ║
║  │  Tag Type:    ○ Hang Tag (Apparel)                             ║
║  │               ● Price Tag (Standard)                           ║
║  │               ○ Label (Adhesive)                               ║
║  │                                                                ║
║  │  Printer:     [Zebra ZD621R                               ▼]  ║
║  │                                                                ║
║  └────────────────────────────────────────────────────────────────╢
║                                                                    ║
║  TAG PREVIEW                                                       ║
║  ┌────────────────────────────────────────────────────────────────╢
║  │  ┌─────────────────────────┐                                   ║
║  │  │ NEXUS CLOTHING          │                                   ║
║  │  │                         │                                   ║
║  │  │ Galaxy V-Neck Tee       │                                   ║
║  │  │ Navy / Medium           │                                   ║
║  │  │                         │                                   ║
║  │  │        $29.00           │                                   ║
║  │  │                         │                                   ║
║  │  │ |||||||||||||||||||     │  <- Barcode                       ║
║  │  │ NXJ1078-NAV-M           │                                   ║
║  │  │                         │                                   ║
║  │  │ [RFID ENCODED]          │  <- Chip indicator                ║
║  │  └─────────────────────────┘                                   ║
║  │                                                                ║
║  └────────────────────────────────────────────────────────────────╢
║                                                                    ║
║  ┌─────────────────────────────────────────────────────────────┐  ║
║  │                                                             │  ║
║  │                    [PRINT 5 TAGS]                           │  ║
║  │                                                             │  ║
║  └─────────────────────────────────────────────────────────────┘  ║
║                                                                    ║
╚════════════════════════════════════════════════════════════════════╝

ZPL Template

^XA
^FO50,50^A0N,30,30^FDNexus Clothing^FS
^FO50,100^A0N,40,40^FD%PRODUCT_NAME%^FS
^FO50,150^A0N,25,25^FD%VARIANT%^FS
^FO50,200^A0N,50,50^FD$%PRICE%^FS
^FO50,280^BY2^BCN,80,Y,N,N^FD%SKU%^FS
^RFW,H,2,4,1^FD%EPC%^FS
^RFR,H,0,12,1^FN0^FS
^XZ

Template Variables:

VariableSourceExample
%PRODUCT_NAME%Product.NameGalaxy V-Neck Tee
%VARIANT%Size/ColorNavy / Medium
%PRICE%Product.Price29.00
%SKU%Product.SKUNXJ1078-NAV-M
%EPC%GeneratedE28011606000020752345

16.6 Local Database Schema

-- Sessions (with auto-save checkpoint support)
CREATE TABLE sessions (
    id TEXT PRIMARY KEY,
    server_session_id TEXT,            -- ID from POST /sessions response
    location_code TEXT NOT NULL,
    count_type TEXT NOT NULL,           -- full_inventory, cycle_count, spot_check, find_item
    section TEXT,                       -- assigned section (replaces zone)
    operator_id TEXT NOT NULL,
    started_at TEXT NOT NULL,
    ended_at TEXT,
    status TEXT DEFAULT 'active',       -- active, paused, completed, cancelled
    notes TEXT,
    expected_count INTEGER,             -- from server, for progress tracking
    last_checkpoint_at TEXT,            -- auto-save: last SQLite flush timestamp
    total_reads_at_checkpoint INTEGER DEFAULT 0,  -- reads saved at last checkpoint
    interrupted INTEGER DEFAULT 0,      -- 1 if app crashed/closed during session
    is_joined INTEGER DEFAULT 0,        -- 1 if operator joined existing session
    synced_at TEXT
);

-- Tag Reads (raw data, deduplicated locally by EPC)
CREATE TABLE tag_reads (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id TEXT NOT NULL,
    epc TEXT NOT NULL,
    rssi INTEGER,
    read_count INTEGER DEFAULT 1,       -- times this EPC was read
    first_seen_at TEXT NOT NULL,
    last_seen_at TEXT NOT NULL,
    UNIQUE (session_id, epc),           -- one row per EPC per session
    FOREIGN KEY (session_id) REFERENCES sessions(id)
);

-- Session Items (aggregated: EPC → SKU resolution)
CREATE TABLE session_items (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id TEXT NOT NULL,
    sku TEXT,
    epc TEXT NOT NULL,
    product_name TEXT,
    quantity INTEGER DEFAULT 1,
    expected_qty INTEGER,
    status TEXT DEFAULT 'matched',  -- matched, over, short, unknown
    FOREIGN KEY (session_id) REFERENCES sessions(id)
);

-- Product Cache
CREATE TABLE products (
    sku TEXT PRIMARY KEY,
    name TEXT NOT NULL,
    barcode TEXT,
    price REAL,
    category TEXT,
    last_synced TEXT NOT NULL
);

-- Tag Mappings (EPC prefix → SKU for offline decoding)
CREATE TABLE tag_mappings (
    epc_prefix TEXT PRIMARY KEY,
    sku TEXT NOT NULL,
    last_synced TEXT NOT NULL
);

-- Sync Queue (chunked upload tracking)
CREATE TABLE sync_queue (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    entity_type TEXT NOT NULL,           -- 'session_chunk', 'session_complete'
    entity_id TEXT NOT NULL,             -- session_id
    action TEXT NOT NULL,                -- 'upload_chunk', 'complete'
    payload TEXT NOT NULL,               -- JSON chunk data
    chunk_index INTEGER,                 -- 0-based chunk number
    total_chunks INTEGER,                -- total expected chunks for this session
    chunks_uploaded INTEGER DEFAULT 0,   -- chunks successfully uploaded so far
    retry_count INTEGER DEFAULT 0,
    created_at TEXT NOT NULL,
    status TEXT DEFAULT 'pending'         -- pending, uploading, completed, failed
);

16.7 Offline Capabilities

FeatureOffline Behavior
LoginUses cached credentials
Session StartCreates local session ID
ScanningFull functionality
Product LookupUses cached catalog
Session SummaryCalculates from local data
SubmitQueues for later sync
Sync StatusShows pending items

Sync Priority

PriorityData TypeFrequency
1 (Critical)Completed sessionsImmediate when online
2 (High)Session chunksBackground chunked upload
3 (Medium)Product updatesPull on app launch
4 (Low)User listDaily refresh

Chunked Upload Strategy

Large sessions (100,000+ tag reads) are uploaded in chunks of 5,000 events each:

Session: 47,000 tag reads → 10 chunks

Chunk 0: events[0..4999]      → POST /sessions/{id}/chunks  ✓
Chunk 1: events[5000..9999]   → POST /sessions/{id}/chunks  ✓
Chunk 2: events[10000..14999] → POST /sessions/{id}/chunks  ✗ (network error)
...retry after reconnect...
Chunk 2: events[10000..14999] → POST /sessions/{id}/chunks  ✓ (idempotent)
Chunk 3-9: ...
POST /sessions/{id}/complete  → Trigger variance calculation

Resume logic: On network failure, call GET /sessions/{id}/upload-status to identify missing chunks and retry only those. Server deduplicates by (session_id, epc) UNIQUE constraint, making retries safe.

Session Auto-Save & Recovery

Auto-save protects against data loss from app crashes, battery death, or accidental closure.

Auto-Save Triggers:

TriggerAction
Every 30 seconds (configurable)Flush tag_reads to SQLite, update last_checkpoint_at
Battery ≤ 20%Force checkpoint + yellow warning
Battery ≤ 10%Force checkpoint + orange warning + “Save & Exit” prompt
Battery ≤ 5%Force checkpoint + auto-pause session
App backgroundedForce checkpoint

Recovery Flow (on app restart):

App Launch
    │
    ├─── Check: Any sessions WHERE status='active' AND ended_at IS NULL?
    │
    ├── NO → Normal flow → Home Dashboard
    │
    └── YES → Show Recovery Dialog
              ┌─────────────────────────────────────────────┐
              │                                             │
              │  ⚠️  Interrupted Session Found              │
              │                                             │
              │  Session: #GM-2024-1229-001                 │
              │  Type: Full Inventory                       │
              │  Tags Read: 2,847                           │
              │  Last Save: 3:42 PM (12 min ago)            │
              │                                             │
              │  ┌─────────────┐  ┌─────────────────────┐  │
              │  │   RESUME    │  │   DISCARD SESSION    │  │
              │  └─────────────┘  └─────────────────────┘  │
              │                                             │
              └─────────────────────────────────────────────┘
  • Resume: Reload cached tag_reads, reconnect reader, continue scanning from checkpoint
  • Discard: Mark session cancelled in SQLite. Data preserved locally but not uploaded to server

Battery Warning Indicators (shown in status bar during scanning):

BatteryColorIconAction
> 20%GreenNormal operation
11-20%YellowWarning badge, checkpoint forced
6-10%Orange▲▲“Save & Exit” prompt
≤ 5%RedAuto-pause, force checkpoint

16.8 Configuration Architecture

Where Configuration Lives

┌─────────────────────────────────────────────────────────────────────────────────┐
│                   RFID CONFIGURATION ARCHITECTURE                                │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│   TENANT ADMIN PORTAL (app.rapos.com)                                            │
│   ┌───────────────────────────────────────────────────────────────────────────┐ │
│   │  Settings > RFID                                                          │ │
│   │  ├── Devices (claim codes, device list)      ← ADMIN CONFIGURES HERE     │ │
│   │  ├── Printers (IP addresses, templates)                                   │ │
│   │  ├── Tag Config (EPC prefix, thresholds)                                  │ │
│   │  └── Templates (label designs)                                            │ │
│   └───────────────────────────────────────────────────────────────────────────┘ │
│                                        │                                         │
│                                        ▼                                         │
│   ┌───────────────────────────────────────────────────────────────────────────┐ │
│   │  CENTRAL API (api.rapos.com)                                              │ │
│   │  ├── GET /api/rfid/config          ← Mobile app fetches on startup        │ │
│   │  ├── GET /api/rfid/products        ← Product catalog cache                │ │
│   │  ├── GET /api/rfid/tag-mappings    ← EPC → SKU mappings                   │ │
│   │  └── POST /api/rfid/sessions       ← Upload scan sessions                 │ │
│   └───────────────────────────────────────────────────────────────────────────┘ │
│                                        │                                         │
│                                        ▼                                         │
│   RAPTAG MOBILE APP (This Chapter)                                               │
│   ┌───────────────────────────────────────────────────────────────────────────┐ │
│   │  Local SQLite Database                                                    │ │
│   │  ├── cached_config     ← Downloaded from API on startup                  │ │
│   │  ├── products          ← Product catalog for offline use                 │ │
│   │  ├── tag_mappings      ← EPC decoding for offline use                    │ │
│   │  └── sessions          ← Locally created, synced when online             │ │
│   └───────────────────────────────────────────────────────────────────────────┘ │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘

Configuration Flow

1. DEVICE REGISTRATION (One-time setup)
   ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
   │ Admin Portal│────▶│ Generate    │────▶│ Display     │
   │ Settings    │     │ Claim Code  │     │ X7K9M2      │
   └─────────────┘     └─────────────┘     └─────────────┘
                                                  │
                                                  ▼
   ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
   │ Scanner     │◀────│ Validate    │◀────│ Enter Code  │
   │ Registered  │     │ & Activate  │     │ on Device   │
   └─────────────┘     └─────────────┘     └─────────────┘

> **Claim Code**: The code is a 6-character alphanumeric string with 24-hour expiry and one-time use. Before initializing the RFID reader, operators must enter the claim code generated in the Admin Portal. See Chapter 05 Section 5.16.1 for full claim code specifications.

2. ONGOING CONFIGURATION SYNC
   ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
   │ App Launch  │────▶│ Check API   │────▶│ Download    │
   │             │     │ /rfid/config│     │ Updates     │
   └─────────────┘     └─────────────┘     └─────────────┘
                                                  │
                                                  ▼
   ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
   │ Update      │◀────│ Merge with  │◀────│ Store in    │
   │ Local Cache │     │ Local Data  │     │ SQLite      │
   └─────────────┘     └─────────────┘     └─────────────┘

What’s Configured Where

SettingLocationNotes
EPC PrefixTenant Admin > RFID > Tag ConfigRead-only in app
Variance ThresholdTenant Admin > RFID > Tag ConfigApplied during session summary
Auto-Save IntervalTenant Admin > RFID > Tag ConfigDefault 30s, synced to app
Chunk Upload SizeTenant Admin > RFID > Tag ConfigDefault 5,000 events
RSSI ThresholdTenant Admin > RFID > Tag ConfigDefault -70 dBm, filter phantom reads
Claim CodesTenant Admin > RFID > DevicesGenerated per location
Printer IPsTenant Admin > RFID > PrintersSynced to app
Label TemplatesTenant Admin > RFID > TemplatesSynced to app
SectionsTenant Admin > RFID > LocationsConfigurable per location
Power LevelMobile App > SettingsUser-adjustable per session
Sound/VibrationMobile App > SettingsUser preference
Session NotesMobile App > Session StartPer-session

API Endpoints for Mobile App

// Configuration downloaded on startup
GET /api/rfid/config
Response: {
  tenant_id: string,
  epc_prefix: string,
  variance_threshold: number,
  auto_save_interval_seconds: number,
  chunk_upload_size: number,
  min_rssi_threshold: number,
  allow_overrides: boolean,
  session_timeout_minutes: number,
  printers: [{
    id: string,
    name: string,
    ip_address: string,
    location_code: string,
    model: string
  }],
  templates: [{
    id: string,
    name: string,
    type: "hang_tag" | "price_tag" | "label",
    zpl_content: string
  }],
  sections: [{
    location_code: string,
    sections: string[]
  }]
}

// Product catalog for offline use
GET /api/rfid/products
Response: [{
  sku: string,
  name: string,
  barcode: string,
  price: number,
  category: string
}]

// EPC → SKU mappings for offline decoding
GET /api/rfid/tag-mappings
Response: [{
  epc_prefix: string,
  sku: string
}]

// Create new counting session
POST /api/rfid/sessions
Body: {
  location_code: string,
  count_type: "full_inventory" | "cycle_count" | "spot_check" | "find_item",
  section: string,
  notes: string
}
Response: {
  session_id: string,
  expected_count: number,
  sections_available: string[]
}

// Join existing session as additional operator
POST /api/rfid/sessions/{sessionId}/join
Body: {
  operator_id: string,
  device_id: string,
  assigned_section: string
}
Response: {
  session_id: string,
  operator_count: number,
  your_section: string,
  session_started_at: string
}

// Upload scan events in chunks (≤5,000 events per chunk)
// Idempotent: duplicate (session_id, epc) pairs are deduplicated server-side
POST /api/rfid/sessions/{sessionId}/chunks
Body: {
  chunk_index: number,
  total_chunks: number,
  operator_id: string,
  device_id: string,
  events: [{
    epc: string,
    rssi: number,
    read_count: number,
    first_seen_at: string,
    last_seen_at: string
  }]
}
Response: {
  events_accepted: number,
  events_deduplicated: number,
  chunks_received: number,
  chunks_expected: number
}

// Check upload progress (for resume after network failure)
GET /api/rfid/sessions/{sessionId}/upload-status
Response: {
  session_id: string,
  status: "uploading" | "complete" | "incomplete",
  chunks_received: number[],
  chunks_missing: number[],
  total_events: number,
  unique_epcs: number
}

// Complete session and trigger variance calculation
POST /api/rfid/sessions/{sessionId}/complete
Body: {
  ended_at: string,
  notes: string
}
Response: {
  session_id: string,
  status: "completed",
  variance_percent: number,
  review_required: boolean
}

16.9 Summary

The Raptag mobile application provides:

  1. Fast Authentication: PIN-based login with offline support
  2. Home Dashboard: At-a-glance view of assigned counts, sync status, and device health
  3. Flexible Counting: Multiple session types for different inventory needs
  4. Multi-Operator Sessions: Multiple operators scanning sections in parallel with server-side deduplication
  5. Real-time Scanning: Live tag counts with progress tracking and signal feedback
  6. Auto-Save & Recovery: 30-second SQLite checkpoints with crash recovery
  7. Accuracy Tracking: Variance calculation and discrepancy flagging
  8. Chunked Sync: Reliable batch uploads (5,000 events/chunk) with idempotent deduplication
  9. Tag Printing: Integrated label printing with SGTIN-96 encoding

Configuration is managed centrally in the Tenant Admin Portal (Chapter 15), with the mobile app downloading settings on startup. This ensures consistent configuration across all devices and enables remote management without physically accessing scanners.


Document Information

AttributeValue
Version5.0.0
Created2025-12-29
Updated2026-02-25
AuthorClaude Code
StatusActive
PartV - Frontend
Chapter16 of 32

This chapter is part of the POS Blueprint Book. All content is self-contained.