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

158 lines
5.8 KiB
Markdown

# 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)
```apps/bff/src/modules/orders/services/order-events.service.ts
@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));
}
}
```
```apps/portal/src/features/orders/views/OrderDetail.tsx
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
- [x] Remove aggressive 5-second polling
- [x] Document interim strategy
### Week 2: Implement SSE Infrastructure
- [x] Create `OrderEventsService` in BFF
- [x] Expose SSE endpoint `GET /orders/:sfOrderId/events`
- [x] Publish fulfillment lifecycle events (activating, completed, failed)
### Week 3: Frontend Integration
- [x] Create `useOrderUpdates` hook
- [x] Wire `OrderDetail` to SSE (no timers)
- [x] 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
- [MDN: Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)
- [NestJS SSE Documentation](https://docs.nestjs.com/techniques/server-sent-events)
- Platform Events (Salesforce → BFF): Already implemented ✅
- SSE (BFF → Frontend): Live in production build
---
**Status**: Phase 1 & 2 Complete, Phase 3 (monitoring) in progress
**Last Updated**: November 2025
**Owner**: Engineering Team