S-CHG 異動紀錄查詢 Feature Spec
Feature 前綴:S-CHG | Feature 目錄:
changeLogs| Route:/change-logs| Backend Controller:ChangeLogsController| DB 資料表: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:支援分頁 + 多維篩選(模組 / 操作類型 / 時間區間 / 操作人員)ChangeLogsController(GET /api/v1/change-logs)- 前端列表頁
/change-logs:篩選列、分頁表格、展開 Before/After - 權限:
ChangeLogs.View(全角色可查) - 文件同步:
feature-map.md、scenarios.md、domain.md、db-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 驗證情境
| 情境 | 觸發條件 | 預期結果 |
|---|---|---|
S-CHG-ERR-001 | 無符合紀錄 | 200 + items: [] + Empty State「查無相符的異動紀錄」 |
S-CHG-ERR-002 | pageSize=501 | 400 ProblemDetails「分頁大小不得超過 500」 |
S-CHG-ERR-003 | dateFrom / dateTo 非法日期字串 | 400 ProblemDetails 日期格式錯誤 |
S-CHG-ERR-004 | 查詢 API 逾時 | 前端 Error Toast「查詢逾時,請稍後再試」 |
S-CHG-ERR-005 | 無 ChangeLogs.View 權限 | 前端 PermissionGuard 隱藏入口;API 回 403 |
S-CHG-VAL-001 | dateFrom > dateTo | inline 紅色提示「起始日期不得晚於結束日期」,不送出 API |
S-CHG-VAL-002 | 手動把 pageSize 改超過 500 | 前端自動截斷為 500 或顯示警示 |
Acceptance Criteria
後端 API(AC-01 ~ 09)
- AC-01
GET /api/v1/change-logs(無篩選)回 200,items結構含id, tableName, recordId, operationType, operatedBy, operatedAt, moduleName - AC-02 ~ 05 各篩選參數:
moduleName/operationType/dateFrom-dateTo/operatedBy(operatedBy不分大小寫部分符合) - AC-06
pageSize=501→ 400 ProblemDetails(RFC 7807) - AC-07
GET /api/v1/change-logs/{id}回單筆含beforeValue與afterValueJSON 字串 - AC-08 無
ChangeLogs.View權限的 JWT → 403 - AC-09 回應格式:
PagedResponse<ChangeLogResponse>(page, pageSize, totalCount, totalPages)
WriteChangeLogService(AC-10 ~ 13)
- AC-10 呼叫
WriteAsync()後新增一筆紀錄,OperatedBy取自ICurrentUserService.Account - AC-11 Create:
BeforeValue = null,AfterValue = 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 ErrordateFrom = dateTo(同一天):視為全天查詢(>= 00:00:00 AND <= 23:59:59.999)- 分頁超過最後一頁:回 200 + 空陣列,不報錯
WriteChangeLogService與主業務交易的關係:建議在 commit 成功後呼叫,避免記錄不存在的異動
資料模型
ChangeLog 資料表(新建)
9 欄位定義:
| 欄位 | 型別 | 說明 |
|---|---|---|
Id | bigint IDENTITY(1,1) PK | 主鍵 |
ModuleName | nvarchar(50) NOT NULL | 功能模組名稱(例:CustomerAccount) |
TableName | nvarchar(100) NOT NULL | 實際 DB 資料表(例:CustomerAccountBaseInfo) |
RecordId | nvarchar(500) NOT NULL | 單一主鍵為字串,複合主鍵為 JSON |
OperationType | nvarchar(10) NOT NULL | Create / Update / Delete |
OperatedBy | nvarchar(50) NOT NULL | 操作人員帳號 |
OperatedAt | datetime2 NOT NULL DEFAULT sysutcdatetime() | 操作時間(UTC) |
BeforeValue | nvarchar(MAX) NULL | 異動前 JSON;Create 時 NULL |
AfterValue | nvarchar(MAX) NULL | 異動後 JSON;Delete 時 NULL |
建議索引:IX_ChangeLog_ModuleName、IX_ChangeLog_OperatedAt、IX_ChangeLog_OperatedBy
後端分層
10 主要檔案:
- Domain:
Oms.Domain/Entities/ChangeLog.cs(繼承BaseEntity,OperatedAt獨立定義) - EF:
Oms.Infrastructure/Persistence/Configurations/ChangeLogConfiguration.cs - Repository:
IChangeLogRepository+ 實作(AddAsync/GetPagedAsync/GetByIdAsync) - Service:
IWriteChangeLogService+WriteChangeLogService(捕捉所有例外降級記 Serilog,不向上拋) - Query:
GetChangeLogsQuery(FluentValidation:PageSize 1~500、DateFrom <= 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.ts(ChangeLog,ChangeLogDetail,ChangeLogsQueryParams) - API:
src/services/api/changeLogsApi.ts+api/changeLogsQueryKeys.ts - Hook:
useChangeLogsQuery(列表)+useChangeLogDetailQuery(lazy,展開才觸發) - UI:
ChangeLogsFilterBar.tsx、ChangeLogsTable.tsx(展開列)、ChangeLogBeforeAfterView.tsx(pretty-print JSON)、ListPage.tsx - 路由:
src/app/(dashboard)/change-logs/page.tsx(PermissionGuard包裝) - Sidebar:更新
src/shared/constants/appConstants.ts
風險
| 風險 | 等級 | 緩解 |
|---|---|---|
| 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 含清除篩選條件按鈕。
相關頁面
- 功能對應:FSTS 功能對應表(S-CHG 列)
- 情境規格:BA 情境規格 §S-CHG
- 自動異動紀錄機制:Auto Change Log
補充資訊
(未來 ingest 新來源會在此追加段落)