S-CHG 異動紀錄查詢 Feature Spec

Feature 前綴:S-CHG | Feature 目錄changeLogsRoute/change-logsBackend ControllerChangeLogsControllerDB 資料表ChangeLog(新建)

本頁摘要 Feature Spec;完整內容見 spec.md。對應 BA 情境見 BA 情境規格 §S-CHG

需求摘要

「異動紀錄查詢」是全新功能模組,用於追蹤系統各模組的資料列層級變更歷程, S-AUDIT 操作紀錄的強化。1

S-AUDIT vs S-CHG 差異

1 二者維度不同:

維度S-AUDIT(操作紀錄)S-CHG(異動紀錄)
記錄粒度API 呼叫層(哪個 Endpoint 被呼叫)資料列層(哪個欄位被改了什麼值)
Before/After有(JSON 欄位層 diff)
觸發時機AuditActionFilter(HTTP 請求進入時)Application Layer Service(資料寫入前後)
查詢用途稽核誰呼叫了什麼 API查詢某筆資料的完整變更歷程

追蹤範圍為全模組通用(CustomerAccount、Stock、CBL Layout 等),操作類型為 Create / Update / Delete。1

Scope

In Scope

2 本 Feature 建立基礎設施與查詢頁面:

  • 新建 ChangeLog 資料表(含 EF Core Migration)
  • WriteChangeLogService:供其他模組 Handler 呼叫,寫入異動紀錄
  • GetChangeLogsQuery:支援分頁 + 多維篩選(模組 / 操作類型 / 時間區間 / 操作人員)
  • ChangeLogsControllerGET /api/v1/change-logs
  • 前端列表頁 /change-logs:篩選列、分頁表格、展開 Before/After
  • 權限:ChangeLogs.View(全角色可查)
  • 文件同步:feature-map.mdscenarios.mddomain.mddb-schema.md

Out of Scope

2 留給後續 Feature:

  • 自動對現有模組回填歷史異動資料(新建後才開始記錄)
  • 匯出(CSV/Excel)、刪除 / 封存(Retention Policy)
  • 即時推播(WebSocket/SignalR)
  • 欄位層 diff 的比較演算法視覺化(僅儲存 JSON)
  • 對 AuditLog(S-AUDIT)表的任何修改

使用者情境

主流程(S-CHG-001 ~ 007)

3 全為 Full Suite

  • 001 預設查詢:進入 /change-logs,依 OperatedAt 降序、每頁 20 筆,顯示分頁資訊
  • 002 依模組名稱篩選:例如 ModuleName = 'CustomerAccount',分頁重置至第 1 頁
  • 003 依操作類型篩選:Create / Update / Delete
  • 004 依時間區間篩選:OperatedAt 落在區間(含邊界、精確到日
  • 005 依操作人員篩選:OperatedBy 部分 / 完整符合
  • 006 展開單筆 Before/After:Expandable Row 或 Drawer 顯示 JSON;Create 時 BeforeValue 為空,Delete 時 AfterValue 為空
  • 007 組合篩選:模組 + 操作類型 + 時間區間 同時成立

異常與 UI 驗證情境

4

情境觸發條件預期結果
S-CHG-ERR-001無符合紀錄200 + items: [] + Empty State「查無相符的異動紀錄」
S-CHG-ERR-002pageSize=501400 ProblemDetails「分頁大小不得超過 500」
S-CHG-ERR-003dateFrom / dateTo 非法日期字串400 ProblemDetails 日期格式錯誤
S-CHG-ERR-004查詢 API 逾時前端 Error Toast「查詢逾時,請稍後再試」
S-CHG-ERR-005ChangeLogs.View 權限前端 PermissionGuard 隱藏入口;API 回 403
S-CHG-VAL-001dateFrom > dateToinline 紅色提示「起始日期不得晚於結束日期」,不送出 API
S-CHG-VAL-002手動把 pageSize 改超過 500前端自動截斷為 500 或顯示警示

Acceptance Criteria

後端 API(AC-01 ~ 09)

5

  • AC-01 GET /api/v1/change-logs(無篩選)回 200,items 結構含 id, tableName, recordId, operationType, operatedBy, operatedAt, moduleName
  • AC-02 ~ 05 各篩選參數:moduleName / operationType / dateFrom-dateTo / operatedByoperatedBy 不分大小寫部分符合
  • AC-06 pageSize=501 → 400 ProblemDetails(RFC 7807)
  • AC-07 GET /api/v1/change-logs/{id} 回單筆含 beforeValueafterValue JSON 字串
  • AC-08ChangeLogs.View 權限的 JWT → 403
  • AC-09 回應格式:PagedResponse<ChangeLogResponse>page, pageSize, totalCount, totalPages

WriteChangeLogService(AC-10 ~ 13)

6

  • AC-10 呼叫 WriteAsync() 後新增一筆紀錄,OperatedBy 取自 ICurrentUserService.Account
  • AC-11 Create:BeforeValue = nullAfterValue = JSON(後)
  • AC-12 Update:兩者皆為 JSON
  • AC-13 Delete:BeforeValue = JSON(前)AfterValue = null

前端(AC-14 ~ 18)

7 篩選列(模組 / 操作類型 / 時間區間 / 操作人員)+ 表格 + 展開列;套用篩選後分頁重置;無資料顯示 Empty State;dateFrom > dateTo 時 inline 錯誤不送 API。

Edge Cases

8 重點處理:

  • BeforeValue / AfterValue 超大 JSON(如 CustomerAccountBaseInfo 25+ 欄位):NVARCHAR(MAX) 容納,前端 JSON.stringify pretty-print 不截斷
  • 並發快速異動:每次 WriteChangeLogService 獨立新增,不合併
  • 複合主鍵的 RecordId:統一以 JSON 字串儲存,例 {"BrokerNo":"9699","AccountNo":100001}
  • WriteChangeLogService 拋例外不中斷主業務寫入交易(採 fire-and-forget 或 try-catch 降級),需記錄 Serilog Error
  • dateFrom = dateTo(同一天):視為全天查詢(>= 00:00:00 AND <= 23:59:59.999
  • 分頁超過最後一頁:回 200 + 空陣列,不報錯
  • WriteChangeLogService 與主業務交易的關係建議在 commit 成功後呼叫,避免記錄不存在的異動

資料模型

ChangeLog 資料表(新建)

9 欄位定義:

欄位型別說明
Idbigint IDENTITY(1,1) PK主鍵
ModuleNamenvarchar(50) NOT NULL功能模組名稱(例:CustomerAccount)
TableNamenvarchar(100) NOT NULL實際 DB 資料表(例:CustomerAccountBaseInfo)
RecordIdnvarchar(500) NOT NULL單一主鍵為字串,複合主鍵為 JSON
OperationTypenvarchar(10) NOT NULLCreate / Update / Delete
OperatedBynvarchar(50) NOT NULL操作人員帳號
OperatedAtdatetime2 NOT NULL DEFAULT sysutcdatetime()操作時間(UTC)
BeforeValuenvarchar(MAX) NULL異動前 JSON;Create 時 NULL
AfterValuenvarchar(MAX) NULL異動後 JSON;Delete 時 NULL

建議索引IX_ChangeLog_ModuleNameIX_ChangeLog_OperatedAtIX_ChangeLog_OperatedBy

後端分層

10 主要檔案:

  • Domain:Oms.Domain/Entities/ChangeLog.cs(繼承 BaseEntityOperatedAt 獨立定義)
  • EF:Oms.Infrastructure/Persistence/Configurations/ChangeLogConfiguration.cs
  • Repository:IChangeLogRepository + 實作(AddAsync / GetPagedAsync / GetByIdAsync
  • Service:IWriteChangeLogService + WriteChangeLogService捕捉所有例外降級記 Serilog,不向上拋
  • Query:GetChangeLogsQuery(FluentValidation:PageSize 1~500DateFrom <= DateTo)與 GetChangeLogByIdQuery
  • DTO:ChangeLogResponse + ToResponse() extension
  • Controller:ChangeLogsController(兩條路由均掛 [RequirePermission("ChangeLogs", "View")]
  • 權限:ResourceDefinitions.ChangeLogs.View + RolePermission seed SQL(Admin / User)
  • Unit Test:GetChangeLogsQueryHandler(六種情境)+ WriteChangeLogService(Create/Update/Delete + 例外不傳播)

前端檔案

11 主要檔案(src/features/changeLogs/):

  • Types:changeLogsTypes.tsChangeLog, ChangeLogDetail, ChangeLogsQueryParams
  • API:src/services/api/changeLogsApi.ts + api/changeLogsQueryKeys.ts
  • Hook:useChangeLogsQuery(列表)+ useChangeLogDetailQuerylazy,展開才觸發)
  • UI:ChangeLogsFilterBar.tsxChangeLogsTable.tsx(展開列)、ChangeLogBeforeAfterView.tsx(pretty-print JSON)、ListPage.tsx
  • 路由:src/app/(dashboard)/change-logs/page.tsxPermissionGuard 包裝)
  • Sidebar:更新 src/shared/constants/appConstants.ts

風險

12

風險等級緩解
ChangeLog 資料量快速膨脹🔴 高覆蓋性索引;後續規劃 Retention Policy
WriteChangeLogService 影響主業務寫入效能🟠 中獨立 try-catch + Serilog Error 降級,不回滾主業務
複合主鍵 RecordId 表示不一致🟠 中定義 統一 JSON 物件字串格式;Service 提供工具方法
Before/After JSON 的敏感資料🟠 中初期如實記錄;後續以 [SensitiveData] Attribute 過濾
既有模組需手動整合 Service🟡 低本 Feature 僅建基礎設施;各模組整合為後續工作
大量資料時查詢慢🟠 中Migration 同步建 ModuleName / OperatedAt / OperatedBy 索引
EF Core Migration 歷史衝突🟡 低git pull main 後再建新 Migration

UI 設計

13 設計稿 docs/features/change-logs/ui.pen(Frame:列表頁 / Empty State / 篩選驗證錯誤)。表格欄位:No / 模組名稱 / 操作類型 / 操作人員 / 所屬券商 / 操作時間 / 展開按鈕。展開列三欄(欄位名稱 / 修改前 / 修改後),欄位名中文化。操作類型 Badge:Create=綠、Update=藍、Delete=紅。Empty State 含清除篩選條件按鈕。

相關頁面

補充資訊

(未來 ingest 新來源會在此追加段落)


參考資料

Footnotes

  1. spec.md §Requirement Summary 2 3

  2. spec.md §Scope 2

  3. 主流程

  4. 異常流程

  5. 後端 API

  6. WriteChangeLogService

  7. 前端

  8. spec.md §Edge Cases

  9. DB 層

  10. Backend 層

  11. Frontend 層

  12. spec.md §Risks

  13. spec.md §UI Design Reference