@devo-bmad-custom/agent-orchestration 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/.agents/skills/tmux-commands/SKILL.md +353 -0
- package/src/bmm/data/project-context-template.md +26 -26
- package/src/bmm/teams/default-party.csv +20 -20
- package/src/bmm/workflows/2-plan-workflows/create-prd/data/domain-complexity.csv +14 -14
- package/src/bmm/workflows/2-plan-workflows/create-prd/data/prd-purpose.md +197 -197
- package/src/bmm/workflows/2-plan-workflows/create-prd/data/project-types.csv +10 -10
- package/src/bmm/workflows/2-plan-workflows/create-prd/templates/prd-template.md +10 -10
- package/src/bmm/workflows/3-solutioning/create-architecture/data/domain-complexity.csv +12 -12
- package/src/bmm/workflows/4-implementation/code-review/instructions.xml +226 -226
- package/src/bmm/workflows/4-implementation/correct-course/checklist.md +288 -288
- package/src/bmm/workflows/4-implementation/correct-course/instructions.md +207 -207
- package/src/bmm/workflows/4-implementation/retrospective/instructions.md +1444 -1444
- package/src/bmm/workflows/4-implementation/sprint-planning/sprint-status-template.yaml +55 -55
- package/src/bmm/workflows/4-implementation/sprint-status/instructions.md +230 -230
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/tech-spec-template.md +74 -74
- package/src/bmm/workflows/document-project/instructions.md +130 -130
- package/src/bmm/workflows/document-project/templates/project-scan-report-schema.json +160 -160
- package/src/bmm/workflows/document-project/workflows/deep-dive-instructions.md +298 -298
- package/src/bmm/workflows/document-project/workflows/deep-dive.yaml +31 -31
- package/src/bmm/workflows/document-project/workflows/full-scan-instructions.md +1106 -1106
- package/src/bmm/workflows/document-project/workflows/full-scan.yaml +31 -31
- package/src/bmm/workflows/qa-generate-e2e-tests/checklist.md +33 -33
- package/src/bmm/workflows/qa-generate-e2e-tests/instructions.md +110 -110
- package/src/core/agents/bmad-master.md +56 -56
- package/src/core/workflows/party-mode/steps/step-02-discussion-orchestration.md +187 -187
- package/src/core/workflows/party-mode/steps/step-03-graceful-exit.md +168 -168
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/SKILL.md +0 -475
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/references/vision-requests.md +0 -736
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/references/visionkit-scanner.md +0 -738
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/weatherkit/SKILL.md +0 -410
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/weatherkit/references/weatherkit-patterns.md +0 -567
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/widgetkit/SKILL.md +0 -497
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/widgetkit/references/widgetkit-advanced.md +0 -871
- package/src/.agents/skills/ui-ux-pro-custom/data/typography.csv +0 -58
- package/src/.agents/skills/ui-ux-pro-custom/data/ui-reasoning.csv +0 -101
- package/src/.agents/skills/ui-ux-pro-custom/data/ux-guidelines.csv +0 -100
- package/src/.agents/skills/ui-ux-pro-custom/data/web-interface.csv +0 -31
- package/src/.agents/skills/ui-ux-pro-custom/scripts/core.py +0 -253
- package/src/.agents/skills/ui-ux-pro-custom/scripts/design_system.py +0 -1067
- package/src/.agents/skills/ui-ux-pro-custom/scripts/search.py +0 -114
- package/src/.agents/skills/ux-audit/SKILL.md +0 -151
- package/src/.agents/skills/websocket-engineer/SKILL.md +0 -168
- package/src/.agents/skills/websocket-engineer/references/alternatives.md +0 -391
- package/src/.agents/skills/websocket-engineer/references/patterns.md +0 -400
- package/src/.agents/skills/websocket-engineer/references/protocol.md +0 -195
- package/src/.agents/skills/websocket-engineer/references/scaling.md +0 -333
- package/src/.agents/skills/websocket-engineer/references/security.md +0 -474
- package/src/.agents/skills/writing-skills/SKILL.md +0 -655
- package/src/.agents/skills/writing-skills/anthropic-best-practices.md +0 -1150
- package/src/.agents/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +0 -189
- package/src/.agents/skills/writing-skills/graphviz-conventions.dot +0 -172
- package/src/.agents/skills/writing-skills/persuasion-principles.md +0 -187
- package/src/.agents/skills/writing-skills/render-graphs.js +0 -168
- package/src/.agents/skills/writing-skills/testing-skills-with-subagents.md +0 -384
- package/src/.claude/commands/bmad-track-compact.md +0 -19
- package/src/.claude/commands/bmad-track-extended.md +0 -19
- package/src/.claude/commands/bmad-track-large.md +0 -19
- package/src/.claude/commands/bmad-track-medium.md +0 -19
- package/src/.claude/commands/bmad-track-nano.md +0 -19
- package/src/.claude/commands/bmad-track-rv.md +0 -18
- package/src/.claude/commands/bmad-track-small.md +0 -19
- package/src/.claude/commands/master-orchestrator.md +0 -15
- package/src/_memory/master-orchestrator-sidecar/docs-index.md +0 -3
- package/src/_memory/master-orchestrator-sidecar/instructions.md +0 -2616
- package/src/_memory/master-orchestrator-sidecar/memories.md +0 -8
- package/src/_memory/master-orchestrator-sidecar/session-state.md +0 -15
- package/src/_memory/master-orchestrator-sidecar/triage-history.md +0 -3
- package/src/_memory/master-orchestrator-sidecar/workflows-overview.html +0 -1230
- package/src/core/agents/master-orchestrator.md +0 -54
- package/src/docs/dev/tmux/actions_popup.py +0 -291
- package/src/docs/dev/tmux/actions_popup.sh +0 -110
- package/src/docs/dev/tmux/claude_usage.sh +0 -15
- package/src/docs/dev/tmux/colors.conf +0 -26
- package/src/docs/dev/tmux/cpu_usage.sh +0 -7
- package/src/docs/dev/tmux/dispatch.sh +0 -10
- package/src/docs/dev/tmux/float_init.sh +0 -13
- package/src/docs/dev/tmux/float_term.sh +0 -23
- package/src/docs/dev/tmux/open_clip.sh +0 -14
- package/src/docs/dev/tmux/paste_clipboard.sh +0 -13
- package/src/docs/dev/tmux/paste_image_wrapper.sh +0 -94
- package/src/docs/dev/tmux/ram_usage.sh +0 -3
- package/src/docs/dev/tmux/title_sync.sh +0 -54
- package/src/docs/dev/tmux/tmux-setup.md +0 -867
- package/src/docs/dev/tmux/tmux.conf +0 -127
- package/src/docs/dev/tmux/xclip +0 -18
|
@@ -1,391 +0,0 @@
|
|
|
1
|
-
# Real-Time Communication Alternatives
|
|
2
|
-
|
|
3
|
-
## Technology Comparison
|
|
4
|
-
|
|
5
|
-
| Feature | WebSocket | SSE | Long Polling | HTTP/2 Push | WebRTC |
|
|
6
|
-
|---------|-----------|-----|--------------|-------------|--------|
|
|
7
|
-
| Bidirectional | Yes | No | Yes | No | Yes |
|
|
8
|
-
| Real-time | Yes | Yes | Near | Yes | Yes |
|
|
9
|
-
| Browser Support | Excellent | Good | Universal | Good | Good |
|
|
10
|
-
| Proxy Issues | Some | Rare | Rare | Some | Some |
|
|
11
|
-
| Overhead | Low | Low | High | Medium | Medium |
|
|
12
|
-
| Use Case | Chat, games | Feeds, updates | Legacy | Assets | Audio/video |
|
|
13
|
-
|
|
14
|
-
## Server-Sent Events (SSE)
|
|
15
|
-
|
|
16
|
-
### When to Use SSE
|
|
17
|
-
|
|
18
|
-
- One-way server-to-client communication
|
|
19
|
-
- Live feeds, notifications, stock tickers
|
|
20
|
-
- Automatic reconnection needed
|
|
21
|
-
- Simpler than WebSockets
|
|
22
|
-
- Better firewall/proxy compatibility
|
|
23
|
-
|
|
24
|
-
### SSE Server (Node.js)
|
|
25
|
-
|
|
26
|
-
```javascript
|
|
27
|
-
const express = require('express');
|
|
28
|
-
const app = express();
|
|
29
|
-
|
|
30
|
-
app.get('/events', (req, res) => {
|
|
31
|
-
// Set SSE headers
|
|
32
|
-
res.setHeader('Content-Type', 'text/event-stream');
|
|
33
|
-
res.setHeader('Cache-Control', 'no-cache');
|
|
34
|
-
res.setHeader('Connection', 'keep-alive');
|
|
35
|
-
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
36
|
-
|
|
37
|
-
// Send initial connection message
|
|
38
|
-
res.write('data: {"message": "Connected"}\n\n');
|
|
39
|
-
|
|
40
|
-
// Send updates every 5 seconds
|
|
41
|
-
const intervalId = setInterval(() => {
|
|
42
|
-
const data = {
|
|
43
|
-
timestamp: Date.now(),
|
|
44
|
-
value: Math.random()
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
res.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
48
|
-
}, 5000);
|
|
49
|
-
|
|
50
|
-
// Cleanup on client disconnect
|
|
51
|
-
req.on('close', () => {
|
|
52
|
-
clearInterval(intervalId);
|
|
53
|
-
res.end();
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
app.listen(3000);
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### SSE Client
|
|
61
|
-
|
|
62
|
-
```javascript
|
|
63
|
-
const eventSource = new EventSource('http://localhost:3000/events');
|
|
64
|
-
|
|
65
|
-
eventSource.onmessage = (event) => {
|
|
66
|
-
const data = JSON.parse(event.data);
|
|
67
|
-
console.log('Received:', data);
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
eventSource.onerror = (error) => {
|
|
71
|
-
console.error('SSE error:', error);
|
|
72
|
-
// Automatically reconnects
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
// Named events
|
|
76
|
-
eventSource.addEventListener('update', (event) => {
|
|
77
|
-
console.log('Update:', event.data);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
// Close connection
|
|
81
|
-
eventSource.close();
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### SSE with Express
|
|
85
|
-
|
|
86
|
-
```javascript
|
|
87
|
-
const express = require('express');
|
|
88
|
-
const app = express();
|
|
89
|
-
|
|
90
|
-
class SSEManager {
|
|
91
|
-
constructor() {
|
|
92
|
-
this.clients = new Set();
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
addClient(res) {
|
|
96
|
-
this.clients.add(res);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
removeClient(res) {
|
|
100
|
-
this.clients.delete(res);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
broadcast(event, data) {
|
|
104
|
-
const message = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
|
|
105
|
-
|
|
106
|
-
this.clients.forEach(client => {
|
|
107
|
-
client.write(message);
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const sseManager = new SSEManager();
|
|
113
|
-
|
|
114
|
-
app.get('/events', (req, res) => {
|
|
115
|
-
res.setHeader('Content-Type', 'text/event-stream');
|
|
116
|
-
res.setHeader('Cache-Control', 'no-cache');
|
|
117
|
-
res.setHeader('Connection', 'keep-alive');
|
|
118
|
-
|
|
119
|
-
sseManager.addClient(res);
|
|
120
|
-
|
|
121
|
-
req.on('close', () => {
|
|
122
|
-
sseManager.removeClient(res);
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
// Broadcast to all clients
|
|
127
|
-
setInterval(() => {
|
|
128
|
-
sseManager.broadcast('update', {
|
|
129
|
-
timestamp: Date.now(),
|
|
130
|
-
activeClients: sseManager.clients.size
|
|
131
|
-
});
|
|
132
|
-
}, 10000);
|
|
133
|
-
|
|
134
|
-
app.listen(3000);
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## Long Polling
|
|
138
|
-
|
|
139
|
-
### When to Use Long Polling
|
|
140
|
-
|
|
141
|
-
- Legacy browser support needed
|
|
142
|
-
- Firewall/proxy blocks WebSockets
|
|
143
|
-
- Very infrequent updates
|
|
144
|
-
- Fallback mechanism
|
|
145
|
-
|
|
146
|
-
### Long Polling Server
|
|
147
|
-
|
|
148
|
-
```javascript
|
|
149
|
-
const express = require('express');
|
|
150
|
-
const app = express();
|
|
151
|
-
|
|
152
|
-
const pendingRequests = new Map();
|
|
153
|
-
const messages = [];
|
|
154
|
-
|
|
155
|
-
app.get('/poll', (req, res) => {
|
|
156
|
-
const clientId = req.query.clientId;
|
|
157
|
-
|
|
158
|
-
// If messages available, send immediately
|
|
159
|
-
if (messages.length > 0) {
|
|
160
|
-
res.json({ messages });
|
|
161
|
-
messages.length = 0; // Clear messages
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Hold request until timeout or new message
|
|
166
|
-
const timeout = setTimeout(() => {
|
|
167
|
-
pendingRequests.delete(clientId);
|
|
168
|
-
res.json({ messages: [] });
|
|
169
|
-
}, 30000); // 30 second timeout
|
|
170
|
-
|
|
171
|
-
pendingRequests.set(clientId, { res, timeout });
|
|
172
|
-
|
|
173
|
-
req.on('close', () => {
|
|
174
|
-
clearTimeout(timeout);
|
|
175
|
-
pendingRequests.delete(clientId);
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
app.post('/send', express.json(), (req, res) => {
|
|
180
|
-
messages.push(req.body.message);
|
|
181
|
-
|
|
182
|
-
// Respond to all pending requests
|
|
183
|
-
pendingRequests.forEach(({ res, timeout }, clientId) => {
|
|
184
|
-
clearTimeout(timeout);
|
|
185
|
-
res.json({ messages });
|
|
186
|
-
pendingRequests.delete(clientId);
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
messages.length = 0; // Clear messages
|
|
190
|
-
res.json({ success: true });
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
app.listen(3000);
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### Long Polling Client
|
|
197
|
-
|
|
198
|
-
```javascript
|
|
199
|
-
const clientId = Math.random().toString(36);
|
|
200
|
-
|
|
201
|
-
async function poll() {
|
|
202
|
-
try {
|
|
203
|
-
const response = await fetch(
|
|
204
|
-
`http://localhost:3000/poll?clientId=${clientId}`,
|
|
205
|
-
{ signal: AbortSignal.timeout(35000) }
|
|
206
|
-
);
|
|
207
|
-
|
|
208
|
-
const data = await response.json();
|
|
209
|
-
|
|
210
|
-
if (data.messages.length > 0) {
|
|
211
|
-
console.log('Received messages:', data.messages);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Immediately poll again
|
|
215
|
-
poll();
|
|
216
|
-
} catch (error) {
|
|
217
|
-
console.error('Polling error:', error);
|
|
218
|
-
// Retry after delay
|
|
219
|
-
setTimeout(poll, 5000);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
poll();
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
## HTTP/2 Server Push (Deprecated)
|
|
227
|
-
|
|
228
|
-
Note: HTTP/2 Server Push is deprecated and removed from Chrome. Use 103 Early Hints instead.
|
|
229
|
-
|
|
230
|
-
```javascript
|
|
231
|
-
// Example for historical context only
|
|
232
|
-
const http2 = require('http2');
|
|
233
|
-
const fs = require('fs');
|
|
234
|
-
|
|
235
|
-
const server = http2.createSecureServer({
|
|
236
|
-
key: fs.readFileSync('server.key'),
|
|
237
|
-
cert: fs.readFileSync('server.crt')
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
server.on('stream', (stream, headers) => {
|
|
241
|
-
if (headers[':path'] === '/') {
|
|
242
|
-
// Push assets before HTML response
|
|
243
|
-
stream.pushStream({ ':path': '/style.css' }, (err, pushStream) => {
|
|
244
|
-
if (!err) {
|
|
245
|
-
pushStream.respondWithFile('style.css');
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
stream.respondWithFile('index.html');
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
server.listen(3000);
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
## Decision Matrix
|
|
257
|
-
|
|
258
|
-
### Choose WebSocket When:
|
|
259
|
-
|
|
260
|
-
- Bidirectional communication needed
|
|
261
|
-
- Low latency critical (< 50ms)
|
|
262
|
-
- High message frequency (> 1 msg/sec)
|
|
263
|
-
- Gaming, chat, collaborative editing
|
|
264
|
-
- Binary data transfer
|
|
265
|
-
- Custom protocol needed
|
|
266
|
-
|
|
267
|
-
### Choose SSE When:
|
|
268
|
-
|
|
269
|
-
- One-way server-to-client only
|
|
270
|
-
- Stock tickers, live feeds
|
|
271
|
-
- News/notifications
|
|
272
|
-
- Simpler implementation preferred
|
|
273
|
-
- Better proxy compatibility needed
|
|
274
|
-
- Automatic reconnection important
|
|
275
|
-
|
|
276
|
-
### Choose Long Polling When:
|
|
277
|
-
|
|
278
|
-
- Legacy browser support required (IE8/9)
|
|
279
|
-
- WebSocket blocked by firewall
|
|
280
|
-
- Very infrequent updates
|
|
281
|
-
- Fallback mechanism only
|
|
282
|
-
|
|
283
|
-
### Choose HTTP Streaming When:
|
|
284
|
-
|
|
285
|
-
- Large data transfers
|
|
286
|
-
- File uploads with progress
|
|
287
|
-
- Video/audio streaming
|
|
288
|
-
- One-way data flow
|
|
289
|
-
|
|
290
|
-
### Choose WebRTC When:
|
|
291
|
-
|
|
292
|
-
- Peer-to-peer communication
|
|
293
|
-
- Audio/video calls
|
|
294
|
-
- Screen sharing
|
|
295
|
-
- File transfer between peers
|
|
296
|
-
- Low latency P2P needed
|
|
297
|
-
|
|
298
|
-
## Hybrid Approach
|
|
299
|
-
|
|
300
|
-
```javascript
|
|
301
|
-
// Socket.IO with automatic fallback
|
|
302
|
-
const io = require('socket.io')(3000, {
|
|
303
|
-
transports: ['websocket', 'polling'], // Try WebSocket first
|
|
304
|
-
upgrade: true,
|
|
305
|
-
allowUpgrades: true
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
io.on('connection', (socket) => {
|
|
309
|
-
console.log('Connected via:', socket.conn.transport.name);
|
|
310
|
-
|
|
311
|
-
socket.conn.on('upgrade', () => {
|
|
312
|
-
console.log('Upgraded to:', socket.conn.transport.name);
|
|
313
|
-
});
|
|
314
|
-
});
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
## Performance Characteristics
|
|
318
|
-
|
|
319
|
-
### Latency (p99)
|
|
320
|
-
|
|
321
|
-
- WebSocket: 5-20ms
|
|
322
|
-
- SSE: 10-50ms
|
|
323
|
-
- Long Polling: 100-500ms
|
|
324
|
-
- HTTP/2: 20-100ms
|
|
325
|
-
|
|
326
|
-
### Throughput (messages/sec)
|
|
327
|
-
|
|
328
|
-
- WebSocket: 10,000+ per connection
|
|
329
|
-
- SSE: 1,000+ per connection
|
|
330
|
-
- Long Polling: 1-10 per connection
|
|
331
|
-
|
|
332
|
-
### Connection Limits (per server)
|
|
333
|
-
|
|
334
|
-
- WebSocket: 50,000-100,000
|
|
335
|
-
- SSE: 50,000-100,000
|
|
336
|
-
- Long Polling: 10,000-20,000
|
|
337
|
-
|
|
338
|
-
### Overhead (per message)
|
|
339
|
-
|
|
340
|
-
- WebSocket: 2-6 bytes
|
|
341
|
-
- SSE: ~20 bytes
|
|
342
|
-
- Long Polling: 500-2000 bytes (HTTP headers)
|
|
343
|
-
|
|
344
|
-
## Migration Path
|
|
345
|
-
|
|
346
|
-
### From Polling to WebSocket
|
|
347
|
-
|
|
348
|
-
```javascript
|
|
349
|
-
// Step 1: Support both
|
|
350
|
-
app.get('/api/messages', (req, res) => {
|
|
351
|
-
// Legacy polling endpoint
|
|
352
|
-
res.json({ messages: getRecentMessages() });
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
io.on('connection', (socket) => {
|
|
356
|
-
// New WebSocket endpoint
|
|
357
|
-
socket.on('subscribe', (channel) => {
|
|
358
|
-
socket.join(channel);
|
|
359
|
-
});
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
// Step 2: Gradually migrate clients
|
|
363
|
-
// Step 3: Deprecate polling endpoint
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
### From SSE to WebSocket
|
|
367
|
-
|
|
368
|
-
```javascript
|
|
369
|
-
// SSE provides read-only, add WebSocket for writes
|
|
370
|
-
app.get('/events', sseHandler); // Keep for reads
|
|
371
|
-
|
|
372
|
-
io.on('connection', (socket) => {
|
|
373
|
-
socket.on('action', (data) => {
|
|
374
|
-
// Handle writes via WebSocket
|
|
375
|
-
processAction(data);
|
|
376
|
-
});
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
// Eventually migrate reads to WebSocket too
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
## Best Practices
|
|
383
|
-
|
|
384
|
-
1. Start with simplest solution (SSE for one-way)
|
|
385
|
-
2. Use Socket.IO for automatic fallbacks
|
|
386
|
-
3. Monitor actual requirements before over-engineering
|
|
387
|
-
4. Consider mobile/network constraints
|
|
388
|
-
5. Implement graceful degradation
|
|
389
|
-
6. Load test before production
|
|
390
|
-
7. Have fallback strategy
|
|
391
|
-
8. Monitor connection success rates
|