9.9 KiB
Traffic Performance Optimization
TL;DR
Quick Summary: Fix TrafficHistory performance — silent auto-refresh (no loading flash), limit data fetched, optimize chart rendering, and add server-side pagination.
Deliverables:
- Silent auto-refresh (no loading state during background updates)
- API limit parameter to cap data fetched
- Client-side chart downsampling (max 200 points)
- Smart CSV export (current page or all with progress)
- Auto-refresh interval increased to 30s
Estimated Effort: Medium Parallel Execution: YES - 2 waves Critical Path: Backend limit → Frontend fetch → Chart/table optimizations
Context
Original Request
User reports: "terlalu banyak data record. realtime tidak smooth (masih ada warna loading). record table terdownload semua."
Architecture Finding
- SSE endpoint exists (
/devices/stream) but only streams device STATUS, not traffic data - Frontend has NO EventSource consumer — SSE endpoint is orphaned
- Traffic uses pure REST polling — every 10s, fetch ALL records → loading flash
- No WebSocket anywhere in the codebase
- TrafficRecorder stores data in Redis (24h TTL) → syncs to PostgreSQL every 5min
Why NOT WebSocket/SSE for Traffic (Yet)
- SSE doesn't support custom
Authorizationheaders — token must be query param or cookie (security tradeoff) - Existing SSE only handles device status — would need new SSE channel for traffic
- Traffic data is already in Redis with 24h TTL — REST with limit is sufficient
- Recommended: Fix REST performance first → evaluate SSE for traffic in future iteration
Work Objectives
Core Objective
Make TrafficHistory page smooth, fast, and non-blocking — no loading flash, limited data, optimized rendering.
Concrete Deliverables
apps/server-core/api/traffic.go— Addlimitquery parameterapps/dashboard-ui/src/views/TrafficHistory.vue— Silent refresh, smart pagination, optimized exportapps/dashboard-ui/src/components/TrafficChart.vue— Downsample data for SVG rendering
Must Have
- Auto-refresh does NOT show loading state (silent background update)
- Auto-refresh does NOT reset pagination page
- API supports
limitparameter (default 500, max 5000) - Chart downsamples to max 200 data points
- CSV export shows progress or limits to current page
- Auto-refresh interval 30s (was 10s)
Must NOT Have (Guardrails)
- Do NOT add WebSocket infrastructure (future iteration)
- Do NOT change TrafficRecorder or Redis storage
- Do NOT change the SSE device status endpoint
- Do NOT change the POST /traffic/report endpoint
- Do NOT change TrafficChart's visual appearance
- Do NOT remove the auto-refresh feature
Verification Strategy
QA Policy
- Frontend:
npm run buildpasses - Backend:
go build ./...passes - Grep: no
setIntervalwith < 20000ms interval - Manual check: no loading flash during auto-refresh
Execution Strategy
Parallel Execution Waves
Wave 1 (Backend + Frontend foundation):
├── Task 1: Add limit param to traffic API [quick]
├── Task 2: Silent auto-refresh + pagination fix [quick]
├── Task 3: Chart downsampling [quick]
Wave 2 (Integration + Polish):
├── Task 4: CSV export optimization [quick]
├── Task 5: Build verify [quick]
TODOs
-
1. Add limit parameter to traffic API
What to do:
- In
apps/server-core/api/traffic.go, modifyparseTimeRangeto also parselimitquery parameter - Add
limitparameter toGetSummary:limit := c.DefaultQuery("limit", "500") - Parse limit as int, cap at 5000 max
- Apply
.Limit(limit)to the GORM query inGetSummary - Also add limit to
GetDeviceTrafficandGetNodeTraffic - Return
total_countin response alongsidetotal_records(total available before limit)
Must NOT do:
- Do NOT change TrafficRecorder
- Do NOT change Redis storage
- Do NOT change POST /traffic/report
References:
apps/server-core/api/traffic.go— Full file (90 lines).parseTimeRangeat line 75,GetSummaryat line 55apps/server-core/internal/traffic/recorder.go—TrafficRecordstruct at line 15
QA Scenarios:
Scenario: API respects limit parameter Tool: Bash (curl) Steps: 1. Start dev server 2. curl -H "Authorization: Bearer <token>" "http://localhost:8080/api/v1/traffic/summary?from=...&to=...&limit=10" Expected Result: Response contains max 10 records, total_count shows actual total Evidence: .sisyphus/evidence/task-1-api-limit.txt Scenario: Build passes Tool: Bash Steps: 1. cd apps/server-core && go build ./... Expected Result: Exit code 0 Evidence: .sisyphus/evidence/task-1-build.txtCommit: YES (groups with 2-5)
- In
-
2. Silent auto-refresh + pagination fix
What to do:
- Modify
fetchTrafficDatato accept optionalsilentparameter (default false) - When
silent=true: skiploading.value = true, skipcurrentPage.value = 1 - Auto-refresh interval calls
fetchTrafficData(true)— silent mode - Manual "Apply Filters" calls
fetchTrafficData()— shows loading, resets page - Change interval from 10000ms to 30000ms
- Add
?limit=500to API URLs - Store
totalCountfrom API response for pagination display - Update pagination display to show "of X total" using totalCount
Must NOT do:
- Do NOT remove auto-refresh
- Do NOT change the date filtering logic
- Do NOT change the chart component
References:
apps/dashboard-ui/src/views/TrafficHistory.vue— Lines 177-205 (fetchTrafficData), 283-293 (interval)apps/dashboard-ui/src/services/api.ts— Base axios instance
QA Scenarios:
Scenario: No loading flash during auto-refresh Tool: Playwright Steps: 1. Open Traffic History page 2. Wait for initial load 3. Observe for 35 seconds — no loading bar should appear after initial load Expected Result: Loading indicator does NOT flash during background refresh Evidence: .sisyphus/evidence/task-2-no-flash.txt Scenario: Build passes Tool: Bash Steps: 1. cd apps/dashboard-ui && npm run build Expected Result: Exit code 0 Evidence: .sisyphus/evidence/task-2-build.txtCommit: YES (groups with 1, 3-5)
- Modify
-
3. Chart downsampling
What to do:
- In
TrafficHistory.vue, add achartDataLimitedcomputed that limits chart data to max 200 points - If data > 200 points, downsample by averaging every N points (N = Math.ceil(data.length / 200))
- Pass
chartDataLimitedto TrafficChart instead ofchartData - Keep full
trafficDatafor table pagination and CSV export
Must NOT do:
- Do NOT change TrafficChart.vue component
- Do NOT change the SVG rendering logic
References:
apps/dashboard-ui/src/views/TrafficHistory.vue— Lines 150-157 (chartData computed)
QA Scenarios:
Scenario: Chart receives max 200 data points Tool: Bash Steps: 1. Grep for chartDataLimited in TrafficHistory.vue Expected Result: Computed property exists with 200-point cap Evidence: .sisyphus/evidence/task-3-downsample.txt Scenario: Build passes Tool: Bash Steps: 1. cd apps/dashboard-ui && npm run build Expected Result: Exit code 0 Evidence: .sisyphus/evidence/task-3-build.txtCommit: YES (groups with 1-2, 4-5)
- In
-
4. CSV export optimization
What to do:
- Change exportToCSV to export only
paginatedData(current page) by default - Add a confirmation: "Export all X records or just current page?"
- Or simpler: always export current filtered data (not limited by pagination)
- Keep export fast by limiting to filtered dataset
Must NOT do:
- Do NOT add async CSV generation (overkill)
- Do NOT change the download mechanism
References:
apps/dashboard-ui/src/views/TrafficHistory.vue— Lines 239-263 (exportToCSV)
QA Scenarios:
Scenario: CSV export works Tool: Bash Steps: 1. cd apps/dashboard-ui && npm run build Expected Result: Exit code 0 Evidence: .sisyphus/evidence/task-4-build.txtCommit: YES (groups with 1-3, 5)
- Change exportToCSV to export only
-
5. Build verify all changes
What to do:
- Run
cd apps/server-core && go build ./... - Run
cd apps/dashboard-ui && npm run build - Grep for
setIntervalwith interval < 20000ms in TrafficHistory.vue - Verify no
loading.value = truein auto-refresh path
References:
- All modified files
QA Scenarios:
Scenario: Full build passes Tool: Bash Steps: 1. cd apps/server-core && go build ./... 2. cd apps/dashboard-ui && npm run build Expected Result: Both exit code 0 Evidence: .sisyphus/evidence/task-5-full-build.txt Scenario: No aggressive polling Tool: Bash Steps: 1. grep -n "setInterval" apps/dashboard-ui/src/views/TrafficHistory.vue Expected Result: Interval >= 20000ms Evidence: .sisyphus/evidence/task-5-polling-check.txtCommit: YES (final commit)
- Run
Commit Strategy
- Commit E: All traffic performance changes
- Files:
api/traffic.go,TrafficHistory.vue - Pre-commit:
go build ./... && cd ../dashboard-ui && npm run build
- Files:
Success Criteria
Verification Commands
cd apps/server-core && go build ./... # Expected: exit 0
cd apps/dashboard-ui && npm run build # Expected: ✓ built in Xs
grep "setInterval" apps/dashboard-ui/src/views/TrafficHistory.vue # Expected: 30000
grep -c "loading.value = true" apps/dashboard-ui/src/views/TrafficHistory.vue # Expected: 1 (only manual refresh)
Final Checklist
- Auto-refresh is silent (no loading flash)
- Auto-refresh does not reset pagination
- API supports limit parameter
- Chart renders max 200 data points
- Auto-refresh interval 30s
- Both backend and frontend build successfully