Bỏ qua

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 File CSV (max 50MB, phải có header row)
orgId Long ID đơn vị Sở/Ban/Ngành sở hữu dữ liệu
systemName String 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 File .sql (max 50MB, chỉ DDL — DML bị bỏ qua)
orgId Long ID đơn vị
systemName String 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:

{
  "columnName": "cccd_number",
  "dataType": "VARCHAR(12)",
  "description": "Số căn cước công dân"
}

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:

{
  "sessionId": 1002
}

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:

{
  "mappingIds": [8001, 8002, 8003, 8005]
}

Response 200:

{
  "success": true,
  "data": {
    "confirmed": 4,
    "skipped": 0,
    "message": "Đã xác nhận 4 ô"
  }
}

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:

{
  "approvalNote": "Phê duyệt ma trận sau khi toàn bộ tranh chấp đã giải quyết"
}

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:

{
  "revokeReason": "Cần cập nhật lại ánh xạ của Sở X do có thay đổi hệ thống nguồn"
}

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