Files
datadunia cbacfea7f2
NexusGuard CI / server-core-test (push) Failing after 3m6s
NexusGuard CI / server-core-build (push) Has been skipped
NexusGuard CI / device-agent-test (push) Failing after 4s
NexusGuard CI / device-agent-cross-build (amd64, linux) (push) Has been skipped
NexusGuard CI / device-agent-cross-build (amd64, windows) (push) Has been skipped
NexusGuard CI / device-agent-cross-build (arm64, linux) (push) Has been skipped
NexusGuard CI / dashboard-test (push) Failing after 4s
NexusGuard CI / dashboard-dist (push) Has been skipped
chore: update submodule refs, clean up plans/evidence, update .gitignore
2026-06-07 23:53:15 +07:00

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)

  1. SSE doesn't support custom Authorization headers — token must be query param or cookie (security tradeoff)
  2. Existing SSE only handles device status — would need new SSE channel for traffic
  3. Traffic data is already in Redis with 24h TTL — REST with limit is sufficient
  4. 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 — Add limit query parameter
  • apps/dashboard-ui/src/views/TrafficHistory.vue — Silent refresh, smart pagination, optimized export
  • apps/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 limit parameter (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 build passes
  • Backend: go build ./... passes
  • Grep: no setInterval with < 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, modify parseTimeRange to also parse limit query parameter
    • Add limit parameter to GetSummary: limit := c.DefaultQuery("limit", "500")
    • Parse limit as int, cap at 5000 max
    • Apply .Limit(limit) to the GORM query in GetSummary
    • Also add limit to GetDeviceTraffic and GetNodeTraffic
    • Return total_count in response alongside total_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). parseTimeRange at line 75, GetSummary at line 55
    • apps/server-core/internal/traffic/recorder.goTrafficRecord struct 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.txt
    

    Commit: YES (groups with 2-5)


  • 2. Silent auto-refresh + pagination fix

    What to do:

    • Modify fetchTrafficData to accept optional silent parameter (default false)
    • When silent=true: skip loading.value = true, skip currentPage.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=500 to API URLs
    • Store totalCount from 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.txt
    

    Commit: YES (groups with 1, 3-5)


  • 3. Chart downsampling

    What to do:

    • In TrafficHistory.vue, add a chartDataLimited computed 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 chartDataLimited to TrafficChart instead of chartData
    • Keep full trafficData for 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.txt
    

    Commit: YES (groups with 1-2, 4-5)


  • 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.txt
    

    Commit: YES (groups with 1-3, 5)


  • 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 setInterval with interval < 20000ms in TrafficHistory.vue
    • Verify no loading.value = true in 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.txt
    

    Commit: YES (final commit)


Commit Strategy

  • Commit E: All traffic performance changes
    • Files: api/traffic.go, TrafficHistory.vue
    • Pre-commit: go build ./... && cd ../dashboard-ui && npm run build

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