API Spec — Edit-History + RefNo + ServiceId Filter
API ที่เพิ่ม/แก้: edit-history aggregate (owner+admin), step-data +refNo, admin-list filter ด้วย serviceId (Codex appId) — พร้อม sequence diagram + req/response
อัปเดต: 2026-06-25
ขอบเขต: API ที่เพิ่ม/แก้ใน session นี้ — edit-history aggregate, step-data + refNo, admin-list filter ด้วย serviceId Service: user-service (
Backend_UserService) · Gateway: APIMexim-az-hub-apim→ DEV UserService API (userservice-api) Base:https://gateway-dev.exim.go.th/userservice-api+/api/user-service/v1Response envelope: ทุก endpoint ห่อด้วยApiResponse<T>={ "data": T, "meta": {...} }🆕 = field/endpoint ที่เพิ่มใหม่ · ✏️ = แก้ไข
1. ภาพใหญ่ (Big Picture)
graph LR
subgraph FE["Frontend (sa-onboarding-demo)"]
A1["Admin: รายละเอียดใบสมัคร<br/>/admin/onboarding-requests/:id"]
A2["Admin: รายการคำขอ (list)<br/>/admin/onboarding-requests"]
R1["Requestor: ประวัติการแก้ไข<br/>/corporate-workspace/:id/edit-history"]
R2["Requestor: ประวัติสถานะ<br/>/corporate-workspace/:id/status-history"]
end
subgraph GW["APIM Gateway"]
P["DEV UserService API<br/>(userservice-api)"]
end
subgraph BE["UserService API (.NET)"]
O["OnboardingController"]
H["GetEditHistory / GetAdminEditHistory<br/>GetStepData / AdminList handlers"]
end
CDX["Codex API<br/>(app registry)"]
A1 -->|"GET summary / step-map / step-data / history / edit-history(admin)"| P
A2 -->|"GET admin/flow-instances ?serviceId="| P
A2 -.->|"GET apps (filter options + lookup)"| CDX
R1 -->|"GET onboarding/.../edit-history (owner)"| P
R2 -->|"GET onboarding/.../history (owner)"| P
P --> O --> H --> DB[("PostgreSQL<br/>FlowInstance / History")]
classDef new fill:#d4f7d4,stroke:#2e7d32,color:#1b5e20;
classDef chg fill:#fff4cc,stroke:#b8860b,color:#7a5a00;
class R1,R2 new;
class A1,A2 chg;
3 features ของ session นี้
| # | Feature | ใช้ที่ไหน |
|---|---|---|
| 1 | 🆕 edit-history aggregate (owner + admin แยก route) | Admin tab “ประวัติการแก้ไข” + Requestor หน้า edit-history |
| 2 | 🆕 refNo ใน step-data response | Admin/Requestor onboarding-runner (step detail) |
| 3 | 🆕 filter admin-list ด้วย serviceId (Codex appId) | Admin หน้ารายการคำขอ (column “บริการ” + filter) |
2. สรุปการเปลี่ยนแปลง (Added / Removed)
| Endpoint | Method | เปลี่ยนอะไร |
|---|---|---|
/onboarding/instances/{id}/edit-history | GET | 🆕 เพิ่มใหม่ (owner) |
/admin/flow-instances/{id}/edit-history | GET | 🆕 เพิ่มใหม่ (admin, Draft = forbidden) |
/onboarding/instances/{id}/steps/{stepType}/data | GET | ✏️ response +refNo |
/admin/flow-instances/{id}/steps/{stepType}/data | GET | ✏️ response +refNo |
/admin/flow-instances | GET | ✏️ query +serviceId (repeated, Guid) |
ไม่มีอะไรลบออกจาก API (เฉพาะ APIM ลบ 2 stale ops
/users/{userId}/.../permissionsที่ backend ไม่มีแล้ว เพื่อ sync ให้ตรง — ดู §6)
3. API Spec รายเส้น
3.1 🆕 GET /onboarding/instances/{id}/edit-history (Owner)
ทุกรอบการแก้ไข (Rework→Resubmit) + comment ธนาคารราย step ในก้อนเดียว — owner เห็นใบตัวเอง
Request
| ส่วน | ค่า |
|---|---|
| path | id : Guid (FlowInstanceId) |
| auth | owner (cookie __Host-onboarding / JWT) · dev = AllowAnonymous |
Response 200 · ApiResponse<EditHistoryDto>
{
"data": {
"rounds": [ // เรียงรอบล่าสุดก่อน
{
"roundNo": 2, // "รอบการแก้ไขครั้งที่ N"
"isLatest": true, // badge "ล่าสุด"
"bankRequestedAt": "2026-06-10T00:00:00Z", // "ธนาคารแจ้งให้แก้ไข"
"resubmittedAt": "2026-06-13T00:00:00Z", // "แก้ไขและยื่นคำขอล่าสุด" (null = ยังไม่ยื่นกลับ)
"corrections": [ // comment จัดกลุ่มตาม step
{
"stepType": "DesignateCustomersStep",
"stepLabel": "ข้อมูลผู้ใช้งาน", // จาก StepCatalog
"notes": [
"ผู้ใช้งานลำดับที่ 2 : ชื่อ-นามสกุลไม่ตรงกับเอกสารยืนยันตัวตน",
"ผู้ใช้งานลำดับที่ 3 : ไม่พบเอกสารประกอบการสมัคร"
]
}
]
}
]
},
"meta": { "apiVersion": "v1", "processingTime": "5ms" }
}
ที่มา: derive จาก
FlowInstanceHistoryrows +ReworkContextJson— ไม่มี table/column ใหม่
3.2 🆕 GET /admin/flow-instances/{id}/edit-history (Admin)
shape เหมือน 3.1 เป๊ะ — ต่างแค่ guard: Draft → 403 + admin เห็นใบที่ ≥ Submitted
Response 200 = เหมือน 3.1 · 403 ถ้าใบเป็น Draft
// 403
{ "data": null, "meta": { "errorCode": "Application.Forbidden", "message": "ไม่มีสิทธิ์ดูใบสมัครสถานะ Draft" } }
3.3 ✏️ GET /onboarding/instances/{id}/steps/{stepType}/data (+ /admin/flow-instances/{id}/...)
ข้อมูล step เดียว — เพิ่ม refNo ใน response
Request
| ส่วน | ค่า |
|---|---|
| path | id : Guid · stepType : string (เช่น CompanyInfoStep) |
Response 200 · ApiResponse<StepDataDto>
{
"data": {
"stepType": "CompanyInfoStep",
"refNo": "FXO-2025-00001234", // 🆕 เลขที่คำขอ (null ถ้ายังไม่ issue RefNo)
"canViewData": true,
"secured": false, // true = sensitive (ไม่ส่ง data)
"dataJson": "{ ... }" // null ถ้า secured / ดูไม่ได้
},
"meta": { "apiVersion": "v1" }
}
3.4 ✏️ GET /admin/flow-instances — filter ด้วย serviceId
เพิ่ม query serviceId (repeated, Guid = Codex appId). flowCode ยังคงไว้เพื่อ compat
Request — query params
| param | type | หมายเหตุ |
|---|---|---|
status | string[] (repeated) | bucket สถานะ |
keyword | string | RefNo / ชื่อบริษัท |
submittedFrom / submittedTo | date (YYYY-MM-DD) | ช่วงวันที่ยื่น |
page / pageSize | int | paging |
sortBy / sortDir | string | refNo|status|submittedAt|lastActionAt · asc|desc |
flowCode | string[] (repeated) | [legacy] |
🆕 serviceId | Guid[] (repeated) | filter ตาม service (Codex appId) |
ตัวอย่าง: GET /admin/flow-instances?status=Submitted&serviceId=2f1c...&serviceId=9a3b...&page=1&pageSize=10
Response 200 · ApiResponse<PagedResult<FlowInstanceSummaryDto>>
{
"data": {
"items": [
{
"flowInstanceId": "e32cf739-...",
"refNo": "FXO-2025-00001234",
"flowCode": "NEW_REQUESTOR",
"serviceId": "2f1c8d40-...", // Codex appId → FE lookup ชื่อบริการ
"serviceName": "FX Online",
"companyName": "A Company จำกัด (มหาชน)",
"status": "Submitted",
"submittedAt": "2026-06-18T15:22:00Z",
"lastActorName": "ธนาคาร",
"lastActionAt": "2026-06-18T15:22:00Z"
}
],
"totalCount": 230, "pageNumber": 1, "pageSize": 10, "totalPages": 23,
"hasNextPage": true, "hasPreviousPage": false
},
"meta": { "apiVersion": "v1" }
}
4. Sequence Diagrams (ลำดับการ call)
4.1 Admin — หน้ารายละเอียดใบสมัคร (info bar + 3 tabs)
sequenceDiagram
autonumber
participant U as Admin
participant FE as Admin Detail Page
participant API as UserService API
U->>FE: เปิด /admin/onboarding-requests/{id}
FE->>API: GET /admin/flow-instances/{id}
API-->>FE: FlowInstanceSummaryDto (info bar)
Note over FE: Tab 1 — รายละเอียดใบสมัคร (lazy)
FE->>API: GET /admin/flow-instances/{id}/step-map
API-->>FE: StepMapDto (รายการ step)
U->>FE: กดเลือก section
FE->>API: GET /admin/flow-instances/{id}/steps/{stepType}/data
API-->>FE: StepDataDto (+refNo) 🆕
Note over FE: Tab 2 — ประวัติสถานะ
FE->>API: GET /onboarding/instances/{id}/history
API-->>FE: HistoryListDto (timeline)
Note over FE: Tab 3 — ประวัติการแก้ไข 🆕
FE->>API: GET /admin/flow-instances/{id}/edit-history
API-->>FE: EditHistoryDto (rounds + comments)
4.2 Requestor — หน้าประวัติการแก้ไข 🆕
sequenceDiagram
autonumber
participant U as Requestor
participant FE as Edit-History Page
participant API as UserService API
U->>FE: เปิด /corporate-workspace/{id}/edit-history
FE->>API: GET /onboarding/instances/{id}/edit-history (owner)
API-->>FE: EditHistoryDto
Note over FE: "จำนวนครั้งที่แก้ไข" = rounds.length<br/>render การ์ดต่อรอบ + timeline + comment ราย step
4.3 Admin — รายการคำขอ + filter ด้วย serviceId 🆕
sequenceDiagram
autonumber
participant U as Admin
participant FE as Admin List Page
participant CDX as Codex API
participant API as UserService API
U->>FE: เปิด /admin/onboarding-requests
FE->>CDX: GET /apps (filter options + lookup ชื่อบริการ)
CDX-->>FE: AppRegistration[] (id + appName)
FE->>API: GET /admin/flow-instances?status=...&page=1
API-->>FE: PagedResult (column "บริการ" = lookup serviceId→appName)
U->>FE: เลือกบริการใน filter → นำไปใช้
FE->>API: GET /admin/flow-instances?serviceId={appId}&... 🆕
API-->>FE: PagedResult (กรองตาม serviceId)
5. Auth / Role (สรุป)
| Endpoint | Role | Guard |
|---|---|---|
/onboarding/.../edit-history | Owner | เห็นใบตัวเอง (cookie/JWT); dev = pass |
/admin/.../edit-history | Admin | Draft = 403; เห็นใบ ≥ Submitted |
/...steps/{stepType}/data | Owner/Admin | route แยก role (owner-guard / admin Draft-forbid) |
/admin/flow-instances | Admin | dev = AllowAnonymous (pre-SIT ใส่ RBAC) |
6. APIM sync (2026-06-25)
sync DEV UserService API บน APIM ให้ เท่ากับ spec จาก pod (119 paths = 119 paths):
- เพิ่ม 6 ops ที่ขาด (รวม
edit-history× 2,application-report× 2,users/me/*permissions× 3) — method/url-template ตรง spec - ลบ 2 stale ops
/users/{userId}/.../permissions(backend เปลี่ยนเป็น/users/me/...แล้ว) - ทำแบบ targeted op add/delete (ไม่ full-import) — routing policy / serviceUrl / props ไม่ถูกแตะ
หมายเหตุ:
serviceIdquery param (3.4) ยังไม่อยู่ใน spec ที่ deploy (PR #858 รอ approve) — APIM forward query param ให้เองอยู่แล้ว จึงใช้งานได้เมื่อ backend deploy