Bỏ qua

Thuộc Tài Liệu API — EP-01: Xác thực & Quản trị Hệ thống

API Chi Tiết — EP-01: Xác Thực & Quản Trị Hệ Thống

Use Cases: UC-AUTH-001, UC-SYS-001, UC-SYS-002, UC-SYS-003, UC-SYS-004 Module: module-auth, module-admin


Xác Thực (Auth)

POST /api/v1/auth/login

Mục đích: Khởi tạo luồng đăng nhập — redirect đến Keycloak login page.

Tham chiếu: UC-AUTH-001, Feature EP-01-001

Xác thực: Không (public endpoint)

Ghi chú: Frontend sử dụng Keycloak PKCE flow trực tiếp. Endpoint này là helper để lấy URL redirect.

Response 200:

{
  "success": true,
  "data": {
    "loginUrl": "https://keycloak.tdl.gov.vn/realms/tdl-realm/protocol/openid-connect/auth?client_id=tdl-frontend&response_type=code&..."
  }
}

POST /api/v1/auth/refresh

Mục đích: Làm mới JWT access token bằng refresh token.

Xác thực: Không (dùng refresh token)

Request Body:

{
  "refreshToken": "eyJhbGciOiJSUzI1NiIs..."
}

Response 200:

{
  "success": true,
  "data": {
    "accessToken": "eyJhbGciOiJSUzI1NiIs...",
    "refreshToken": "eyJhbGciOiJSUzI1NiIs...",
    "expiresIn": 300
  }
}

Response 401: Refresh token hết hạn — client redirect về login.


POST /api/v1/auth/logout

Mục đích: Đăng xuất — revoke token tại Keycloak.

Xác thực: Bearer Token

Request Body:

{
  "refreshToken": "eyJhbGciOiJSUzI1NiIs..."
}

Response 204: No content — đăng xuất thành công.


Quản Lý Người Dùng

GET /api/v1/users

Mục đích: Danh sách người dùng (phân trang, tìm kiếm).

Tham chiếu: UC-SYS-001, Feature EP-01-002

Phân quyền: Role: Admin

Query Parameters:

Parameter Kiểu Bắt buộc Mặc định Mô tả
search String Không Tìm theo tên, email
orgId Long Không Lọc theo đơn vị
role String Không Lọc theo vai trò
status String Không Lọc: ACTIVE, INACTIVE, PENDING
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:

{
  "success": true,
  "data": {
    "content": [
      {
        "id": 1,
        "email": "nguyen.van.a@soyte.gov.vn",
        "fullName": "Nguyễn Văn A",
        "orgUnit": { "id": 5, "name": "Sở Y tế", "code": "ID01.05" },
        "roles": ["DATA_OWNER"],
        "status": "ACTIVE",
        "ssoLinked": false,
        "createdAt": "2026-04-01T10:00:00+07:00",
        "lastLoginAt": "2026-04-08T08:30:00+07:00"
      }
    ],
    "pageable": {
      "sort": { "sorted": true, "unsorted": false, "empty": false },
      "offset": 0,
      "pageNumber": 0,
      "pageSize": 20,
      "paged": true,
      "unpaged": false
    },
    "totalPages": 18,
    "totalElements": 350,
    "last": false,
    "size": 20,
    "number": 0,
    "sort": { "sorted": true, "unsorted": false, "empty": false },
    "numberOfElements": 1,
    "first": true,
    "empty": false
  }
}

POST /api/v1/users

Mục đích: Tạo mới người dùng (pre-provisioning trước khi user đăng nhập SSO).

Tham chiếu: UC-SYS-001

Phân quyền: Role: Admin

Request Body:

{
  "email": "nguyen.van.b@soyte.gov.vn",
  "fullName": "Nguyễn Văn B",
  "orgUnitId": 5,
  "roles": ["DATA_OWNER"],
  "status": "ACTIVE"
}

Validation: - email bắt buộc, format email hợp lệ, unique - fullName bắt buộc - orgUnitId bắt buộc, phải tồn tại trong cây tổ chức - roles bắt buộc, ít nhất 1 vai trò hợp lệ

Response 201: User đã tạo. Khi user đăng nhập SSO lần đầu, hệ thống mapping bằng email.

Response 409: Email đã tồn tại.


GET /api/v1/users/{id}

Mục đích: Chi tiết người dùng.

Phân quyền: Role: Admin

Response 200:

{
  "success": true,
  "data": {
    "id": 1,
    "email": "nguyen.van.a@soyte.gov.vn",
    "fullName": "Nguyễn Văn A",
    "orgUnit": { "id": 5, "name": "Sở Y tế", "code": "ID01.05" },
    "unit": { "id": 51, "name": "Phòng Nghiệp vụ Y", "code": "ID01.05.01" },
    "roles": ["DATA_OWNER"],
    "status": "ACTIVE",
    "ssoLinked": false,
    "createdAt": "2026-04-01T10:00:00+07:00",
    "lastLoginAt": "2026-04-08T08:30:00+07:00"
  }
}

PUT /api/v1/users/{id}

Mục đích: Cập nhật thông tin người dùng.

Phân quyền: Role: Admin

Request Body:

{
  "fullName": "Nguyễn Văn A (đã cập nhật)",
  "orgUnitId": 5,
  "unitId": 51
}

Ghi chú: Không thể thay đổi email (email là mapping key với SSO).


PATCH /api/v1/users/{id}/status

Mục đích: Thay đổi trạng thái tài khoản (active/inactive).

Phân quyền: Role: Admin

Request Body:

{
  "status": "INACTIVE",
  "reason": "Chuyển công tác"
}

Business Rules: - Admin không thể deactivate chính mình → 422 SELF_DEACTIVATE_FORBIDDEN


DELETE /api/v1/users/{id}

Mục đích: Xóa tài khoản người dùng.

Phân quyền: Role: Admin

Business Rules: - Admin không thể xóa chính mình → 422 SELF_DELETE_FORBIDDEN - User có dữ liệu audit liên quan → soft-delete (chuyển INACTIVE), không hard-delete

Response 204: Xóa thành công.


Phân Quyền Vai Trò

GET /api/v1/users/{id}/roles

Mục đích: Xem danh sách vai trò hiện tại của user.

Tham chiếu: UC-SYS-002, Feature EP-01-003

Phân quyền: Role: Admin

Response 200:

{
  "success": true,
  "data": {
    "id": 1,
    "roles": [
      {
        "role": "DATA_OWNER",
        "assignedAt": "2026-04-01T10:00:00+07:00",
        "assignedBy": "uuid-admin"
      }
    ],
    "availableRoles": ["MANAGER", "DATA_OWNER", "APPROVER", "STAFF", "ADMIN"]
  }
}

PUT /api/v1/users/{id}/roles

Mục đích: Gán/cập nhật vai trò cho user. Hỗ trợ multi-role.

Phân quyền: Role: Admin

Request Body:

{
  "roles": ["DATA_OWNER", "MANAGER"]
}

Business Rules: - Ít nhất 1 vai trò - Vai trò phải nằm trong danh sách hợp lệ - Thay đổi vai trò được ghi audit log

Response 200: Vai trò đã cập nhật.


Quản Lý Cây Tổ Chức

GET /api/v1/org-units

Mục đích: Danh sách cây tổ chức (toàn bộ hoặc lọc).

Tham chiếu: UC-SYS-003, Feature EP-01-004

Phân quyền: Role: Admin, Manager

Query Parameters:

Parameter Kiểu Mô tả
parentId Long Lọc con trực tiếp của đơn vị cha
search String Tìm theo tên hoặc mã
format String tree (cây phân cấp) hoặc flat (danh sách phẳng, mặc định)

Response 200 (format=tree):

{
  "success": true,
  "data": [
    {
      "id": 1,
      "code": "ID01.01",
      "name": "Công an TP",
      "children": [
        {
          "id": 11,
          "code": "ID01.01.01",
          "name": "Phòng CS QLHC về TTXH",
          "children": []
        }
      ]
    }
  ]
}

Response 200 (format=flat):

{
  "success": true,
  "data": {
    "content": [
      {
        "id": 1,
        "code": "ID01.01",
        "name": "Công an TP",
        "level": "TINH",
        "parentId": null,
        "active": true
      }
    ],
    "pageable": {
      "sort": { "sorted": true, "unsorted": false, "empty": false },
      "offset": 0,
      "pageNumber": 0,
      "pageSize": 50,
      "paged": true,
      "unpaged": false
    },
    "totalPages": 1,
    "totalElements": 15,
    "last": true,
    "size": 50,
    "number": 0,
    "sort": { "sorted": true, "unsorted": false, "empty": false },
    "numberOfElements": 15,
    "first": true,
    "empty": false
  }
}

POST /api/v1/org-units

Mục đích: Tạo đơn vị mới trong cây tổ chức.

Phân quyền: Role: Admin

Request Body:

{
  "code": "ID01.05.02",
  "name": "Phòng Y tế Dự phòng",
  "parentId": 5
}

Validation: - code bắt buộc, unique, format IDxx.xx.xx - name bắt buộc - parentId phải tồn tại (nếu có)

Response 201: Đơn vị đã tạo.


PUT /api/v1/org-units/{id}

Mục đích: Cập nhật thông tin đơn vị.

Phân quyền: Role: Admin

Request Body:

{
  "name": "Phòng Y tế Dự phòng (đổi tên)",
  "isActive": true
}

Ghi chú: Mã đơn vị (code) không thể thay đổi sau khi tạo.


DELETE /api/v1/org-units/{id}

Mục đích: Xóa đơn vị.

Phân quyền: Role: Admin

Business Rules: - Đơn vị có đơn vị con → 422 ORG_UNIT_HAS_CHILDREN - Đơn vị có user liên kết → 422 ORG_UNIT_HAS_USERS


PATCH /api/v1/org-units/{id}/move

Mục đích: Thay đổi vị trí đơn vị trong cây (đổi cha).

Phân quyền: Role: Admin

Request Body:

{
  "newParentId": 3
}

Business Rules: - Không thể di chuyển thành con của chính mình (circular reference) → 422


POST /api/v1/org-units/import

Mục đích: Import cây tổ chức từ file CSV.

Phân quyền: Role: Admin

Request: multipart/form-data

Field Kiểu Bắt buộc Mô tả
file File CSV với cột: code, name, parentCode

Response 200:

{
  "success": true,
  "data": {
    "imported": 45,
    "skipped": 2,
    "errors": [
      { "row": 15, "code": "ID01.99", "reason": "parentCode ID01.50 không tồn tại" }
    ]
  }
}

Master Data & Seed

POST /api/v1/master-data/seed

Mục đích: Import Master Data (Domain, Sub Domain, Data Element cốt lõi) từ CSV khi triển khai lần đầu.

Tham chiếu: UC-SYS-004, Feature EP-01-005

Phân quyền: Role: Admin

Request: multipart/form-data

Field Kiểu Bắt buộc Mô tả
file File CSV theo template (type, code, name, parentCode, description)
type String DOMAIN, SUB_DOMAIN, DATA_ELEMENT, ORG_UNIT

Response 200:

{
  "success": true,
  "data": {
    "type": "DATA_ELEMENT",
    "imported": 120,
    "skipped": 3,
    "errors": [
      { "row": 55, "reason": "Sub Domain DM1.99 không tồn tại" }
    ]
  }
}

GET /api/v1/master-data/catalogs

Mục đích: Danh sách danh mục dùng chung (kiểu dữ liệu, sensitivity level, trạng thái...).

Phân quyền: Role: Admin

Response 200:

{
  "success": true,
  "data": {
    "dataTypes": ["VARCHAR", "INTEGER", "BOOLEAN", "DATE", "TIMESTAMP", "JSONB", "TEXT"],
    "sensitivityLevels": ["PUBLIC", "INTERNAL", "CONFIDENTIAL", "SECRET"],
    "deStatuses": ["DRAFT", "IN_REVIEW", "APPROVED", "PUBLISHED"],
    "discoveryMethods": ["CSV", "SQL_DDL", "MANUAL"]
  }
}

Hệ Thống (Cross-cutting)

GET /api/v1/me

Mục đích: Thông tin user hiện tại (profile + vai trò + đơn vị).

Phân quyền: Tất cả user đã đăng nhập

Response 200:

{
  "success": true,
  "data": {
    "id": 1,
    "email": "nguyen.van.a@soyte.gov.vn",
    "fullName": "Nguyễn Văn A",
    "orgUnit": { "id": 5, "name": "Sở Y tế", "code": "ID01.05" },
    "unit": { "id": 51, "name": "Phòng Nghiệp vụ Y", "code": "ID01.05.01" },
    "roles": ["DATA_OWNER", "MANAGER"],
    "activeRole": "DATA_OWNER",
    "permissions": ["VIEW_OWN_ORG_MAPPING", "CONFIRM_MAPPING", "DISPUTE_OWN_ORG"]
  }
}

POST /api/v1/me/switch-role

Mục đích: Chuyển đổi vai trò active (cho user multi-role).

Request Body:

{
  "role": "MANAGER"
}

Business Rules: - Vai trò phải nằm trong danh sách vai trò đã gán cho user - Menu/quyền thay đổi theo vai trò active

Response 200: Vai trò đã chuyển, trả thông tin profile mới.


Cập nhật lần cuối: 2026-04-08