Skip to content

BSS UXI Design Specification - Attendant & Rider Apps

Document Purpose: Comprehensive UXI design specification for BSS Attendant and Rider mobile applications, implementing "Workflow as an integral act" with QR code interactions and form-based user experience.

Reference Workflows: - Attendant Workflow: bss-attendant-workflow-enhanced.md - Rider Workflow: bss-rider-workflow.md

Design Philosophy: - Single Form Continuity: One persistent form that evolves through the workflow - QR-Driven Interactions: QR codes as primary interaction mechanism - Real-Time State Visibility: Transparent system state and progress feedback - Mobile-First Design: Touch-optimized, thumb-friendly layouts


Design Principles

1. Workflow as Integral Act

The entire service transaction is presented as a single, coherent journey rather than disconnected screens.

Implementation: - Single persistent form that expands and updates through workflow stages - Progressive disclosure: Information appears as it becomes relevant - Contextual actions: Buttons change based on workflow state - Visual continuity: Smooth transitions without jarring screen changes - Clear progress indicators showing current position in workflow

2. QR-Driven Interaction Model

QR codes serve as primary interaction mechanism for identity verification, payment, and service coordination.

Implementation: - Camera-first design with QR scanner ready on app launch - Different QR purposes clearly distinguished (customer ID, payment, asset) - Fallback options: Manual entry when QR scanning fails - Dynamic QR code generation for payments - Multi-format support: QR codes, barcodes, NFC tags

3. Real-Time State Transparency

Users see system state, progress, and changes in real-time.

Implementation: - MQTT-driven real-time status updates - Live progress indicators on multi-step processes - State history audit trail in expandable sections - Errors shown inline with recovery suggestions - Skeleton screens during async operations

4. Mobile-First Touch Design

Optimized for one-handed mobile operation in field conditions.

Implementation: - Critical actions within thumb reach zone - Large touch targets: Minimum 44x44pt (Apple HIG) - Swipe gestures for secondary actions - Minimal text entry: QR scanning and selection over typing - High contrast for bright outdoor conditions


Attendant App Design

Screen 1: Home / Ready State

Purpose: Dashboard when no active service transaction

Layout Hierarchy:

Header (64px)
├── Station Name & Location
└── Battery Availability Count

Main Content Area
├── Primary CTA: Scan Customer QR (280px tall, centered)
│   ├── Camera Icon (80px)
│   └── Label "Scan Customer QR"
├── Secondary Actions (48px tall each)
│   ├── Manual Entry Button
│   └── View History Button
└── Current Queue Section
    ├── Section Header "Current Queue (2)"
    └── Queue Items (80px each)
        ├── Customer Name & Status
        └── Progress Indicator

Bottom Navigation (60px)
├── Settings Icon
├── Reports Icon
└── Alerts Icon

Key Measurements: - Screen Width: 375px (iPhone standard) - Header Height: 64px - Primary Button: 280px × 180px - Secondary Buttons: Full width × 48px - Queue Items: Full width × 80px - Bottom Nav: Full width × 60px

Color Scheme (Following DIRAC Color System): - Primary Action: Light Cyan (#E0F7FA) - DIRAC System Color - Success States: Light Green (#C8E6C9) - Internal Actor Color - Warning States: Gold (#FFD700) - External System Color - Background: White (#FFFFFF) - Text Primary: Dark Gray (#212121) - Text Secondary: Medium Gray (#757575)

Typography: - Header: SF Pro Display Bold, 20px - Section Titles: SF Pro Text Semibold, 16px - Body Text: SF Pro Text Regular, 14px - Button Labels: SF Pro Text Medium, 16px

User Interactions: - Tap "Scan Customer QR" → Opens camera with QR scanner overlay - Tap Manual Entry → Shows customer ID input dialog - Tap Queue Item → View transaction details (read-only) - Swipe Down → Refresh station status


Screen 2: Service Event Form - Progressive States

State 1: Customer Verified (After QR Scan)

Layout:

Progress Bar (8px)
└── Step 2 of 6 (33% complete)

Scrollable Content
├── Customer Information Card (Collapsible)
│   ├── Avatar & Name
│   ├── Customer ID
│   ├── Phone Number
│   └── Verification Badge
│
├── Subscription Status Card (Collapsible)
│   ├── Plan Name
│   ├── Period (Start - End, Days Remaining)
│   └── Status Badge (ACTIVE/EXPIRED)
│
├── Quota Status Card (Collapsible)
│   ├── Swap-Count Progress Bar
│   │   └── "6 / 10 used (4 remaining)"
│   ├── Electricity Progress Bar
│   │   └── "344 / 400 kWh (56 kWh left)"
│   └── Payment Status Badge
│
├── Asset Return Section (Active)
│   ├── Expected Battery ID
│   ├── Scan Button (Primary, Full Width, 120px)
│   └── Alternative: "First Visit" Button (Secondary)
│
└── Future Steps (Grayed Out)
    ├── Asset Issuance (Step 4)
    ├── Payment (Step 5)
    └── Service Complete (Step 6)

Bottom Action Bar (Fixed, 80px)
└── Cancel Service Button

Card Specifications: - Card Padding: 16px - Card Margin: 12px horizontal, 8px vertical - Card Border Radius: 12px - Card Shadow: 0 2px 4px rgba(0,0,0,0.1)

Progress Bar: - Height: 8px - Background: Light Gray (#E0E0E0) - Fill: Light Cyan (#00BCD4) - Animation: Smooth transition on step change

Collapsible Card Behavior: - Tap header to expand/collapse - Chevron icon rotates 180° on state change - Smooth height animation (300ms ease-in-out) - Collapsed height: 60px (shows summary only) - Expanded height: Variable based on content

State 2: Battery Scanned (Asset Return Verified)

Changes from State 1:

Asset Return Section (Now Completed) ✅
├── Scanned Battery: BAT-12345 (matches expected)
├── Ownership: ✅ Verified
├── Condition: ✅ Acceptable  
├── Incoming Electricity: 15% SOC (4.8 kWh)
│   ├── Battery icon with percentage
│   └── kWh value below
└── Auto-collapse after 2 seconds

Asset Issuance Section (Now Active)
├── Instruction: "Scan Outgoing Battery"
├── Scan Button (Primary, Full Width, 120px)
└── Available Battery Count: "12 batteries available"

Visual Feedback on Scan Success: - Green checkmark animation (500ms) - Haptic feedback (medium impact) - Success sound (optional, can be disabled) - Section border briefly pulses green - Auto-scroll to next active section

State 3: Outgoing Battery Scanned

Changes:

Asset Issuance Section (Completed) ✅
├── Outgoing Battery: BAT-67890
├── Outgoing Electricity: 95% SOC (30.4 kWh)
├── Net Electricity Delivered: 80% (25.6 kWh)
│   ├── Calculation shown clearly
│   └── Visual: 95% - 15% = 80% with battery icons
└── Auto-collapse after 2 seconds

Quota Validation Section (Auto-calculated, Read-only)
├── Swap-Count Impact
│   └── "6 → 7 used (3 remaining) ✅"
├── Electricity Impact  
│   └── "344 → 369.6 kWh used (30.4 kWh left) ✅"
└── Status: ✅ Sufficient Quotas
    OR
    ❌ Quota Exhausted - Top-up Required

Payment Section (Conditionally Active)
├── IF quotas sufficient: "No Payment Required"
├── IF quota exhausted: Payment QR Code & Amount

Quota Exhaustion Flow:

Payment Section (Active when quota exhausted)
├── Top-up Amount Breakdown
│   ├── Swap-Count Deficit: "1 swap needed"
│   ├── Electricity Deficit: "30 kWh needed"
│   └── Total Amount Due: "$15.00" (Large, bold)
│
├── Payment QR Code (300px × 300px, centered)
│   ├── Generated dynamically
│   └── Odoo payment link encoded
│
├── Payment Instructions
│   └── "Ask rider to scan QR with their phone"
│
└── Payment Status Indicator
    ├── Initial: ⏳ "Awaiting Payment..."
    ├── Success: ✅ "Payment Received"
    └── Auto-refresh every 3 seconds

Payment QR Code Specifications: - Size: 300px × 300px - Margin: 24px all sides - Background: White - Foreground: Black - Error Correction: Level H (30%) - Encoding: Odoo payment URL with parameters: - merchant_id - amount - service_description - customer_id - transaction_id

State 4: Payment Completed (or Not Required)

Changes:

Payment Section (Completed) ✅
├── Payment Status: ✅ Paid
├── Receipt ID: PAY-78910
├── Amount: $15.00
└── Timestamp

Service Complete Section (Now Active)
├── Summary of Transaction
│   ├── Customer: John Doe
│   ├── Incoming Battery: BAT-12345 (15% → Returned)
│   ├── Outgoing Battery: BAT-67890 (95% → Issued)
│   ├── Net Electricity: 25.6 kWh delivered
│   ├── Updated Quotas
│   │   ├── Swaps: 7/10
│   │   └── Electricity: 369.6/400 kWh
│   └── Payment: $15.00 (if applicable)
│
└── Confirm Button (Primary, Full Width, 60px)
    └── "Complete Service & Hand Over Battery"

Complete Service Button: - Height: 60px - Background: Light Green (#4CAF50) - Text: White, Bold, 18px - Haptic feedback on tap - Disabled until all validations pass - Loading spinner during MQTT publish


Screen 3: Receipt & Confirmation

Purpose: Transaction summary and digital receipt

Layout:

Header (80px)
├── Success Icon (48px checkmark in circle)
└── "Service Complete!"

Receipt Content (Scrollable)
├── Transaction ID
├── Timestamp
├── Customer Information
├── Service Details
│   ├── Battery Swap
│   │   ├── Returned: BAT-12345 (15% SOC)
│   │   └── Issued: BAT-67890 (95% SOC)
│   └── Electricity Delivered: 25.6 kWh
├── Quota Status (Updated)
│   ├── Swaps Remaining: 3
│   └── Electricity Remaining: 30.4 kWh
├── Payment Information (if applicable)
│   ├── Amount: $15.00
│   └── Receipt: PAY-78910
└── Next Service Date Estimate

Bottom Actions (Fixed, 120px)
├── Share Receipt Button (Secondary, 48px)
├── Print Receipt Button (Secondary, 48px)
└── New Service Button (Primary, 56px)

Receipt Styling: - Background: White card on light gray background - Card padding: 24px - Font: Monospace for IDs and numbers - Dividers between sections (1px, #E0E0E0) - Success color accents for positive values

Share/Print Actions: - Share: Opens native share sheet (email, SMS, WhatsApp) - Print: Sends to Bluetooth thermal printer if configured - Receipt format: Plain text with clear structure


Rider App Design

Screen 1: Service Discovery (W1)

Purpose: Find available swap stations and batteries based on service bundle

Layout:

Header (120px)
├── User Avatar & Name
├── Active Plan Badge
└── Quick Quota Summary
    ├── Swaps: 4 remaining
    └── kWh: 56 remaining

Map View (Primary, 60% of screen)
├── User Location Pin (Blue)
├── Station Markers (Green with battery icon)
│   ├── Size indicates availability
│   └── Tap to select
├── Zoom Controls
└── Center on User Button

Station List (Bottom Sheet, Draggable)
├── Handle (Drag indicator, 4px × 32px)
├── Results Count: "3 stations nearby"
└── Station Cards (Scrollable)
    ├── Station Name & Distance
    ├── Available Batteries Count
    ├── Estimated Wait Time
    ├── Directions Button
    └── Signal Intent Button (Primary)

Map Specifications: - Zoom level: Auto-adjust to show all stations within 10km - User location: Blue pulsing circle - Station markers: Custom icon (battery symbol) - Marker size: 32px-48px based on battery count - Selected marker: Highlighted with ring

Bottom Sheet Behavior: - Initial state: Collapsed (showing 2 cards) - Drag up: Expands to show full list - Drag down: Collapses to minimum - Snap points: 30%, 60%, 90% of screen height - Dismiss: Swipe down past 30%

Station Card:

Station Card (Full Width, 120px)
├── Station Name (Bold, 16px)
├── Distance & Direction
│   └── "2.3 km • Northwest"
├── Battery Availability
│   ├── Icon count (battery icons × available count)
│   └── "12 batteries • No wait"
├── Quick Actions
    ├── Directions (Icon button, opens maps app)
    └── Signal Intent (Primary, 40px tall)

Color Coding for Availability: - High availability (8+): Green - Medium availability (4-7): Yellow - Low availability (1-3): Orange - No availability: Red (grayed out, no intent button)


Screen 2: Service Intent Signal (W2)

Trigger: Rider taps "Signal Intent" on a station card

Layout (Modal overlay):

Modal (Rounded corners, slides up)
├── Header
│   ├── Station Name
│   └── Close Button (×)
│
├── Confirmation Message
│   └── "Signal your arrival to Nairobi Hub 01?"
│
├── Your Service Requirements (Read-only)
│   ├── Service: Battery Swap
│   ├── Current Battery: BAT-12345
│   └── Estimated Service Time: 5-10 minutes
│
├── Estimated Arrival Time (Editable)
│   ├── Picker: "15 minutes" (default)
│   └── Options: 5, 10, 15, 20, 30, 45, 60 minutes
│
└── Action Buttons (Stacked, Full Width)
    ├── Confirm & Navigate (Primary, 56px)
    │   └── "Send Signal & Get Directions"
    └── Cancel (Secondary, 48px)

After Confirmation:

Success State (Replaces modal content)
├── Success Icon (Animated checkmark)
├── Message: "Station notified of your arrival"
├── Status Updates (Real-time)
│   ├── ✅ Signal sent
│   ├── ✅ Station acknowledged
│   └── ⏳ Attendant preparing...
└── Navigate Button (Primary)
    └── Opens navigation app with destination

Modal Specifications: - Width: 90% of screen width - Max width: 400px - Border radius: 20px (top corners) - Background: White - Backdrop: Semi-transparent dark (#000000, 50% opacity) - Animation: Slide up from bottom (300ms)


Screen 3: At Station - Check-in (W3)

Purpose: Location authentication and customer-location binding

Layout:

Header (Contextual)
├── Station Name
├── Status: "You're here!"
└── Distance: "Within 50m"

Main Content
├── Check-in Prompt
│   └── "Show your QR code to the attendant"
│
├── Customer QR Code (Large, 320px × 320px)
│   ├── Customer ID encoded
│   ├── ServicePlan ID encoded
│   └── Session token encoded
│
├── QR Code Label
│   └── Customer ID: CUST-12345
│
└── Alternative Check-in Methods
    ├── NFC Tap (if supported)
    │   └── "Or tap your phone to the station reader"
    └── Manual Code Entry
        └── "Code: 1234-5678"

Status Panel (Below QR, Collapsible)
├── Your Service Details
│   ├── Plan: Weekly Freedom Basic
│   ├── Swaps Left: 4
│   ├── kWh Left: 56
│   └── Current Battery: BAT-12345
└── Station Status
    ├── Queue Position: 2nd in line
    └── Estimated Wait: 8 minutes

QR Code Specifications: - Size: 320px × 320px - Margin: 32px all sides - Background: White card with shadow - Brightness: Auto-boost to maximum - Timeout: Regenerates every 60 seconds for security - Encoding Format:

{
  "customer_id": "CUST-12345",
  "plan_id": "bss-plan-weekly-freedom-nairobi-v2-plan1",
  "session_token": "encrypted_session_token",
  "timestamp": "2025-11-18T10:30:00Z",
  "station_id": "nairobi-hub-01"
}

Auto-brightness: - Screen brightness forced to 100% on this screen - Prevents screen dimming while QR displayed - Restores previous brightness on exit


Screen 4: Service in Progress (W4 & W5)

Purpose: Real-time service progress tracking

Layout:

Progress Timeline (Vertical, left-aligned)
├── 1. Check-in ✅ Completed (10:25 AM)
├── 2. Battery Return ⏳ In Progress
│   ├── "Attendant scanning your battery..."
│   └── Spinner animation
├── 3. Battery Issuance ⏺ Pending
├── 4. Payment (if needed) ⏺ Pending
└── 5. Complete ⏺ Pending

Current Step Details (Card)
├── Step Title: "Battery Return"
├── Description
│   └── "Attendant is verifying your battery"
├── What's Happening (Real-time updates)
│   ├── ✅ Battery ID verified: BAT-12345
│   ├── ✅ Ownership confirmed
│   ├── ⏳ Checking battery condition...
│   └── Last updated: 2 seconds ago
└── Estimated Time Remaining: "2-3 minutes"

Bottom Actions
└── Need Help? Button (Secondary)
    └── Opens help options (call, message)

Timeline Styling: - Line thickness: 4px - Line color: Light gray (#E0E0E0) - Active step: Light cyan (#00BCD4) - Completed step: Light green (#4CAF50) - Step circle: 32px diameter - Icon size: 20px inside circle

Real-Time Updates: - MQTT subscription to service event topics - Updates appear as they occur (no manual refresh) - Smooth animation when new updates arrive - "Last updated" timestamp for transparency

Payment Step (When Triggered):

Payment Step (Active)
├── Payment Required Notice
│   ├── Reason: "Quota Top-up Required"
│   └── Amount: $15.00
│
├── Payment Breakdown
│   ├── Swap-Count Top-up: $10.00
│   └── Electricity Top-up: $5.00
│
├── Payment QR Code (Generated by attendant)
│   └── "Scan the QR code shown by attendant"
│
└── OR Manual Payment Options
    ├── M-Pesa Button
    ├── Card Payment Button
    └── Other Payment Methods

Payment Flow: 1. System detects quota exhaustion 2. Rider notified: "Top-up required: $15.00" 3. Attendant generates payment QR 4. Rider scans QR with phone 5. Opens Odoo payment page 6. Rider completes payment 7. Confirmation → Service resumes


Screen 5: Service Complete

Purpose: Transaction confirmation and receipt

Layout:

Success Animation (Top, 200px)
├── Animated checkmark (2s animation)
└── "Service Complete!"

Transaction Summary Card
├── Service Type: Battery Swap
├── Timestamp: 10:35 AM
├── Duration: 10 minutes
│
├── Battery Exchange
│   ├── Returned: BAT-12345 (15% → 4.8 kWh)
│   └── Received: BAT-67890 (95% → 30.4 kWh)
│
├── Energy Received: 25.6 kWh
│
├── Payment (if applicable)
│   ├── Amount Paid: $15.00
│   └── Receipt: PAY-78910
│
└── Updated Quotas
    ├── Swaps Remaining: 3 / 10
    │   └── Progress bar (70% consumed)
    ├── Electricity Remaining: 30.4 / 400 kWh
        └── Progress bar (92% consumed)

Important Information (Warning card, if applicable)
└── "Low on quotas! 30.4 kWh remaining"
    └── Suggestion: "Consider topping up"

Bottom Actions
├── Save Receipt Button (Secondary, 48px)
├── Rate Experience Button (Secondary, 48px)
└── Done Button (Primary, 56px)
    └── Returns to home screen

Receipt Export Options: - Email receipt - Download PDF - Share via SMS/WhatsApp - Add to digital wallet (Apple Wallet, Google Pay)


Shared Design Components

1. Battery Level Indicator

Visual Component (Reusable across both apps):

Battery Icon Component
├── Outline: Battery shape (40px × 20px)
├── Fill: Colored bar based on percentage
│   ├── 80-100%: Green
│   ├── 40-79%: Yellow
│   ├── 10-39%: Orange
│   └── 0-9%: Red
├── Percentage Label
│   └── "95%" (Below or beside icon)
└── kWh Value (Optional)
    └── "30.4 kWh" (Smaller text)

Usage: - Asset return/issuance sections - Transaction summaries - Battery fleet displays

2. Progress Bar

Specifications:

Progress Bar Component
├── Height: 8px (default) or 12px (large)
├── Background: Light gray (#E0E0E0)
├── Fill: Dynamic color based on context
│   ├── Quota usage: Light cyan (#00BCD4)
│   ├── Success: Green (#4CAF50)
│   └── Warning: Orange (#FF9800)
├── Border Radius: 4px
├── Animation: Smooth fill transition (500ms)
└── Label (Optional)
    ├── Above: "6 / 10 used"
    └── Below: "(4 remaining)"

3. Status Badge

Component:

Status Badge
├── Size: 24px height
├── Padding: 8px horizontal, 4px vertical
├── Border Radius: 12px (pill shape)
├── Font: Bold, 12px, Uppercase
└── Color Variants:
    ├── ACTIVE: Green background, white text
    ├── PENDING: Yellow background, dark text
    ├── EXPIRED: Red background, white text
    ├── COMPLETE: Blue background, white text
    └── SUSPENDED: Gray background, white text

4. Collapsible Card

Behavior Specification:

Collapsible Card Component
├── Header (Always visible, 60px)
│   ├── Title (Left-aligned)
│   ├── Summary (Below title, smaller)
│   └── Chevron Icon (Right-aligned, rotates on toggle)
│
├── Content (Expandable, variable height)
│   ├── Padding: 16px
│   └── Content elements
│
└── Interaction
    ├── Tap header to toggle
    ├── Smooth height animation (300ms ease-in-out)
    ├── Haptic feedback on toggle
    └── State persists during session

Animation Curve: - Easing: Cubic-bezier(0.4, 0.0, 0.2, 1) - Duration: 300ms - Property: Max-height (for smooth collapse)

5. Action Button Variants

Primary Button:

Specifications:
├── Height: 56px (default) or 48px (compact)
├── Width: Full width or auto (with min-width: 160px)
├── Background: Light Cyan (#00BCD4) or Green (#4CAF50)
├── Text: White, Bold, 16px
├── Border Radius: 8px
├── Shadow: 0 4px 8px rgba(0,0,0,0.15)
├── Active State: Darken 10%, scale 0.98
└── Disabled State: Gray (#BDBDBD), no shadow

Secondary Button:

Specifications:
├── Height: 48px
├── Background: Transparent or Light Gray (#F5F5F5)
├── Border: 2px solid Light Gray (#E0E0E0)
├── Text: Dark Gray (#424242), Medium, 14px
├── Border Radius: 8px
├── Active State: Background Light Gray (#EEEEEE)
└── Disabled State: Faded (opacity: 0.5)

Icon Button:

Specifications:
├── Size: 48px × 48px (touch target)
├── Icon Size: 24px
├── Background: Transparent or subtle color
├── Border Radius: 24px (circular)
├── Active State: Background tint
└── Ripple Effect: Material Design ripple

6. QR Code Scanner Overlay

Full-Screen Component:

Scanner Overlay
├── Camera View (Full screen)
├── Viewfinder Frame (280px × 280px, centered)
│   ├── Corner brackets (white, 4px thick)
│   ├── Scanning line (animated, moves up/down)
│   └── Semi-transparent mask around frame
├── Instructions (Top, 80px from top)
│   └── "Align QR code within frame"
├── Torch Toggle (Top right, icon button)
├── Close Button (Top left, × icon)
└── Manual Entry Option (Bottom, 80px from bottom)

Scanner Animation: - Scanning line: 2px height, white with glow - Movement: Top to bottom, 2s loop - Glow effect: Box-shadow with light cyan

Success Feedback: - Green flash over frame (200ms) - Haptic feedback (success pattern) - Success sound (if enabled) - Auto-dismiss scanner after 500ms


QR Code Integration Patterns

QR Code Types & Encoding

1. Customer Identity QR

Used by: Rider app (displayed), Attendant app (scanned)

Encoded Data:

{
  "type": "customer_identity",
  "customer_id": "CUST-12345",
  "plan_id": "bss-plan-weekly-freedom-nairobi-v2-plan1",
  "session_token": "enc_token_xyz789",
  "timestamp": "2025-11-18T10:30:00Z",
  "expires": "2025-11-18T10:31:00Z",
  "checksum": "abc123def456"
}

Security: - Regenerates every 60 seconds - Session token encrypted with AES-256 - Timestamp validation (±2 minutes tolerance) - Checksum prevents tampering

2. Payment QR

Used by: Attendant app (generated), Rider app/phone (scanned)

Encoded Data:

https://payments.odoo.oves.com/pay?
  merchant=nairobi-hub-01
  &amount=15.00
  &currency=USD
  &service=battery-swap-topup
  &customer=CUST-12345
  &transaction=TXN-789456
  &signature=sig_xyz789abc

Specifications: - Format: URL with query parameters - Opens: Odoo payment page in default browser - Signature: HMAC-SHA256 for verification - Expiration: 10 minutes

3. Battery Asset QR

Used by: Attendant app (scanned)

Encoded Data:

{
  "type": "battery_asset",
  "asset_id": "BAT-12345",
  "fleet_id": "battery-fleet-kenya-premium",
  "last_service": "2025-11-15T08:00:00Z",
  "soc_percent": 15,
  "health_status": "good"
}

Usage: - Scanned during asset return - Scanned during asset issuance - Validates against expected asset in ServicePlan


Form-Based UX Architecture

Single Persistent Form Pattern

Core Concept: The service transaction is represented as a single form that evolves through states rather than navigating between separate screens.

Implementation Strategy:

1. Form State Machine

Form States (Attendant App):
├── IDLE (Home screen)
├── CUSTOMER_SCANNED (Step 2)
├── ASSET_RETURN_ACTIVE (Step 3)
├── ASSET_RETURN_COMPLETE
├── ASSET_ISSUANCE_ACTIVE (Step 4)
├── ASSET_ISSUANCE_COMPLETE
├── PAYMENT_REQUIRED (Step 5, conditional)
├── PAYMENT_AWAITING
├── PAYMENT_COMPLETE
├── SERVICE_READY_TO_COMPLETE (Step 6)
└── SERVICE_COMPLETE (Receipt screen)

State Transitions: - Triggered by user actions (scanning, button taps) - Triggered by system events (MQTT messages, validations) - Each transition updates form sections visibility/content - Progress bar reflects current state

2. Section Visibility Rules

Visibility Matrix:

State                    | Customer | Subscription | Quota | Asset Return | Asset Issue | Payment | Complete
-------------------------+----------+--------------+-------+--------------+-------------+---------+---------
CUSTOMER_SCANNED         | Visible  | Visible      | Visible| Active      | Hidden      | Hidden  | Hidden
ASSET_RETURN_COMPLETE    | Collapsed| Collapsed    | Collapsed| Completed | Active      | Hidden  | Hidden
ASSET_ISSUANCE_COMPLETE  | Collapsed| Collapsed    | Updated| Completed   | Completed   | Active  | Hidden
PAYMENT_COMPLETE         | Collapsed| Collapsed    | Updated| Collapsed   | Collapsed   | Complete| Active

Behavior: - Visible: Section displayed in expanded state - Collapsed: Section displayed in collapsed state (summary only) - Active: Section is current focus, highlighted, interactive - Completed: Section shows checkmark, auto-collapses after 2s - Hidden: Section not rendered in DOM - Updated: Section content refreshed with new data

3. Progressive Disclosure Mechanics

Information Reveal Strategy:

Initial Display (Minimal):
└── Show only immediately relevant information

User Progresses:
├── Completed sections collapse automatically
├── Next section expands and scrolls into view
├── Summary information moves to collapsed headers
└── Detailed info hidden but accessible via tap

Benefits:
├── Reduced cognitive load
├── Clear focus on current step
├── Easy access to previous information if needed
└── Mobile-friendly (less scrolling)

Example - Quota Status Section:

Collapsed View (60px):
┌─────────────────────────────────┐
│ 📊 Quotas: 4 swaps, 56 kWh  [▼]│
└─────────────────────────────────┘

Expanded View (180px):
┌─────────────────────────────────┐
│ 📊 QUOTA STATUS            [▲] │
├─────────────────────────────────┤
│ Swap-Count                      │
│ ████████░░ 6/10 (4 remaining)   │
│                                 │
│ Electricity-Fuel                │
│ ███████████░ 344/400 kWh        │
│ (56 kWh remaining)              │
│                                 │
│ Payment Status: CURRENT ✅      │
└─────────────────────────────────┘


State Management & Real-Time Updates

MQTT Integration for Live Updates

Subscription Topics (Attendant App):

Topics to Subscribe:
├── echo/abs/attendant/plan/{plan_id}/payment_received
├── echo/abs/attendant/plan/{plan_id}/quota_updated
├── echo/abs/attendant/station/{station_id}/queue_updated
└── emit/abs/bss/service/+/status_change

Event Handling:

// Pseudo-code for real-time form updates
mqtt.on('message', (topic, payload) => {
  const event = JSON.parse(payload);

  switch (event.type) {
    case 'payment_received':
      updateFormSection('payment', {
        status: 'complete',
        receipt_id: event.receipt_id
      });
      transitionFormState('PAYMENT_COMPLETE');
      break;

    case 'quota_updated':
      updateFormSection('quota', {
        swaps_remaining: event.swaps_remaining,
        kwh_remaining: event.kwh_remaining
      });
      break;

    case 'queue_updated':
      updateQueueDisplay(event.queue_data);
      break;
  }
});

Update Animation: - Changed values briefly highlight (yellow background fade) - Duration: 1s fade out - Smooth number transitions (count-up animation) - Status badges transition with scale effect

Local State Management

State Structure:

interface AttendantFormState {
  currentStep: number; // 1-6
  formState: FormStateEnum;

  customer: {
    id: string;
    name: string;
    phone: string;
    verified: boolean;
  };

  subscription: {
    plan_id: string;
    plan_name: string;
    start_date: Date;
    end_date: Date;
    status: 'ACTIVE' | 'EXPIRED' | 'SUSPENDED';
  };

  quotas: {
    swap_count: { used: number; limit: number; };
    electricity: { used: number; limit: number; };
    payment_status: 'CURRENT' | 'OVERDUE';
  };

  assetReturn: {
    expected_battery_id: string;
    scanned_battery_id: string | null;
    incoming_soc: number | null;
    ownership_verified: boolean;
    condition: 'good' | 'damaged' | null;
  };

  assetIssuance: {
    outgoing_battery_id: string | null;
    outgoing_soc: number | null;
    net_electricity_delivered: number | null;
  };

  payment: {
    required: boolean;
    amount: number;
    qr_code_data: string | null;
    status: 'pending' | 'awaiting' | 'complete' | null;
    receipt_id: string | null;
  };

  validation: {
    can_proceed: boolean;
    blocking_issues: string[];
  };
}

State Persistence: - Local storage backup every state change - Restore on app crash/restart - Clear on successful completion - Retain for 24 hours in case of issues


Error Handling & User Feedback

Error Categories & Responses

1. Scan Errors

QR Scan Failures:

Error Display (Toast notification):
┌─────────────────────────────────┐
│ ⚠️ QR Code Not Recognized       │
│ Try again or use Manual Entry   │
│ [Retry] [Manual Entry]          │
└─────────────────────────────────┘

Duration: 5 seconds or until dismissed
Position: Bottom of screen, above actions

Battery Mismatch:

Error Display (Inline, in Asset Return section):
┌─────────────────────────────────┐
│ ❌ Battery Mismatch              │
│                                 │
│ Expected: BAT-12345             │
│ Scanned:  BAT-99999             │
│                                 │
│ Please scan the correct battery │
│ [Try Again]                     │
└─────────────────────────────────┘

Haptic: Error pattern
Sound: Error beep (if enabled)

2. Quota Exhaustion

Graceful Handling:

Quota Exhaustion Display:
┌─────────────────────────────────┐
│ ⚠️ Quota Exhausted               │
│                                 │
│ Swap-Count: 10/10 (0 left)     │
│ Top-up required: $10.00         │
│                                 │
│ Electricity: 400/400 kWh (0)   │
│ Top-up required: $5.00          │
│                                 │
│ Total Payment: $15.00           │
│                                 │
│ [Generate Payment QR]           │
└─────────────────────────────────┘

User Guidance: - Clear explanation of issue - Specific quota deficits shown - Calculated top-up amount - Direct action to resolve (payment)

3. Payment Timeout

Timeout Handling:

After 5 minutes of awaiting payment:
┌─────────────────────────────────┐
│ ⏰ Payment Timeout               │
│                                 │
│ Payment not received within     │
│ expected time (5 minutes)       │
│                                 │
│ Options:                        │
│ • [Refresh Status] Check again  │
│ • [Generate New QR] New code    │
│ • [Cancel Service] Abort swap   │
└─────────────────────────────────┘

4. Network Errors

Offline State:

Banner (Fixed at top):
┌─────────────────────────────────┐
│ 📡 Offline Mode                  │
│ Changes will sync when online   │
└─────────────────────────────────┘

Behavior:
├── Form remains functional
├── Actions queued locally
├── Syncs when connection restored
└── Conflict resolution UI if needed

Connection Restored:

Toast (Auto-dismiss after 3s):
┌─────────────────────────────────┐
│ ✅ Back Online                   │
│ Syncing changes...              │
└─────────────────────────────────┘

Validation Feedback

Real-Time Validation:

Field-Level Validation (Example: Manual Entry):
┌─────────────────────────────────┐
│ Customer ID                     │
│ [CUST-_____]                    │
│                                 │
│ ❌ ID must be 5 digits           │
└─────────────────────────────────┘

Valid State:
┌─────────────────────────────────┐
│ Customer ID                     │
│ [CUST-12345] ✅                  │
└─────────────────────────────────┘

Form-Level Validation:

"Complete Service" button states:

Disabled (issues present):
┌─────────────────────────────────┐
│ [Complete Service - Disabled]   │
│                                 │
│ Cannot proceed:                 │
│ • Payment not received          │
│ • Battery not handed over       │
└─────────────────────────────────┘

Enabled (ready):
┌─────────────────────────────────┐
│ [✅ Complete Service]            │
│ All validations passed          │
└─────────────────────────────────┘


Accessibility & Internationalization

Accessibility Standards

WCAG 2.1 Level AA Compliance:

Color Contrast: - Text on background: Minimum 4.5:1 ratio - Large text (18px+): Minimum 3:1 ratio - Interactive elements: Clear focus indicators - Status not conveyed by color alone (icons + text)

Touch Targets: - Minimum size: 44px × 44px (Apple HIG) - Spacing between targets: 8px minimum - Larger targets for primary actions: 56px height

Screen Reader Support:

ARIA Labels (Examples):
├── "Scan customer QR code button"
├── "Customer John Doe, verified"
├── "Quota status: 4 swaps remaining out of 10"
├── "Payment required: 15 dollars"
└── "Service complete button, enabled"

Keyboard Navigation (For tablet/web versions): - Logical tab order following visual flow - Enter/Space activates buttons - Esc dismisses modals - Arrow keys navigate lists

Dynamic Type Support: - Text scales with system font size settings - Layout adapts to larger text (iOS Dynamic Type, Android) - Minimum font size: 14px (before scaling)

Internationalization

Supported Languages (Initial): - English (en-US) - Swahili (sw-KE) - Primary for Kenya market - French (fr-FR) - For potential expansion

i18n Implementation:

// String resources structure
{
  "en-US": {
    "attendant.home.scan_button": "Scan Customer QR",
    "attendant.form.quota_status": "Quota Status",
    "attendant.form.swaps_remaining": "{remaining} swaps remaining",
    "attendant.payment.amount_due": "Amount Due: ${amount}",
    "attendant.complete.success": "Service Complete!"
  },
  "sw-KE": {
    "attendant.home.scan_button": "Changanua QR ya Mteja",
    "attendant.form.quota_status": "Hali ya Mgao",
    "attendant.form.swaps_remaining": "Mabadiliko {remaining} yaliyobaki",
    "attendant.payment.amount_due": "Kiasi Kinachohitajika: ${amount}",
    "attendant.complete.success": "Huduma Imekamilika!"
  }
}

Number & Currency Formatting: - Currency: Locale-aware (USD, KES, etc.) - Numbers: Locale-specific thousand separators - Dates: Locale-specific formats - Time: 12/24-hour based on locale

RTL Support (Future): - Layout mirroring for RTL languages - Icon directionality adjustments - Text alignment changes


Technical Implementation Specifications

Technology Stack

Frontend Framework: - React Native (mobile apps) - React version: 18.x - TypeScript for type safety

State Management: - React Context API for global state - React hooks (useState, useEffect, useReducer) - Local storage persistence: AsyncStorage (React Native)

MQTT Client: - Library: mqtt.js or paho-mqtt - WebSocket over TLS (wss://) - Auto-reconnection with exponential backoff

QR Code: - Generation: react-native-qrcode-svg - Scanning: react-native-camera or expo-camera - Barcode support: Multiple formats (QR, Code128, etc.)

Navigation: - React Navigation 6.x - Stack navigator for screen flow - Modal presentation for overlays

Component Architecture

Folder Structure:

/src
  /components
    /shared
      - Button.tsx
      - Card.tsx
      - ProgressBar.tsx
      - StatusBadge.tsx
      - BatteryIcon.tsx
      - QRScanner.tsx
    /attendant
      - ServiceEventForm.tsx
      - AssetReturnSection.tsx
      - AssetIssuanceSection.tsx
      - PaymentSection.tsx
      - QuotaDisplay.tsx
    /rider
      - StationMap.tsx
      - StationCard.tsx
      - ServiceProgress.tsx
      - CustomerQRCode.tsx
  /screens
    /attendant
      - HomeScreen.tsx
      - ServiceScreen.tsx
      - ReceiptScreen.tsx
    /rider
      - DiscoveryScreen.tsx
      - IntentScreen.tsx
      - CheckInScreen.tsx
      - ProgressScreen.tsx
      - CompleteScreen.tsx
  /services
    - mqttService.ts
    - qrService.ts
    - locationService.ts
    - apiService.ts
  /store
    - attendantContext.tsx
    - riderContext.tsx
  /utils
    - formatters.ts
    - validators.ts
    - constants.ts
  /types
    - models.ts
    - api.ts

API Integration Points

GraphQL Endpoints (via FED):

# Query customer and plan data
query GetCustomerServicePlan($customerId: ID!) {
  customer(id: $customerId) {
    id
    name
    phone
    servicePlans {
      id
      templateId
      subscriptionStart
      subscriptionEnd
      serviceStates {
        serviceId
        used
        quota
      }
      paymentStatus
    }
  }
}

# Mutation for service completion
mutation CompleteServiceEvent($input: ServiceEventInput!) {
  completeServiceEvent(input: $input) {
    transactionId
    updatedQuotas {
      serviceId
      used
      quota
    }
    receipt {
      id
      amount
      timestamp
    }
  }
}

MQTT Topics:

Attendant App Subscriptions:
├── echo/abs/attendant/plan/{plan_id}/payment_received
├── echo/abs/attendant/plan/{plan_id}/quota_updated
├── echo/abs/attendant/station/{station_id}/queue_updated
└── emit/odoo/payment/plan/{plan_id}/payment_confirmed

Rider App Subscriptions:
├── echo/abs/rider/plan/{plan_id}/service_progress
├── echo/abs/rider/plan/{plan_id}/payment_required
└── emit/abs/bss/service/{customer_id}/status_change

Performance Optimizations

Rendering: - React.memo for expensive components - useMemo for computed values - useCallback for event handlers - Virtualized lists for long queues/station lists

Images & Assets: - SVG icons (scalable, small file size) - WebP format for photos - Lazy loading for off-screen content - Image caching with react-native-fast-image

Network: - GraphQL query batching - MQTT message compression - Optimistic UI updates - Background sync for offline changes

Storage: - IndexedDB/AsyncStorage for local data - Cache ServicePlan data (1-hour TTL) - Queue failed API calls for retry - Clean up old cached data periodically


Next Steps: Implementation Roadmap

Phase 1: Core Attendant App (Weeks 1-3)

  1. ✅ Home screen with QR scanner
  2. ✅ Service Event Form structure
  3. ✅ Customer verification flow
  4. ✅ Asset return/issuance sections
  5. ✅ Basic MQTT integration

Phase 2: Payment & Completion (Weeks 4-5)

  1. ✅ Payment QR generation
  2. ✅ Payment status polling
  3. ✅ Service completion flow
  4. ✅ Receipt generation

Phase 3: Rider App Foundation (Weeks 6-8)

  1. ✅ Service discovery with map
  2. ✅ Station list and filtering
  3. ✅ Intent signaling flow
  4. ✅ Customer QR code display

Phase 4: Rider Service Tracking (Weeks 9-10)

  1. ✅ Check-in screen
  2. ✅ Service progress tracking
  3. ✅ Payment flow (rider side)
  4. ✅ Completion and receipt

Phase 5: Polish & Testing (Weeks 11-12)

  1. ✅ Error handling refinement
  2. ✅ Offline mode testing
  3. ✅ Accessibility audit
  4. ✅ Performance optimization
  5. ✅ User acceptance testing

Design Review Checklist

  • Workflow Integration: Designs map to finalized workflow documents
  • QR Code Patterns: All QR interactions clearly specified
  • Form Continuity: Single persistent form pattern implemented
  • Real-Time Updates: MQTT integration points defined
  • Mobile Optimization: Touch targets, thumb zones, gestures
  • Error Handling: Comprehensive error states and recovery
  • Accessibility: WCAG 2.1 AA compliance planned
  • Internationalization: i18n structure defined
  • Component Reusability: Shared components identified
  • State Management: Clear state structure and transitions
  • Performance: Optimization strategies outlined
  • DIRAC Alignment: Color system and component integration

Document Status: Ready for Figma Implementation
Last Updated: 2025-11-18
Version: 1.0
Approved for: UXI Design Phase