專案

一般

配置概況

動作

討論 #1424

進行中

Feature #1422: [功能開發] Backend Admin 營運 Dashboard(全案場適用,A17 首站)

[架構] Dashboard REST/WebSocket 資料分工與事件契約

是由 陳國瑋 於 約 2 個月 前加入. 於 15 天 前更新.

狀態:
New
優先權:
Normal
被分派者:
-

概述

閱讀基準: 主需求 #1422 與 HTML Mock v0.4/附件 #1121。以下沿用主票區塊編號,依畫面由上到下、由左到右說明。Mock 數字皆為假資料;功能適用所有案場,A17 不是固定規則。

本票要完成什麼:讓整張 Dashboard 用簡單、一致的方式取得資料

本票負責案場範圍、權限、REST/WebSocket 分工、資料狀態與前後端契約。畫面/公式分別由 #1423、#1460、#1461、#1462、#1463、#1486 定義,不在本票建立第二套算法。

既有 GET /api/connector/dashboard 只有部分Connector統計;管理頁search與單支detail socket可重用,但不能直接當成整張Dashboard的資料來源。需要新的typed Overview與最小Dashboard socket。

先記住三件事:

  1. 一次Overview取得一般資料,首載/每5分鐘/手動刷新。
  2. 一條Dashboard WebSocket只更新「06 Connector即時狀態」與「04 案場即時負載」。
  3. Socket連不到就提示並保留資料;不另建REST備援、自動重連或gap recovery。

1. 先依畫面順序看資料通道

「REST-owned」表示由Overview負責更新;「WS-owned live state」表示socket接手後只由socket負責更新,兩者不能互相覆寫。(DEC-031/032)

主票位置/畫面 首次資料 後續更新 Dashboard socket斷線時
01 案場名稱/一般資料時間 Overview 共用5分鐘/手動Overview 照常更新一般資料與其品質
02 需留意事項 Overview 同上,REST-only 照常;不改成其他備援模式
03 六張KPI Overview 同上,全部REST 照常;不訂閱KPI WS事件
04 目前功率/open buckets Overview bootstrap LIVE_LOAD_UPDATED replacement 保留最後值/時間、標停止更新;無資料—
04 即時/今日/7日完整歷史 一次Overview給三組 同一Overview更新歷史;WS另負責open/跨界finalized 一般歷史可刷新,但不得冒充即時recovery
05 群組容量/Slots/Queue摘要 Overview 共用5分鐘/手動Overview 照常,非WS
06 五項摘要/Top-8預覽 Overview bootstrap CONNECTOR_LIVE_BLOCK_UPDATED整區replacement 保留最後值/時間、標停止更新;無資料—
07 30日用量、03-5今日已完成量 同一Overview/Usage read model 共用5分鐘/手動Overview 照常,非Usage WS
08 結算流程、03-6上月電費 Overview 共用5分鐘/手動Overview 照常,非Billing WS

按需打開的介面另外處理,不混入首頁更新:

介面 資料通道
06「查看全部」Full List Drawer 開啟、搜尋、「摘要分類」/Charge Group 篩選、換頁時 POST /api/connector/search,REST server pagination
單支Connector detail 既有detail API;打開時才使用既有單Connector socket,關閉釋放

「一條Dashboard socket」指首頁本體,不是禁止按需使用既有單支detail flow;也不能因此替每張preview card建立socket。

2. 整體資料流程與scope

登入使用者
    ↓
既有 SS3A dashboard function 授權
    ↓
Backend 解析本 Branch 唯一 enabled Building
    ├─ 不是恰好1筆 → 設定異常,不載入營運數字
    └─ 恰好1筆
          ├─ GET /api/dashboard/overview
          │      ├─ 一般區塊+三組歷史
          │      └─ 兩個live blocks初始畫面
          └─ 短效、一次性Dashboard ticket
                 ↓
             raw WebSocket
                 ├─ DASHBOARD_LIVE_SNAPSHOT
                 ├─ CONNECTOR_LIVE_BLOCK_UPDATED
                 └─ LIVE_LOAD_UPDATED

2.1 案場由Backend決定(DEC-029)

  • 每個EMS Branch恰好一筆enabled Building;零筆/多筆回明確configuration error,FE顯示整頁「案場設定異常」並隱藏營運資料。
  • 不任選第一筆、不跨Building加總、不顯示假0;不沿用任選預設案場的查詢方式。
  • Overview/ticket request、WebSocket URL不傳FE指定buildingId;Drawer的Dashboard read mode也依相同resolver。
  • Overview response、ticket binding、event envelope明確帶相同Backend-resolved buildingId;FE只套用相符資料,cache按buildingId隔離。
  • Header/Sidebar顯示Backend案場識別,timezone供日期與時間呈現;不提供site selector。
  • A17只用來驗證,不能出現在固定數字/公式/cutoff/query分支。

2.2 權限沿用dashboard function(DEC-030)

條件 應有結果
administrator/power_user/association/dealer,經既有dashboard function授權 相同唯讀Dashboard、Overview與ticket能力
只有adm_user/member/hq/engineer,未取得dashboard function Overview/ticket為403;無有效ticket不能建立Dashboard socket
多role使用者已有允許權限 依既有function機制授權,不因同時擁有其他role拒絕

不新增role/function、不在Java硬編碼role判斷;補Overview/ticket API mapping,依主票以冪等migration確認role-function mapping並驗證重啟後授權快取。

FE依function控制menu/route,未授權不先載入或短暫顯示資料;隱藏menu不能代替Backend授權。既有管理頁/Engineer Tools導覽沿用目的頁權限,Dashboard不附帶Start/Stop、Reset、Queue、帳務或工程指令能力。

3. Overview REST契約:一個週期、一份一般資料

新增typed GET /api/dashboard/overview,回傳案場識別、generatedAt、各source的品質/時間及各section。(DEC-002保留部分/DEC-032)

時機 Request
頁面首次載入 一次Overview
Dashboard保持掛載期間每300秒 每輪一次Overview,不是每卡各一次
使用者手動刷新 一次Overview,不動socket
卸載Dashboard 釋放timer與socket資源

同一成功response的REST-owned sections共用generatedAt;需要各別品質判斷的來源另外回dataStatus、freshness、updatedAt及必要lastSuccessfulAt。

3.1 接手前後不得覆寫錯的資料

首載REST bootstrap
     ↓
兩個live blocks可以先顯示初始資料
     ↓
收到DASHBOARD_LIVE_SNAPSHOT → socket接手
     ↓
之後Overview刷新:
   一般區塊/歷史 → 可更新
   Connector live/目前功率與open buckets → 不覆寫

只有整頁reload才重取ticket、重新嘗試socket。手動刷新不重建連線;socket中斷也不解除live ownership讓REST冒充備援。

3.2 REST失敗不代表全頁歸零

單一source失敗只影響相依section,其他成功部分繼續顯示,Overview標PARTIAL或可診斷source status。初次無成功資料顯示Error/—;後續失敗可依各區契約保留同building成功cache,附更新失敗與lastSuccessfulAt,不假裝最新。

不能catch後回0、不能從preview/其他卡猜值,production不能退回fixture。需留意事項aggregate ERROR依#1463顯示不可取得,不能拿舊cards冒充本次結果;不是所有section都能不分狀態套同一fallback。

4. WebSocket契約:三種訊息、區塊取代

V1沿用raw WebSocket,不引入STOMP。每個掛載的Dashboard本體只有一條案場socket。(DEC-008保留部分/009/031)

4.1 Ticket與envelope

Ticket短效、一次性,綁定登入管理員與Backend-resolved Building,只有具dashboard function者可取得。

Envelope欄位 用途
schemaVersion FE判斷是否支援此契約版本
type 下表三種訊息之一
buildingId 案場隔離,不接受不符scope資料
occurredAt 事件資料時間
data 對應type的typed區塊payload

不傳raw DB row、JWT、ticket、currentIdTag或不必要個資;前端不對不支援schema或錯scope猜測套用。

4.2 訊息內容

type 什麼時候/送什麼 FE如何套用
DASHBOARD_LIVE_SNAPSHOT 建連後,兩個live blocks完整目前狀態 接手目前live state,不等於重送整個Dashboard/全部歷史
CONNECTOR_LIVE_BLOCK_UPDATED Connector五項summary+totals+Backend排序Top-8 整個區塊replacement,FE不自己算分類/排名
LIVE_LOAD_UPDATED currentPowerKw、LIVE/TODAY/SEVEN_DAYS三種open bucket;跨界可帶剛結束finalized 目前值與bucket各自取代,按buildingId+rangeCode+bucketStartAt合併

不用細碎delta讓FE重算total、bucket、priority或平均功率。Backend可以內部debounce/coalescing保護資源,但不承諾固定5秒更新或P95 2秒SLO,也不為這個要求先建專用架構。

4.3 連不到/中斷時就明示

情況 頁首與兩個live blocks
首次連線失敗 明示無法連線;已有初始資料可保留並標未即時更新,沒有資料則—與「即時資料暫時無法取得」。
已連線後中斷 明示連線中斷,保留最後成功資料/時間並標「已停止更新」。
其他REST區塊 仍依共用Overview正常更新,不因socket中斷停止。

不做: REST polling fallback、定時更新模式切換、自訂capped exponential backoff、jitter、背景自動重連、visibility reconnect、sequence/gap recovery、專用Retry。使用者整頁reload才再嘗試。

Connection state與source freshness獨立:連著不代表資料FRESH,斷線也不改寫Backend已回傳的來源品質。

4.4 部署前提(DEC-009)

V1為單一active ems_branch instance。未來多instance/HA的session fan-out與授權一致性另案設計,不在本功能預做。

5. 品質欄位:0、未知、失敗、過期分開

狀態 契約與畫面
COMPLETE且數值0 成功確認的0,不是缺值
null 未知,不轉0
PARTIAL且Backend有安全值 可顯示,明示不完整;FE不自行加出部分合計
PARTIAL無安全值 null/—,例如不完整的案場功率、未全數完成的上月金額
ERROR 文字說明來源無法取得,不冒充正常
STALE 文字標過期與資料時間,不使用正常成功樣式

(DEC-006保留部分/015/028/033)

Backend依資料來源設定全系統stale cutoff:Connector、MeterValue、Billing可不同,但所有案場共用;FE不硬編碼秒數。V1不做per-building override、設定table/API/UI、設定權限或audit trail。

6. Connector:相同snapshot支援首頁與完整清單

6.1 Summary/Top-8契約

Backend從完整案場Connector集合分類、排序,再回固定五個bucket、total、abnormalTotal與最多8筆items。(DEC-034~038,詳細#1423)

不變條件 說明
五類順序 NEEDS_ATTENTION、CHARGING、WAITING、AVAILABLE、OTHER
分類互斥 每Connector恰好一類,count總和=total;NEEDS_ATTENTION.count=abnormalTotal
原始事實 OCPP connection、runtime、Queue分層保留,不被displayBucket取代
Unknown/NOT_PLUGGED Unknown不當AVAILABLE/OTHER;NOT_PLUGGED依#1423既定mapping歸OTHER
非空/空 非空固定五項含0;空時FE顯示Empty,Backend仍五個0
摘要互動 純資訊不可點擊,不進Tab、不發request
FE預覽 Desktop≥1240顯示8、Tablet640~1239顯示6、Mobile<640顯示4;不傳viewport/requestedLimit
Item metadata displayBucket、isAbnormal、severity、priorityReason;FE不重判
Footer FE只依totals與visible slice算隱藏總數/異常數,不從Top-8推完整統計

Preview與Full List共用priority:OFFLINE+ACTIVE → FAULTED → OFFLINE/STALE/BLOCKED → SUSPENDED_EVSE/UNAVAILABLE → SUSPENDED_EV → CHARGING → PREPARING/Waiting → AVAILABLE。同層持續時間由久至新、Connector ID穩定排序,詳細多條件處理見#1423 UI-DEC-007。

排序是只讀呈現,不改Queue priority;OFFLINE+ACTIVE不產生「離線充電/待reconciliation」推論(主票及#1463/#1486較新決策)。

6.2 完整清單仍用既有REST search

完整集合(Backend限制目前案場)
       ↓ 全部條件filter
       ↓ 共用DASHBOARD_PRIORITY sort
       ↓ 固定size=20 paginate
       ↓ Spring Page回應

沿用POST /api/connector/search、SearchConnectorDto的page/size與Spring Page metadata;補 keyword 所需的 Charge Point ID/車位、displayBucket、Charge Group、OpenAPI及contract tests。不得先分頁才filter/sort。

Dashboard Full List 的分類欄位命名為「摘要分類」,request 使用 displayBucket;未傳為全部,值限 NEEDS_ATTENTION/CHARGING/WAITING/AVAILABLE/OTHER。它直接重用Summary分類,不把 Connector runtime status 與 Queue status 混成另一組選項。既有管理頁的原始 status 條件維持相容。(DEC-043)

Drawer固定sortMode=DASHBOARD_PRIORITY,不提供使用者sidx/sord控制;/connector/list未用此mode時保留原欄位排序。(DEC-039~041)

Request 最小欄位為 page、固定 size=20、keyword、可選 displayBucket、可選 chargeGroupId、固定 sortMode;不得傳 buildingId。Response 每筆至少回 connectorId、chargePointId、location/floor/parkingSpaceNo、chargeGroup、displayBucket、isAbnormal/severity/priorityReason、OCPP connection/runtime/Queue 分層狀態、nullable currentPowerKw、updatedAt/freshness;外層沿用 Spring Page metadata。完整欄位表以 #1423 第6.3節為準。

只提供前後頁、頁次/總數;0~20不顯示換頁,多頁first/last按鈕正確。改搜尋/篩選回第1頁。Search/filter/page只存目前page memory,close/reopen保留,reload/navigation重設;不存URL、history、local/sessionStorage、Backend或WS。

不提供page-size、頁碼列、直接跳頁、Grid/Table、virtualization或完整inventory WS。

7. 其他區塊:只對接既有決策,不另建算法

依主票畫面順序:

區塊 本票須遵守的關鍵規則 完整公式
02 Attention 明確既有狀態、非零類別數、類內distinct、固定順序/路由;只看current負載品質,無推論或新告警 #1463 ATT-DEC-001~008
03 KPI enabled CP persisted連線;Connector可服務allowlist;canonical ACTIVE;ELIGIBLE distinct/未插槍互斥;today Usage重用;上月全COMPLETE金額。全部REST、不重複功率 #1486 KPI-DEC-001~011
04 Live Load 60分鐘/1分、今天/15分、含今天7日/1小時;時間加權kW;OPEN與品質分離,未知功率null+PARTIAL;無插值/跨缺口線 #1462 LOAD-DEC-001~007
05 Group/Queue 群組自身容量/Slots,不加總成案場契約容量;只顯示既有source、status、priority、reason、waitingSince/duration #1462、#1423 UI-DEC-010/011
07 Usage 固定30日、COMPLETED最終Wh/開始日、正電量次數、Backend平均;不碰raw MeterValue/費率分段,不顯示時間使用率 #1461 USG-DEC-001~010
08 結算流程 最近已存在資料期間、四列純資訊、Footer既有帳單/請款頁;不等同上月電費的固定上一日曆月 #1460 BIL-DEC-001~003

8. 工程分工與交付

負責方 交付內容
Backend/REST current-building resolver、DashboardController/Service、typed Overview/各section DTO與source isolation、共用聚合。
Backend/WS ticket、handler、session registry、三種typed message,短效一次性授權與single-instance前提。
Backend/Connector 共用summary/Top-8 ranking;既有search補 displayBucket/keyword/Charge Group、最小response欄位、DASHBOARD_PRIORITY與20筆分頁,管理頁原始status/排序相容。
Backend/Load current/三range歷史query與時間加權、open/finalized replacement,品質依#1462。
Backend/權限與文件 dashboard API mapping、OpenAPI @Schema、method與DTO欄位註解、security/contract tests。
FE /dashboard頁面、單一Overview hook/300秒timer與socket hook、REST/WS state分離、unmount釋放、全部畫面與states、RWD/keyboard/來源時間。
QA/效能 權限/scope/typed contract、socket failure無備援、source隔離、各子票數據與RWD、baseline與首站驗證。

不改OCPP、Queue/Rotation、Slot allocation、charging lifecycle、帳務計算或排程,不新增告警引擎、Dashboard inventory或業務mutation。

9. 效能與驗收

9.1 先量測,不先加架構(DEC-042)

A17或代表性等量資料執行aggregate query EXPLAIN,量測Overview endpoint P50/P95,記錄環境、主要table row count/分布、暖機、併發、sample size、量測起訖,使結果可重現。

避免N+1、無界查詢、重複聚合;只有量測證明影響正常使用,才提出query/普通index優化。不把P95<1.5秒當V1 SLA,不先建snapshot table、專用cache、效能排程或新constraint。跨案場SLA若日後需要另定資料量/負載模型。

9.2 驗收清單

  • 唯一Building正常、零/多筆設定錯誤;request不含FE案場選擇、response/ticket/event一致,cache/event不跨scope。
  • 四允許role與多role正向、未授權403、無有效ticket拒絕WS;無credential/個資洩漏或mutation。
  • 首載/每300秒/手動每輪一個Overview,無各section timer;同response generatedAt一致、source失敗隔離。
  • 初次Error不假0/fixture;refresh只保留同案場資料與時間,依各區品質規則顯示。
  • socket接手後,timer/手動Overview不覆寫live;斷線時也不形成fallback。
  • Dashboard本體一條raw socket、三typed訊息只更新兩區,full list走REST、detail按需釋放。
  • 首次失敗/後續中斷都有提示,最後資料/時間保留、無資料—;無backoff、jitter、自動/visibility重連、sequence/gap recovery、專用Retry。
  • 其他REST區塊在socket中斷後照常;整頁reload才新建連線。
  • 五bucket互斥、Top-8與8/6/4、priority穩定、summary不可點,0/1/2/8/9/30/100與各斷點正確。
  • search完整集合依 keyword/displayBucket/Charge Group filter→sort→20分頁、30/100為2/5頁、0~20無換頁;六個「摘要分類」選項、最小response契約與page memory正確,管理頁原始status/sorting無回歸。
  • Load、Attention、KPI、Usage、Billing公式與來源狀態符合第7節子票;無額外range、時間使用率或預估費用。
  • 320px以上無頁面水平捲軸;390/768/1024/1440可讀;文字狀態/focus/對比符合WCAG 2.2 AA基本要求。
  • EXPLAIN與P50/P95條件完整,無固定秒數SLA。
  • production無API/WS error→fixture fallback。

功能實作E2E impact為Add,依主票與各子票新增/更新UI、REST/WS failure、權限、RWD與大量資料case,按priority/trigger納release pack;本次不產生PASS/FAIL或宣稱已跑測試。

10. 決策追溯:現行與已撤回分開

決策 現行有效內容/本文位置
DEC-002 保留Overview bootstrap;第3節;fallback部分撤回
DEC-006 Backend管理source cutoff原則;第5節,設定範圍依033
DEC-008 raw WS;第4節,sequence/gap recovery撤回
DEC-009~030 未被取代的部署/只讀/公式/顯示/權限保留;非兩區WS方案由031取代
DEC-029/030 唯一enabled Building與dashboard function;第2節
DEC-031/032 兩區WS、無備援;共用5分鐘Overview;第1、3~4節
DEC-033 全系統per-source defaults、無案場override;第5節
DEC-034~041 Connector summary/preview/Drawer記憶體/固定分頁排序;第6節
DEC-042 可重現效能baseline而非1.5秒SLA;第9節
DEC-043 Full List「摘要分類」使用 displayBucket;request/response 最小契約;第1、6、8~9節
已撤回提案 取代規則
DEC-001 FE選building DEC-029 Backend唯一案場
DEC-003 capped exponential backoff/60秒fallback DEC-031 無備援與自動重連
DEC-004 固定5秒coalescing產品契約 DEC-031 只容許內部資源保護,不承諾秒數
DEC-005 Operational Event P95 2秒SLO DEC-031 不列V1驗收承諾
DEC-007 per-building cutoff override DEC-033 全系統來源預設
DEC-014 reconnect/gap recovery部分 DEC-031撤回;REST歷史+WS區間ownership保留
DEC-021/023~028要求Attention/KPI走WS部分 DEC-031/032改共用REST;各公式/呈現仍保留

歷史討論仍在原票J5641及更早journals,本次不刪除。現行架構已整理至DEC-043,完成全Dashboard一致性review後才整併v1.0;不以本次文字整理視為已進入實作。

需求管理與本次編輯

  • 本票仍是已確認需求的追蹤票,不代表已完成開發或通過測試;指派、狀態、進度、附件與父子關係均維持原狀。
  • v0.4 Draft 文件套件已依 #1422 DOC-DEC-001 發布並保留 v0.2/v0.3;目前閱讀基準為 PDF #1119、Markdown #1120、HTML #1121。此版仍是 review Draft,尚非 v1.0。
  • 2026-09-14:僅重整 Description、說明與排版,將已確認決策併入對應畫面/工程工作;決策編號保留供追溯。E2E impact:No catalog change(沒有修改產品行為、公式或 API 契約);功能實作時仍須遵循主票與本票驗收。
  • 2026-09-16:依 Ken 確認新增 DEC-043;Full List Drawer 使用 displayBucket 作為「摘要分類」,明列 request/response 最小契約並保留管理頁原始 status 相容性。本輪只更新需求,不變更 WebSocket、作業邏輯、Issue 狀態/進度或附件。
動作

匯出至 Atom PDF