Feature #1398
進行中
Feature #1397: [功能開發] LIFF DriverState、離峰充電與 Remote Operation 狀態契約重構
[Backend] 實作 DriverState、離峰排程與 Remote Operation lifecycle
是由 陳國瑋 於 5 天 前加入.
於 約 21 小時 前更新.
概述
h2. 目標
依父項 #1397 及其英文/繁體中文規格附件,完成 Branch/HQ 後端的 DriverState、長期離峰充電排程與 RemoteStart/RemoteStop operation lifecycle。附件內容為本子任務的需求與驗收基準。
h2. 實作範圍
- 由 Branch 作為 DriverState 與 actions 的唯一業務狀態來源;HQ 僅做契約一致的 passthrough/推播。
- 正確區分 PUBLIC/PRIVATE Connector,以及 MANUAL/OFF_PEAK 操作來源。
- 支援 OFF_PEAK_WAITING、QUEUED、PREPARING、CHARGING、FINISHING 等狀態與對應 semantic actions。
- PREPARING 僅代表已有持久化且尚未終結的 RemoteStart;不得直接以 raw OCPP PREPARING 推導。
- FINISHING 代表已有持久化且尚未終結的 RemoteStop。
- 擴充既有 e_remote_transaction_log,保存 business operation lifecycle、source、request actor、deadline、transaction correlation、終結結果等必要資料。
- e_connector_priority 保存來源與 requestedBy;Priority 真正建立前,已開啟離峰的私樁回 OFF_PEAK_WAITING,建立後回 QUEUED。
- 保存離峰設定 enabledBy,以及本離峰時段 current-window suppression;StopTransaction 後以中性原因 TRANSACTION_ENDED_FOR_CURRENT_WINDOW 結束本輪,但不關閉長期離峰模式。
- RemoteStart/RemoteStop 處理 Accepted、Rejected、timeout、有限 retry、late event reconciliation,並可在服務重啟後還原未完成 operation。
- Command API 執行 authoritative authorization/business guard,針對不允許、衝突、重複 operation 回傳結構化 403/409 與 operationId;避免 API 與 MQ consumer 重複維護授權判斷。
- 產出完整 OpenAPI DTO/enum/action contract,並透過 RabbitMQ/WebSocket 將最新 snapshot 推送至 HQ/LIFF。
- 加入必要 schema migration、單元/整合測試、重啟恢復測試及 regression cases;依專案規範維護 E2E catalog。
h2. 驗收重點
- 公樁不進入私樁離峰排程,保留公樁預留 slot 行為。
- 私樁離峰開啟後,即使尚未建立 e_connector_priority,也立即可由 OFF_PEAK_WAITING 的 action 取消排隊;Priority 建立後轉 QUEUED。
- CloudLink/Fortune 在「先插槍、尚未按開始」時,不會因 raw PREPARING 誤顯示為正在啟動。
- RemoteStart/RemoteStop 失敗或逾時時,DriverState 能顯示可理解的暫態結果,再回復正確的 READY/OFF_PEAK_WAITING/QUEUED 狀態,而非讓使用者只看到可重複按下的開始按鈕。
- 服務重啟、重複 request、late OCPP event 不會造成重複開始/停止或狀態倒退。
- API、MQ event、WebSocket snapshot 與 OpenAPI contract 一致。
h2. 不含範圍
- 不修改 LIFF/FE source code;前端串接由另一張子任務處理。
- Charge Group 刪除 guard 另見 #1395。
- PUBLIC slot 設定 guard 與 runtime slots==0 防線另見 #1396。
檔案
- 狀態 從 New 變更為 In Progress
- 開始日期 從 2026-07-29 變更為 2026-07-31
已依 #1397 中英文需求附件啟動 #1398。完成 git pull、建立 feature/redmine-1398-driver-state-offpeak-backend 與本地 ticket 快照;目前進行需求衝突確認及現況程式碼/DB/E2E impact review,尚未開始 coding。
#1397 需求附件已於 2026-07-31 修訂並重新上傳:
- 英文附件 #1102:redmine-1397-driver-state-offpeak-requirements-rev-20260731.md
- 繁中附件 #1103:redmine-1397-driver-state-offpeak-requirements-zh-TW-rev-20260731.md
本 BE ticket 依修訂契約實作:driverState 僅提供 actions[];統一語意 command API;START_CHARGING/STOP_CHARGING 成功 dispatch 回 202 與 operationId;同步取消/離峰命令回 200;operationResult 僅推送目標使用者;初始快照只含未完成 activeOperation、不重播 terminal result;RemoteStop deadline 30 秒;RemoteStart 沿用各廠牌既有等待時間,deadline 後另有 30 秒事件對帳寬限。
需求確認 Gate 已通過:Ken 確認 #1397 附件 #1102/#1103 為本 ticket 正式需求基準。現在進入 implementation plan 階段;Plan 核准前不修改業務程式碼。
Implementation plan 已完成並附上,狀態為 Awaiting Ken approval;尚未修改業務程式碼。
Plan 明列 schema、Branch/HQ semantic command API、DriverState actions[]、RemoteStart/Stop lifecycle、離峰 actor/queue source/current-window suppression、targeted WebSocket、測試與 E2E impact。
已補上與英文附件 #1104 內容對等的繁體中文 Backend implementation plan;兩版均為 Awaiting Ken approval,尚未修改業務程式碼。
Implementation Plan Gate 已通過:Ken 已核准英文附件 #1104 與繁中附件 #1105。已依 SOP 執行 git pull --ff-only origin private,feature branch HEAD 與 origin/private 同為 9a27ab4;現在進入階段 3 實作與單元測試。
2026-07-31 Backend 部署/測試進度更新
#1398 Backend 已部署至:
- Ken Branch/Charge Point 測試環境
- docker1 HQ staging
本輪安全 Smoke/Contract 共 6 案,全部 PASS:
- Branch/HQ api-docs 與 container health。
- Branch direct connector snapshot:public CP001-002 回 READY、actions-only driverState、activeOperation=null。
- HQ 透過 LINE/building binding 取得相同 snapshot。
- 公樁 DISABLE_OFF_PEAK 由 semantic command API 回 409 OFF_PEAK_PRIVATE_ONLY 與最新 driverState。
- 上述拒絕不建立 e_remote_transaction_log 或 e_connector_priority。
- HQ WebSocket initial fetch 回 101,第一個 frame 為 AVAILABLE/READY/START_CHARGING snapshot。
完整實車/LIFF E2E 尚未執行,現階段整體維持 PARTIAL。Ken 已決定先等待 #1399 Frontend 完成;之後依父項 #1397 附件 #1106(redmine-1397-liff-manual-e2e-test-plan-zh-TW.md)執行 16 個 LIFF 人工 E2E 案例,覆蓋公/私樁、手動/離峰、queue、operation lifecycle、WebSocket、多使用者與重啟恢復。
本地測試報告已同步標記此暫停點;此 note 不代表 #1398 已完成完整 E2E 或可結案。
h3. 2026-07-31 OpenAPI response schema 修正
FE 回報 HQ POST /api/connector/commands 的 200/202/403/409 response body 在 OpenAPI 只標為通用 object,導致 yarn openapi:refresh 無法產生具體型別。
原因:endpoint 需要用 ResponseEntity<?> 原樣透傳 Branch 的 200/202/403/409,但原本 @ApiResponse 沒有明確指定 response schema。
已於 #1398 程式補上 OpenAPI annotation:
- HQ
POST /api/connector/commands
** 200 OK、202 Accepted:ConnectorCommandResponse
** 403 Forbidden、409 Conflict:ConnectorCommandErrorResponse
- Branch internal
POST /api/cp/hq/connector/commands 同步補相同 schema,避免 HQ/Branch contract 不一致。
Runtime HTTP status 與 response body 語意不變,只修正 OpenAPI contract。E2E Catalog 不新增案例。
驗證:
-
java/ems_hq: mvn -q -DskipTests compile PASS
-
java/ems_branch: mvn -q -DskipTests compile PASS
-
git diff --check PASS
已同步於 #1399 補 FE 使用說明,包含 request body、200/202/403/409 response 欄位與 FE AI 串接重點。
h3. 2026-07-31 Push 與 HQ staging 部署確認
已依 Ken 要求將 #1398 推上 remote,並重新部署 HQ staging。
- Remote branch:
feature/redmine-1398-driver-state-offpeak-backend
- Latest commit:
a21baa3(含部署驗證紀錄)
- Main implementation commit:
095d58a
- HQ staging build:
mvn -DskipTests -Ddeploy.target=staging package PASS
- HQ staging deploy:docker1
/opt/ems/ems_hq/api/api.jar
- Deployed JAR SHA-256:
d796ced0cbbd8cd18feedbe7cd52d3b914210642a2b83cfa8e8a9fbc5e9d759b
- Container:
ems-hq-staging-api 已重建並為 Up
已從 docker1 local http://127.0.0.1:7050/api-docs 驗證 HQ staging OpenAPI:
-
POST /api/connector/commands 200 → ConnectorCommandResponse
-
POST /api/connector/commands 202 → ConnectorCommandResponse
-
POST /api/connector/commands 403 → ConnectorCommandErrorResponse
-
POST /api/connector/commands 409 → ConnectorCommandErrorResponse
因此 FE 重新執行 yarn openapi:refresh 時,應可取得具體 response types,不再只有通用 object。
匯出至 Atom
PDF