Feature #1380
進行中[FE] Branch Admin 工程師工具 UI Implementation
0%
概述
Branch Admin 工程師工具(FE Implementation Spec)¶
1. 目標與範圍¶
在 Branch Admin 新增一個只供 Engineer 使用的「工程師工具」工作頁,讓工程師可以:
- 對指定 CloudLink Connector 執行受控 Modbus 讀取與控制。
- 由 Branch 向指定 Charge Point 發送 OCPP 1.6 CSMS Command。
- 查詢每次操作的 request、response、錯誤、耗時與完整 event timeline。
- 以 Fortune(華城)充電樁測試為主要情境,同時支援 CloudLink 與其他廠牌的 capability 顯示。
Backend 對應票為 #1381,目前已完成並部署至 Jimmy 與 A17。FE 不需要自行設計 Backend contract;本 Description、Backend OpenAPI 與附件 Plan 為實作依據。
2. 權限與導覽¶
- 新路由:
/engineer-tools。 - 側邊欄名稱:「工程師工具」。
- 只有取得 Backend Engineer function/menu 的使用者顯示入口並可進入。
- 不要在 FE hardcode
ADMIN、power_user或只判斷 role name;這兩個既有帳號已由 Backend 加入 Engineer Role。 - FE 隱藏入口不是安全邊界,所有 API 仍由 Backend 驗證權限。
- 在既有 Connector 清單或詳情頁增加工具 icon,可 deep-link:
/engineer-tools?connectorId={connectorId}&tab=ocpp - 進入 deep-link 後仍須重新向 API 取得 target 與 capability,不可直接信任 query string。
3. 頁面 Layout¶
沿用既有 dashboard shell,使用全寬工作區,不做 landing page,也不要把整個頁面包成多層 Card。
Target Bar¶
頁面頂部固定顯示:
- Charge Point searchable select
- Connector searchable select
- online/offline status
- vendor
- model
- firmware version
- capability badge
規則:
- 先選 Charge Point,再載入該 Charge Point 的 catalog/capability。
- Connector 只在 connector-level command 或 Modbus command 時必填。
- 從 Connector deep-link 進入時,自動解析並預選其 Charge Point 與 Connector。
Tabs¶
Target Bar 下方固定三個 tabs:
ModbusOCPP操作紀錄
Desktop:command list 與 form/result 使用左右兩欄。
Mobile:改為上下排列。
Command list、form、status panel 應有穩定尺寸,切換 command 或狀態時不得造成整頁寬度跳動或文字重疊。
4. Command Catalog 與 Capability¶
畫面能力唯一來源:
GET /api/engineer/commands/catalog?chargePointId={chargePointId}
回傳共 31 筆:19 個 OCPP commands + 12 個 Modbus operations。
每筆主要欄位:
-
protocol:OCPP或MODBUS commandcategory-
targetLevel:CHARGE_POINT或CONNECTOR -
riskLevel:LOW、MEDIUM、HIGH writeOperation-
schema:產生表單與前端預驗證使用的 JSON Schema -
capability:VERIFIED、UNVERIFIED、UNSUPPORTED capabilityNote
Capability UI:
-
VERIFIED:正常啟用。 -
UNVERIFIED:允許執行,但在送出按鈕附近顯示非阻斷警告。 -
UNSUPPORTED:禁用執行按鈕並顯示capabilityNote。 - 不要在 FE 重複維護 vendor allowlist 或自行把
UNVERIFIED判定成 supported。 - FE 可以維護中文標籤、欄位順序與圖示,但 command key、schema、target、risk、capability 必須來自 API。
5. Modbus Tab¶
Modbus 只允許 CloudLink Connector。其他廠牌 catalog 會回 UNSUPPORTED,UI 必須禁用。
允許的 12 個 Operations¶
Read:
CONNECTION_TESTREAD_SUPPLY_STATEREAD_VOLTAGEREAD_CURRENTREAD_ACTIVE_POWERREAD_APPARENT_POWERREAD_POWER_FACTORREAD_TOTAL_ENERGYREAD_BALANCEREAD_METER_ID
Write:
SET_SUPPLY_STATESET_METER_ID
UI 分組:
- 連線與狀態
- 電力讀值
- 控制
禁止提供:
- raw Modbus function code
- raw register address/value
- raw payload
- 清除歷史資料
- Browser 直接連 charge_point API
Read operation 的 parameters 必須是空 object。
SET_SUPPLY_STATE:
{
"connectorId": "CP001-001",
"operation": "SET_SUPPLY_STATE",
"parameters": { "enabled": true }
}
SET_METER_ID:
{
"connectorId": "CP001-001",
"operation": "SET_METER_ID",
"parameters": { "meterId": 1 }
}
meterId 範圍為 1–255。
文案使用「供電控制」;可以用次要說明標示底層由智慧電表 Test Mode 執行,但不要新增獨立 Test Mode command。
確認規則:
- Read command:直接執行,不顯示確認。
-
SET_SUPPLY_STATE、SET_METER_ID:各顯示一次簡短確認。 - 不要求填寫「操作原因」。
- 不做額外第二次確認。
6. OCPP Tab¶
提供以下全部 19 個 OCPP 1.6 CSMS → Charge Point commands:
RemoteStartTransactionRemoteStopTransactionResetChangeAvailabilityUnlockConnectorTriggerMessageDataTransferGetConfigurationChangeConfigurationClearCacheReserveNowCancelReservationSetChargingProfileClearChargingProfileGetCompositeScheduleGetDiagnosticsUpdateFirmwareGetLocalListVersionSendLocalList
功能要求:
- command 依 catalog
category分組,並提供搜尋。 - 使用 segmented control 切換「表單」與「JSON」。
- 兩種模式共用同一份 payload state,切換模式不能丟失資料。
- 表單依 catalog
schema產生或映射。 - schema validation error 顯示到 JSON path/欄位。
- Backend 仍會執行同一份 schema validation,FE validation 只是提早提示。
-
Reset送出前顯示一次簡短確認。 - 其他 OCPP command 不增加確認。
-
GetDiagnostics、UpdateFirmware的 HTTP/HTTPS location 由 Engineer 輸入;FE 不需實作檔案上傳。
OCPP request:
{
"chargePointId": "CP001",
"connectorId": null,
"command": "TriggerMessage",
"payload": {
"requestedMessage": "Heartbeat"
}
}
若 command 為 connector-level,送出 connectorId;Backend 會驗證該 Connector 是否屬於選定 Charge Point,並在需要時補入 OCPP numeric connectorId。
7. Backend API Contract¶
7.1 Catalog¶
GET /api/engineer/commands/catalog?chargePointId={chargePointId}
用途:取得 31-command catalog、schema、risk、target 與 capability。
7.2 Execute OCPP¶
POST /api/engineer/ocpp/commands
Body:
{
"chargePointId": "CP001",
"connectorId": null,
"command": "TriggerMessage",
"payload": {
"requestedMessage": "Heartbeat"
}
}
7.3 Execute Modbus¶
POST /api/engineer/modbus/commands
Body:
{
"connectorId": "CP001-001",
"operation": "READ_SUPPLY_STATE",
"parameters": {}
}
7.4 Command Detail¶
GET /api/engineer/commands/{commandLogId}
主要欄位:
- target snapshot:chargePointId、connectorId、connectorNo、vendor、model、firmwareVersion
- protocol、command、capability、operatorId
- correlationId、ocppUniqueId
- requestPayload、maskedRequestPayload、responsePayload
- state、protocolStatus
- errorCode、errorDescription、errorDetails
- createdAt、sentAt、respondedAt、completedAt、elapsedMs
- events
顯示規則:
- 預設顯示
maskedRequestPayload,不要預設展開 rawrequestPayload。 - event timeline 依
sequenceNo顯示。 - correlationId、ocppUniqueId、commandLogId 提供 copy icon。
- 長 JSON 與 ID 必須 wrap/scroll,不得撐破 drawer。
7.5 Command Search¶
POST /api/engineer/commands/search
Body 所有 filter 都可選:
{
"from": null,
"to": null,
"protocol": null,
"command": null,
"chargePointId": null,
"connectorId": null,
"operatorId": null,
"state": null,
"correlationId": null,
"ocppUniqueId": null,
"page": 0,
"size": 20
}
規則:
-
page從 0 起算。 -
size最大 100。 - response 是 Spring Page,使用
content、totalElements、totalPages、number、size。
8. 202 Response 與 Polling¶
兩支 execute API 成功時回 HTTP 202:
{
"commandLogId": "uuid",
"correlationId": "uuid",
"ocppUniqueId": "uuid",
"state": "SENT",
"capability": "UNVERIFIED",
"createdAt": "2026-07-14T22:43:17.151298"
}
核心規則:
- HTTP 202/
SENT只表示 Branch 已把 OCPP CALL 送入 WebSocket。 - 這不代表 Charge Point 已執行完成。
- FE 必須用
commandLogId輪詢 detail API。 - 建議畫面可見時每 1 秒輪詢一次。
- 使用者離開頁面不會取消已送出的 command。
- 快速設備可能在 POST 回來前已完成;FE 要先檢查 create response 的
state,若已是 terminal 就不需等待。
Non-terminal states:
CREATEDVALIDATEDDISPATCHINGSENTRUNNING
Terminal states,收到後停止 polling:
COMPLETEDREJECTEDCALL_ERRORSEND_FAILEDFAILEDTIMEOUTSTATUS_UNKNOWN
GetDiagnostics、UpdateFirmware 可能先進入 RUNNING,後續 progress 由 detail events 顯示。
9. 操作紀錄 Tab¶
Filters:
- 時間範圍
- protocol
- command
- Charge Point
- Connector
- operator
- state/result
- correlationId
- ocppUniqueId
Table columns:
- 執行時間
- protocol/command
- target
- operator
- state/protocol status
- elapsed
- correlationId
點擊 row 開啟 detail drawer,顯示:
- target/device snapshot
- masked request/response JSON
- CALLERROR 或 local error
- command event timeline
- commandLogId、correlationId、ocppUniqueId
10. HTTP Error Handling¶
-
400:payload/schema/target/Modbus parameters 錯誤。顯示 Backend message,schema error 儘量對應到欄位。 -
401:未登入;沿用既有 refresh/sign-out middleware。 -
403:沒有 Engineer function 權限。 -
404:Charge Point、Connector 或 operation 不存在。 -
409:同一 Charge Point 已有進行中的GetDiagnostics或UpdateFirmware。 -
422:capability 為 unsupported,或對非 CloudLink Connector 執行 Modbus。 -
503:設備 offline 或 WebSocket dispatch 失敗。錯誤 message 會包含已建立的commandLogId,UI 應提供前往 detail 的入口。
11. React Implementation Guidance¶
先在 react/branch 更新 Backend types:
# .env.local 的 NEXT_PUBLIC_API_URL 指向含 #1381 的 Branch API
yarn openapi:refresh
Backend OpenAPI tag:[B135]工程師工具。
必須:
- 使用既有
lib/query-api/openapi.ts的$api/fetchClient。 - 沿用既有 JWT middleware、React Query、React Hook Form、Zod、shadcn、Sonner/SweetAlert2 pattern。
- 不要另建未帶 auth/refresh middleware 的 API client。
- 不要手改
lib/data/ems.json或lib/data/emsapi.ts。 - 在
config/menus.ts註冊 route/menu,但顯示權限仍以 Backend function/menu 為準。
建議 feature 結構:
app/(dashboard)/engineer-tools/
├── page.tsx
├── components/
│ ├── target-bar.tsx
│ ├── command-list.tsx
│ ├── modbus-command-form.tsx
│ ├── ocpp-command-form.tsx
│ ├── command-status-panel.tsx
│ ├── operation-table.tsx
│ └── operation-detail-drawer.tsx
├── hooks/
│ └── engineer-command-hooks.ts
└── lib/
├── schema.ts
└── presentation.ts
這不是一般 CRUD,建議以 typed $api.useQuery/useMutation 建立專用 hooks,不必勉強套完整 CRUD factory。
12. 驗收條件¶
- 只有取得 Engineer function 的使用者看得到並能進入工程師工具。
- Charge Point/Connector target 可選取,deep-link 可正確預選。
- Catalog 回傳的 31 commands 都能正確分組與顯示 capability。
- Modbus 不提供任何 raw register/function/payload 入口。
- 19 個 OCPP commands 都可由 schema 建立 payload,表單/JSON 模式切換不丟資料。
-
UNVERIFIED可送出且有警告;UNSUPPORTED禁用並顯示原因。 - Command POST 後顯示 operation panel,正確輪詢至 terminal state。
-
REJECTED、CALL_ERROR、SEND_FAILED、TIMEOUT不得顯示為成功。 - 操作紀錄支援 server-side filter/pagination,detail drawer 顯示 masked payload 與完整 timeline。
- Reset、供電控制、Meter ID 修改各只有一次簡短確認;不要求操作原因。
- Desktop/mobile 無文字重疊、截斷或切換造成的 layout shift。
- 完成後通過
yarn lint與yarn build。
13. Backend 現況與測試限制¶
Jimmy 已驗證:
- Engineer Role login
- 31-command catalog
- 真實 CP001
READ_SUPPLY_STATEModbus E2E - OCPP
TriggerMessageAccepted/Rejected - search/detail
- 未登入 401
- raw Modbus operation 400
Fortune(華城)設備在 Jimmy 2026-07-14 測試時離線;A17 於 2026-07-16 已通過 TriggerMessage(Heartbeat) 低風險實機 E2E。這只證明基礎 OCPP 通訊路徑可用,尚未完成 19-command capability matrix,因此 FE 仍必須將其 capability 呈現為 UNVERIFIED 與非阻斷警告,不能顯示為 VERIFIED。
Backend E2E 報告:test_report/20260714_001_redmine_1381_engineer_command_e2e.md。
14. 附件與關聯票¶
- Backend:#1381(Resolved)
- 附件:
branch-admin-engineer-command-plan.md - 附件包含完整產品決策、資料表、OCPP schema、測試矩陣與後續 Fortune 實機驗證計畫。
若本 Description 與既有 Journal 有差異,以本 Description 與最新 Backend OpenAPI 為準;Journal 只作進度歷史,不作需求拼接來源。
檔案