Knowledge Base Management API Documentation

Service: HPCN AI Agent Service
Base URL: /ai-service/api
Authentication: Traefik forward-auth headers (X-Auth-Email, X-Auth-User-ID, X-Auth-Work-Unit)


Table of Contents


Overview

Knowledge Base Management API cho phép quản lý danh mục (categories), cột dữ liệu (columns), và bản ghi (records) của Knowledge Base. Dữ liệu được lưu trữ trong MongoDB với hỗ trợ multi-tenant.

Hierarchy:

KBCategory (Danh mục: DM_XXX)
  ├── KBColumnDef (Cột: name, data_type, source_config)
  └── KBDataRecord (Bản ghi: DL_N, dynamic data)

Authentication

Tất cả requests đều yêu cầu Traefik forward-auth headers:

X-Auth-Email: user@company.com
X-Auth-User-ID: <uuid>
X-Auth-Work-Unit: <unit>
X-Tenant-Id: 2122030000

Tenant ID được trích xuất tự động từ headers. Không cần truyền vào URL hay body.


Common Response Format

Success Response

{
  "success": true,
  "data": [
    { "field1": "value1", ... }
  ],
  "length": 1,
  "total_record": 100
}

Error Response

{
  "success": false,
  "data": [],
  "length": 0,
  "error": "Lỗi mô tả chi tiết",
  "error_code": 7000000
}

Error Codes

Code Message Cause
MSG_0001 Tên danh mục/cột/bản ghi không được để trống Empty name field
MSG_0002 Danh mục đã tồn tại Duplicate category name in tenant
MSG_0007 Cột dữ liệu đã tồn tại Duplicate column name in category
MSG_0014 Không thể xóa danh mục. Danh mục hiện đang được sử dụng bởi: {names} Category is referenced by other columns
MSG_0015 Không thể xóa cột này. Cột dữ liệu hiện đang được sử dụng bởi: {names} Column is referenced by other columns

API Endpoints

Categories

1. List Categories (US_06_01)

GET /kb/categories

Description: Lấy danh sách tất cả danh mục của tenant, kèm statistics.

Query Parameters:

Name Type Default Description
page integer 1 Trang thứ mấy (1-indexed)
page_size integer 20 Số record/trang (1-100)
sort_by string created_at Sắp xếp theo: name, created_at, updated_at, category_code
sort_order string desc asc | desc
keyword string null Tìm kiếm trong name, description (contains, case-insensitive)

Response:

{
  "success": true,
  "data": [
    {
      "category_id": "507f1f77bcf86cd799439011",
      "category_code": "DM_LOAI_DICH_VU",
      "name": "Loại dịch vụ",
      "description": "Danh mục các loại dịch vụ",
      "so_cot": 5,
      "so_active": 15,
      "so_pending": 3,
      "tong_ban_ghi": 18,
      "created_at": "2026-06-15T10:30:00+00:00",
      "updated_by": "user@company.com"
    }
  ],
  "length": 1,
  "total_record": 15
}

Example:

curl -X GET "https://api.example.com/ai-service/api/kb/categories?page=1&page_size=20&keyword=loai" \
  -H "X-Auth-Email: user@company.com" \
  -H "X-Auth-User-ID: 550e8400-e29b-41d4-a716-446655440000" \
  -H "X-Tenant-Id: 2122030000"

2. Create Category (US_07_01_01)

POST /kb/categories

Description: Thêm mới danh mục. Mã danh mục (category_code) được auto-generate từ tên.

Request Body:

{
  "name": "Loại dịch vụ",
  "description": "Danh mục các loại dịch vụ (tùy chọn)"
}

Response:

{
  "success": true,
  "data": [
    {
      "category_id": "507f1f77bcf86cd799439011",
      "category_code": "DM_LOAI_DICH_VU",
      "name": "Loại dịch vụ"
    }
  ],
  "length": 1
}

Validation Rules:

Example:

curl -X POST "https://api.example.com/ai-service/api/kb/categories" \
  -H "Content-Type: application/json" \
  -H "X-Auth-Email: user@company.com" \
  -d '{
    "name": "Loại dịch vụ",
    "description": "Danh mục các loại dịch vụ"
  }'

3. Update Category (US_07_01_02)

PUT /kb/categories/{category_id}

Description: Sửa thông tin danh mục.

Path Parameters:

Name Type Description
category_id string MongoDB ObjectId của danh mục

Request Body:

{
  "name": "Tên danh mục mới (tùy chọn)",
  "description": "Mô tả danh mục mới (tùy chọn)"
}

Response:

{
  "success": true,
  "data": [
    {
      "category_id": "507f1f77bcf86cd799439011",
      "name": "Tên danh mục mới"
    }
  ],
  "length": 1
}

Example:

curl -X PUT "https://api.example.com/ai-service/api/kb/categories/507f1f77bcf86cd799439011" \
  -H "Content-Type: application/json" \
  -H "X-Auth-Email: user@company.com" \
  -d '{
    "name": "Loại dịch vụ (cập nhật)",
    "description": "Danh mục các loại dịch vụ - bản cập nhật"
  }'

4. Get Category References (US_07_01_03)

GET /kb/categories/{category_id}/references

Description: Kiểm tra danh mục có đang được tham chiếu bởi cột khác không. Dùng trước khi xóa.

Response:

{
  "success": true,
  "data": [
    {
      "type": "column",
      "column_id": "507f191e810c19729de860ea",
      "column_name": "Dropdown - Dịch vụ",
      "category_id": "507f1f77bcf86cd799439011"
    }
  ],
  "length": 1,
  "is_referenced": true
}

Example:

curl -X GET "https://api.example.com/ai-service/api/kb/categories/507f1f77bcf86cd799439011/references" \
  -H "X-Auth-Email: user@company.com"

5. Delete Category (US_07_01_03)

DELETE /kb/categories/{category_id}

Description: Xóa danh mục. Chỉ được phép nếu danh mục không được tham chiếu bởi bất kỳ cột nào. Xóa cascade: toàn bộ columns và records của danh mục.

Response:

{
  "success": true,
  "data": [
    {
      "category_id": "507f1f77bcf86cd799439011",
      "deleted": true
    }
  ],
  "length": 1
}

Error Response (nếu được tham chiếu):

{
  "success": false,
  "data": [],
  "length": 0,
  "error": "Không thể xóa danh mục. Danh mục hiện đang được sử dụng bởi: Dropdown - Dịch vụ"
}

Example:

curl -X DELETE "https://api.example.com/ai-service/api/kb/categories/507f1f77bcf86cd799439011" \
  -H "X-Auth-Email: user@company.com"

Columns

1. List Columns by Category (US_06_01)

GET /kb/categories/{category_id}/columns

Description: Lấy danh sách cột của một danh mục.

Response:

{
  "success": true,
  "data": [
    {
      "column_id": "507f191e810c19729de860ea",
      "name": "Tên dịch vụ",
      "data_type": "textbox",
      "required": true,
      "description": "Tên của dịch vụ",
      "order": 1,
      "source_config": null,
      "updated_at": "2026-06-15T10:30:00+00:00",
      "updated_by": "user@company.com"
    },
    {
      "column_id": "507f191e810c19729de860eb",
      "name": "Loại dịch vụ",
      "data_type": "dropdown",
      "required": false,
      "description": "Phân loại dịch vụ",
      "order": 2,
      "source_config": {
        "type": "data_source",
        "category_id": "507f1f77bcf86cd799439012",
        "display_column_id": "507f191e810c19729de860ec"
      }
    }
  ],
  "length": 2
}

2. Create Column (US_07_02_01)

POST /kb/categories/{category_id}/columns

Description: Thêm mới cột vào danh mục.

Request Body:

{
  "name": "Tên cột",
  "data_type": "textbox",
  "required": false,
  "description": "Mô tả cột (tùy chọn)",
  "order": 1,
  "source_config": null
}

Parameters:

Field Type Required Options Description
name string Tên cột, unique per category
data_type string textbox, textarea, number, dropdown, multi_select, email Kiểu dữ liệu
required boolean true/false Default: false
description string Mô tả cột
order integer Thứ tự hiển thị (default: 0)
source_config object Cấu hình datasource cho dropdown/multi_select

source_config Schema:

Type 1: Dropdown/Multi_select từ danh mục khác (data_source)

{
  "type": "data_source",
  "category_id": "507f1f77bcf86cd799439012",
  "display_column_id": "507f191e810c19729de860ec"
}

Type 2: Dropdown/Multi_select manual (hardcoded)

{
  "type": "manual",
  "values": ["Option 1", "Option 2", "Option 3"]
}

Response:

{
  "success": true,
  "data": [
    {
      "column_id": "507f191e810c19729de860ea",
      "name": "Tên dịch vụ",
      "data_type": "textbox"
    }
  ],
  "length": 1
}

Examples:

Textbox đơn giản:

curl -X POST "https://api.example.com/ai-service/api/kb/categories/507f1f77bcf86cd799439011/columns" \
  -H "Content-Type: application/json" \
  -H "X-Auth-Email: user@company.com" \
  -d '{
    "name": "Tên dịch vụ",
    "data_type": "textbox",
    "required": true,
    "order": 1
  }'

Dropdown từ danh mục khác:

curl -X POST "https://api.example.com/ai-service/api/kb/categories/507f1f77bcf86cd799439011/columns" \
  -H "Content-Type: application/json" \
  -H "X-Auth-Email: user@company.com" \
  -d '{
    "name": "Loại dịch vụ",
    "data_type": "dropdown",
    "source_config": {
      "type": "data_source",
      "category_id": "507f1f77bcf86cd799439012",
      "display_column_id": "507f191e810c19729de860ec"
    },
    "order": 2
  }'

Dropdown manual:

curl -X POST "https://api.example.com/ai-service/api/kb/categories/507f1f77bcf86cd799439011/columns" \
  -H "Content-Type: application/json" \
  -H "X-Auth-Email: user@company.com" \
  -d '{
    "name": "Mức độ ưu tiên",
    "data_type": "dropdown",
    "source_config": {
      "type": "manual",
      "values": ["Thấp", "Trung bình", "Cao", "Cấp bách"]
    },
    "order": 3
  }'

3. Update Column (US_07_02_02)

PUT /kb/categories/{category_id}/columns/{column_id}

Description: Sửa thông tin cột.

Request Body:

{
  "name": "Tên cột mới (tùy chọn)",
  "data_type": "textbox",
  "required": true,
  "description": "Mô tả mới",
  "order": 2,
  "source_config": null
}

Response:

{
  "success": true,
  "data": [
    {
      "column_id": "507f191e810c19729de860ea",
      "name": "Tên cột mới"
    }
  ],
  "length": 1
}

4. Get Column References (US_07_02_03)

GET /kb/categories/{category_id}/columns/{column_id}/references

Description: Kiểm tra cột có đang được tham chiếu bởi cột khác không (trong source_config).

Response:

{
  "success": true,
  "data": [
    {
      "type": "column",
      "column_id": "507f191e810c19729de860eb",
      "column_name": "Loại dịch vụ (dropdown)",
      "category_id": "507f1f77bcf86cd799439011"
    }
  ],
  "length": 1,
  "is_referenced": true
}

5. Delete Column (US_07_02_03)

DELETE /kb/categories/{category_id}/columns/{column_id}

Description: Xóa cột. Chỉ được phép nếu không được tham chiếu bởi cột khác.

Response:

{
  "success": true,
  "data": [
    {
      "column_id": "507f191e810c19729de860ea",
      "deleted": true
    }
  ],
  "length": 1
}

6. Clone Column (US_07_02_04)

POST /kb/categories/{category_id}/columns/{column_id}/clone

Description: Nhân bản cột. Tên mới = tên cũ + "_copy" (nếu trùng thêm số).

Response:

{
  "success": true,
  "data": [
    {
      "column_id": "507f191e810c19729de860ed",
      "name": "Tên dịch vụ_copy"
    }
  ],
  "length": 1
}

Records

1. List Records by Category (US_06_01/02/03)

GET /kb/categories/{category_id}/records

Description: Lấy danh sách bản ghi của một danh mục, hỗ trợ filter, search, sort.

Query Parameters:

Name Type Default Description
page integer 1 Trang thứ mấy
page_size integer 20 Số record/trang
sort_by string created_at Sắp xếp theo: created_at, updated_at, record_code
sort_order string desc asc | desc
status string null pending | active
updated_by string null Filter theo user update (email hoặc "system")
created_from date null Từ ngày (YYYY-MM-DD)
created_to date null Đến ngày
updated_from date null Từ ngày cập nhật
updated_to date null Đến ngày cập nhật
keyword string null Tìm kiếm full-text trên tất cả fields trong data dict

Response:

{
  "success": true,
  "data": [
    {
      "record_id": "507f191e810c19729de860ee",
      "record_code": "DL_1",
      "data": {
        "Tên dịch vụ": "Tư vấn kỹ thuật",
        "Loại dịch vụ": "Dịch vụ hỗ trợ",
        "Mức độ ưu tiên": "Cao"
      },
      "business_status": "active",
      "created_at": "2026-06-15T10:30:00+00:00",
      "updated_at": "2026-06-16T14:20:00+00:00",
      "updated_by": "user@company.com"
    }
  ],
  "length": 1,
  "total_record": 50
}

Example:

curl -X GET "https://api.example.com/ai-service/api/kb/categories/507f1f77bcf86cd799439011/records?page=1&status=active&keyword=tư+vấn" \
  -H "X-Auth-Email: user@company.com"

2. Create Record (US_07_03_01)

POST /kb/categories/{category_id}/records

Description: Thêm mới bản ghi. Record được tạo với trạng thái "pending". Mã record (record_code) được auto-generate.

Request Body:

{
  "data": {
    "Tên dịch vụ": "Tư vấn kỹ thuật",
    "Loại dịch vụ": "Dịch vụ hỗ trợ",
    "Mức độ ưu tiên": "Cao"
  }
}

Validation:

Response:

{
  "success": true,
  "data": [
    {
      "record_id": "507f191e810c19729de860ee",
      "record_code": "DL_51",
      "business_status": "pending"
    }
  ],
  "length": 1
}

Example:

curl -X POST "https://api.example.com/ai-service/api/kb/categories/507f1f77bcf86cd799439011/records" \
  -H "Content-Type: application/json" \
  -H "X-Auth-Email: user@company.com" \
  -d '{
    "data": {
      "Tên dịch vụ": "Tư vấn kỹ thuật",
      "Loại dịch vụ": "Dịch vụ hỗ trợ",
      "Mức độ ưu tiên": "Cao"
    }
  }'

3. Update Record (US_07_03_02)

PUT /kb/categories/{category_id}/records/{record_id}

Description: Sửa bản ghi (chỉ field data, status không đổi).

Request Body:

{
  "data": {
    "Tên dịch vụ": "Tư vấn kỹ thuật (cập nhật)",
    "Loại dịch vụ": "Dịch vụ hỗ trợ"
  }
}

Response:

{
  "success": true,
  "data": [
    {
      "record_id": "507f191e810c19729de860ee",
      "record_code": "DL_51"
    }
  ],
  "length": 1
}

4. Activate Records (US_07_03_03)

PUT /kb/categories/{category_id}/records/activate

Description: Kích hoạt bản ghi (pending → active). Trigger ingest vào vector store. Bulk operation.

Request Body:

{
  "record_ids": [
    "507f191e810c19729de860ee",
    "507f191e810c19729de860ef"
  ]
}

Response:

{
  "success": true,
  "data": [
    {
      "activated_count": 2,
      "ingest_count": 2,
      "batch_id": "batch_20260616_001"
    }
  ],
  "length": 1
}

Notes:


5. Deactivate Records (US_07_03_04)

PUT /kb/categories/{category_id}/records/deactivate

Description: Vô hiệu hóa bản ghi (active → pending). Bulk operation.

Request Body:

{
  "record_ids": [
    "507f191e810c19729de860ee"
  ]
}

Response:

{
  "success": true,
  "data": [
    {
      "deactivated_count": 1
    }
  ],
  "length": 1
}

Data Models

KBCategory

interface KBCategory {
  category_id: string;           // MongoDB ObjectId
  category_code: string;         // DM_XXX (auto-generated)
  name: string;                  // Tên danh mục (unique per tenant)
  description?: string;          // Mô tả
  created_at: string;            // ISO 8601 timestamp
  created_by: string;            // Email người tạo
  updated_at: string;            // ISO 8601 timestamp
  updated_by: string;            // Email người cập nhật
}

KBColumnDef

type ColumnDataType = 
  | "textbox"
  | "textarea"
  | "number"
  | "dropdown"
  | "multi_select"
  | "email";

interface KBColumnDef {
  column_id: string;             // MongoDB ObjectId
  category_id: string;           // Reference to KBCategory._id
  name: string;                  // Tên cột (unique per category)
  data_type: ColumnDataType;     // Kiểu dữ liệu
  required: boolean;             // Có bắt buộc hay không
  description?: string;          // Mô tả
  order: number;                 // Thứ tự hiển thị
  source_config?: {
    type: "data_source" | "manual";
    // For data_source:
    category_id?: string;        // Reference category
    display_column_id?: string;  // Display column
    // For manual:
    values?: string[];           // Hardcoded options
  };
  created_at: string;
  created_by: string;
  updated_at: string;
  updated_by: string;
}

KBDataRecord

type BusinessStatus = "pending" | "active";

interface KBDataRecord {
  record_id: string;             // MongoDB ObjectId
  record_code: string;           // DL_N (auto-generated)
  category_id: string;           // Reference to KBCategory._id
  data: {
    [key: string]: any;          // Dynamic fields per column
  };
  business_status: BusinessStatus;
  created_at: string;
  created_by: string;
  updated_at: string;
  updated_by: string;
}

Integration Examples

Example 1: Create Category with Columns and Records

// 1. Create category
const categoryRes = await fetch('/ai-service/api/kb/categories', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Auth-Email': 'user@company.com',
    'X-Auth-User-ID': 'xxx',
    'X-Tenant-Id': '2122030000'
  },
  body: JSON.stringify({
    name: "Loại dịch vụ",
    description: "Danh mục các loại dịch vụ"
  })
});
const category = await categoryRes.json();
const categoryId = category.data[0].category_id;

// 2. Create columns
const col1Res = await fetch(
  `/ai-service/api/kb/categories/${categoryId}/columns`,
  {
    method: 'POST',
    headers: { /* ... */ },
    body: JSON.stringify({
      name: "Tên dịch vụ",
      data_type: "textbox",
      required: true,
      order: 1
    })
  }
);

// 3. Create record
const recordRes = await fetch(
  `/ai-service/api/kb/categories/${categoryId}/records`,
  {
    method: 'POST',
    headers: { /* ... */ },
    body: JSON.stringify({
      data: {
        "Tên dịch vụ": "Tư vấn kỹ thuật"
      }
    })
  }
);
const record = await recordRes.json();
console.log('Record created:', record.data[0].record_code); // DL_1

// 4. Activate record
await fetch(
  `/ai-service/api/kb/categories/${categoryId}/records/activate`,
  {
    method: 'PUT',
    headers: { /* ... */ },
    body: JSON.stringify({
      record_ids: [record.data[0].record_id]
    })
  }
);

Example 2: Create Dropdown with Data Source

// Create dropdown that pulls data from another category
const dropdownRes = await fetch(
  `/ai-service/api/kb/categories/cat-main-id/columns`,
  {
    method: 'POST',
    headers: { /* ... */ },
    body: JSON.stringify({
      name: "Loại dịch vụ",
      data_type: "dropdown",
      source_config: {
        type: "data_source",
        category_id: "cat-service-type-id",
        display_column_id: "col-service-name-id"
      }
    })
  }
);

Example 3: Search Records with Filters

// Search for records created in June 2026, status active
const searchRes = await fetch(
  `/ai-service/api/kb/categories/cat-id/records?` +
  `status=active&` +
  `created_from=2026-06-01&` +
  `created_to=2026-06-30&` +
  `keyword=tư+vấn&` +
  `page=1&page_size=50`,
  {
    headers: { /* ... */ }
  }
);
const results = await searchRes.json();
console.log(`Total records: ${results.total_record}`);

Best Practices

  1. Always validate tenant context: Endpoints automatically filter by tenant from headers. Never pass tenant_id in URL.

  2. Handle pagination: Implement pagination in FE to avoid loading too many records at once.

  3. Check references before delete: Always call GET references endpoint before DELETE to prevent errors.

  4. Bulk activate/deactivate: Use bulk endpoints for multiple records to avoid N+1 requests.

  5. Error handling: Always check success field in response. Don't assume success based on HTTP 200.

  6. Audit trail: All modifications (create/update/delete) are logged in KBAuditLog collection with actor email and before/after data.


Last Updated: 2026-06-22
API Version: 1.0