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:
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:
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:
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:
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:
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
}
}
¶
{
"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:
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:
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:
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 | Có | 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 | Có | CSV theo template (type, code, name, parentCode, description) |
| type | String | Có | 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:
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