專案

一般

配置概況

討論 #1424

是由 陳國瑋 於 26 天 前更新

# ## 現行 Connector Full List 固定排序:DEC-041 

 **狀態:已確認(2026-09-05,Ken)** 

 - Dashboard 資料取得與即時更新需求(現行有效版) Drawer 不提供使用者排序控制,完整清單固定使用與 Top-8 preview 相同的 Backend operational priority hierarchy。 
 - 現有 `POST /api/connector/search`/`SearchConnectorDto` 增加 stable `sortMode = DASHBOARD_PRIORITY`;此 mode 下 Backend 先套搜尋/篩選,再以共用 priority ranking 排序,最後固定每 20 筆分頁。 
 - Dashboard Frontend 不從使用者輸入產生 `sidx`/`sord`;既有 `/connector/list` 管理頁未使用此 mode 時,原欄位排序維持不變。 
 - 同層級依狀態持續時間由久至新,再以 Connector ID 作 deterministic tie-breaker;搜尋/篩選不改變排序規則。 
 - 不新增 sorting state persistence、WebSocket inventory 或另一套 ranking;這是唯讀 read model/presentation contract,不改變營運作業邏輯。 

 > **Revision 2026-09-05**:本 description 只保留目前可供實作與驗收的 ## 現行 Connector Full List 固定分頁:DEC-040 

 **狀態:已確認(2026-09-05,Ken)** 

 - 完整清單只走 REST,使用/擴充既有 `POST /api/connector/search`;不透過 Dashboard WebSocket 傳完整 inventory。 
 - Request 沿用既有 `page`、`size` 欄位,Dashboard Drawer 固定 `size = 20`;不另建 `pageSize` 或 Dashboard 專用分頁 endpoint。 
 - Response 沿用既有 Spring Page metadata;Frontend 以 `content`、`totalElements`、`totalPages`、`number`、`first`、`last` 等欄位呈現頁次與控制狀態。 
 - 搜尋或篩選條件改變時回到第 1 頁,Server 先對完整資料集套用全部條件,再排序與分頁;不得只篩選目前載入的 20 筆。既有 DTO 未涵蓋的 Charge Point ID/Charge Group 條件須於實作時擴充並補 contract tests。 
 - V1 規格。先前的 capped exponential backoff、60 秒 REST polling fallback、sequence/gap recovery、固定 5 秒 coalescing、Operational Event P95 2 秒 SLO、per-building stale cutoff override,以及要求 KPI/需留意事項/群組資料走 WebSocket 的方案,均已被 DEC-031~033 取代,不得作為開發依據。完整討論歷程仍保留於 J5641 及更早的 Redmine journals。 只提供上一頁/下一頁;1~20 筆隱藏換頁控制。不提供 page-size selector、頁碼列、直接跳頁、virtualization 或完整 inventory 的 WS fallback。 
 - Query state 的保存生命週期仍依 DEC-039;完整清單已由 #1423 UI-DEC-020/DEC-041 確認固定 Backend priority sorting,不保存或提供使用者 sorting state。 
 - 本決策只定義唯讀查詢與顯示,不修改 Connector/Queue/OCPP/charging 作業邏輯。 

 ## 背景與目標 現行 Connector Full List Drawer 狀態 Ownership:DEC-039 

 Branch Admin `/dashboard` 目前沒有正式營運內容。既有 `GET /api/connector/dashboard` 只有 Connector 總數、Available、Charging、Faulted、公用與私人數量;既有 Connector 管理頁 **狀態:已確認(2026-09-05,Ken)** 

 - Drawer 的搜尋、篩選與目前頁碼由 Frontend page memory 擁有;同一個 Dashboard page instance 關閉/重開 Drawer 時保留。 
 - 頁面 reload 或離開 Dashboard route 後返回時恢復預設搜尋、篩選、priority sorting 與第一頁。 
 - V1 不將此 state 寫入 URL/browser history、localStorage/sessionStorage、Backend preference API 或 WebSocket;REST search API 與單 只接收當次查詢條件,不負責保存 UI state。 
 - 此決策不變更 Connector search domain 或 Dashboard live event contract;固定 page size 與換頁規則已由 #1423 UI-DEC-019/DEC-040 確認。 

 ## 現行 Connector Status Summary 互動邊界:DEC-038 

 **狀態:已確認(2026-09-05,Ken)** 

 - 五個 Status summary 項目為純資訊 presentation,不是 link/button/Tab stop;點擊或觸控不開 Drawer、不套 filter、不導頁,也不送出 request。 
 - 單支 detail 仍由 Connector preview card 開啟;完整清單仍由「查看全部」開啟。Summary 不建立第三套入口。 
 - Backend 不需要 bucket-to-filter mapping、summary click API、URL query 欄位或額外 WebSocket 可部分重用,但不足以直接支援整張營運 Dashboard。 event;DEC-035~037 的 aggregation 與固定五項 contract 不變。 
 - 此決策只收斂 UI/API 邊界,不改變 Connector、Queue、OCPP 或 charging behavior。 

 V1 建立所有 EMS Branch 共用的唯讀 Dashboard。A17 只作第一個資料、公式及效能驗證案場,任何 API、UI、WebSocket、freshness ## 現行 Connector Status Summary 零值呈現:DEC-037 

 **狀態:已確認(2026-09-05,Ken)** 

 - Backend 的 REST Overview 與 `CONNECTOR_LIVE_BLOCK_UPDATED` 對任何 Connector `total` 都固定回傳五個 bucket,stable codes/順序沿用 DEC-036;每個 `count` 可為 0,避免空案場使用不同 response shape。 
 - `total > 0` 時 FE 固定顯示全部五項,包含零值;WebSocket replacement 只更新數字,不讓項目因 0/非 0 切換而出現、消失或重排。 
 - `total = 0` 時 FE 隱藏整組 Status summary,顯示 Connector Empty State。有效 0 不得被解讀為 Loading、Error、Unknown 或 query 不得硬編碼 A17。 null。 
 - 本決策只固定 transport contract 與 presentation,不新增事件類型、fallback、retry、資料修正或 operational state。 

 本票只定義資料 ownership、REST/WebSocket channel、Frontend state 與跨區塊 contract;各區塊完整資料公式分別由 #1423、#1460、#1461、#1462、#1463、#1486 管理。 ## 現行 Connector Status Summary Mapping:DEC-036 

 **狀態:已確認(2026-09-04,Ken)** 

 - Backend 依固定 precedence 將每個 Connector 歸入第一個符合的 bucket:`NEEDS_ATTENTION`「需留意」→ `CHARGING`「充電進行中」→ `WAITING`「準備/排隊」→ `AVAILABLE`「可用」→ `OTHER`「其他狀態」。 
 - NEEDS_ATTENTION 使用既有 abnormal 集合:OFFLINE、FAULTED、STALE、BLOCKED、SUSPENDED_EVSE、UNAVAILABLE、null/unknown/資料不足;其 count 必須等於 `abnormalTotal`。 
 - CHARGING 收非異常的 CHARGING/SUSPENDED_EV/FINISHING;WAITING 收非異常的 PREPARING/ENQUEUED/Queue ELIGIBLE;AVAILABLE 收排除特殊中性狀態後的 AVAILABLE;OTHER 收 RESERVED、NOT_PLUGGED、Queue PAUSED/FINISHED及其他已辨識的中性狀態。Unknown 不得落入 AVAILABLE/OTHER。 
 - Summary 使用固定 stable codes/order;FE 固定映射中文 label。REST Overview 與 `CONNECTOR_LIVE_BLOCK_UPDATED` 共用 mapping;Top-8 item 的 `displayBucket`/`isAbnormal` 必須一致。 
 - 本 mapping 只控制唯讀 presentation,不建立新的 Attention category/告警,也不改變 OCPP、runtime、Queue 或 charging 邏輯。 

 ## V1 簡化原則 現行 Connector Status Summary 計數:DEC-035 

 **狀態:已確認(2026-09-04,Ken)** 

 - Backend 依目前 building 的同一份 Connector snapshot,替每個 Connector 指定且只指定一個 Dashboard 只查詢、彙整與顯示既有狀態,不執行 Remote Start/Stop、Reset、Queue/Rotation、帳務或其他 mutation。 presentation `displayBucket`;所有 bucket count 無重複、無遺漏,加總必須等於 `total`。 
 - 只有「Connector 即時狀態」與「案場即時負載」需要 WebSocket;其他區塊使用同一個 `displayBucket` 不取代 OCPP connection、Connector runtime 或 Queue status/reason;Card/Drawer 仍分層顯示原始狀態。此分類唯讀,不回寫或改變任何 operational state。 
 - REST Overview bootstrap 與 `CONNECTOR_LIVE_BLOCK_UPDATED` 共用同一 bucket aggregation;Frontend 直接呈現 summary counts,不從 Top-8 preview 重算。Top-8 item 同時帶自己的 `displayBucket`。 
 - Bucket codes、labels、mapping 與 precedence 已由 #1423 UI-DEC-015/DEC-036 確認;FE/BE 必須共用固定 contract。 

 ## 現行 Connector Preview Payload:DEC-034 

 **狀態:已確認(2026-09-04,Ken)** 

 - Backend 先對目前 building 的完整 Connector 集合進行 priority ranking 與 abnormal classification,再固定回傳最多前 8 筆 `items`,並附 `total`、`abnormalTotal`;每筆帶 Backend authoritative `isAbnormal`、`severity`、`priorityReason`。 
 - REST response。 Overview bootstrap 與 `CONNECTOR_LIVE_BLOCK_UPDATED` 共用同一 service、snapshot 與 contract;WebSocket 更新時 replacement 整個 Connector summary + Top-8 preview,不傳完整 inventory。 
 - WebSocket 失敗時誠實提示使用者,不建立 Frontend 不傳 viewport/device/requestedLimit,也不重排或重判異常;只依 breakpoint 顯示 items 前 8/6/4 筆,並由 Backend totals 與 visible slice 計算純顯示用 `hiddenCount`/`hiddenAbnormalCount`。 
 - 完整清單、搜尋、篩選與 server pagination 仍由 Drawer 呼叫 REST fallback、custom retry、背景自動重連或 gap recovery。 search API。此決策不新增 transport、fallback、business rule 或作業 mutation。 

 ## 現行 V1 Freshness 設定規則:DEC-033 

 **狀態:已確認(2026-09-04,Ken)** 

 - Dashboard V1 的 stale cutoff 由 Backend 依資料來源分別設定全系統預設值,例如 Connector status 與 MeterValue 可使用不同門檻。 
 - 同一份 Backend 版本/部署設定對所有案場套用同一套 source defaults;不得硬編碼 A17 或任何特定 building。 
 - V1 優先重用既有 endpoint、權限與 domain service;不建立重複的 不提供 per-building stale cutoff override,也不新增對應資料表、設定 API、Admin UI、管理權限或變更 audit。 
 - REST Overview 與 Dashboard inventory、告警引擎或作業狀態。 WebSocket 使用同一份 Backend freshness policy,回傳 `updatedAt`、`freshness`,以及顯示/判斷所需的 deadline 或 cutoff metadata;Frontend 不硬編碼秒數。 
 - A17 只用來驗證通用 default 是否符合正常回報週期及營運容忍度。若未來有案場確實需要不同門檻,必須另開 Feature 定義資料模型、權限、稽核與 migration,不在本 Dashboard V1 預先開發。 
 - 本決策撤回 DEC-007;DEC-006 的「Backend 集中管理、適用所有案場」原則繼續有效。 

 ## Building Scope 與權限(DEC-029/030) 現行 REST 更新規則:DEC-032 

 **狀態:已確認(2026-09-04,Ken)** 

 ### 更新節奏 

 - 所有 REST-owned sections 共用一個 Dashboard refresh cycle:頁面首次載入、頁面開啟期間每 5 分鐘一次,以及使用者手動刷新。 
 - 每個 EMS Branch cycle 只呼叫一次 `GET /api/dashboard/overview`;不為 KPI、需留意事項、Group、Usage、Billing 或 Live Load 歷史 series 建立個別 timer/request。 
 - 本規則取代下方表格與相關子票中的帳務 15 分鐘、群組低頻刷新、不同區塊 5/15/60 分鐘等舊週期;這些舊段落只保留為討論歷程。 

 ### REST 與 WebSocket ownership 

 - Overview 首次載入可提供「Connector 即時狀態」與「案場即時負載」的 bootstrap 值,使頁面先有可辨識的最後狀態。 
 - 收到第一筆 `DASHBOARD_LIVE_SNAPSHOT` 後,兩個即時區塊的畫面 ownership 交由 WebSocket;後續定時或手動 Overview response 只套用 REST-owned sections,不覆寫 live state。 
 - WebSocket 首次連線失敗或後續中斷時,5 分鐘 REST refresh 仍只更新一般區塊;不得更新兩個即時區塊、不得顯示「定時更新模式」,也不得讓使用者誤認即時連線仍正常。 
 - 手動刷新只重新取得 Overview,不重新取得 ticket 或重建 WebSocket;只有重新載入整個頁面才重新嘗試 WebSocket,沿用 DEC-031。 

 ### UI 與錯誤邊界 

 - Header 分開呈現:一是 WebSocket 即時連線狀態,二是一般 REST 資料的最後成功更新時間/5 分鐘週期。 
 - Overview refresh 成功時,同一份 response 的 V1 必須且只能有一筆 enabled Building。Backend 自動解析該 Building;Frontend REST-owned sections 使用同一個 `generatedAt`;Frontend 不把不同週期取得的資料拼成一次看似一致的 snapshot。 
 - Refresh 失敗時沿用已確認的各 section 狀態規則:保留同 building 的最後成功 REST 資料並顯示更新失敗/`lastSuccessfulAt`,等待下個 5 分鐘 cycle 或手動刷新;不新增 immediate retry、backoff 或另一套 polling。 
 - 首次 Overview 失敗時,不得顯示 fixture 或把未知值轉成 0。 

 ### Backend 要開發的內容 

 - `GET /api/dashboard/overview` 在單一 response 回傳所有 REST-owned sections、`generatedAt`、各 source dataStatus/freshness/updatedAt 及必要的 `lastSuccessfulAt`。 
 - 讓 Overview snapshot 的 Overview/ticket bootstrap 欄位與 WebSocket live payload 使用相同 domain aggregation,但不建立額外 fallback endpoint、per-section refresh API 或 Dashboard background job。 
 - 保持 current-building scope、SS3A 權限、null/0 與 read-only 規則不變。 

 ### Frontend 要開發的內容 

 - 使用單一 Overview query/timer 實作首次載入、300 秒 refetch 及手動刷新;Dashboard unmount 後不保留另一組頁面 timer。 
 - Live Load 的 LIVE/TODAY/SEVEN_DAYS series 隨同一 Overview 一次取得;range button 只切換 cache,不發 request 與 或改變 WebSocket URL 不傳 `buildingId`。 lifecycle,refresh 後保留 selectedRange;完整互動與 Empty/Error 規則見 #1462 LOAD-DEC-007。 
 - 分層保存 REST-owned state 與兩個 WS-owned live state;收到第一筆 WS snapshot 後,Overview refresh 不得覆寫 live state。 
 - Header 同時顯示獨立的 WebSocket 連線狀態與一般資料更新狀態;刷新按鈕的文字/accessible name 明確表示只刷新一般資料。 

 ### Acceptance Criteria 

 - [ ] 頁面首次載入只送出一個 Overview response、ticket binding 與所有 request,之後每 300 秒最多一個;手動刷新也只送出一個。 
 - [ ] Billing、Usage、KPI、Attention、Group 與歷史 series 沒有各自 timer 或重複 Overview request。 
 - [ ] 同一次成功 response 的 REST-owned sections 使用相同 `generatedAt`。 
 - [ ] WebSocket 接手後,定時/手動 Overview refresh 不改變兩個 live blocks;socket 斷線期間仍不形成 REST fallback。 
 - [ ] 即時連線中斷時,一般 REST 區塊仍可每 5 分鐘更新,Header 也能同時表達這兩種不同狀態。 
 - [ ] Refresh error 保留同 building 最後成功資料並標示時間;首次 error 不顯示 fixture 或假 0。 
 - [ ] 本決策不新增業務 mutation、retry scheduler、資料修正或設備控制。 

 ## 現行 V1 傳輸規則:DEC-031 

 **狀態:已確認(2026-09-04,Ken)** 

 > 本節是目前有效的傳輸需求。下方較早提出的 Dashboard 全區 WebSocket、REST polling fallback、capped exponential backoff、jitter、sequence/gap recovery、固定 5 秒 coalescing 與 P95 2 秒 propagation SLO,均保留作為討論歷程,但不再是 V1 開發依據。 

 - V1 保留一條案場層級 Dashboard WebSocket,但只更新「Connector 即時狀態」與「案場即時負載」。 
 - `GET /api/dashboard/overview` 仍提供整張 Dashboard 首次載入所需的 snapshot;WebSocket 建立後,只 replacement 上述兩個即時區塊。 
 - Connector message 回傳整個即時狀態 summary(固定五個 bucket,包含 count = 0)、Backend 排序/分類後的 Top-8 preview、`total` 與 `abnormalTotal`;Frontend 只顯示前 8/6/4 筆,完整清單、搜尋及分頁仍走 REST(DEC-034/037)。 
 - Live Load message 更新 `currentPowerKw` 與目前進行中的 open buckets;完整「即時/今日/7 日」歷史 series 仍走 REST。 
 - 六張 KPI、需留意事項、群組容量/Slots、30 日用量、今日已完成充電量、結算流程及上月電費不訂閱 Dashboard WebSocket。 
 - WebSocket event 明確帶 Backend-resolved `buildingId`,Frontend 只套用 scope 相符的資料。 首次連線失敗或已連線後中斷時,Header 與兩個即時區塊顯示「即時連線中斷」。 
 - enabled Building 為零筆或多筆時,Backend 回明確 configuration error;Frontend 顯示整頁「案場設定異常」,隱藏營運數字,不得任選第一筆、跨 Building 加總或顯示假 若已有最後成功資料,畫面保留資料與最後更新時間,但明確標示「已停止更新」;若尚無資料,顯示 `—` 與「即時資料暫時無法取得」。不得清成 0。 
 - Header/Sidebar 只顯示 V1 不做 REST polling fallback、不顯示「定時更新模式」,也不開發 custom backoff、jitter、背景自動重連、sequence/gap recovery或專用 Retry workflow。 
 - 使用者重新載入整個頁面時,才重新取得 ticket 並嘗試建立新 WebSocket。 
 - WebSocket 斷線只影響兩個即時區塊;其他已成功載入的 REST 區塊仍可查看。 
 - Backend 回傳的唯讀案場名稱與 timezone,不提供 site selector。 的 source freshness/stale cutoff、null/0、building scope、SS3A 權限及 Dashboard 唯讀邊界繼續有效;socket 是否連線與資料來源本身是否 stale 必須分開呈現。 
 - V1 沿用既有 SS3A `dashboard` function,不新增 role/function。既有 `administrator`、`power_user`、`association`、`dealer` 可看同一份唯讀 Dashboard;只有 `adm_user`、`member`、`hq`、`engineer` 時不自動取得權限。 message type 收斂為 `DASHBOARD_LIVE_SNAPSHOT`、`CONNECTOR_LIVE_BLOCK_UPDATED`、`LIVE_LOAD_UPDATED`。同一 WebSocket 內採整區 replacement,不新增 client-side delta merge。 
 - 本決策完整取代 DEC-003 與 DEC-005;並取代 DEC-002 的 fallback/重連部分、DEC-004 的固定 5 秒產品契約、DEC-008 的 sequence/gap recovery、DEC-014 的重連/gap recovery,以及 DEC-021/023~028 中要求非上述兩個區塊使用 WebSocket 的傳輸部分。這些決策的資料公式、Backend authoritative aggregation、security 與 presentation 規則仍有效。 
 - 非即時 REST 區塊已由 DEC-032 確認為頁面首載、共用 5 分鐘 Overview cycle 與手動刷新。 

 ## 背景 

 所有案場共用的 Branch Admin Dashboard 主需求為 #1422;A17 僅是第一個驗證基準。 

 本票用於定義 Dashboard 各區塊的資料更新通道:哪些資料使用 REST API、哪些適合透過 WebSocket 即時推送,以及兩者如何在 initial load、重連、stale、partial data 與權限控制下協作。 

 **本票架構決策已確認;內容尚待全 Dashboard 鎖版後整併,議題仍維持 New/0%,不代表已進入開發。** 

 ## 現有程式碼觀察 

 ### 已有能力 

 - `react/branch` 已有 `useAdminConnectorSocket()`。 
 - `java/ems_branch` 已有 `/ws/admin/connectors/{connectorId}`。 
 - 既有流程先以 SS3A REST API 與 取得 30 秒、一次性、connector-bound ticket,再建立 WebSocket。 
 - 新連線會收到 `CONNECTOR_SNAPSHOT`,後續可收到 `OPERATION_RESULT`。 
 - `ConnectorEventPublisher` 已涵蓋 Connector status、MeterValue、Transaction、queue、off-peak、offline 等多條異動路徑,並在 commit 後重查 authoritative snapshot。 
 - Server 已使用 `ConcurrentWebSocketSessionDecorator` 保護並行推送。 

 ### 現有限制 

 - 現有 Admin WebSocket 是「一個 Connector 一條連線」,不適合 Dashboard ticket API 都必須 mapping 至 `dashboard` function;Frontend 隱藏 menu 不能取代 同時顯示 20/30/100 個 Connector。 
 - 若 Dashboard 為每個 Connector 建立 socket,會造成 N 張 ticket、N 條連線、N 組重連與 browser/server 資源放大。 
 - 現有 WebSocket contract 是 FE 手寫型別,不在 OpenAPI 內;Dashboard event contract 必須另外版本化與測試。 
 - Charge Point ONLINE/heartbeat、billing、usage trend 並非全部都有現成 Dashboard event publisher。 
 - WebSocket 只是一種 transport,不可取代資料庫 authoritative state,也不可讓斷線後的舊資料看起來仍是即時資料。 

 ## Proposed Architecture 

 採用: 

 > 一次 REST bootstrap + 一條案場層級 Dashboard WebSocket + REST drill-down 

 ### Initial load 

 1. `GET /api/dashboard/overview` 載入完整初始畫面、歷史資料與非即時資料;Frontend 不傳 `buildingId`。 
 2. Backend 解析目前 EMS Branch 中唯一一個 enabled Building,並以其 `buildingId`、名稱與 timezone 作為整份 Dashboard scope。 
 3. 以具 Dashboard function 的 403 與 REST endpoint 取得一次性、短效 ticket;ticket 綁定使用者與 Backend 已解析的 `buildingId`。 
 4. 建立一條 `/ws/admin/dashboard?ticket=...`,WebSocket URL 不接受 Frontend 任意指定案場。 
 5. WebSocket ticket authorization。 先回 `DASHBOARD_LIVE_SNAPSHOT`,作為即時區塊的 authoritative initial state。 
 6. 後續只推送有變化的「區塊 replacement event」,不傳 raw database rows,也不要求 FE 自行重算全站統計。 

 V1 的「所有案場共用」是同一套功能部署至各 EMS Branch;不是在單一 Branch 內提供案場切換或跨案場彙總。所有 response/event 仍必須帶 Backend 解析後的 `buildingId`,供 scope 驗證與避免資料混用。 

 ## 現行資料通道矩陣(DEC-031/032) 區塊與資料通道矩陣 

 | Dashboard 區塊 | 首次資料 資訊 | 後續更新 Primary channel | WebSocket 失敗時 更新策略 | 
 |---|---|---|---| 
 | Header 案場資訊、一般資料時間 | `GET /api/dashboard/overview` Backend 解析的目前案場名稱、buildingId、timezone、選擇的圖表 range | 同一 Overview 每 5 分鐘/手動刷新 REST | 照常更新 首次載入;案場名稱為唯讀識別,不提供切換 | 
 | Header | REST 狀態 `generatedAt`、WS connection state、最後 event 時間、各 source freshness | Hybrid | REST 提供 source snapshot;FE 顯示 socket 狀態;WS 推 freshness transition | 
 | 六張 KPI 需留意事項(#1463 ATT-DEC-001/002) | Overview Connector FAULTED、CP OFFLINE、current Live Load STALE/PARTIAL/ERROR、既有 Queue BLOCKED | 同一 Overview 每 5 分鐘/手動刷新 WebSocket + REST bootstrap | 照常更新,不使用 WS fallback authoritative state commit/freshness transition 後重算 category summary;歷史 Live Load gap 與 WAITING duration 不產生告警 | 
 | 需留意事項 需留意事項(#1463/#1460) | Overview 四步驟結算流程的既有未完成/異常狀態 | 同一 Overview 每 5 分鐘/手動刷新 REST | 照常更新,不使用 15 分鐘 refetch 或手動刷新;V1 不新增 billing WS 或 overdue 判斷 | 
 | Charge Group 容量/Slots/Queue 摘要 KPI Row | Overview CP ONLINE/OFFLINE/UNKNOWN、enabled/disabled counts(#1486 KPI-DEC-002) | 同一 Overview 每 5 分鐘/手動刷新 WebSocket + REST bootstrap | 照常更新,不使用 WS persisted connection state transition 後以 NETWORK_HEALTH_UPDATED replacement;Heartbeat 未改變狀態時不推送 | 
 | 30 日 Usage、今日已完成充電量 KPI Row | Overview Connector 可服務摘要、Connector status、「充電進行中」active sessions、「等待供電」distinct ELIGIBLE、Queue blocked、目前總功率 | 同一 Overview 每 5 分鐘/手動刷新 WebSocket + REST bootstrap | 照常更新,不使用 WS Connector/transaction/parent CP/Queue transition 後更新 CONNECTOR_OVERVIEW_UPDATED;次要功率沿用 LIVE_LOAD_UPDATED | 
 | 四步驟結算、上月電費 KPI Row | Overview 「今日已完成充電量」與已完成 Sessions(重用 #1461 today daily bucket) | 同一 Overview 每 REST | 首載、每 5 分鐘/手動刷新 分鐘 refetch、手動刷新;V1 不新增 Usage/Energy WebSocket | 照常更新,不使用 WS | 
 | Connector 即時狀態摘要/Top-8 Live Load(#1462 LOAD-DEC-001/004) | Overview currentPowerKw、LIVE/TODAY/SEVEN_DAYS open buckets、跨界 finalized bucket、latestMeterAt、freshness/source status;不含推算的案場契約容量、利用率或剩餘容量 | WebSocket + REST bootstrap | `CONNECTOR_LIVE_BLOCK_UPDATED` MeterValue 事件聚合,最多每 5 秒推一次;不重送完整 series | 
 | Live Load 歷史 series(#1462 LOAD-DEC-003/004) | LIVE:最近 60 分鐘/1 分鐘 bucket;TODAY:案場當日 00:00 至現在/15 分鐘 bucket;SEVEN_DAYS:含今天 7 個案場日曆日/1 小時 bucket;Y 值為 time-weighted averagePowerKw | REST + WebSocket bucket replacement | 保留最後資料並標示已停止更新;無資料顯示 `—` REST 提供完整 snapshot;WS 只更新 open/finalized buckets,不重送整段 series | 
 | Group Capacity | contract capacity、allocated power、reserved slots 等設定 | REST | 首載/手動刷新/低頻刷新 | 
 | Group Capacity | occupied、available、waiting、blocked、longest wait | WebSocket + REST bootstrap | Transaction/queue/status commit 後更新 | 
 | Connector 完整清單 Grid | `POST /api/connector/search` 固定五項的互斥 displayBucket summary(含零值)、Top-8 preview、total、abnormalTotal、item displayBucket/isAbnormal/severity/priorityReason | 開啟 Drawer、搜尋、篩選或換頁時重新查詢 WebSocket + REST bootstrap | 不受 Dashboard socket 影響 Server 統一 bucket aggregation、排序/分類並推送整個 Top-8 replacement;total > 0 時 FE 顯示五項,total = 0 顯示 Empty State;summary 為不可點擊的純資訊,FE 不從 preview 重算,只依 breakpoint 顯示 8/6/4 | 
 | Connector detail Full List | 既有 detail API 搜尋、filter、固定 Backend priority sorting、固定 20 筆 pagination | REST | 使用/擴充既有 `POST /api/connector/search`;固定 `DASHBOARD_PRIORITY` mode,Server 對完整結果 filter → priority sort → paginate;Drawer 不提供使用者排序,既有管理頁排序不受影響;query state 生命週期依 DEC-039 | 
 | Connector Detail Drawer 開啟時才使用既有單 | 單支 Connector socket 完整狀態 | 依既有 detail flow 顯示錯誤;關閉即釋放 既有單 Connector WebSocket | Drawer 開啟時才建立;關閉即釋放 | 
 | 案場即時負載目前值/open buckets Usage Trend(#1461 USG-DEC-001~009) | Overview bootstrap 最近 30 個案場日曆日(含今天)的有效 kWh、valid Sessions、平均每次充電量;固定 30 daily buckets;成功無使用為 0、未知為 null;全段零為 COMPLETE + EMPTY;initial/refresh error、lastSuccessfulAt、STALE;依 building timezone 的交易開始日歸屬;異常 Completed 排除筆數與 PARTIAL status;不含時間使用率 | `LIVE_LOAD_UPDATED` replacement REST | 保留最後資料並標示已停止更新;無資料顯示 `—` 首載、5 分鐘 refresh;有 cache 時保留最後成功 snapshot;平均值由 Backend 計算;Sessions 僅 COMPLETED + positive energy;ACTIVE 不估算;跨日不拆分 | 
 | Live Load 即時/今日/7 日完整 series 結算流程(#1460 BIL-DEC-001/002/003) | Overview periodYear/periodMonth/timezone、Connector 結算、門牌結算、Billing status、Invoice status | 同一 Overview 每 5 分鐘/手動刷新;WS 只 replacement open bucket | 保留 REST series;不得冒充仍即時 | 首載、15 分鐘 refresh、手動刷新;唯讀;導覽 route 由 FE 固定 | 

 ## Overview REST Contract(DEC-002 保留部分/DEC-032) 不適合透過 WebSocket 的資料 

 - 新增 typed `GET /api/dashboard/overview`,一次回傳目前 Building 的案場識別、`generatedAt`、各 source 的狀態/時間,以及所有 Dashboard sections。 歷史趨勢整段 series。 
 - 更新時機只有:頁面首次載入、Dashboard 保持掛載期間每 300 秒一次、使用者手動刷新。 結算流程沿用 attachment #1110 四步驟面板;透過 REST 提供正式資料與 Backend 決定的最近結算期間,詳見 #1460 BIL-DEC-001/002。 
 - 每個更新週期只送一個 Overview request;KPI、Attention、Group、Usage、Billing 與歷史 series 不得各自建立 timer 或重複 request。 完整 Connector inventory、搜尋結果與分頁。 
 - 同一份成功 response 的 REST-owned sections 使用相同 `generatedAt`。每個需要獨立品質判斷的 source/section 另回 `dataStatus`、`freshness`、`updatedAt` 及必要的 `lastSuccessfulAt`。 案場名稱、時區、Charge Group contract capacity 等低頻設定。 
 - WebSocket 尚未接手前,Overview 可顯示兩個 live blocks 的 bootstrap。收到 socket initial snapshot 後,定時或手動 Overview refresh 不得覆寫 Connector 即時狀態與案場即時負載的 live state。 Export/報表。 
 - 手動刷新只更新 REST-owned sections,不重建 WebSocket;只有重新載入整頁才重新取得 ticket 並嘗試連線。 
 - 任何可由 REST refresh error 可保留同一 Backend-resolved Building 的最後成功資料,但必須標示更新失敗與 `lastSuccessfulAt`;首次失敗不得顯示 fixture 或假 0,也不得跨 Building 使用 cache。 查詢且容許 1–15 分鐘延遲的資料。 

 理由:這些資料更新頻率低、payload 可能較大,或需要 query parameter/pagination;WebSocket 不會因此提供足夠效益,反而增加事件契約與一致性成本。 

 ## Dashboard WebSocket Contract(DEC-008 保留部分/DEC-009/031) Event Contract 

 建議 envelope: 

 ```json 
 { 
   "schemaVersion": "1", 
   "type": "CONNECTOR_OVERVIEW_UPDATED", 
   "buildingId": 123, 
   "sequence": 42, 
   "occurredAt": "2026-08-10T16:00:00+08:00", 
   "data": {} 
 } 
 ``` 

 V1 event types: 

 - V1 沿用 raw WebSocket,不引入 STOMP。每張 Dashboard 頁面只建立一條案場層級 Dashboard socket,不為每張 Connector card 建立連線。 `DASHBOARD_LIVE_SNAPSHOT` 
 - Dashboard ticket 必須短效、一次性、綁定登入管理員與 Backend-resolved Building,且只有具 `dashboard` function 的使用者可取得。 `NETWORK_HEALTH_UPDATED` 
 - V1 只允許三種 message type: 
   `ALERTS_UPDATED` 
 - `DASHBOARD_LIVE_SNAPSHOT`:連線建立後提供兩個 live blocks 的完整目前狀態。 
   `LIVE_LOAD_UPDATED` 
 - `CONNECTOR_LIVE_BLOCK_UPDATED`:replacement 整個 Connector summary + bounded Top-8 preview。 
   `CHARGE_GROUP_OVERVIEW_UPDATED` 
 - `LIVE_LOAD_UPDATED`:replacement `currentPowerKw` 與三種 range 的目前 open buckets;跨 bucket 邊界時可同時帶 finalized bucket。 `CONNECTOR_OVERVIEW_UPDATED` 
 - `SOURCE_FRESHNESS_UPDATED` 

 規則: 

 - Event envelope 至少包含 `schemaVersion`、`type`、`buildingId`、`occurredAt` 與 typed `data`;不傳 raw DB row、JWT、ticket、currentIdTag 或不必要個資。 以「區塊 replacement」為主,不讓 FE 由細碎 delta 自行推導 summary/排序。 
 - Message 採區塊 replacement。Frontend 不從細碎 delta 自行重算 total、bucket、priority ranking、功率平均或其他 domain state。 每條連線的 `sequence` 單調遞增;initial live snapshot 必須先於後續 update。 
 - V1 以單一 active `ems_branch` instance 為部署前提;若未來要多 instance/HA,須另案設計 session fan-out 與授權,不在本需求預做。 FE 忽略較舊 sequence;發現 gap、重連或 schemaVersion 不支援時,重新取得 snapshot。 
 - Backend 可為資源保護做內部 debounce/coalescing,但 V1 不把固定 所有 event 帶 server `occurredAt`;各資料區塊另帶 source `updatedAt`/freshness。 
 - Dashboard preview 不回 currentIdTag 等不必要的敏感欄位;詳細資料留在既有權限控制的 detail flow。 
 - Unknown/null 不可轉成 Available/0。 

 ## Event Trigger 與節流 

 | Source | Trigger | 建議推送 | 
 |---|---|---| 
 | Connector StatusNotification | status commit 後 | 2 秒內更新 Connector/KPI/Alerts | 
 | Transaction start/stop | transaction commit 後 | 2 秒內更新 Connector/KPI/Group | 
 | Queue/off-peak/rotation | priority lifecycle commit 後 | 2 秒內更新 Group/Connector/Alerts | 
 | CP offline watchdog/connection transition | ONLINE/OFFLINE/UNKNOWN transition | 2 秒內更新 Network/Connector/Alerts | 
 | MeterValue | 有新 power value | coalesce;最多每 5 秒或 P95 2 秒列為產品驗收承諾。 秒更新 Live Load/受影響 preview | 
 | Heartbeat | 每次 heartbeat | 不逐次推送;只在 connection/freshness class 改變時推 | 
 | Usage aggregate | 時間累積 | REST 每 5 分鐘 | 
 | 結算流程 | 帳務異動/月結後由下一次 REST refresh 反映 | REST 每 15 分鐘或手動刷新;不新增 WS | 

 ### 連線失敗與中斷 實際秒數須以通用協定與服務排程為基礎,並由 A17 起逐步用不同 Connector 規模與 MeterValue 頻率的代表性案場驗證;不得只用單一案場樣本硬編碼。Browser WebSocket 沒有 backpressure,因此不得把每筆 raw MeterValue 原樣 fan-out。 

 ## 斷線、Stale 與降級 

 - 首次連線失敗,或已連線後中斷時,Header 與兩個 live blocks 顯示「即時連線中斷」。 Dashboard 是唯讀頁,可採 capped exponential reconnect;不能只顯示一次錯誤後永久停止更新。 
 - 已有最後成功資料時保留資料與最後更新時間,並明確標示「已停止更新」;尚無資料時顯示 `—` 與「即時資料暫時無法取得」。不得清成 WS 斷線時保留最後資料,但立即顯示「即時連線中斷」;不可清成 0。 
 - V1 不做 超過各 source cutoff 後,該資料標示 STALE,且 stale power 不納入 current total。 
 - WebSocket 無法恢復時,允許以 REST 30/60 秒 polling fallback、定時更新模式、custom backoff、jitter、背景自動重連、sequence/gap recovery、頁面回到 visible 自動重連或區塊專用 Retry。 降級,但 UI 必須明示「定時更新模式」,不可冒充即時。 
 - 其他 REST-owned sections 不受 socket 中斷影響;使用者重新載入整個頁面時,才重新取得 ticket 並嘗試建立新 socket。 手動 Refresh 同時重新取得 REST overview 與新的 WebSocket ticket。 
 - WebSocket Browser 回到 visible state 時檢查 connection state 與 source freshness 是兩件事:連線中不代表資料一定 fresh,斷線也不能改寫 Backend 已提供的 source quality。 freshness;必要時重新 bootstrap。 
 - Server 重啟、sequence gap 或 event parse failure 均以重新 snapshot 恢復,不嘗試從 client cache 猜測遺失事件。 

 ## Freshness 與資料品質(DEC-006 保留部分/DEC-015/028/033) Backend 開發影響 

 - Stale cutoff 由 Backend 依資料來源設定全系統預設值;Connector、MeterValue、Billing 等來源可不同,但所有案場使用相同設定。Frontend 不硬編碼秒數。 新增 Dashboard-level ticket、handler、session registry、broadcaster、live snapshot service 與 typed WS DTO。 
 - V1 不提供 per-building override,不新增設定 table、管理 API/UI、設定權限或 audit trail;特殊案場未來另開 Feature。 新增 current-building scope resolver:必須確認 Branch 內 enabled Building 恰好一筆;所有 Dashboard query 共用同一 scope,Overview 回傳 `buildingId`、名稱與 timezone。零筆或多筆時回明確 configuration error,禁止任選第一筆、跨案場加總或回傳零值 Dashboard。 
 - COMPLETE 沿用現有一次性 ticket、post-commit authoritative re-query 與 concurrent send 保護模式。 
 - 新增 CP lifecycle/freshness transition 的 0 是有效值;`null` 表示未知。Backend 子查詢失敗不得回 0,Frontend 也不得從其他卡片或 Dashboard event hook;不可假設 Connector publisher 能涵蓋所有 CP online/heartbeat 異動。 
 - Connector/queue/transaction/MeterValue event 需做 section invalidation 與 debounce/coalesce。 
 - Billing/usage 不新增 WebSocket publisher。 
 - Connector Full List 沿用/擴充既有 `POST /api/connector/search` 與 `SearchConnectorDto`:固定接收 `size = 20`、沿用 `page` 與 Spring Page response metadata;新增 stable `sortMode = DASHBOARD_PRIORITY`,先對完整資料集套用搜尋/篩選,再重用 preview 猜值。 ranking service 排序,最後分頁。既有 query 未涵蓋的 Charge Point ID/Charge Group 條件需補 DTO、query 與 contract tests;既有管理頁未使用此 mode 時保留原 `sidx`/`sord` 行為,不新增完整 inventory WebSocket。 
 - PARTIAL 有 Backend 認定安全的值時可保留並標示可能不完整;沒有安全值時回 `null`/顯示 `—`。ERROR/STALE 必須有文字狀態,不得只靠顏色。 沿用既有 SS3A `dashboard` function:將 Overview 與 ticket API mapping 至此 function,不新增 `dashboard_view` 或其他 role/function;Dashboard WebSocket 只接受由已授權 ticket endpoint 核發的有效 ticket。部署 migration 必須冪等確認 `administrator`、`power_user`、`association`、`dealer` 四個 role 的既有 mapping,並在 Branch 重啟後使授權快取生效。 
 - 一個 source 失敗只影響相依 section;其餘成功 sections 繼續顯示。 若未來採多 instance,in-memory session registry 與 sequence 需另行評估跨 instance fan-out;V1 不應默認單 instance 永遠成立。 

 ## Connector 即時狀態(DEC-034~038/#1423 UI-DEC-001~017) Frontend 開發影響 

 ### Summary - 新增一個 Dashboard socket hook,不可對 preview 每張卡呼叫 `useAdminConnectorSocket()`。 
 - Frontend 不送 `buildingId`、不顯示案場 selector;Header/Sidebar 只顯示 Overview 回傳的目前案場名稱。若 Backend 無法解析唯一 enabled Building,顯示整頁設定錯誤並隱藏營運數字,不得顯示 0 或 fixture。 
 - Dashboard menu/route 依 Backend 回傳的既有 `dashboard` function 顯示;Frontend 隱藏不是安全邊界,Overview 與 Preview 

 ticket API 仍須由 Backend 回 403。四個允許 role 看到同一份唯讀 Dashboard,不因角色分出不同資料版本。 
 - 將 REST overview 與 WS live section 分層保存;以 server event replacement 更新對應 section。 
 - Header 明確區分:REST 最後成功更新、WS 連線狀態、source freshness。 
 - kWh/Sessions 切換使用同一個固定 30 日 REST range,不重建不相關的 live socket;V1 不送出 7/90 日或自訂 range 查詢。 
 - Usage daily buckets 必須直接使用 Backend 對目前 Building 的完整 回傳的完整 30 日序列;Frontend 不自行補缺日為 0。明確的 0 顯示零值,null 顯示資料缺口並標示 PARTIAL。 
 - 時間使用率已依 #1461 USG-DEC-005 移除;第三個摘要依 USG-DEC-006 改為 Backend REST 回傳的 averageEnergyPerSessionKWh,不新增 WebSocket event。 
 - Connector 集合使用同一份 authoritative snapshot 進行分類與排序,再回傳固定五項 summary、`total`、`abnormalTotal` 及最多 Top-8 `items`。 Full List Drawer 固定每頁 20 筆,只顯示上一頁/下一頁與頁次/總筆數;1~20 筆隱藏換頁控制。任一搜尋/篩選改變時回第 1 頁並送出完整 Server query;固定要求 `DASHBOARD_PRIORITY`,不呈現或保存 sorting control/state,也不提供 page-size selector、直接跳頁或 virtualization。 
 - 五個互斥 `displayBucket` 固定依序為:`NEEDS_ATTENTION`「需留意」→ `CHARGING`「充電進行中」→ `WAITING`「準備/排隊」→ `AVAILABLE`「可用」→ `OTHER`「其他狀態」。每個 Connector 恰好一類,bucket counts 合計等於 `total`,`NEEDS_ATTENTION.count = abnormalTotal`。 detail drawer 開啟後才沿用既有單 Connector socket。 
 - Unknown/資料不足歸 NEEDS_ATTENTION;NOT_PLUGGED 歸 OTHER。Card/Drawer 仍分層顯示 OCPP connection、Connector runtime 結算面板的 /bill/list 與 Queue 原始狀態,不以 `displayBucket` 覆蓋 domain state。 /invoice/list 導覽由 FE 使用既有 route;Backend REST/WS contract 不回傳 URL。 
 - `total > 0` 時固定顯示包含零值的五項;`total = 0` 時隱藏 summary 並顯示 Connector Empty State。0 不得當成 Loading/Error/Unknown。 Usage initial error 不得顯示 0;refresh error 時可保留同 building 最後成功 snapshot,但必須顯示 lastSuccessfulAt/refresh error,並依 Backend freshness deadline 轉為 STALE。 
 - 五個 summary 項目是不可點擊的純資訊,不是 link/button/filter shortcut,也不進入 Tab 順序。單支 detail 由 preview card 開啟,完整清單由「查看全部」開啟。 Production API/WS error 不得 fallback 到 fixture。 
 - Backend payload 固定最多 Top-8,不接受 viewport/requestedLimit。Frontend 依 breakpoint 顯示 Desktop 8、Tablet 6、Mobile 4 筆,並以 Backend totals 計算隱藏總數與隱藏異常數;不自行重排或重判異常。 WebSocket contract 為手寫型別時,需有 fixture/parser/unknown event/schema version tests。 

 ### 固定 Priority Hierarchy ## Acceptance Criteria 

 Backend 對 Preview - [ ] Dashboard 不論有 1、2、30 或 100 個 Connector,本體只建立 1 條案場級 WebSocket。 
 - [ ] `GET /api/dashboard/overview` 與 Full List 共用以下順序: 

 1. Charge Point OFFLINE 且 Connector 有 ACTIVE transaction。 Dashboard ticket request 不需要 Frontend 傳 `buildingId`;Backend 自動解析唯一 enabled Building,且 Overview 回傳其 `buildingId`、名稱與 timezone。 
 2. Connector FAULTED。 - [ ] Dashboard 不提供案場 selector 或跨案場彙總;同一份程式可部署至所有 EMS Branch,A17 不得被硬編碼。 
 3. Charge Point OFFLINE、資料 STALE、Queue BLOCKED。 - [ ] Branch 內 enabled Building 為零筆或多筆時顯示明確設定錯誤,所有營運區塊不載入,且未知資料不得顯示為 0。 
 4. Connector SUSPENDED_EVSE、UNAVAILABLE。 - [ ] 每個 Dashboard WS event 的 `buildingId` 必須等於 ticket 綁定的 Backend-resolved Building;不符時 FE 拒絕套用並重新 bootstrap。 
 5. - [ ] 只有開啟 Connector SUSPENDED_EV。 detail drawer 時,才可額外建立 1 條既有 connector-bound WebSocket。 
 6. Connector CHARGING。 - [ ] 初始 REST 與 initial WS snapshot 不會發生舊事件覆蓋新資料。 
 7. - [ ] Connector PREPARING/Waiting。 status/transaction/queue/CP connection transition 在 commit 後於目標延遲內反映。 
 8. - [ ] Connector AVAILABLE。 

 同一層級依異常/狀態持續時間由久至新,再以 可服務摘要由 Backend 以 enabled CP scope、parent CP ONLINE 與固定 Connector ID 作 deterministic tie-breaker。排序只用於唯讀顯示,不修改 Queue priority、Connector status 或 charging lifecycle。 

 ## allowlist 計算;REST 與 CONNECTOR_OVERVIEW_UPDATED 結果一致,FE 不由 preview 重算。 
 - [ ] 「充電進行中」依每個 Connector Full List Drawer(DEC-039~041/#1423 UI-DEC-018~020) 

 的 canonical current ACTIVE transaction 計算,舊孤兒 ACTIVE 不得重複計數;Session count 與 Live Load power 可獨立更新/顯示狀態。 
 - 使用/擴充既有 `POST /api/connector/search`;完整 inventory、搜尋與分頁不透過 Dashboard WebSocket。 [ ] 「等待供電」只計 Queue ELIGIBLE 的 distinct Connector;NOT_PLUGGED 另列且與主數字互斥,BLOCKED 不納入並沿用需留意事項。 
 - `SearchConnectorDto` 沿用 `page`/`size` [ ] MeterValue 不逐筆無限制推送;Live Load 有明確 coalesce 上限。 
 - [ ] REST Live Load series 明確回傳 range、building timezone、bucket 起訖、averagePowerKw、bucketState 與 Spring Page response metadata,Dashboard 固定 `size = 20`。結果 1~20 筆隱藏換頁控制;多頁只提供上一頁/下一頁與「第 X / Y 頁・共 N 個」。 dataStatus;OPEN/FINALIZED、COMPLETE/PARTIAL/ERROR、0/null 不得混用。 
 - 搜尋文字或任一篩選改變時回第 [ ] LIVE/TODAY/SEVEN_DAYS 分別符合 60 分鐘/1 分鐘、當日/15 分鐘、7 個案場日曆日/1 小時定義。 
 - [ ] LIVE_LOAD_UPDATED 不重送完整 series;一般 event 更新三種 open buckets,跨界 event 正確提供 finalized/new open bucket。 
 - [ ] FE 只以 buildingId + rangeCode + bucketStartAt replacement 合併;gap/重連後以 REST snapshot 恢復。 
 - [ ] Usage trend、四步驟結算流程、完整 Connector list 不走 WS;結算流程依 #1460 使用 REST。 
 - [ ] Connector Full List 未套條件 30 筆為 2 頁、100 筆為 5 頁;每頁最多 20 筆,Page metadata、內容與 Footer 一致 
 - [ ] 搜尋/篩選改變時回第 1 頁。Server 必須對完整資料集先 filter、再依固定 頁且 Server 查完整集合;0~20 筆不顯示換頁控制,第一/最後一頁按鈕狀態正確,且無 page-size selector、直接跳頁或 virtualization 
 - [ ] Drawer 沒有排序控制;未篩選與篩選後結果都依 UI-DEC-007 固定 priority hierarchy sort、最後 paginate;不得只處理目前 與 deterministic tie-breaker 排序,再切成 20 筆。 筆頁面 
 - 既有 keyword/status 等條件可重用;Charge Point ID/Charge Group 等缺少條件須補 DTO、query、OpenAPI [ ] Dashboard request 使用 `DASHBOARD_PRIORITY` 且不接受使用者 sorting state;`/connector/list` 既有欄位排序沒有回歸 
 - [ ] 「今日已完成充電量」與已完成次數直接等於 #1461 today daily bucket;不使用 ACTIVE MeterValue 暫估、不另建 WebSocket 或第二套聚合。 
 - [ ] WS 斷線時立即顯示非即時狀態,資料不清 0;超過 cutoff 正確標示 STALE。 
 - [ ] KPI source 的 COMPLETE/PARTIAL/ERROR、value/null、freshness 與 contract tests。 updatedAt 在 REST/WS 語意一致;source failure 只影響相依 Card,refresh error 可保留同 building 成功快取但不得假裝最新。 
 - [ ] WS 無法恢復時可進入明示的 REST polling fallback。 
 - [ ] sequence gap/server restart/schemaVersion 不支援會重新 snapshot。 
 - [ ] `administrator`、`power_user`、`association`、`dealer` 透過既有 `dashboard` function 可取得 Overview 與 ticket;不新增另一個 Dashboard Drawer 不提供 sorting control。既有 search endpoint 增加 stable `sortMode = DASHBOARD_PRIORITY`;Dashboard 不接受使用者產生的 `sidx`/`sord`,既有 `/connector/list` 管理頁原欄位排序保持不變。 role/function。 
 - Search/filter/page state 只存在目前 [ ] 僅有 `adm_user`、`member`、`hq` 或 `engineer` role、但未取得 `dashboard` function 的使用者,直接呼叫 Overview/ticket API 必須得到 403;沒有有效 ticket 的 WebSocket handshake 不得建立 Dashboard page memory;close/reopen 保留,reload/navigation 重設。不寫 URL、history、localStorage、sessionStorage、Backend preference 或 WebSocket。 session。 
 - V1 不提供 page-size selector、頁碼列、直接跳頁、Grid/Table toggle 或 virtualization。 [ ] Ticket 一次性、短效且綁定使用者與 Backend-resolved building scope;Frontend menu 隱藏不能取代 Backend 授權。 
 - [ ] Dashboard event 不洩漏 currentIdTag、JWT、ticket 或不必要個資。 
 - [ ] 「需留意事項」每個 category 都能追溯到既有 authoritative state;不以自由文字、等待時間或前端比較推導新異常。 
 - [ ] categoryCount 等於 affectedCount > 0 的 categories 數量;每類 affectedCount 依穩定 entity/entry/step identifier distinct,FE 不重新加總或跨類去重。 
 - [ ] categories array 只含全部非零 allowlisted categories 並保持固定順序;viewport 只影響換行,不影響資料或 DOM 順序。 
 - [ ] 摘要只有導覽作用,不觸發 Reset、Start/Stop、Queue/Rotation、帳務或工單 mutation。 
 - [ ] 390/768/1024/1440 px 的 loading、connected、reconnecting、fallback、stale state 均可辨識。 
 - [ ] A17 壓測驗證同時在線管理者、MeterValue 頻率、payload size、server buffer 與 browser CPU/memory。 

 ## 其他區塊的有效資料規則 待確認事項 

 ### - [x] V1 由 Backend 自動解析 Branch 唯一 enabled Building:Frontend 的 REST/ticket request 與 WebSocket URL 不傳 `buildingId`;Overview response、ticket binding 與 event envelope 明確帶 Backend-resolved `buildingId`(DEC-029,取代 DEC-001)。 
 - [x] V1 沿用既有 `dashboard` function 與既有四個 role mapping:`administrator`、`power_user`、`association`、`dealer`;不新增 role/function(DEC-030)。 
 - [x] Dashboard WebSocket 採 capped exponential backoff:1、2、4、8、16、30 秒,30 秒封頂並加入 ±20% jitter。 
 - [x] WebSocket 中斷期間啟用每 60 秒完整 Overview REST polling fallback。 
 - [x] Live Load(DEC-012~015 保留資料公式;詳見 #1462) 

 Load 採 Backend server-side 5 秒 coalescing,最多每 5 秒推送一次完整負載摘要。 
 - [x] V1 Live Load 不以 Charge Group contract capacity 加總推算案場契約容量、利用率或剩餘容量;只顯示案場即時總功率及各群組自身容量。 加總推算案場契約容量、利用率或剩餘容量(DEC-012/#1462)。 
 - 保留「即時/今日/7 日」三種 series。X 軸分別為最近 60 分鐘/1 分鐘 bucket、今日 00:00 至現在/15 分鐘 bucket、含今天 7 個案場日曆日/1 小時 bucket;Y 軸為「充電功率(kW)」的 [x] Live Load 三種 X 軸與 bucket、Y 軸 time-weighted averagePowerKw。 averagePowerKw 依 DEC-013/#1462 LOAD-DEC-003。 
 - [x] REST 回完整 series;WebSocket 只 replacement currentPowerKw 與 open/跨界 提供完整 series,WebSocket 只更新 currentPowerKw、三種 open buckets 與跨界 finalized buckets。Frontend 不自行積分、平均、插值或跨資料缺口連線。 bucket(DEC-014/#1462 LOAD-DEC-004)。 
 - `bucketState` 的 OPEN/FINALIZED [x] bucketState 與 `dataStatus` 的 COMPLETE/PARTIAL/ERROR 分離;完整零負載為 0 dataStatus 分離;unknown 充電功率採 strict null + COMPLETE,存在未知充電功率時整個 bucket 為 `null` + PARTIAL。 

 ### 需留意事項(DEC-016~022;詳見 #1463) 

 PARTIAL,不插值或部分合計(DEC-015/#1462 LOAD-DEC-005)。 
 - 只彙整既有明確狀態:CP OFFLINE、Connector FAULTED、current [x] 使用者可見名稱為「需留意事項」,只彙整既有明確狀態,不新增 Queue mismatch/SLA、scheduler-health、容量告警或作業 workflow(DEC-016/#1463 ATT-DEC-001)。 
 - [x] 只有 current Live Load STALE/PARTIAL/ERROR、Queue BLOCKED,以及既有結算未完成/異常。不新增 mismatch、waiting SLA、scheduler-health、容量告警、派工或自動修復。 STALE/PARTIAL/ERROR 建立一個需留意 category;歷史 bucket gap 只在圖表顯示(DEC-017/#1463 ATT-DEC-002)。 
 - 頁首 `categoryCount` 是非零 category 數量;每類另回 [x] 需留意頁首使用非零 categoryCount;各類使用 distinct `affectedCount`,不跨 affectedCount,不跨 category 推導共同 推導 root cause。 cause(DEC-018/#1463 ATT-DEC-003)。 
 - 固定 [x] 全部非零 categories 依固定 allowlist 順序並顯示全部非零 categories;COMPLETE + 0 顯示精簡 Empty State,PARTIAL/ERROR 不得冒充正常。 順序輸出並 responsive 換行,不做 Top N/Drawer/分頁(DEC-019/#1463 ATT-DEC-004)。 
 - Deep link 由 Frontend 固定 allowlist 映射至既有 route/section,只導覽、不執行 mutation。Attention 由 Overview [x] Operational Event propagation SLO:正常運作條件下,從 Backend DB commit 成功至 FE 收到並套用更新的 P95 ≤ 2 秒。 
 - [x] REST 更新,不訂閱 Dashboard WebSocket。 

 ### KPI(DEC-023~028 保留資料公式;詳見 #1486) 

 overview 保留完整 live data,作為 bootstrap、手動刷新與 WebSocket fallback。 
 - [x] V1 不支援同一 Branch deployment scope 多個 `ems_branch` replicas;Dashboard WebSocket fan-out 以單一 active instance 為部署前提。 
 - [x] V1 延用現有 raw WebSocket,以版本化 envelope 定義 contract,不引入 STOMP/message broker sub-protocol。 
 - [x] 所有案場的 source stale cutoff 由 Backend 依資料來源集中定義與判定,並把 freshness/updatedAt/cutoff metadata 回傳給 FE;不得硬編碼 A17 或由 FE 自行設定。 
 - [x] Charge Point 連線使用 enabled CP 連線 KPI 直接使用指定 building 的 persisted OCPP ONLINE/OFFLINE/UNKNOWN,不用 Heartbeat 時間另建 Dashboard cutoff。 connection state;REST bootstrap 後只在狀態 transition 時以 NETWORK_HEALTH_UPDATED replacement,不逐筆推送 Heartbeat(DEC-023/#1486 KPI-DEC-002)。 
 - [x] Connector 可服務數由 Backend 依 enabled 可服務 KPI 要求 parent CP scope、parent CP ONLINE 與固定 runtime allowlist 計算;Frontend 不從 bounded preview 重算。 且 Connector status 位於固定 allowlist;REST bootstrap 後由 CONNECTOR_OVERVIEW_UPDATED replacement 更新,unknown 不得視為可服務(DEC-024/#1486 KPI-DEC-003)。 
 - 「充電進行中」以每 Connector 最多一筆 [x] 「充電進行中」以 canonical ACTIVE transaction 計算;不以 raw CHARGING、Queue 或功率推導,也不重複顯示 currentPowerKw。 計數;CONNECTOR_OVERVIEW_UPDATED 更新 Session count,LIVE_LOAD_UPDATED 獨立更新卡片次要功率(DEC-025/#1486 KPI-DEC-004)。 
 - [x] 「等待供電」只計 Queue ELIGIBLE 的 distinct Connector;NOT_PLUGGED 另列且互斥,BLOCKED 留在需留意事項。 為互斥的次要數量、BLOCKED 留在需留意事項,並以 CONNECTOR_OVERVIEW_UPDATED replacement 更新(DEC-026/#1486 KPI-DEC-005)。 
 - [x] 「今日已完成充電量」重用 Usage 的 #1461 today daily bucket;ACTIVE 不以 MeterValue 暫估。 bucket,只走 REST 5 分鐘 refresh;ACTIVE 不估算且不新增 Usage/Energy WebSocket(DEC-027/#1486 KPI-DEC-006)。 
 - 「上月電費」使用上一完整日曆月,只有資料完整時顯示總額,否則顯示 `—` 與完成筆數。 [x] 六張 KPI 共用 Loading/0/null/PARTIAL/Initial Error/Refresh Error/STALE 契約;source failure 隔離、同 building cache 保留與 REST/WS status 一致(DEC-028/#1486 KPI-DEC-007)。 
 - 六張 KPI 全部由 Overview [x] Connector Full List 不提供使用者排序;固定使用 Backend priority hierarchy 與 deterministic tie-breaker,filter 後排序再做 20 筆 server pagination(DEC-041/#1423 UI-DEC-020)。 

 - [x] V1 不提供 per-building stale cutoff override;只使用 Backend 各資料來源的全系統預設值,不新增設定儲存、管理 API/UI、權限或 audit(DEC-033,撤回 DEC-007)。 

 ## 建議預設決策 

 - V1 延續現有 raw WebSocket,不為單一 Dashboard 引入 STOMP。 
 - REST 更新,不訂閱 overview 保留所有區塊,作為 bootstrap 與降級來源。 
 - 一條 Dashboard WebSocket;狀態呈現沿用 source-isolated COMPLETE/PARTIAL/ERROR/STALE contract。 socket 推送 bounded section replacement。 
 - Live Load 5 秒 coalesce;其他 operational event propagation P95 ≤ 2 秒。 
 - read-only Dashboard 可持續 capped exponential reconnect,並在失敗時切 60 秒 REST polling。 
 - stale cutoff 由 Backend 統一定義並在 response/event 回傳,不由 FE 各自硬編碼。 

 ## 已確認決策 

 ### Usage、結算與 Queue(DEC-010/011;詳見 #1460/#1461) DEC-001:V1 明確使用 buildingId 作為 Dashboard scope(已由 DEC-029 取代) 

 **狀態:已取代(2026-09-04,Ken)** 

 > 歷史決議曾要求 Frontend 在 Overview、ticket 與 WebSocket URL 指定 `buildingId`,並提供切換 building 的 lifecycle。Ken 後續確認 EMS Branch 的部署模型為「每個 Branch 自動顯示其唯一 enabled Building」,因此上述 client-selected scope 不再適用;目前規範以 DEC-029 為準。 

 - Usage 固定最近 保留不變的原則:Dashboard 資料必須以 `buildingId` 隔離,response/event 必須可驗證 scope,且不得跨案場混用。 
 - 已取消的要求:Frontend 傳入或切換 `buildingId`、URL 帶 buildingId,以及為 V1 實作案場 selector。 

 ### DEC-002:Overview API 保留完整即時摘要 

 **狀態:已確認(2026-09-01,Ken)** 

 - `GET /api/dashboard/overview` 必須回傳 Dashboard 所需的完整初始資料,包含即時摘要與非即時區塊。 
 - 即時摘要至少包含 Network Health、operational alerts、Connector summary/bounded preview、active sessions、queue/group runtime 與 current live load。 
 - WebSocket 的用途是接續 REST snapshot 提供後續增量更新,不是 Dashboard 唯一資料來源。 
 - 首次畫面可先以 REST 完成顯示;取得 WebSocket initial snapshot 後,再依 server sequence/occurredAt 套用較新的資料,避免舊資料覆蓋新資料。 
 - 手動 Refresh 必須重新取得完整 overview,並重新建立對應 building 的 WebSocket session。 
 - WebSocket 無法建立或持續中斷時,Overview API 可作為 polling fallback;UI 必須明示目前為定時更新模式。 
 - REST 與 WebSocket 必須共用相同的 Dashboard aggregation/presentation service 或明確共用規則,避免同一 KPI 在兩種通道出現不同公式。 
 - Partial/stale/null 語意在 REST 與 WebSocket 必須一致;未知值不得轉為 0 或 AVAILABLE。 

 ### DEC-003:WebSocket 指數退避重連與 60 秒 REST 降級 

 **狀態:已確認(2026-09-01,Ken)** 

 - WebSocket 非預期中斷後採 capped exponential backoff,重連等待序列為 1、2、4、8、16、30 秒,後續每次最多等待 30 個案場日曆日(含今天),保留 kWh/Sessions,平均每次充電量由 Backend 計算;不提供 7/90 日、自訂範圍或時間使用率。 秒。 
 - 四步驟結算流程期間由 每次等待加入 ±20% jitter,避免多個 Dashboard client 在服務恢復時同時重連。 
 - WebSocket 一中斷,FE 必須立即顯示「即時連線中斷/定時更新模式」,不可繼續把最後 snapshot 標示為即時。 
 - 中斷期間保留最後成功資料,不清為 0;各資料仍依 Backend 依最近結算資料回傳;四列維持純資訊,Frontend footer 導向既有帳單/請款頁。 提供的 cutoff 判斷 freshness/stale。 
 - Queue 只顯示既有 source、status、priority、statusReason、waitingSince/duration;V1 不新增 SLA、timeout、override、設定頁或狀態轉換。 

 ## WebSocket 中斷期間每 60 秒重新呼叫完整 `GET /api/dashboard/overview`。 
 - REST polling 與 WebSocket 背景重連可以同時進行,但目前 Branch 同時間只允許一個 reconnect loop 與一個 polling timer。 
 - Browser network 由 offline 轉 online,或頁面由 hidden 回到 visible 時,可立即嘗試一次重連,不必等待目前 backoff timer。 
 - WebSocket 恢復後,必須先收到/取得新的 `DASHBOARD_LIVE_SNAPSHOT`,確認 buildingId 與版本正確,再停止 REST polling;僅 socket open 不視為資料已恢復即時。 
 - 使用者離開 Dashboard 時,必須取消目前 Branch 的 socket、backoff timer 與 polling timer。 
 - 預期的授權錯誤(401/403)、不支援的 schemaVersion,或 Backend 開發內容 無法解析唯一 enabled Building 時不做無限重試,應停止並顯示可診斷錯誤。 

 ### DEC-004:Live Load 採 5 秒 Server-side Coalescing 

 **狀態:已確認(2026-09-02,Ken)** 

 - [ ] 建立 current-building resolver,讓 Overview、ticket、WebSocket 與所有 query 共用唯一 enabled Building scope。 MeterValue 更新由 Backend 在 server side 合併;Dashboard browser 不接收每筆 raw MeterValue。 
 - [ ] 建立 typed `DashboardController`/`DashboardService`/Overview DTO,按 同一 building 的 Live Load 最多每 5 秒推送一次,5 秒窗內的多筆讀值合併為一份重新計算後的完整 `LIVE_LOAD_UPDATED` section 回傳 status、freshness 與時間 metadata。 replacement。 
 - [ ] 建立最小 Dashboard ticket、WebSocket handler、session registry 與三種 typed message;使用區塊 replacement,不加入 fallback/retry/gap recovery。 Payload 至少帶 `buildingId`、`occurredAt`、`sequence`、`currentPowerKw`、`latestMeterAt` 與 freshness/source status。依 DEC-012/#1462,不回傳由 Charge Group contract capacity 加總推算的案場 `contractCapacityKw`、`utilizationPercent` 或 `remainingCapacityKw`。 
 - [ ] 建立 聚合只納入 Backend 判定為未 stale 的 enabled Connector summary/Top-8 共用分類排序 service,供 Overview 最新有效 Power value;未知值保留 `null`,不得以 0 代替。 
 - 沒有新 MeterValue 或沒有實際 Live Load/freshness 變化時,不需固定每 5 秒推送。 
 - Connector FAULTED、Charge Point connection transition、Transaction start/stop、Queue/off-peak/rotation 等 operational event 使用獨立更新路徑,不得為等待 Live Load 5 秒窗口而延遲。 
 - Coalescing key 必須包含 `buildingId`,不可把不同案場的讀值合併。 
 - V1 預設窗口為 5 秒,實作時由 Backend configuration 管理;若 A17 壓測證明需調整,必須保留同樣的事件語意並更新需求決策。 
 - 驗收需量測 A17 的 MeterValue 頻率、單一窗口合併數、WebSocket payload size、server buffer 與 `CONNECTOR_LIVE_BLOCK_UPDATED` 使用。 browser CPU/memory。 

 ### DEC-005:Operational Event 更新延遲 SLO 採 P95 ≤ 2 秒 

 **狀態:已確認(2026-09-02,Ken)** 

 - 正式名稱使用 **Operational Event propagation SLO**,不使用帶有對外合約/賠償語意的 SLA。 
 - [ ] 擴充既有 正常運作條件下,Operational Event 更新延遲目標為 **P95 ≤ 2 秒**。 
 - 計時起點:產生 Dashboard 狀態變化的 Backend database transaction 成功 commit。 
 - 計時終點:Frontend 收到、通過 `schemaVersion`/`buildingId`/`sequence` 驗證,並將 replacement event 套用至 Dashboard state。 
 - 適用事件: 
   - Connector search:Charge runtime status transition。 
   - Charge Point ID/Charge Group 條件、`DASHBOARD_PRIORITY` mode、固定 20 筆 pagination 及完整 Page metadata;保持既有管理頁 sorting 相容。 OCPP connection transition。 
   - Transaction start/stop lifecycle。 
   - Queue/off-peak/rotation lifecycle 與 blocked transition。 
   - 由上述事件衍生的 operational alerts、KPI、Group/Connector overview 更新。 
 - [ ] 建立 不包含設備實際狀態發生至 Branch 收到 OCPP/Modbus 訊息前的延遲;該區段屬設備與通訊層。 
 - 不適用於 Live Load;Live Load current/series read model與 `LIVE_LOAD_UPDATED` replacement,遵守 #1462 bucket/quality contract。 依 DEC-004 採 5 秒 server-side coalescing。 
 - [ ] 聚合 Attention、KPI、Group、Usage、Settlement/Billing 等 REST-owned sections,遵守各 child issue 的既有公式,不新增作業邏輯。 不適用於 Usage Trend、四步驟結算流程與完整搜尋;這些區塊依 REST refresh 規則。 
 - [ ] 沿用既有 `dashboard` function,補 Overview/ticket API mapping、OpenAPI `@Schema`、method/DTO 註解與 security/contract tests。 WebSocket 中斷時不套用 2 秒 SLO,改依 DEC-003 的 60 秒 REST polling fallback,並明示非即時模式。 
 - [ ] 優先採 read-only aggregate;只有 驗收需記錄至少 event type、buildingId、commit timestamp、event occurredAt、client received/applied timestamp、latency 與成功/失敗結果。 
 - 報告至少提供 sample size、P50、P95、P99、max 與未達標比例;P95 達標不代表可忽略遺失、亂序或無法解析的事件。 
 - 測試時的 client/server clock 必須同步;若 client timestamp 不可靠,需以可重現的 server-side correlation 或測試 harness 量測。 

 ### DEC-006:Stale Cutoff 由 Backend 集中管理,適用所有案場 

 **狀態:已確認(2026-09-02,Ken)** 

 - Dashboard 是所有案場共用功能;A17 只是第一個驗證/導入案場,不是功能範圍、資料模型或 freshness 規則的唯一依據。 
 - Backend 依資料來源分別定義 stale cutoff,例如 OCPP Heartbeat、Connector Status、MeterValue 與其他 operational source;不同來源不得共用一個沒有語意的固定秒數。 
 - REST overview 與 WebSocket event 必須使用同一個 Backend freshness policy,回傳 `updatedAt`、`freshness` 與可解釋的 cutoff metadata。 
 - FE 只依 Backend 回傳的 stable code 呈現 FRESH/STALE/ERROR/NOT_CONFIGURED 等狀態,不自行硬編碼秒數或以 browser clock 另建一套規則。 
 - Cutoff 的預設值應由協定行為、服務排程、裝置正常回報週期及營運容忍度共同決定,不能從單一 A17 EXPLAIN 證明必要時才提出普通 index,不預先建立 當下樣本直接推廣到所有案場。 
 - A17 Phase 0 的用途是驗證通用預設值、查詢效能與 UI 行為;若結果不合理,V1 應修正通用 source default,不得在程式碼加入 `if buildingId == A17` 類型特例。 
 - 每次 bootstrap 都必須套用 Backend-resolved Building 的 freshness policy,並以 response/event `buildingId` 驗證 scope;V1 不提供案場切換。 
 - Per-building override 已由 DEC-033 明確撤回;V1 只使用 Backend 各資料來源的全系統預設值。 

 ### DEC-007:允許受控的 Per-building Stale Cutoff Override(已撤回) 

 **狀態:已由 DEC-033 取代(2026-09-04,Ken)** 

 - 此段原本會要求 per-building 設定儲存、管理 API/UI、額外權限及變更稽核,超出唯讀 Dashboard snapshot table或新 constraint。 V1 所需範圍。 
 - V1 不實作 override、precedence、設定資料表、設定頁或 audit trail。 
 - 現行規則以 DEC-033 為準:Backend 依 source 維護全系統 default,所有案場共用;特殊案場需求未來另開 Feature。 

 ## Frontend 開發內容 ### DEC-008:V1 延用 Raw WebSocket,不引入 STOMP 

 **狀態:已確認(2026-09-02,Ken)** 

 - [ ] 重新實作 `/dashboard`,依既有 `dashboard` function 控制 menu/route;未授權時不載入或短暫顯示資料。 V1 延續現有 Spring `WebSocketHandler`/JSON message 模式,不啟用 STOMP sub-protocol、topic subscription 或 STOMP broker relay。 
 - [ ] 建立單一 Overview query/300 秒 timer/手動刷新,以及一個 Dashboard browser 對一個 `buildingId` 建立一條 socket;授權仍使用短效、一次性、admin identity + building-bound ticket。 
 - 所有訊息使用統一、版本化 envelope,至少包含 `schemaVersion`、`type`、`buildingId`、`sequence`、`occurredAt` 與 `data`。 
 - Event type 採明確 allowlist;FE 對未知 type 應安全忽略並記錄可診斷資訊,不可把未知 payload 套入既有區塊。 
 - FE 不支援 `schemaVersion` 時應停止套用資料、顯示版本不相容並重新 bootstrap/要求更新,不得陷入無限重連。 
 - 每次新 socket hook;Dashboard unmount 時釋放資源。 session 先送 `DASHBOARD_LIVE_SNAPSHOT`,再送後續 replacement events;sequence 的作用域與重置規則必須在 contract tests 固定。 
 - [ ] 分離 REST-owned state 與兩個 WS-owned live blocks;socket 接手後,Overview refresh 不覆寫 live state。 Server 端沿用 synchronized/decorated session send、send time limit 與 buffer size limit,並對慢速 client 執行可觀測的關閉與恢復。 
 - [ ] Header 分別呈現案場名稱、一般 REST 最後更新、WebSocket connection state及 source freshness;手動刷新不假裝會重連。 Raw WebSocket contract 雖不由 OpenAPI 自動產生,Backend DTO、FE TypeScript type、fixture、parser 與 contract test 必須同步維護。 
 - [ ] 實作 Connected、首次連線失敗、連線後中斷;中斷保留最後資料/時間並顯示已停止更新,不啟動 REST fallback。 若未來出現多種動態 topic、client-side subscribe/unsubscribe、跨服務 broker routing 或大規模 fan-out,再另立決策評估 STOMP;不得在 V1 預先增加未使用的協定層。 

 ### DEC-009:V1 限定單一 Ems Branch Instance 

 **狀態:已確認(2026-09-03,Ken)** 

 - Dashboard 功能仍適用所有案場;本決策只限制同一個 Branch deployment scope 的執行拓撲,不代表只支援單一案場。 
 - [ ] 實作 V1 假設同一 deployment scope 只有一個 active `ems_branch` application instance 負責 REST、Dashboard WebSocket session 與 event fan-out。 
 - V1 可沿用 in-memory ticket store、session registry、coalescing timer 與 per-session sequence;不實作跨 instance session discovery 或 distributed sequence。 
 - 部署文件與 release checklist 必須明確標示 `ems_branch replicas = 1`;在未完成 multi-instance 設計前,不得把同一 scope 水平擴充至兩個以上 replicas。 
 - Sticky session 不能單獨解決問題:業務事件可能在沒有該 browser session 的另一 instance commit;因此不得把 load-balancer affinity 宣稱為完整跨 instance fan-out。 
 - 若誤以多 instance 部署,REST overview 仍可能可用,但 WebSocket 可能漏推、重複或亂序;系統不得將這種拓撲標示為受支援。 
 - 未來若需要 HA/水平擴充,必須另案設計 shared event fan-out、跨 instance authorization/ticket、session routing、sequence/deduplication、coalescing ownership 與 failure recovery;可評估既有 RabbitMQ,但不能直接假設現有 Connector 五項 summary、Top-8 responsive preview、detail、Full List Drawer、固定排序/分頁與 page-session state。 exchange 已滿足 Dashboard contract。 
 - [ ] 實作 KPI、Attention、Live Load、Group、Usage、Settlement 的 Loading/Empty/Partial/Error/Stale、RWD、keyboard與文字狀態。 Multi-instance 支援完成前,部署變更的驗收需確認實際 replica count,並測試 restart 後依 DEC-003 重新 bootstrap/恢復 socket。 

 ### DEC-010:Dashboard Queue 資料通道維持唯讀 

 **狀態:已確認(2026-09-03,Ken)** 

 - REST/WebSocket 可傳送既有 queue source、status、priority、statusReason、waitingSince/waiting duration,供 Dashboard 顯示。 
 - [ ] Production API/WebSocket error 不得 fallback 到 fixture。 `BLOCKED` 沿用既有 Backend 狀態進入 Needs Attention;WAITING/ELIGIBLE 不新增 timeout 或 severity 判定。 
 - 本 Dashboard 不新增 Queue SLA、threshold/override、Admin 設定、Rotation scheduler-health 或對應 persistence。 
 - Dashboard publisher/aggregation 不得寫回 queue、改變 priority/slot、觸發 rotation dispatch 或送出 OCPP command。 
 - 此決策只收斂 Dashboard V1 scope,不影響既有 queue/off-peak/rotation lifecycle event 繼續觸發畫面更新。 

 ## Acceptance Criteria 

 ### Scope、權限與資料隔離 DEC-011:結算流程期間由 Backend 回傳 

 **狀態:已確認(2026-09-03,Ken)** 

 - [ ] 同一套功能可部署至所有 EMS Branch,A17 不出現在程式判斷或固定資料中。 四步驟結算流程維持 REST-only;WebSocket 不推送月份或帳務狀態。 
 - [ ] 唯一 enabled Building 正常載入;零筆/多筆顯示設定異常並隱藏營運資料。 Overview response 依 buildingId 回傳最近結算資料期間的 periodYear、periodMonth 與 timezone。 
 - [ ] Overview/ticket/socket 不接受 Frontend building selector;response/ticket/event 的 resolved `buildingId` 一致。 只格式化 Backend 回傳的期間,不用 browser 日曆或「目前月份減一」自行推算。 
 - [ ] 四個允許 role 可讀取 Overview/取得 ticket;未具 `dashboard` function 時 API 為 403、socket 無有效 ticket 時拒絕。 最新期間即使為 pending/partial/error,仍回傳並照實呈現,不得自動退回前一期掩蓋異常。 
 - [ ] 新一期資料尚未建立時顯示資料庫中最近存在的期間;完全沒有資料時回明確 Empty 語意與 null 期間。 
 - REST initial load、15 分鐘 refresh 與手動 refresh 使用同一套 period selection 規則。 
 - 此決策只定義 Dashboard 及 deep links 不執行任何業務 mutation,也不洩漏 credential/個資。 read model,不更動既有結算排程、重算或 Billing/Invoice lifecycle。 
 - 詳細 UI 與驗收例子見 #1460 BIL-DEC-002。 

 ### DEC-012:Live Load 不推算案場層級契約容量 

 **狀態:已確認(2026-09-03,Ken)** 

 - 本決策修正 DEC-004 原 payload 對案場 contractCapacityKw/utilizationPercent 的假設;DEC-004 的 5 秒 server-side coalescing、currentPowerKw 與 freshness 規則維持不變。 
 - Live Load 的 REST/WebSocket read model 只需回傳案場 currentPowerKw、latestMeterAt 與 freshness/source status,不回傳由 SUM(group.contractCapacity) 產生的案場 contractCapacityKw、utilizationPercent 或 remainingCapacityKw。 
 - 原因是現有 contractCapacity 屬 Charge Group 排程容量;系統沒有 authoritative building-level 契約容量或足以判斷群組容量是否可加總的上游電力拓撲。 
 - Group Capacity 仍透過 REST 回傳各群組自己的 contract capacity/allocated power,並透過 Hybrid channel 更新 occupied/available/waiting/blocked 等既有 runtime 資訊。 
 - FE 不得從群組陣列自行相加或計算案場利用率/餘裕;未知 currentPowerKw 仍依 null/freshness 規則呈現。 
 - V1 不新增 building capacity 設定、拓撲、告警門檻或管理 UI,也不修改 SlotCalculator、queue、rotation、OCPP 或其他作業邏輯。 
 - 詳細 UI、Backend 與驗收規則見 #1462 LOAD-DEC-001。 

 ### DEC-013:Live Load Series 軸線與 Bucket Contract 

 **狀態:已確認(2026-09-03,Ken)** 

 - [ ] 首載及每 300 秒最多一個 Overview request;手動刷新也只送一個,沒有各 section timer。 保留 LIVE、TODAY、SEVEN_DAYS 三種 read-only 檢視。 
 - [ ] 同一次 response LIVE:rangeStartAt = generatedAt 往前 60 分鐘,bucketDurationSeconds = 60,最多 60 點。 
 - TODAY:依 building timezone 從案場當日 00:00 至 generatedAt,bucketDurationSeconds = 900,最多 96 點。 
 - SEVEN_DAYS:依 building timezone 從今天前第 6 個日曆日 00:00 至 generatedAt,bucketDurationSeconds = 3600,最多 168 點;語意是含今天的 7 個日曆日,不是 rolling 168 hours。 
 - Y 軸固定為「充電功率(kW)」;每個 point 為該 bucket 的 REST-owned sections 使用相同 `generatedAt`;section failure 不清空其他成功內容。 time-weighted averagePowerKw,不是 kWh、契約容量、容量利用率或 bucket peak。 
 - [ ] Refresh error 只保留同 Building cache並顯示 `lastSuccessfulAt`;首次 error 不顯示 fixture/假 0。 Backend 必須先依 Connector 最新有效 Power.Active.Import 重建 site power timeline,再做 time-weighted average;不可直接對不同 Connector、不同回報頻率的 raw MeterValue rows 加總或算術平均。 
 - [ ] Socket 接手後,Overview timer與手動刷新不覆寫兩個 live blocks;socket 中斷時也不形成 REST fallback。 series 至少回傳 rangeCode、rangeStartAt、rangeEndAt、timezone、bucketDurationSeconds 與 points;每個 point 至少包含 bucketStartAt、bucketEndAt、averagePowerKw、bucketState、dataStatus。 
 - 最後一個尚未結束的 bucket 標示 bucketState = OPEN;已結束者為 FINALIZED。成功確認為零時 averagePowerKw = 0、dataStatus = COMPLETE;資料不可確認時為 null 並搭配 dataStatus = PARTIAL/ERROR,不得補零。 
 - Y 軸從 0 起算,上限依有效 series 自動取整;不使用群組容量合計作為固定上限或容量線。 
 - FE 可依 viewport 減少可見 tick label 避免重疊,但不得刪除/合併 Backend points 或改變 range;tooltip 顯示完整 bucket 起訖與區間平均功率。 
 - currentPowerKw 大數字是 generatedAt 的目前功率,與最後一個進行中 bucket 的區間平均值可以不同,UI 必須分別標示。 
 - 歷史 series 由 REST 提供,WebSocket 依 DEC-004 提供 currentPowerKw;open/finalized bucket 更新通道已由 DEC-014 確認。 
 - 本決策只增加唯讀查詢、DTO 與圖表呈現,不改變 MeterValue 採集間隔、設備控制或充電作業。 

 ### DEC-014:REST Series Snapshot + WebSocket 簡化行為 Bucket Replacement 

 **狀態:已確認(2026-09-03,Ken)** 

 - [ ] Dashboard 本體只有一條案場 socket,且只更新 Connector 即時狀態與案場即時負載;完整清單及其他 sections 不走 WS。 REST 是完整 Live Load series 的 authoritative snapshot;用於 bootstrap、range 切換、手動 refresh、WebSocket reconnect 與 sequence gap recovery。 
 - [ ] LIVE_LOAD_UPDATED 一般 event 只包含 currentPowerKw 與 LIVE/TODAY/SEVEN_DAYS 三個 open bucket replacements,不包含完整歷史陣列。 
 - 三種 message 均為 typed section replacement,Frontend 不由 raw delta 重算 domain state。 open buckets 一併推送,server 不追蹤 client 目前選取的 range,也不新增 range subscription protocol。 
 - [ ] 首次連線失敗與連線後中斷都顯示明確提示;已有資料保留並標示已停止更新,無資料顯示 `—`,不清成 0。 每個 bucket 以 rangeCode + bucketStartAt 識別,並帶 bucketEndAt、averagePowerKw、bucketState、dataStatus 與 freshness metadata。 
 - [ ] 中斷後沒有 polling fallback、backoff/jitter、自動重連、sequence/gap recovery、visibility reconnect 或專用 Retry;整頁 reload 才重新連線。 跨越 1 分鐘/15 分鐘/1 小時邊界時,event 必須傳送剛完成的 finalized bucket;同一 event 可同時傳送下一個 open bucket。 
 - [ ] FE 只做 replacement:相同 key 取代,新的 key 加入並依 DEC-013 裁切視窗;不得用 currentPowerKw 或 event arrival time 自行積分/重算平均。 
 - currentPowerKw 是目前 snapshot;open bucket averagePowerKw 是從 bucketStartAt 至 event occurredAt 的區間平均,兩者可以不同。 
 - sequence gap、重連、schemaVersion 不支援或 buildingId 不符時,FE 不補猜 bucket,重新取得 REST snapshot。 
 - WebSocket 中斷不阻止其他 斷線期間沿用 DEC-003 的 60 秒 REST sections 依 polling fallback;恢復後先取得 authoritative snapshot 再繼續 replacements。 
 - 沿用 DEC-004 的 5 分鐘週期更新。 秒 server-side coalescing,沒有資料/freshness 變化時不固定空推送。 
 - 本決策不改變 MeterValue 採集、charging、queue、rotation 或 OCPP 作業。 

 ### Connector DEC-015:Bucket Time State 與 Data Quality 分離 

 **狀態:已確認(2026-09-03,Ken)** 

 - [ ] 0/1/2/8/9/30/100 筆及 390/768/1024/1440px 均不破版;Top-8 payload 在 Desktop/Tablet/Mobile 分別顯示 8/6/4。 不使用同一欄位混合表示「時間未結束」與「資料不完整」;正式分成 bucketState 與 dataStatus。 
 - [ ] 五個 bucketState enum 為 OPEN/FINALIZED,只描述時間區間是否結束。 
 - dataStatus enum 為 COMPLETE/PARTIAL/ERROR,只描述資料品質;OPEN + COMPLETE 與 FINALIZED + PARTIAL 都是合法組合。 
 - 重建 site power timeline 時,fresh fact 明確顯示 Connector 未充電則貢獻 0;正在充電則必須有仍在 effective freshness cutoff 內且可正規化的有效 Power.Active.Import。 
 - 最新有效 Power 只可在 cutoff 內沿用;超過 cutoff、缺值、負值、unit 無法解析、充電/交易狀態不明或可能 offline charging 時,對應時間片段為 unknown。 
 - bucket 互斥、合計等於 total、NEEDS_ATTENTION 等於 abnormalTotal;非空包含零值五項,空案場顯示 Empty State。 只要存在 unknown 充電功率,就回 averagePowerKw = null、dataStatus = PARTIAL;不得回已知部分合計、coverage percentage、插值或預測。 
 - [ ] 五個 summary items 不可點擊、不進 Tab;preview card 與「查看全部」仍分別支援 detail/完整清單。 查詢/計算失敗回 null + ERROR;完整且整段零負載回 0 + COMPLETE。 
 - [ ] Preview OPEN bucket 只計算已經過時間,不對未來補 0;finalized replacement 重新套用同一品質規則。 
 - FE 對 PARTIAL/ERROR 畫缺口並提供文字狀態,不以前值補點、不跨缺口連線,也不只靠顏色。 
 - 詳細規則與 fixture/驗收需求見 #1462 LOAD-DEC-005。 
 - 本決策不改變 MeterValue 採集或任何 charging lifecycle。 

 ### DEC-016:「需留意事項」只彙整既有明確狀態 

 **狀態:已確認(2026-09-03,Ken)** 

 - 使用者可見名稱由 NEEDS ATTENTION 改為「需留意事項」,主標題使用「目前有 N 類項目需要留意」。 
 - 本區塊是 read-only category summary/deep link,不是待辦、派工、通知升級或自動修復 workflow。 
 - V1 只納入既有 authoritative state:CP OFFLINE、Connector FAULTED、Queue BLOCKED、明確 source STALE/PARTIAL/ERROR,以及 #1460 四步驟結算流程既有未完成/異常狀態。 
 - 不新增 Queue mismatch、waiting timeout/SLA、rotation scheduler-health、案場容量/餘裕告警、預測規則或跨案場排名。 
 - Operational categories 可隨既有 post-commit event/freshness transition 更新;結算類別維持 REST refresh,不新增 billing WebSocket。 
 - Backend 回傳 stable category code、count、必要 display parameters 與 Full List 共用固定 priority hierarchy;同層級順序穩定,搜尋/篩選後仍先排序再分頁。 target identifier;FE 不用中文自由文字判斷類型。 
 - [ ] Drawer 固定每頁 20 筆;30/100 筆為 2/5 頁,0~20 筆隱藏換頁控制,第一/最後一頁按鈕狀態正確。 摘要項目只能導覽至既有管理頁或 Dashboard 區塊,不執行任何業務 mutation。 
 - [ ] Drawer 無 sorting/page-size/direct-jump/view-toggle/virtualization;close/reopen 保留搜尋/篩選/頁碼,reload/navigation 重設。 categoryCount/類別內 distinct 依 DEC-018 確認;current Live Load 納入範圍依 DEC-017 確認;固定順序/顯示全部非零類別/responsive layout 依 DEC-019 確認。Empty State 依 DEC-020/#1463 ATT-DEC-005、Partial/Error 依 DEC-021/ATT-DEC-006、deep link 依 DEC-022/ATT-DEC-007 確認。 
 - [ ] `DASHBOARD_PRIORITY` 不改變既有 `/connector/list` 欄位排序;完整清單永遠透過 REST,不擴大 Dashboard WS payload。 詳細 UI、Backend 與驗收規則見 #1463 ATT-DEC-001。 

 ### 其他區塊與品質 DEC-017:只有 Current Live Load 品質異常進入需留意事項 

 **狀態:已確認(2026-09-03,Ken)** 

 - [ ] current Live Load 三種 range、X/Y 軸、bucket、time-weighted average、0/null/PARTIAL 規則符合 #1462;不顯示推算的案場容量/利用率。 freshness = STALE 或 dataStatus = PARTIAL/ERROR 時,產生一個「即時負載資料不完整」category。 
 - [ ] Attention 類別、count、順序、Empty/Partial/Error及固定 判定直接使用 Backend current source state;不新增 FE timer、bucket gap count 或其他推測門檻。 
 - currentPowerKw = 0 + COMPLETE 與 bucketState = OPEN + dataStatus = COMPLETE 都是正常狀態,不產生 category。 
 - finalized 歷史 bucket 的 null + PARTIAL/ERROR 只留在 series/tooltip,不產生 category、不增加摘要總數。 
 - REST overview 與需留意事項 WebSocket replacement 使用同一判定;current source 恢復 FRESH/COMPLETE 後移除 category。 
 - category deep link 符合 #1463,且不新增告警或 workflow。 只定位至 Dashboard Live Load 區塊,不建立新頁面或任何 mutation。 
 - [ ] 六張 KPI 最終 fixture 必須分別驗證 current quality failure 會出現摘要,以及 historical-only gap 不會出現摘要。 
 - 詳細規則見 #1463 ATT-DEC-002 與 #1462 LOAD-DEC-006。 

 ### DEC-018:Attention Category Count 與 Affected Count 分離 

 **狀態:已確認(2026-09-03,Ken)** 

 - 頁首 categoryCount = affectedCount > 0 的 scope、公式、0/null/status、RWD與固定 deep link 符合 #1486;全部由 category 數量,文案為「目前有 N 類項目需要留意」。 
 - 每個 category 另回 affectedCount;categoryCount 不等於 affectedCount 加總,也不代表設備、事件或根因總數。 
 - CP/Connector/Queue/Settlement 分別依自身穩定 ID 或 step code 做 category 內 distinct;即時負載資料不完整 category 存在時 affectedCount = 1。 
 - affectedCount = 0 的 category 不出現在 categories array,也不計入 categoryCount。 
 - 不跨 category 去重,不建立 CP/Connector/source status 的共同根因推導或 suppression。 
 - REST 更新。 overview 與 WebSocket replacement 使用同一份 Backend-produced categoryCount/affectedCount;FE 不重新計算。 
 - [ ] 30 日 Usage 與四步驟結算符合 #1461/#1460;不加入額外 range、時間使用率或 billing WebSocket。 摘要來源為 PARTIAL/ERROR 時不得用 categoryCount = 0 冒充無異常;其整體顯示規則依 #1463 後續決策。 
 - [ ] 狀態不只靠顏色,keyboard focus、status message與文字對比符合 WCAG 2.2 AA 基本要求;320px 以上無頁面級水平捲軸。 詳細 UI/驗收例子見 #1463 ATT-DEC-003。 

 ### DEC-019:Attention Allowlist 固定順序並顯示全部非零類別 

 **狀態:已確認(2026-09-03,Ken)** 

 - V1 categories 固定順序為 CHARGE_POINT_OFFLINE、CONNECTOR_FAULTED、LIVE_LOAD_DATA_UNRELIABLE、QUEUE_BLOCKED、SETTLEMENT_INCOMPLETE_OR_ERROR。 
 - [ ] Production build 不包含 API/WebSocket error REST overview 與 WebSocket replacement 都回傳全部 affectedCount > 0 的 allowlisted categories,並保持固定相對順序。 
 - affectedCount = 0 的 category 省略;不依 affectedCount、時間或顏色動態重排。 
 - 不做 Top N、顯示上限、查看全部、Drawer、展開、分頁或使用者自訂排序。 
 - FE 依 response/contract 順序 render;DOM、keyboard focus 與視覺順序一致,不用 CSS order 改變語意。 
 - Desktop 使用 auto-fit grid;Tablet 兩欄;390 px Mobile 單欄。換行不得改變 categoryCount/affectedCount 或建立水平捲軸。 
 - Unknown category code 採安全 fallback 並記錄診斷,不映射成既有類別。 
 - 新增 category 必須另行更新 allowlist、順序、來源、文案與 contract tests。 
 - 詳細 UI 與驗收規則見 #1463 ATT-DEC-004。 


 ### DEC-020:Attention Empty State 必須由 Backend 的完整結果明確判定 

 **狀態:已確認(2026-09-04,Ken)** 

 - attention aggregate 明確回傳 dataStatus、categoryCount、categories 與 updatedAt;若時間沿用 overview generatedAt,OpenAPI contract 必須寫清楚。 
 - 只有 dataStatus = COMPLETE、categoryCount = 0、categories = [] 三項同時成立,FE 才顯示「目前沒有需留意事項」。 
 - HTTP 200、categories 欄位缺漏、空白畫面或 request 尚未完成,不等同於已確認沒有異常。 
 - Empty State 保留區塊但縮為一列中性偏綠狀態,不產生五張零值卡片,也不沿用紅色警示樣式。 
 - WebSocket replacement 可使 UI 在非零 categories 與 COMPLETE Empty State 間切換;FE 只 render Backend 結果,不掃描其他區塊重新計算。 
 - dataStatus = PARTIAL/ERROR 時不得以 categoryCount = 0 宣稱正常;呈現與 count contract 依 DEC-021/#1463 ATT-DEC-006。 
 - 本決策只定義 read-only presentation state,不新增告警引擎、通知、待辦或任何作業 mutation。 
 - 詳細 UI、mock 與驗收條件見 #1463 ATT-DEC-005。 

 ### DEC-021:Attention Aggregate 的 PARTIAL 與 ERROR 呈現契約 

 **狀態:已確認(2026-09-04,Ken)** 

 - dataStatus = PARTIAL 表示部分來源有可用結果;categories 保留目前已確認的非零類別,categoryCount 等於該陣列數量。 
 - PARTIAL 且 categoryCount > 0 時,FE 顯示「已確認 N 類」與黃色「數量可能不完整」提示;categoryCount = 0 時只顯示部分資料無法確認,不得顯示正常 Empty State。 
 - aggregate PARTIAL 是 presentation completeness,不新增第六個 category、不計入 categoryCount;特定 current Live Load 品質異常仍依 DEC-017 使用既有 LIVE_LOAD_DATA_UNRELIABLE category。 
 - dataStatus = ERROR 時 categoryCount = null、categories = [],FE 顯示「需留意事項暫時無法取得」,不得用 0 或綠色狀態冒充正常。 
 - Backend 視情況提供 updatedAt、errorAt 與 lastSuccessfulAt;FE 不用本機時間或 HTTP 200 推測資料狀態。 
 - Error State 不新增區塊專用 Retry,沿用頁面既有 refresh;網路重連與 REST fallback 仍沿用既有 DEC-003/005。 
 - REST snapshot/WebSocket replacement 回復有效狀態後,以 Backend 最新結果取代 Partial/Error。 
 - 本決策只定義 read-only response 與 presentation,不修改 OCPP、Queue、結算或其他作業邏輯。 
 - 詳細 UI、mock 與驗收規則見 #1463 ATT-DEC-006。 

 ### DEC-022:Attention Deep Link 由 Frontend 固定映射,不接受任意 URL 

 **狀態:已確認(2026-09-04,Ken)** 

 - 五個 V1 category code 固定對應:CHARGE_POINT_OFFLINE → fixture fallback。 /cp/list、CONNECTOR_FAULTED → /connector/list、LIVE_LOAD_DATA_UNRELIABLE → #load、QUEUE_BLOCKED → #connectors、SETTLEMENT_INCOMPLETE_OR_ERROR → #billing。 
 - Backend 回 stable category code 與必要 identifiers,不回任意 URL;Frontend 以 allowlist 映射 route/anchor。 
 - affectedCount 不改變目的地;V1 不新增 filter query parameter、category detail API 或 Queue 專用頁。 
 - Unknown code 不建立未知 link,且不得 fallback 至任一既有類別。 
 - 同頁 anchor 後移動 keyboard focus 至目標 section;跨頁使用既有 router 與 route permission。 
 - 整張 card 是單一可存取 link,顯示可見操作文案;不得巢狀互動元件。 
 - Deep link 只做導覽,不執行 mutation,也不改變 OCPP、Queue、結算或其他作業邏輯。 
 - 詳細 mapping、mock 與驗收規則見 #1463 ATT-DEC-007。 
 ### DEC-023:Charge Point 連線 KPI 沿用 Persisted Connection State 

 ## E2E Test Impact **狀態:已確認(2026-09-04,Ken)** 

 - Dashboard 正式實作屬 **Add**;需由實作 ticket 新增/更新 UI、REST contract、WebSocket failure、權限、RWD與 Connector large-data cases,並依 priority/trigger 納入 release pack。 KPI scope 為指定 building 下 `enabled = true` 的 Charge Point;ONLINE 為分子,enabled total 為分母,OFFLINE/UNKNOWN 分別回傳。 
 - 本次 description 去矛盾沒有改變已確認產品行為,分類為 **No catalog change**;不產生 run-specific PASS/FAIL,也不宣稱已完成 E2E。 Disabled CP 不進入分子/分母;可另回 disabledCount 供 FE 說明,但不建立離線事件。 
 - 唯一判準是既有 persisted `ocppConnectionStatus`;Dashboard 不比較 lastHeartbeat、不新增 cutoff,也不修改 WebSocket/BootNotification/Heartbeat watchdog 的既有狀態維護。 
 - REST overview 回傳完整 connection summary;狀態 transition commit 後,案場級 socket 以 `NETWORK_HEALTH_UPDATED` replacement 更新整組數字。 
 - 沒有造成 ONLINE/OFFLINE/UNKNOWN transition 的一般 Heartbeat 不逐次推送。 
 - CP runtime status 與 OCPP connection state 保持分離;ONLINE + FAULTED 等組合不得被簡化或覆寫。 
 - FE 固定將 card 導向 `/cp/list`;event/REST payload 不回傳任意 navigation URL。 
 - 本決策只新增 read-only aggregation 與 presentation event,不改變設備連線、離線判定或充電作業。 
 - 詳細 DTO、UI 與驗收規則見 #1486 KPI-DEC-002。 

 ## 現行決策索引 ### DEC-024:Connector 可服務摘要由 Backend 統一計算 

 **狀態:已確認(2026-09-04,Ken)** 

 - DEC-002:保留 Overview bootstrap;其 fallback/重連部分由 DEC-031 取代。 分母為指定 building 下、enabled Charge Point 所屬的所有 Connector;disabled CP 下的 Connector 排除。 
 - DEC-006:Backend 管理 source cutoff 原則保留;override 最終以 DEC-033 為準。 分子同時要求 parent CP persisted OCPP connection = ONLINE,且 Connector status 位於 AVAILABLE、PREPARING、ENQUEUED、CHARGING、SUSPENDED_EV、SUSPENDED_EVSE、FINISHING、RESERVED allowlist。 
 - DEC-008:保留 raw WebSocket;sequence/gap recovery 部分由 DEC-031 取代。 FAULTED、UNAVAILABLE、null/unknown status,或 parent CP OFFLINE/UNKNOWN 均不算可服務。 
 - DEC-009~030:保留各項部署前提、唯讀邊界、資料公式、顯示及權限;其中非 Connector/Live Load sections 使用 Backend 回 serviceable/total/nonServiceable/faulted counts;REST overview 與 WebSocket 的部分由 DEC-031 取代。 共用同一 read model,FE 不從 bounded preview 重算。 
 - DEC-031:現行資料通道與斷線簡化方案。 Connector status 或 parent CP connection transition commit 後,以 `CONNECTOR_OVERVIEW_UPDATED` replacement 更新整組 summary;不為每個 Connector 建 socket。 
 - DEC-032:現行單一 Overview/5 分鐘/手動刷新規則。 未造成狀態 transition 的 Heartbeat 不因此推送 Connector summary。 
 - DEC-033:現行 整張卡由 FE 固定導向 `/connector/list`;payload 不回任意 URL。 
 - 本決策只定義唯讀分類與顯示,不新增 health scheduler、timeout、狀態修正或充電操作。 
 - 詳細 UI、DTO 與驗收規則見 #1486 KPI-DEC-003。 

 ### DEC-025:「充電進行中」使用 Canonical ACTIVE Transaction 

 **狀態:已確認(2026-09-04,Ken)** 

 - 使用者可見名稱固定為「充電進行中」。 
 - Backend per-source global freshness defaults;V1 無 per-building override。 對指定 building 的每個 Connector 解析最多一筆 canonical current transaction:currentTransactionId 指向 ACTIVE 優先;否則只有最新 transaction 為 ACTIVE 才計入。 
 - DEC-034~041:現行 較舊孤兒 ACTIVE row 不計;raw CHARGING、currentPowerKw、Queue 或尚未建立 StartTransaction 的 operation 不可單獨增加 Session count。 
 - ACTIVE Session 即使處於 suspended/finishing,或 parent CP offline/disabled,仍顯示至 transaction 正式結束,避免隱藏待 reconciliation 資料。 
 - REST overview 提供完整 activeSessionCount;transaction start/stop commit 後以 `CONNECTOR_OVERVIEW_UPDATED` replacement 更新。 
 - 卡片次要 `currentPowerKw` 直接讀 Live Load current snapshot,並由 `LIVE_LOAD_UPDATED` 獨立更新;功率 unknown 不把已知 Session count 清為 0。 
 - FE 固定將卡片導向 `/connector/list`;payload 不回傳任意 URL。 
 - 本決策只定義唯讀統計,不新增 timeout、自動結束、交易補寫或其他 charging mutation。 
 - 詳細 DTO、UI 與驗收規則見 #1486 KPI-DEC-004。 

 ### DEC-026:「等待供電」使用 Queue ELIGIBLE 的 Distinct Connector preview、summary、Drawer state、固定 pagination與固定 priority sorting。 

 ## 已取代的討論歷程索引 **狀態:已確認(2026-09-04,Ken)** 

 - DEC-001 Backend 以指定 building 範圍內 `e_connector_priority.charge_status = ELIGIBLE` 的 Frontend building selection 由 DEC-029 取代。 `COUNT(DISTINCT connector_id)` 回傳 waitingForPowerCount;同一 Connector 的 MANUAL/OFF_PEAK 多筆 Queue row 不重複計數。 
 - DEC-003 NOT_PLUGGED 不代表目前有供電需求,不納入主數字;notPluggedCount 只計有 NOT_PLUGGED、且沒有任何 ELIGIBLE row 的 capped exponential backoff/60 秒 distinct Connector,確保「另有」與主數字互斥。 
 - BLOCKED 不納入等待供電,沿用「需留意事項」既有 Queue BLOCKED category;CHARGING、PAUSED、FINISHED、null/unknown 也不納入。 
 - REST fallback 由 DEC-031 取代。 overview 提供完整 aggregate;Queue state commit 且 aggregate 改變後,以 `CONNECTOR_OVERVIEW_UPDATED` replacement 更新 waitingForPowerCount/notPluggedCount。 
 - DEC-004 的固定 FE 不從 bounded preview、runtime、等待秒數、slot 或 scheduler 狀態重算,整張卡固定導向 `/connector/list`。 
 - 本決策只定義唯讀統計與傳輸,不新增 Queue timeout、SLA、scheduler、狀態轉換或修正行為。 
 - 詳細 DTO、UI 與驗收規則見 #1486 KPI-DEC-005。 

 ### DEC-027:「今日已完成充電量」重用 Usage Today Bucket 

 **狀態:已確認(2026-09-04,Ken)** 

 - 使用者可見名稱固定為「今日已完成充電量」,避免「今日累積電量」被誤解為包含 ACTIVE transaction 的即時估算。 
 - 主數字與次要完成次數分別讀取 #1461 Usage response 中 `date = rangeEndDate` daily bucket 的 validEnergyKWh/sessionCount;同一 response 不建立第二個獨立計算結果。 
 - eligibility、building timezone、transaction startTimestamp 日期歸屬、跨日不拆分與 0/null/PARTIAL/ERROR/cache/STALE 規則全部沿用 #1461 USG-DEC-001~009。 
 - ACTIVE 不以 MeterValue 差值估算;完成並取得最終 energy_consumed 後,才於下一次成功 REST refresh 納入。 
 - 取得方式為 REST 首載、每 5 秒產品 coalescing contract 由 DEC-031 取代;Backend 僅可作內部資源保護,不列固定秒數驗收。 分鐘 refetch 與手動刷新;V1 不新增 Usage/Energy WebSocket event。 
 - DEC-005 FE 固定將 Card 導向同頁 `#usage`,移除昨日同時段比較,不自行重算或寫入任何交易資料。 
 - 詳細 UI 與驗收規則見 #1486 KPI-DEC-006。 

 ### DEC-028:KPI 狀態採 Source-isolated Presentation Contract 

 **狀態:已確認(2026-09-04,Ken)** 

 - 每個 KPI 依賴的 source/section 提供 value(可為 null)、dataStatus、freshness 與 updatedAt;需要顯示快取來源時提供或保留 lastSuccessfulAt。 
 - COMPLETE 的 Operational Event P95 2 秒 SLO 由 DEC-031 取代。 0 是有效值;null 是未知。Backend 子查詢失敗不得回 0,Frontend 也不得從 preview 或其他資料重算。 
 - DEC-007 PARTIAL 有 Backend 認定可安全顯示的 value 時保留並標示可能不完整;沒有安全值時回 null/顯示 `—`。 
 - Initial ERROR 沒有快取時顯示 `—`;refresh error 可保留目前 Backend-resolved building 的最後成功 snapshot,但必須顯示更新失敗與 lastSuccessfulAt,且不得跨 Branch/building 沿用。 
 - STALE 可保留最後成功值,但需顯示資料已過期且不能使用正常/綠色語意;無可用值時顯示 `—`。 
 - 一個 source 失敗只影響相依 Card,Overview 其他成功 sections 繼續顯示。REST snapshot 與 WebSocket replacement 的 per-building stale cutoff override 由 DEC-033 取代。 value/null/status/freshness 語意必須一致。 
 - DEC-014 WebSocket 中斷不把值清成 0;freshness 仍由 DEC-006/033 的 reconnect/gap recovery 部分由 DEC-031 取代;REST series + WS open-bucket replacement 的資料 ownership 保留。 Backend source-default policy 決定。 
 - DEC-021/023~028 中要求 Attention/KPI 走 這是唯讀 presentation contract,不新增 event type、資料修正或業務 mutation;完整 UI 與驗收規則見 #1486 KPI-DEC-007。 

 ### DEC-029:V1 自動使用 Branch 唯一 Enabled Building,不提供案場切換 

 **狀態:已確認(2026-09-04,Ken)** 

 - Dashboard 適用所有案場,意思是同一套功能部署到每個 EMS Branch;V1 不在單一 Branch 內做跨案場總覽或 site switcher。A17 只作第一個資料與效能驗證基準,任何層都不得 hardcode A17。 
 - `GET /api/dashboard/overview` 不接受 Frontend `buildingId`;Backend 必須解析目前 Branch 中唯一一筆 enabled Building,並回傳 `buildingId`、案場名稱與 timezone。所有 KPI、圖表、Connector、Queue 與帳務 query 都使用同一個 resolved scope。 
 - Dashboard ticket request 與 WebSocket 的部分由 DEC-031 取代;其資料公式與 URL 也不接受 Frontend 選案場。Backend 將 ticket 綁定 admin identity 與 resolved `buildingId`;每個 event envelope 仍帶該 `buildingId`,Frontend 必須驗證一致後才套用。 
 - enabled Building 恰好一筆才可載入 Dashboard。零筆或多筆均視為 configuration error:Backend 不可使用 `LIMIT 1`/任選第一筆、跨 Building 彙總或產生全零 snapshot;Frontend 顯示整頁「案場設定異常」,不顯示營運數字。 
 - Header/Sidebar 的案場名稱是唯讀識別,不是 selector。若未來要在單一 deployment 支援多 Building,必須另開需求重新定義授權、切換、快取、ticket 與聚合,不屬於 V1。 
 - 本決策取代 DEC-001 中「Frontend 指定/切換 buildingId」的部分;`buildingId` 作為資料隔離與 event 驗證欄位的原則繼續保留。 

 ### DEC-030:沿用既有 Dashboard Function 與四個既有角色 

 **狀態:已確認(2026-09-04,Ken)** 

 - V1 沿用既有 SS3A `dashboard` function,不建立 `dashboard_view`、Dashboard 專用 role 或不同角色版本的 Dashboard。 
 - 可存取角色固定沿用既有 mapping:`administrator`、`power_user`、`association`、`dealer`。這四個 role 看到同一份唯讀 Dashboard。 
 - 僅有 `adm_user`、`member`、`hq` 或 `engineer` role 不會自動取得 Dashboard;若同一 member 另有上述任一允許 role,則透過該 role 的 `dashboard` function 取得權限。 
 - Overview API 與 Dashboard ticket API 必須 mapping 到既有 `dashboard` function。Frontend 依 Backend 回傳的 function 決定 menu/route 是否可見,但安全邊界仍在 Backend:未授權直接呼叫 API 回 403,未持有效 ticket 不得建立 Dashboard WebSocket。 
 - 不以 Java/Frontend hardcode role name 判斷權限;實際授權由 SS3A role → function → API mapping 決定。部署用冪等 migration 確認四個 role mapping 與新增 API mapping,並於 Branch 重啟後載入最新授權快取。 
 - 此決策只控制「能否看 Dashboard」,不改變 Dashboard 的 read-only 邊界,也不授予 Remote Start/Stop、Reset、Queue、Rotation、帳務修改或 Engineer command 權限。 

 ### DEC-040:Connector Full List 固定使用 20 筆 Server Pagination 

 **狀態:已確認(2026-09-05,Ken)** 

 - 架構與完整規則以上方「現行 Connector Full List 固定分頁」及 #1423 UI-DEC-019 為準。 
 - 現有 endpoint/request/response contract 優先重用;只補足本需求確實缺少的 filter 與 contract tests,不建立另一套 Dashboard inventory service。 
 - 這是 REST read model 與 Frontend presentation 決策,不增加 WebSocket 重連/fallback,也不改變任何營運作業邏輯。 

 ### DEC-041:Connector Full List 固定 Backend Priority Sorting 

 **狀態:已確認(2026-09-05,Ken)** 

 - 架構與完整規則以上方「現行 Connector Full List 固定排序」及 #1423 UI-DEC-020 為準。 
 - `DASHBOARD_PRIORITY` 是既有 search endpoint 的固定 read mode,不是使用者可調整的排序選項;Backend 必須重用 Top-8 priority ranking 並在 pagination 前完成排序。 
 - 既有管理頁 sorting contract 保留。 保留,避免 Dashboard 簡化方案縮減 `/connector/list` 原有能力。 
 - 本決策不新增 transport、持久化 sorting preference 或 operational mutation。 

 ## 需求管理狀態 

 - Parent:#1422 
 - Related:#1423(Connector)、#1460(結算)、#1461(Usage)、#1462(Live Load)、#1463(需留意事項)、#1486(KPI) Related:#1423(Connector 數量彈性顯示規則)、#1462(案場即時負載與群組容量顯示規則)、#1463(需留意事項摘要與顯示規則) 
 - Requirement status:**現行架構決策已整理至 DEC-041;Connector 子需求已鎖定,其他 status:**本票架構決策(含 DEC-034~041)已確認;Connector 數量/完整清單子需求已鎖定,待其他 Dashboard 決策待整體一致性稽核後再整併最終 v1.0 文件** 需求完成後整併** 
 - Issue status:維持 New/0%,不代表已進入開發 Final specification:全部決策完成後整併至 #1422 的 v1.0 最終需求文件 
 - Implementation tickets:整體需求鎖定後才建立 tickets:需求鎖定後才建立 FE/BE/QA child issues 

返回