c9 · dev-tools-integration
Integrate qflow with qtap dev-tools in app.qpoint.io — qflow as bird's-eye view, dev-tools as detail inspector, fed by live production SSE traffic.
Two-Pronged Approach
Prong 1: Standalone qflow experiment
A self-contained experiment in the qflow dev harness that connects directly to qtap's SSE stream via a Vite proxy. Useful for rapid visual iteration without running the full dev-tools app.
Prong 2: Integration into dev-tools app
The adapter and integration code designed to work inside the qtap dev-tools app. qflow gets added as a dependency, and a new Traffic.vue page component is created that instantiates qflow and feeds it events from the existing Pinia stores (connections, HTTP transactions).
Implementation Plan
New files
SseFeed.js — SSE adapter with LiveFeed-compatible interface
SseFeed {
constructor(url, { batchWindowMs = 200 })
onBatch(cb) // same callback as LiveFeed
start() // opens EventSource
stop() // closes EventSource
get running()
get status() // 'disconnected' | 'connecting' | 'connected' | 'error'
onStatusChange(cb)
}
- Uses native
EventSourceAPI (auto-reconnect built in) - Listens for
connection.openedandrequest.http_transactionSSE events - Micro-batches: accumulates events, flushes every ~200ms
- Transforms events via adapter before emitting
adapter.js — Pure functions: qtap events → qflow audit-log format
connectionToAuditLog(connection)—source.address.ip→sourceAddress,source.exe→sourceExe,destination.address.ip→destinationAddress, etc.httpTransactionToAuditLog(transaction)— addsrequest.method→method, derivesactionfrom response status (2xx/3xx = ALLOW, 4xx/5xx = DENY)- Defensive optional chaining on all nested fields
App.vue — Replicated from c5 with changes:
- Add
feedModetoggle ('mock'|'live') in the Feed control group - When
'live': createSseFeedinstead ofLiveFeed, hide mock-only Generation controls - Connection status indicator (colored dot: green/yellow/red + text) in header
- Both feeds share the
onBatch(cb)/start()/stop()interface —handleBatch()works unchanged
Replicated from c5:
LiveFeed.js,NodeRegistry.js,mock-data.js,shapes/,main.js,index.html
Modified shared files
dev/vite.config.js — Add SSE proxy:
proxy: {
'/devtools/api': {
target: `http://localhost:${process.env.QTAP_PORT || 10001}`,
changeOrigin: true,
}
}
Dev-Tools Integration Design
The dev-tools app (qtap/pkg/devtools/app/) already has:
- SSE events flowing through a Web Worker →
useEvents()composable → Pinia stores - Tab-based UI in
App.vuewith panels: Welcome, Processes, Connections, Requests, Redis, MySQL, Kafka, gRPC - Connection and HTTP transaction data in
useConnectionsStore()anduseHttpStore()
Integration points
New tab: "Traffic"
- Add
{ id: 'traffic', label: 'Traffic' }to thetabsarray inApp.vue - Add
<Traffic v-else-if="activeTab === 'traffic'" />to the panel content
New page: components/pages/Traffic.vue
- Imports
useTrafficViz(orTrafficVizcomponent) from@qpoint-io/qflow - Watches
useConnectionsStore().connectionsBufferanduseHttpStore().requestsBuffer - On new connection/HTTP events, transforms via adapter and feeds into qflow's stage
Data flow:
qtap SSE → Web Worker → useEvents() → Pinia stores
├── connectionsStore → Traffic.vue → adapter → qflow
└── httpStore → Traffic.vue → adapter → qflow
No SseFeed or EventSource needed — dev-tools already handles SSE. The Traffic panel simply watches existing stores and routes new items into qflow.
What moves to dev-tools later
| Built in c7 experiment | Moves to dev-tools app |
|---|---|
adapter.js | Yes — same transformation logic |
SseFeed.js | No — dev-tools already has SSE via useEvents() |
App.vue (standalone) | No — replaced by Traffic.vue page |
| Visualization tuning | Yes — best config gets baked into Traffic.vue |
Execution Order
- Create
adapter.js(pure functions, no dependencies) - Create
SseFeed.js(depends on adapter) - Replicate c5 files:
LiveFeed.js,NodeRegistry.js,mock-data.js,shapes/,main.js - Create
App.vue(based on c5, add feed mode toggle + SSE integration) - Create
index.html - Update
dev/vite.config.js(add proxy) - Update
dev/experiments/CYCLES.md
Verification
npm run dev— confirm c7 appears in experiment list at localhost:3334- Mock mode: select mock, Play — behaves like c5
- Live mode:
sudo qtap --enable-dev-tools, select live, Play — real traffic visualized - Disconnect: stop qtap — status shows "Connecting...", auto-reconnects when restarted
Outcome: