# Sự kiện thời gian thực (SignalR)

> Luồng sự kiện WebSocket cấp năng lượng cho bảng điều khiển trực tiếp — các nhóm hub, payload sự kiện và ngữ nghĩa timestamp của dự đoán.

Các cập nhật trực tiếp đi qua một hub SignalR tại **`/hub/realtime`**. Xác thực dùng
cùng JWT như REST API, truyền dưới dạng `?access_token=<jwt>` (hoặc một header
`Authorization`).

Luồng sự kiện là **at-most-once và fire-and-forget** — nó không bao giờ là nguồn
sự thật. Các sự kiện bị bỏ lỡ trong lúc mất kết nối sẽ không được phát lại; trạng
thái có thẩm quyền luôn đến từ REST API (`/api/inference/status`,
`/api/system/status`) và cơ sở dữ liệu trên box.

## Các nhóm đăng ký

Các luồng tần số cao là opt-in theo từng nhóm, chỉ tham gia khi một màn hình tiêu
thụ được mount và tự động tham gia lại khi kết nối lại:

| Nhóm | Mang | Được tiêu thụ bởi |
|---|---|---|
| `sensors` | Các lô đọc cảm biến trực tiếp | Realtime Monitor |
| `predictions` | Các lô dự đoán mới | Biểu đồ bảng điều khiển |
| `logs` | Toàn bộ luồng log (mọi mức) | Chỉ trang LogViewer |
| `alerts` | Chỉ các mục log Warning/Error | Chuông thông báo, toàn ứng dụng |

Nhóm `alerts` tồn tại để các cảnh báo nổi lên khắp nơi mà không phải stream toàn bộ
"vòi rồng" `logs` tới mọi bảng điều khiển.

## Sự kiện (server → client)

| Sự kiện | Điểm nổi bật của payload |
|---|---|
| `SensorReading` | `channelIndex`, `value`, `timestamp` |
| `NewPrediction` | `predictions`, `confidenceScores`, `modelId`, `inferenceTimeMs`, các timestamp cửa sổ (bên dưới) |
| `InferenceStateChanged` | `state` ∈ `idle · ready · running`, datasource đang hoạt động, mô hình đã nạp — phát ra ở mọi chuyển tiếp vòng đời |
| `InferenceFaulted` | `reason`, `datasourceId` — đồng thời hiện banner lỗi chặn |
| `HealthMetricsUpdate` | CPU/GPU/bộ nhớ, uptime |
| `ModelActivated` | `modelId`, `version`, các shape, kích thước file |
| `ModelUploadProgress` | Các pha upload/xác thực, thông báo lỗi nếu thất bại |
| `OutputWriteFailed` | Gộp theo từng sink — cảnh báo đầu tiên tức thì, sau đó một lần mỗi cửa sổ 30 giây |
| `LogEntryAdded` | Mục log (mức, thông báo, logger, metadata) |

## Ngữ nghĩa timestamp của dự đoán

Một dự đoán mô tả một cửa sổ đầu vào *trong quá khứ*. Mọi timestamp đều là Unix
epoch mili-giây từ **một đồng hồ** — backend đóng dấu mỗi mẫu một lần tại thời điểm
đọc, và giá trị đó được truyền qua pipeline, không bao giờ được sinh lại:

| Trường | Ý nghĩa |
|---|---|
| `windowStartTimestamp` | Mẫu đầu vào cũ nhất trong cửa sổ |
| `windowEndTimestamp` | Mẫu đầu vào mới nhất — thời điểm "tính đến" mà dự đoán có hiệu lực |
| `timestamp` | Phản chiếu `windowEndTimestamp` (tương thích) |
| `emittedAt` | Thời gian đồng hồ backend lúc phát — `emittedAt − windowEndTimestamp` ≈ độ trễ end-to-end |

Trên bảng điều khiển, vệt dự đoán **trễ hơn** vệt cảm biến một cách rõ ràng đúng
bằng độ trễ pipeline thực. Khoảng cách đó là một tín hiệu vận hành có chủ đích,
không phải lỗi render.

## Bảo đảm phân phối

Consumer chậm không bao giờ làm chậm suy luận: các broadcast tới bảng điều khiển là
fire-and-forget, và các sự kiện tới một client không theo kịp sẽ bị bỏ và đếm
(`/api/inference/backpressure`). Các sự kiện đáng thông báo được khử trùng lặp và
giới hạn tốc độ để chuông vẫn hữu ích — xem [Thông báo](/vi/operate/notifications/).

## Bước tiếp theo

  - [Tổng quan API](/vi/api-reference/overview/) — Các bề mặt REST và xác thực.
  - [Giám sát](/vi/operate/monitoring/) — Nơi các sự kiện này hiển thị trong UI.
  - [Thông báo](/vi/operate/notifications/) — Sự kiện nào phát cảnh báo, và cái gì giữ im lặng.
