Thuộc Tài Liệu API — EP-03: Khám phá, Đối chiếu & Bản đồ Hiện trạng
API Chi Tiết — EP-03: Khám Phá, Đối Chiếu & Bản Đồ Hiện Trạng¶
Use Cases: UC-DISC-001, UC-DISC-002, UC-MAP-001, UC-MAP-002, UC-MAP-003, UC-CONFIRM-001–005 Module: module-discovery, module-matching, module-mapping, module-confirm
Discovery — Upload & Parse¶
POST /api/v1/discovery/upload-csv¶
Mục đích: Upload file CSV của đơn vị, parse header để trích xuất danh sách field names.
Tham chiếu: UC-DISC-001, Feature EP-03-001
Xác thực: Bearer Token (bắt buộc)
Phân quyền: - Role: Manager - Data Ownership: Không áp dụng (Manager xem toàn bộ)
Request: multipart/form-data
| Field | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
| file | File | Có | File CSV (max 50MB, phải có header row) |
| orgId | Long | Có | ID đơn vị Sở/Ban/Ngành sở hữu dữ liệu |
| systemName | String | Có | Tên hệ thống/CSDL nguồn (VD: "HIS_BENHVIEN") |
Response Codes:
| Code | Mô tả |
|---|---|
| 201 | Parse thành công, session đã tạo |
| 400 | File không hợp lệ (không phải CSV, không có header, quá lớn) |
| 401 | Chưa xác thực |
| 403 | Không phải Manager |
Response 201:
{
"success": true,
"data": {
"id": 1001,
"orgId": 5,
"orgName": "Sở Y tế",
"method": "CSV",
"status": "COMPLETED",
"fieldsFound": 47,
"fileName": "his_benhvien_schema.csv",
"createdAt": "2026-04-08T14:30:00+07:00"
}
}
Response 400 (parse lỗi):
{
"success": false,
"error": {
"type": "validation_error",
"code": "CSV_PARSE_FAILED",
"message": "Không tìm thấy header row trong file CSV",
"details": {
"fileName": "data.csv",
"reason": "File rỗng hoặc không có dòng header"
}
}
}
POST /api/v1/discovery/upload-ddl¶
Mục đích: Upload file SQL DDL (.sql), parse câu lệnh CREATE TABLE để trích xuất field names + kiểu dữ liệu.
Tham chiếu: UC-DISC-001, Feature EP-03-001
Xác thực: Bearer Token (bắt buộc)
Phân quyền: Role: Manager
Request: multipart/form-data
| Field | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
| file | File | Có | File .sql (max 50MB, chỉ DDL — DML bị bỏ qua) |
| orgId | Long | Có | ID đơn vị |
| systemName | String | Có | Tên hệ thống nguồn |
Response 201:
{
"success": true,
"data": {
"id": 1002,
"method": "SQL_DDL",
"status": "COMPLETED",
"fieldsFound": 182,
"tablesFound": 24,
"dmlStatementsSkipped": 15,
"preview": [
{ "table": "benh_nhan", "columns": 12 },
{ "table": "don_thuoc", "columns": 8 },
{ "table": "kham_benh", "columns": 15 }
]
}
}
Ghi chú: - Hệ thống chỉ parse DDL (CREATE TABLE). DML (INSERT, UPDATE, DELETE) bị bỏ qua và đếm. - Giới hạn file: 50MB. - Trích xuất: tên bảng, tên cột, kiểu dữ liệu, nullable, default.
POST /api/v1/discovery/manual-entry¶
Mục đích: Khai báo thủ công danh sách fields cho đơn vị không có file CSV/DDL.
Tham chiếu: UC-DISC-001, Feature EP-03-002
Xác thực: Bearer Token (bắt buộc)
Phân quyền: Role: Manager
Request Body:
{
"orgId": 5,
"systemName": "HE_THONG_NOI_BO",
"fields": [
{
"tableName": "nhan_su",
"columnName": "ho_ten",
"dataType": "VARCHAR(100)",
"description": "Họ và tên nhân viên",
"nullable": false
},
{
"tableName": "nhan_su",
"columnName": "cccd",
"dataType": "VARCHAR(12)",
"description": "Số căn cước công dân",
"nullable": false
}
]
}
Validation:
- fields phải có ít nhất 1 item
- columnName bắt buộc cho mỗi field
- dataType bắt buộc
Response 201: Tương tự upload-csv.
Discovery — Quản Lý Sessions & Fields¶
GET /api/v1/discovery/sessions¶
Mục đích: Danh sách Discovery sessions, lọc theo đơn vị.
Phân quyền: Role: Manager
Query Parameters:
| Parameter | Kiểu | Bắt buộc | Mặc định | Mô tả |
|---|---|---|---|---|
| orgId | Long | Không | — | Lọc theo đơn vị |
| status | String | Không | — | Lọc: PROCESSING, COMPLETED, FAILED |
| page | Integer | Không | 0 | Trang |
| size | Integer | Không | 20 | Số item/trang |
| sort | String | Không | createdAt,desc | Sắp xếp |
Response 200: Danh sách phân trang Discovery sessions.
GET /api/v1/discovery/sessions/{id}/fields¶
Mục đích: Danh sách fields đã trích xuất từ một session (phân trang, tìm kiếm).
Phân quyền: Role: Manager
Query Parameters:
| Parameter | Kiểu | Bắt buộc | Mặc định | Mô tả |
|---|---|---|---|---|
| search | String | Không | — | Tìm theo tên field |
| tableName | String | Không | — | Lọc theo tên bảng |
| page | Integer | Không | 0 | Trang |
| size | Integer | Không | 50 | Số item/trang |
Response 200:
{
"success": true,
"data": {
"items": [
{
"id": 5001,
"tableName": "benh_nhan",
"columnName": "cccd_so",
"dataType": "VARCHAR(12)",
"nullable": false,
"description": null,
"sourceMethod": "SQL_DDL"
}
],
"meta": { "page": 0, "size": 50, "totalElements": 182 }
}
}
PUT /api/v1/discovery/fields/{id}¶
Mục đích: Chỉnh sửa field đã parse (nếu parse không chính xác).
Phân quyền: Role: Manager
Request Body:
Matching — Kích Hoạt & Kết Quả¶
POST /api/v1/matching/run¶
Mục đích: Kích hoạt AI matching cho một Discovery session. Job xử lý nền (async).
Tham chiếu: UC-MAP-001, Feature EP-03-004
Phân quyền: Role: Manager
Request Body:
Response 202 (Accepted):
{
"success": true,
"data": {
"sessionId": 1002,
"status": "PROCESSING",
"totalFields": 182,
"message": "Matching đang xử lý. Theo dõi tiến trình qua GET /matching/sessions/{id}/status"
}
}
Business Rules: - Session phải có status = COMPLETED (đã parse xong) - Idempotency: Nếu matching đã chạy cho session này → trả 200 với kết quả hiện có - Matching chạy nền qua Redis Queue, không chặn HTTP request
GET /api/v1/matching/sessions/{id}/status¶
Mục đích: Kiểm tra tiến trình matching.
Phân quyền: Role: Manager
Response 200:
{
"success": true,
"data": {
"sessionId": 1002,
"status": "COMPLETED",
"totalFields": 182,
"suggestedCount": 145,
"skippedCount": 37,
"processingTimeMs": 28500,
"completedAt": "2026-04-08T14:31:28+07:00"
}
}
GET /api/v1/matching/sessions/{id}/results¶
Mục đích: Danh sách kết quả matching chi tiết (phân trang).
Tham chiếu: UC-MAP-001, UC-MAP-002
Phân quyền: Role: Manager
Query Parameters:
| Parameter | Kiểu | Mô tả |
|---|---|---|
| status | String | Lọc: AI_SUGGESTED, AI_HIGH_CONFIDENCE, NO_MATCH, CONFIRMED, REJECTED |
| minScore | Float | Lọc: confidence score tối thiểu |
| page, size, sort | — | Phân trang chuẩn |
Response 200:
{
"success": true,
"data": {
"items": [
{
"id": 8001,
"fieldId": 5001,
"fieldName": "cccd_so",
"tableName": "benh_nhan",
"dataType": "VARCHAR(12)",
"suggestedDe": {
"id": 101,
"code": "DE001-DM1.1",
"name": "Số CCCD",
"domain": "Con người",
"subDomain": "Định danh"
},
"confidenceScore": 0.94,
"currentState": "AI_HIGH_CONFIDENCE",
"algoBreakdown": {
"scoreSynonym": 1.0,
"scoreTrigram": 0.87,
"scoreLevenshtein": 0.80,
"dataTypePenalty": false
}
}
],
"meta": { "page": 0, "size": 20, "totalElements": 182 }
}
}
Source Mapping — Manager Review¶
PATCH /api/v1/source-mappings/{id}/confirm¶
Mục đích: Manager xác nhận một match (field → Data Element).
Tham chiếu: UC-MAP-002
Phân quyền: Role: Manager
Request Body: Không cần (confirm match hiện tại)
Response 200:
{
"success": true,
"data": {
"id": 8001,
"currentState": "CONFIRMED",
"confirmedBy": "uuid-manager",
"confirmedAt": "2026-04-08T15:00:00+07:00"
}
}
Idempotency: Nếu đã CONFIRMED → trả 200 với data hiện tại, không lỗi.
PATCH /api/v1/source-mappings/{id}/override¶
Mục đích: Manager override match — chọn Data Element khác thay vì gợi ý AI.
Phân quyền: Role: Manager
Request Body:
{
"dataElementId": 205,
"reason": "AI gợi ý sai — field này thuộc DE 'Mã số thuế' không phải 'Số CCCD'"
}
Bản Đồ Hiện Trạng (Source Mapping Approval)¶
GET /api/v1/source-mappings/matrix¶
Mục đích: Ma trận Source Mapping — Data Element x Đơn vị. Trả về cấu trúc ma trận với trạng thái từng ô.
Tham chiếu: UC-MAP-003
Phân quyền:
- Role: Manager, Approver (xem toàn bộ)
- Policy: Data Owner → redirect sang /matrix/my-org
Query Parameters:
| Parameter | Kiểu | Mô tả |
|---|---|---|
| domainId | Long | Lọc theo Domain |
| orgId | Long | Lọc theo đơn vị |
| state | String | Lọc theo trạng thái ô |
| page, size | — | Phân trang (theo Data Elements) |
Response 200:
{
"success": true,
"data": {
"domains": ["DM1: Con người", "DM2: Tổ chức"],
"organizations": [
{ "id": 1, "name": "Công an", "code": "ID01.01" },
{ "id": 2, "name": "Sở Tài chính", "code": "ID01.02" }
],
"matrix": [
{
"dataElement": {
"id": 101, "code": "DE001-DM1.1", "name": "Số CCCD",
"domain": "Con người", "subDomain": "Định danh"
},
"cells": [
{ "orgId": 1, "state": "CONFIRMED", "confidenceScore": 0.94 },
{ "orgId": 2, "state": "EMPTY", "confidenceScore": null }
],
"overlapCount": 3,
"ownerProposal": { "orgId": 1, "orgName": "Công an" }
}
],
"meta": { "page": 0, "size": 20, "totalElements": 500 }
}
}
GET /api/v1/source-mappings/matrix/my-org¶
Mục đích: Chỉ hiển thị cột của đơn vị mình (read-only).
Tham chiếu: UC-CONFIRM-001
Phân quyền:
- Role: Data Owner
- Data Ownership: Tự động lọc theo org_id từ JWT — không thể xem đơn vị khác
Response 200: Tương tự /matrix nhưng cells chỉ chứa 1 đơn vị (đơn vị của user).
Xác Nhận Hiện Trạng — Data Owner¶
PATCH /api/v1/source-mappings/confirm-batch¶
Mục đích: Data Owner xác nhận đồng ý toàn bộ hoặc một phần hiện trạng đơn vị.
Tham chiếu: UC-CONFIRM-002
Phân quyền:
- Role: Data Owner
- Data Ownership: Chỉ xác nhận ô thuộc org_id mình
- State Guard: Chỉ xác nhận ô đang ở trạng thái cho phép (AI_SUGGESTED, AI_HIGH_CONFIDENCE, DATABASE)
Request Body:
Response 200:
PATCH /api/v1/source-mappings/{id}/dispute¶
Mục đích: Đánh dấu ô ma trận là DISPUTED khi không đồng ý với kết quả matching.
Tham chiếu: UC-CONFIRM-003
Phân quyền: - Role: Data Owner, Manager - Data Ownership: Data Owner chỉ dispute ô đơn vị mình; Manager dispute bất kỳ ô nào
Request Body:
{
"disputeNote": "Trường CCCD này không phải dữ liệu đơn vị chúng tôi quản lý, mà là do Công an cung cấp qua liên thông"
}
Validation:
- disputeNote bắt buộc, tối thiểu 20 ký tự
Response 200:
{
"success": true,
"data": {
"id": 8003,
"currentState": "DISPUTED",
"disputeNote": "...",
"disputedBy": "uuid-data-owner",
"disputedAt": "2026-04-08T16:00:00+07:00"
}
}
PATCH /api/v1/source-mappings/{id}/resolve¶
Mục đích: Approver giải quyết tranh chấp DISPUTED theo 1 trong 3 hướng.
Tham chiếu: UC-CONFIRM-004
Phân quyền: Role: Approver
Request Body:
{
"resolution": "CONFIRM_ORIGINAL",
"reason": "Sau khi họp kỹ thuật, xác nhận ánh xạ gốc là chính xác"
}
Phê Duyệt Hiện Trạng (Source Mapping Approval)¶
POST /api/v1/source-mapping-approval/approve¶
Mục đích: Approver phê duyệt ma trận hiện trạng (Source Mapping) tổng thể.
Tham chiếu: UC-CONFIRM-005
Phân quyền: Role: Approver
State Guard (HARD):
- confirmedOrgsPercent > 70% — Hơn 70% đơn vị đã xác nhận
- disputedCount = 0 — Không còn ô DISPUTED nào
- Vi phạm → 409 Conflict (hệ thống block)
Request Body:
Response 201 (Created):
{
"success": true,
"data": {
"id": 1,
"approvalVersion": 1,
"status": "APPROVED",
"confirmedOrgsPercent": 85.00,
"totalOrgsCount": 40,
"confirmedOrgsCount": 34,
"approvedAt": "2026-04-08T17:00:00Z",
"approvedBy": 5
}
}
Response 409 (guard vi phạm):
{
"success": false,
"error": {
"type": "BUSINESS_ERROR",
"code": "SOURCE_MAPPING_APPROVAL_DISPUTED_REMAINING",
"message": "Cannot approve source mapping: there are unresolved DISPUTED cells"
}
}
GET /api/v1/source-mapping-approval/status¶
Mục đích: Kiểm tra trạng thái phê duyệt và các chỉ số (metrics) hiện tại.
Phân quyền: Role: Manager, Approver
Response 200:
{
"success": true,
"data": {
"currentlyApproved": false,
"canApprove": true,
"blockingReason": null,
"confirmedOrgsPercent": 85.00,
"disputedCount": 0,
"confirmedOrgsCount": 34,
"totalOrgsCount": 40,
"currentApproval": null
}
}
POST /api/v1/source-mapping-approval/{id}/revoke¶
Mục đích: Thu hồi bản phê duyệt hiện tại (để cập nhật lại ma trận).
Phân quyền: Role: Approver
Request Body:
Response 200:
{
"success": true,
"data": {
"id": 1,
"status": "REVOKED",
"revokedAt": "2026-04-09T09:00:00Z",
"revokedBy": 5,
"revokeReason": "..."
}
}
GET /api/v1/source-mapping-approval/history¶
Mục đích: Xem lịch sử các lần phê duyệt và thu hồi.
Phân quyền: Role: Manager, Approver
Response 200: Danh sách phân trang SourceMappingApprovalResponse.
Cập nhật lần cuối: 2026-04-19