WellNuo/backend/docs/EQUIPMENT_STATUS.md
Sergei f69ddb7538 Add equipment status mapping documentation and tests
- Created comprehensive EQUIPMENT_STATUS.md documentation covering:
  - All valid status values (none, ordered, shipped, delivered, demo, active)
  - Database schema details
  - Navigation logic based on equipment status
  - hasDevices flag calculation
  - Code locations for reading/setting status

- Added unit tests for equipment status mapping:
  - Tests for all valid status values
  - Demo serial number detection (DEMO-00000, DEMO-1234-5678)
  - Real device activation
  - hasDevices calculation for each status
  - Default value handling (null → 'none')

- All tests passing (13/13)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-29 11:18:16 -08:00

5.1 KiB

Equipment Status Mapping

Overview

The equipment_status field tracks the state of IoT equipment for each beneficiary in the WellNuo system.

Database Field

  • Table: beneficiaries
  • Column: equipment_status (VARCHAR)
  • Default: 'none'
  • Constraint: No CHECK constraint defined in schema (any string value allowed)

Valid Status Values

Status Description When Set User Flow
none No equipment ordered or assigned • Initial beneficiary creation
• Default state
User sees "Purchase Equipment" screen
ordered Equipment ordered, payment completed • After successful Stripe payment
• Order status: paid
User sees "Order Tracking" screen
shipped Equipment in transit • Order status changes to shipped
• Tracking number assigned
User sees "Delivery Status" screen
delivered Equipment arrived at destination • Order status changes to delivered User sees "Activate Equipment" screen
demo Demo mode activated (no real devices) • User activates with serial DEMO-00000 or DEMO-1234-5678 Full app access with simulated data
active Real equipment activated and operational • User activates with real device serial number Full app access with real sensor data

Code Locations

Setting Status

// Initial creation (none)
POST /api/me/beneficiaries
   equipment_status: 'none'

// Activation (demo or active)
POST /api/me/beneficiaries/:id/activate
   isDemoMode = serialNumber === 'DEMO-00000' || serialNumber === 'DEMO-1234-5678'
   equipment_status: isDemoMode ? 'demo' : 'active'

// Order status changes (ordered, shipped, delivered)
POST /api/webhook/stripe
   Updates based on Stripe events

Reading Status

// List beneficiaries
GET /api/me/beneficiaries
   equipmentStatus: beneficiary.equipment_status || 'none'
   hasDevices: beneficiary.equipment_status === 'active' || beneficiary.equipment_status === 'demo'

// Get single beneficiary
GET /api/me/beneficiaries/:id
   equipmentStatus: beneficiary.equipment_status || 'none'
   hasDevices: beneficiary.equipment_status === 'active' || beneficiary.equipment_status === 'demo'

Navigation Logic (NavigationController)

The equipmentStatus determines which screen to show after login/beneficiary creation:

if (equipmentStatus === 'none') {
   /(auth)/purchase - Buy equipment
}

if (equipmentStatus === 'ordered' || equipmentStatus === 'shipped') {
   /(tabs)/beneficiaries/:id/equipment - Track delivery
}

if (equipmentStatus === 'delivered') {
   /(auth)/activate - Activate equipment
}

if (equipmentStatus === 'active' || equipmentStatus === 'demo') {
   /(tabs)/dashboard - Full app access
}

hasDevices Flag

Critical for navigation: hasDevices is derived from equipmentStatus:

hasDevices = (equipmentStatus === 'active' || equipmentStatus === 'demo')

This flag is used in:

  • Navigation decisions (show dashboard vs purchase)
  • Feature access control (sensors, alarms, etc.)
  • UI conditional rendering

Issues Found

  1. No Database Constraint: The equipment_status column has no CHECK constraint, allowing any string value

    • Risk: Typos, invalid values, inconsistent casing
    • Recommendation: Add CHECK constraint in future migration
  2. Frontend Handling: Frontend code should handle all possible statuses gracefully

    • Current implementation uses fallback: equipmentStatus || 'none'
    • UI should handle unexpected values with default behavior
  3. Order Status Sync: Need to verify that order status changes properly update equipment_status

    • Check Stripe webhook handlers
    • Verify order table → beneficiaries sync

Testing Requirements

Unit Tests Needed

  • Activation sets correct status (demo vs active)
  • Beneficiary creation defaults to 'none'
  • hasDevices calculation is correct
  • ⚠️ Status transitions (none → ordered → shipped → delivered → active)
  • ⚠️ Invalid status handling

Integration Tests Needed

  • ⚠️ Order webhook → equipment_status update
  • ⚠️ Navigation flow for each status
  • ⚠️ UI rendering for each status

Recommendations

  1. Add Database Constraint (Future Migration):

    ALTER TABLE beneficiaries
    ADD CONSTRAINT check_equipment_status
    CHECK (equipment_status IN ('none', 'ordered', 'shipped', 'delivered', 'demo', 'active'));
    
  2. Create Constants File:

    // constants/equipmentStatus.js
    const EQUIPMENT_STATUS = {
      NONE: 'none',
      ORDERED: 'ordered',
      SHIPPED: 'shipped',
      DELIVERED: 'delivered',
      DEMO: 'demo',
      ACTIVE: 'active'
    };
    
  3. Add Status Validation in API endpoints:

    function isValidEquipmentStatus(status) {
      return ['none', 'ordered', 'shipped', 'delivered', 'demo', 'active'].includes(status);
    }
    
  4. Add Logging for status changes:

    console.log(`[EQUIPMENT_STATUS] ${beneficiaryId}: ${oldStatus}${newStatus}`);