Assist_Design/docs/orders/ORDER-STATUS-UPDATES-STRATEGY.md
barsa 8c89109213 Update worktree setup and enhance BFF with SupportModule integration
- Changed worktree setup command from npm to pnpm for improved package management.
- Added SupportModule to app.module.ts and router.config.ts for better support case handling.
- Refactored OrderEventsService to utilize OrderUpdateEventPayload for improved type safety.
- Updated InvoicesList component to use INVOICE_STATUS for status filtering and improved type definitions.
- Enhanced SimActions and SimDetailsCard components to utilize SimStatus for better state management.
- Refactored Subscription components to leverage new utility functions for status handling and billing cycle labels.
- Improved SupportCasesView with better state management and error handling.
- Updated API query keys to include support cases for better data retrieval.
2025-11-18 14:06:27 +09:00

5.8 KiB

Order Status Updates Strategy

Current Problem

The frontend was polling order details every 5-15 seconds, causing:

  • Unnecessary load on backend (Salesforce API calls, DB queries)
  • High API costs
  • Battery drain on mobile devices
  • Network waste

Root Cause

Polling is a workaround for lack of real-time push notifications.

When the backend completes provisioning and updates Salesforce, the frontend has no way to know except by repeatedly asking "is it done yet?"

The Right Solution

Phase 1: Remove Aggressive Polling

  • Polling loop removed from OrderDetail (Nov 2025)
  • Order details now fetched once on mount and whenever the SSE stream notifies of a change
  • Manual refresh handled via SSE-triggered re-fetch; no background polling left in the page

Phase 2: Server-Sent Events (Implemented Nov 2025)

Architecture (now live):

┌─────────────┐         ┌─────────────┐        ┌──────────────┐
│  Salesforce │         │     BFF     │        │   Frontend   │
│             │         │             │        │              │
│  Platform   │──Event─▶│ Provisioning│───SSE──│  OrderDetail │
│  Event      │         │  Processor  │        │  Component   │
└─────────────┘         └─────────────┘        └──────────────┘
                              │
                              │ 1. Provisions WHMCS
                              │ 2. Updates Salesforce
                              │ 3. Publishes SSE event
                              ▼

Key pieces:

  • OrderEventsService keeps per-order subscribers alive, sends heartbeats, and emits order.update events
  • GET /orders/:sfOrderId/events exposes the SSE stream (guarded by the same JWT auth pipeline)
  • OrderFulfillmentOrchestrator now publishes updates when Salesforce status flips to Activating, when provisioning succeeds, and when failures occur
  • useOrderUpdates hook opens the SSE connection from the browser and triggers a re-fetch of order details when an update arrives
  • OrderDetail now relies on SSE instead of timers (auto-updating as soon as the backend pushes a change)
@Injectable()
export class OrderEventsService {
  private readonly observers = new Map<string, Set<InternalObserver>>();

  subscribe(orderId: string): Observable<MessageEvent> {
    return new Observable<MessageEvent>(subscriber => {
      // ... connection bookkeeping + heartbeat ...
    });
  }

  publish(orderId: string, update: OrderUpdateEventPayload): void {
    const event = this.buildEvent("order.update", update);
    currentObservers.forEach(observer => observer.next(event));
  }
}
const fetchOrder = useCallback(async (): Promise<void> => {
  if (!params.id) {
    return;
  }
  // ... fetch with AbortController + state updates ...
}, [params.id]);

const handleOrderUpdate = useCallback(
  (event: OrderUpdateEventPayload) => {
    if (!params.id || event.orderId !== params.id) {
      return;
    }
    void fetchOrder();
  },
  [fetchOrder, params.id]
);

useOrderUpdates(params.id, handleOrderUpdate);

Phase 3: Alternative - WebSockets (More Complex)

WebSockets provide bidirectional communication but are more complex to implement and maintain:

  • Requires WebSocket server setup (socket.io or ws)
  • More complex authentication
  • Requires load balancer configuration (sticky sessions)
  • Better for real-time chat, less ideal for status updates

SSE is simpler and sufficient for status updates.

Implementation Priority

  1. Remove aggressive polling (Nov 2025)
  2. Ship SSE-based order updates (Nov 2025)
  3. ⏭️ Optional: Consider WebSockets only if you need bidirectional messaging

Benefits of SSE Approach

Zero polling - No unnecessary requests
Instant updates - Frontend knows immediately when status changes
Simple protocol - SSE is built into browsers, no library needed
Automatic reconnection - Browsers handle reconnection automatically
Lower costs - Fewer Salesforce API calls
Better UX - Users see status changes in real-time
Less backend load - No repeated queries

Migration Path

Week 1: Remove Polling

  • Remove aggressive 5-second polling
  • Document interim strategy

Week 2: Implement SSE Infrastructure

  • Create OrderEventsService in BFF
  • Expose SSE endpoint GET /orders/:sfOrderId/events
  • Publish fulfillment lifecycle events (activating, completed, failed)

Week 3: Frontend Integration

  • Create useOrderUpdates hook
  • Wire OrderDetail to SSE (no timers)
  • Auto-refetch details on push updates

Week 4: Post-launch Monitoring

  • Add observability for SSE connection counts
  • Track client error rates and reconnection attempts
  • Review UX analytics after rollout

Testing Considerations

  • Test SSE connection drops and automatic reconnection
  • Test multiple tabs subscribing to same order
  • Test SSE with load balancer (ensure sticky sessions or shared pub/sub)
  • Test browser compatibility (SSE supported in all modern browsers)
  • Monitor SSE connection count and memory usage

References


Status: Phase 1 & 2 Complete, Phase 3 (monitoring) in progress
Last Updated: November 2025
Owner: Engineering Team