1. Search API
Search Tool
  • Tổng quan Cấu trúc Hệ thống
  • Bussiness | Logic
    • Nghiệp vụ & Luồng Tìm kiếm
  • Project
    • Search API
      • Tổng quan
      • Architecture
        • User Guide
        • Database Schema
        • System Architecture
        • Code Structure
      • Deployment
        • Product
      • API Interface
        • Tài liệu Tham khảo API
        • Go - Auth
          • Đăng nhập
          • Đăng ký (Public)
        • Go - User
          • Danh sách User (Phân trang)
          • Tạo User
          • Lấy tất cả User
          • Profile cá nhân
          • Chi tiết User
          • Cập nhật User
          • Xóa User
          • Đổi mật khẩu
        • Go - System
          • Nhật ký hoạt động (Phân trang)
          • Cập nhật dữ liệu Search
          • Test Webhook receiver
        • Go - Server
          • Danh sách Server (Phân trang)
          • Tạo Server
          • Lấy tất cả Server
          • Chi tiết Server
          • Cập nhật Server
          • Xóa Server
        • Go - Tasks
          • Tạo nhiều task Search
          • Lấy tất cả task Search
          • Reset trạng thái tất cả nhiệm vụ Search
          • Tạo nhiều task Anchor Text
          • Lấy tất cả nhiệm vụ Anchor Text
          • Reset trạng thái tất cả nhiệm vụ Anchor Text
        • Go - Webhook
          • Webhook cập nhật trạng thái (Dùng WEBHOOK_KEY)
          • Lấy Proxy cho Tool
          • Lấy Proxy có thể rotate
          • Cập nhật kết quả Search
          • Kết quả rotate Proxy
          • Cập nhật kết quả Anchor Text
          • Nhận kết quả từ Tool (v2)
        • Bun - Main
          • Thông tin server Bun
          • Health Check
          • Lấy file Log
        • Bun - Task
          • Danh sách Search Tasks
          • Tạo nhiều Search Tasks
          • Xóa tất cả Search Tasks
          • Xóa Search Task
          • Reset trạng thái Search
          • Reset running process
          • Danh sách Anchor Tasks
          • Tạo nhiều Anchor Tasks
          • Xóa tất cả Anchor Tasks
          • Xóa Anchor Task
          • Reset trạng thái Anchor
          • Reset running process
    • Search tool
      • Tổng quan
      • Architecture
        • User Guide
        • Database Schema
        • System Architecture
        • Code Structure
      • Deployment
        • Product
  • Schemas
    • LoginRequest
    • ProxyRequest
    • CreateUserRequest
    • KeywordTaskRequest
    • UpdateUserRequest
    • SearchAutomationRequest
    • ChangePasswordRequest
    • CreateServerRequest
    • AnchorTextTaskRequest
  1. Search API

Tổng quan

Search Tool API — Technical Documentation#

Stack: Go 1.22 · Fiber v2 · GORM · MongoDB Driver · Redis · JWT · Uber Dig (DI) · gocron
Module name: tool-search-api
Default port: 33003

1. Hướng Dẫn Sử Dụng (Local Development)#

1.1 Yêu Cầu Hệ Thống#

Công cụPhiên bản tối thiểu
Go1.22+
Docker & Docker ComposeLatest
Make (tùy chọn)Any

1.2 Cài Đặt & Chạy Local#

Bước 1 — Vào thư mục project API và copy file môi trường:
Bước 2 — Cấu hình .env: Chỉnh sửa file .env theo hướng dẫn ở mục 1.3.
Bước 3 — Khởi động các service nền bằng Docker:
Lệnh này sẽ khởi động: MySQL, MongoDB, Redis.
Bước 4 — Chạy ứng dụng:
Bước 5 — Kiểm tra:
GET http://localhost:33003/
# Trả về: {"message": "Hello, World API!"}

1.3 Biến Môi Trường (.env)#

BiếnVí dụMô tả
APP_MODEdevelopmentChế độ chạy (development / production)
AUTO_MIGRATE_DATABASEtrueTự động migrate schema MySQL khi khởi động
SERVER_PORT33003Port HTTP server lắng nghe
API_KEYB7j&Kq9G...API Key xác thực nội bộ
DB_MONGO_HOSTsearch_api_mongodbHost MongoDB (tên container khi dùng Docker)
DB_MONGO_PORT27017Port MongoDB
DB_MONGO_USERrootUsername MongoDB
DB_MONGO_PASSPwDev123Password MongoDB
DB_MONGO_NAMEsearch-api-mongodbTên database MongoDB
DB_MYSQL_HOSTsearch_api_mysqlHost MySQL
DB_MYSQL_PORT3306Port MySQL
DB_MYSQL_USERrootUsername MySQL
DB_MYSQL_PASSPwDev123Password MySQL
DB_MYSQL_NAMEsearch-api-mysqlTên database MySQL
REDIS_HOSTsearch_api_redisHost Redis
REDIS_PORT6379Port Redis
REDIS_USER(empty)Username Redis
REDIS_PASS(empty)Password Redis
REDIS_DB0Index database Redis
JWT_SECRETsecret-keySecret key để ký JWT token
ENABLE_PUSH_MESSAGE_ERROR_TO_TELEGRAMtrueBật/tắt thông báo lỗi qua Telegram
PROXY_USE_MAX2Số lần proxy được sử dụng tối đa
PROXY_ROTATE_MAX_CONCURRENT1Số luồng rotate proxy đồng thời tối đa
API_SEARCH_TOKEN6MuRot4V...Token xác thực cho tool search gọi vào API
WEBHOOK_HOSThttp://127.0.0.1:33003Base URL của chính server này (dùng trong webhook)
WEBHOOK_TASK_UPDATE_STATUS_URL.../webhook/task/update-statusURL webhook cập nhật trạng thái task
WEBHOOK_PROXY_GET_PROXY_URL.../webhook/proxy/get-proxyURL webhook lấy proxy
WEBHOOK_KEY255d00cc...Secret key để xác thực webhook request
WEBHOOK_URL.../webhook/task/update-processURL webhook cập nhật tiến trình task
WEBHOOK_UPDATE_SEARCH_RESULT.../webhook/update-search-resultURL webhook cập nhật kết quả tìm kiếm
WEBHOOK_UPDATE_SEARCH_ANCHOR_TEXT.../webhook/update-search-anchor-textURL webhook cập nhật anchor text
TELEGRAM_BOT_TOKEN(cần điền)Token Telegram Bot
TELEGRAM_CHAT_ID(cần điền)Chat ID nhận thông báo thông thường
TELEGRAM_CHAT_ERROR_ID(cần điền)Chat ID nhận thông báo lỗi
TELEGRAM_CHAT_REPORT_ID(cần điền)Chat ID nhận báo cáo
SCHEDULE_RESET_TASK(cron expr)Cron để reset task tự động
SCHEDULE_SEND_TASK(cron expr)Cron để gửi task tự động
SCHEDULE_SEARCH_KEYWORD(cron expr)Cron để search keyword
SCHEDULE_REPORT_TRAFFIC(cron expr)Cron để báo cáo traffic
LIMIT_SEND_TASK_PER_SERVER(số nguyên)Giới hạn task gửi đến 1 server
WHITE_LIST_IP_TOOL_SEARCH(IP list)Danh sách IP được phép truy cập search routes

2. Database Schema#

Dự án dùng hai loại database:
MySQL (GORM) - Lưu dữ liệu cấu trúc: users, servers, activity_logs
MongoDB - Lưu dữ liệu linh hoạt: keywords, keyword_results, proxies, anchor_texts

2.1 MySQL Tables#

Table: users#

Quản lý tài khoản người dùng, phân quyền đăng nhập.
CộtKiểuRàng buộcMô tả
idINTPK, AUTO_INCREMENTID định danh người dùng
nameVARCHAR(255)NOT NULLTên hiển thị
passwordVARCHAR(255)NOT NULLMật khẩu (đã hash bcrypt)
emailVARCHAR(255)UNIQUE, NOT NULLEmail dùng để đăng nhập
first_nameVARCHAR(255)NULLTên
last_nameVARCHAR(255)NULLHọ
roleINTDEFAULT 1Phân quyền: 0 = Admin, 1 = User
created_atDATETIMEAUTOThời điểm tạo
updated_atDATETIMEAUTOThời điểm cập nhật cuối
deleted_atDATETIMENULLSoft delete (GORM)

Table: servers#

Quản lý danh sách server tool dùng để phân phối task tìm kiếm.
CộtKiểuRàng buộcMô tả
idINTPK, AUTO_INCREMENTID server
nameVARCHAR(255)NOT NULLTên server (ví dụ: "Server-01-HN")
is_activeTINYINT(1)DEFAULT 0Trạng thái hoạt động (1 = active)
ipVARCHAR(255)NOT NULLĐịa chỉ IP của server tool
is_priorityTINYINT(1)DEFAULT 0Ưu tiên nhận task (1 = ưu tiên cao)
limit_processINTSố process tối đa server có thể xử lý
current_processINTSố process đang chạy hiện tại
created_atDATETIMEAUTOThời điểm tạo
updated_atDATETIMEAUTOThời điểm cập nhật cuối
deleted_atDATETIMENULLSoft delete (GORM)

Table: activity_logs#

Ghi lại mọi hành động của người dùng (audit trail).
CộtKiểuRàng buộcMô tả
idINTPK, AUTO_INCREMENTID log
user_idINTFK -> users.id, NULLID người dùng thực hiện hành động
actionVARCHAR(255)NOT NULLTên hành động (vd: "Đăng nhập", "Tạo keyword")
parameterJSONNULLTham số yêu cầu đính kèm (body/query)
model_nameVARCHAR(255)NOT NULLTên model bị tác động (vd: "user", "keyword")
model_idINTNOT NULLID của bản ghi bị tác động
old_valueJSONNULLGiá trị trước khi thay đổi
new_valueJSONNULLGiá trị sau khi thay đổi
ip_addressVARCHAR(255)IP của client gọi request
user_agentVARCHAR(255)User-Agent của client
created_atDATETIMEAUTOThời điểm ghi log
updated_atDATETIMEAUTOCập nhật lần cuối

2.2 MongoDB Collections#

Collection: keywords#

Lưu danh sách từ khoá cần theo dõi SEO ranking.
FieldKiểuBắt buộcMô tả
_idObjectIDYesID MongoDB tự sinh
keywordStringYesTừ khoá cần tìm kiếm
statusNumberYes0 = Disable, 1 = Enable
deviceArray[Number]YesThiết bị: 0 = Desktop, 1 = Mobile
engineArray[Number]YesCông cụ tìm kiếm: 0 = GoogleVN, 1 = Google, 2 = Coc Coc
result_numNumberYesSố kết quả tìm kiếm cần lấy
created_byNumberNoID user tạo keyword
is_runningBooleanNotrue nếu đang trong quá trình tìm kiếm
created_atDatetimeNoThời điểm tạo
updated_atDatetimeNoThời điểm cập nhật
Enum Engine: 0 = GoogleVN, 1 = Google, 2 = Coc Coc

Collection: keyword_results#

Lưu kết quả tìm kiếm thực tế của từng keyword theo từng lần chạy.
FieldKiểuBắt buộcMô tả
_idObjectIDYesID kết quả
keyword_idStringYesID keyword cha
keyword_schedule_idObjectIDYesID schedule (lần chạy cụ thể)
keywordStringYesTừ khoá (denormalized để query nhanh)
deviceNumberYesThiết bị: 0 = Desktop, 1 = Mobile
device_osNumberNoOS: 0 = Windows/Android, 1 = MacOS/iOS
engineNumberYesCông cụ: 0 = GoogleVN, 1 = Google, 2 = Coc Coc
result_numNumberNoSố kết quả tối đa
is_scan_domainBooleanNoCó quét domain không
search_dataObjectNoDữ liệu kết quả (xem bên dưới)
statusNumberNo0 = Unknown, -1 = Error, -2 = Not Found, -3 = Captcha, 1 = Success
created_atDatetimeNoThời điểm tạo
updated_atDatetimeNoThời điểm cập nhật
Cấu trúc search_data:
{
  "ads": [
    { "url": "https://...", "rank": 1, "type": "company", "confirm_status": true, "label": "", "title": "...", "description": "..." }
  ],
  "search": [
    { "url": "https://...", "rank": 1, "type": "competitors", "confirm_status": false, "label": "", "title": "...", "description": "..." }
  ]
}
Enum type: "company" = Domain của công ty, "competitors" = Domain đối thủ

Collection: proxies#

Quản lý proxy trong hệ thống (MongoDB).
FieldKiểuBắt buộcMô tả
_idObjectIDYesID
ipStringYesĐịa chỉ IP proxy
portNumberYesPort proxy
usernameStringNoUsername xác thực proxy
passwordStringNoPassword xác thực proxy
rotate_urlStringYesURL để trigger rotate IP
rotate_timeNumberNoThời gian giữa mỗi lần rotate (giây), mặc định 60
next_rotateDatetimeNoThời điểm tiếp theo được phép rotate
last_used_atDatetimeNoLần cuối proxy được sử dụng
in_useNumberNoSố task đang dùng proxy này
proxy_usedArrayNoDanh sách task đã dùng: [{task_id, proxy_url}]
used_countNumberNoTổng số lần đã sử dụng
is_captchaBooleanNotrue nếu proxy bị captcha
is_errorBooleanNotrue nếu proxy đang bị lỗi
is_successBooleanNotrue nếu proxy vừa thành công
error_countNumberNoSố lỗi liên tiếp (reset về 0 khi thành công)
is_activeBooleanNotrue nếu proxy còn hoạt động
ip_publicStringNoIP public thực tế sau rotate
regionStringNoKhu vực địa lý của proxy
disable_auto_rotateBooleanNotrue = tắt tự động rotate
is_rotatingBooleanNotrue nếu đang trong quá trình rotate
rotate_serverStringNoTên server đang thực hiện rotate
areaStringNoKhu vực proxy: "global" hoặc "vn"
auth_tokenStringNoToken xác thực nhà cung cấp proxy
package_nameStringNoTên gói dịch vụ proxy
created_atDatetimeNoThời điểm tạo
updated_atDatetimeNoThời điểm cập nhật

Collection: anchor_texts#

Lưu task tìm kiếm anchor text (backlink) theo domain.
FieldKiểuBắt buộcMô tả
domainStringYesDomain cần tìm anchor text (vd: example.com)
anchor_keyArray[String]YesDanh sách từ khoá anchor cần tìm
webhook_urlStringYesURL để gửi kết quả về khi hoàn thành
proxy_urlStringYesURL proxy để sử dụng khi tìm kiếm
searchedNumberNoSố lần đã tìm kiếm
statusNumberNo0 = Unknown, -1 = Error, -2 = Not Found, -3 = Captcha, 1 = Success

3. System Architecture#

+------------------------------------------------------------------+
|                        CLIENTS                                    |
|  Admin Frontend (Vue 3)  |  Tool Search (Node.js/Bun)            |
+-------------+------------+--------------+------------------------+
              |  JWT Auth                  |  API Key / Webhook Key
              v                           v
+------------------------------------------------------------------+
|                  SEARCH TOOL API (Go + Fiber)                    |
|                        Port: 33003                               |
|                                                                  |
|  Middleware: CORS | Helmet | Logger | JWT | API Key | WH Key     |
|                                                                  |
|  Route Groups:                                                   |
|  /api/*         (JWT Auth)   - User, Proxy, Server, Keyword      |
|  /search/*      (API Key)    - KeywordPoolTask CRUD              |
|  /anchor-text/* (API Key)    - AnchorText CRUD                   |
|  /webhook/*     (WH Key)     - Proxy & Search result callbacks    |
|  /ws            (Socket.IO)  - Real-time updates                 |
|                                                                  |
|  Scheduler (gocron):                                             |
|  - Reset proxy errors | Send search tasks | Keyword search cron  |
+---+------------------+------+-----+-----------------------------+
    |                  |            |
+---v---+     +--------v-------+  +-v---------+
| MySQL |     |    MongoDB     |  |   Redis   |
| GORM  |     | (Mongo Driver) |  |  (Cache)  |
|       |     |                |  |           |
|users  |     |keywords        |  |task cache |
|servers|     |keyword_results |  |locks      |
|act_   |     |proxies         |  |           |
|logs   |     |anchor_texts    |  +-----------+
+-------+     |keyword_pool_   |
              |  tasks         |
              +----------------+

Luồng hoạt động chính#

1. Keyword Search Flow (qua keyword_pool_tasks làm buffer trung gian):
[Cron SCHEDULE_SEARCH_KEYWORD - gocron]
  -> keyword.service.SearchKeyword()
  -> Lấy tất cả keyword status=Enable từ MongoDB (keywords)
  -> Tạo SearchKeywordRequest cho từng tổ hợp (keyword x engine x device)
  -> Lưu vào MongoDB: keyword_pool_tasks   <-- buffer/queue

[Cron keyword_pool_task - goroutine, loop mỗi 60s]
  -> Lấy tất cả task từ keyword_pool_tasks
  -> Kiểm tra Redis cache (key: keyword_engine_device_os):
       - Nếu có cache -> gọi hook_url trả kết quả luôn -> xóa task
       - Nếu chưa có -> đưa vào filteredTasks
  -> Đánh dấu filteredTasks: Status = PROCESSING
  -> Phân phối task đến Tool Servers (servers table) theo weighted:
       IsPriority=true: trọng số 5 | thường: trọng số 2
  -> POST http://{server.IP}/api/searches  (gửi batch đến Tool)
  -> Nhận response IDs -> xóa task khỏi keyword_pool_tasks
  -> Nếu lỗi: reset Status = NEW để retry vòng sau
Tool (Bun/Elysia) nhận và xử lý task:
  -> Lưu vào collection searches (MongoDB của Tools)
  -> Cron (every 1s): pick PENDING -> Chrome launch -> search Google/CocCoc
  -> Lưu kết quả vào searches.search_data
  -> POST {webhook_url} = /webhook/update-search-result/:id
  -> API cập nhật kết quả vào keyword_results

2. Anchor Text Flow (tương tự, qua anchor_texts làm buffer):
[Caller] POST /anchor-text/search
  -> Lưu vào MongoDB: anchor_texts  <-- buffer

[Cron anchor_text - goroutine, loop mỗi 60s]
  -> Lấy tất cả anchor text tasks
  -> Kiểm tra Redis cache (key: domain_anchor_text):
       - Nếu có cache -> gọi hook_url -> xóa task
       - Nếu chưa -> phân phối đến Tool servers (weighted)
  -> POST http://{server.IP}/api/search-anchor-texts
  -> Tool crawl anchor text -> POST /webhook/update-search-anchor-text/:id

3. Proxy Rotation Flow:
[Tool cần proxy]
  -> POST /webhook/proxy/get-proxy  {task_id, proxy_url}
  -> API tìm proxy khả dụng (is_active, in_use < max, không lỗi)
  -> Đánh dấu in_use++, ghi task_id vào proxy.proxy_used
  -> Trả về {host, port, username, password}

[Tool sau khi rotate xong]
  -> POST /webhook/proxy-rotation-result/:id
  -> API cập nhật ip_public, region, reset is_rotating=false

4. Code Structure#

api/
├── cmd/
│   └── main.go                    # Entry point
│
├── bootstrap/
│   ├── routes.go                  # Đăng ký toàn bộ routes + cron
│   ├── cron/                      # Cron job configs (gocron)
│   ├── injection/                 # Dependency Injection (Uber Dig)
│   └── socket/                    # Socket.IO server setup
│
├── internal/                      # Core business logic
│   ├── activity_log/
│   │   ├── activity_log.go        # Model (MySQL)
│   │   ├── dto/
│   │   ├── handler/               # GET /activity-log (pagination)
│   │   ├── repository/
│   │   └── service/
│   │
│   ├── anchor_text/
│   │   ├── anchor_text.go         # Model (MongoDB)
│   │   ├── cron/
│   │   ├── dto/
│   │   ├── handler/               # POST /search, GET /get-all, GET /reset-all-status
│   │   ├── repository/
│   │   └── service/
│   │
│   ├── keyword/
│   │   ├── keyword.go             # Model (MongoDB) + Device/Engine/Status enums
│   │   ├── cron/
│   │   ├── dto/
│   │   ├── handler/               # CRUD + reset
│   │   ├── repository/
│   │   └── service/
│   │
│   ├── keyword_pool_task/
│   │   ├── handler/               # POST /, GET /get-all, GET /reset-all-status
│   │   ├── repository/
│   │   └── service/
│   │
│   ├── keyword_result/
│   │   ├── keyword_result.go      # Model (MongoDB) + SearchData, SearchResult
│   │   ├── cron/
│   │   ├── dto/
│   │   ├── handler/               # POST (create), PUT /update-search-data/:id
│   │   ├── repository/
│   │   └── service/
│   │
│   ├── proxy/
│   │   ├── proxy.go               # Model (MongoDB) + ProxyArea enum
│   │   ├── cron/
│   │   ├── dto/
│   │   ├── handler/               # CRUD + import Excel + change_status
│   │   ├── repository/
│   │   └── service/
│   │
│   ├── server/
│   │   ├── server.go              # Model (MySQL)
│   │   ├── handler/               # CRUD
│   │   ├── repository/
│   │   └── service/
│   │
│   ├── user/
│   │   ├── user.go                # Model (MySQL) + RoleType enum
│   │   ├── dto/
│   │   ├── handler/               # Login, Register, CRUD
│   │   ├── repository/
│   │   └── service/
│   │
│   └── webhook/
│       ├── dto/
│       ├── handler/               # get_proxy, proxy_rotation_result,
│       │                          # update_search_result, update_search_anchor_text
│       └── service/
│
├── pkg/                           # Shared utilities
│   ├── env.go                     # EnvStruct + LoadEnv()
│   ├── api/                       # HTTP clients gọi external APIs
│   ├── apperror/                  # Custom error types
│   ├── cache/                     # Redis wrapper
│   ├── database/                  # DB connections (MySQL + MongoDB)
│   ├── excel/                     # Excel reader (import proxy)
│   ├── jwt/                       # JWT create & parse
│   ├── logger/                    # Zap logger + lumberjack rotation
│   ├── messages/                  # Standard response format
│   ├── middleware/                 # JWT, Webhook, Error middlewares
│   ├── scheduler/                 # gocron wrapper
│   ├── telegram/                  # Telegram notifications
│   └── validate/                  # Request validation
│
├── common/
│   ├── const.go
│   └── paging.go                  # Pagination struct
│
├── go.mod                         # Go module
├── .env.example
└── docker-compose.yaml

Middleware Authorization Summary#

Route GroupAuth Method
GET /Public
POST /api/user/loginPublic
POST /api/user/registerPublic
**/api/**JWT Bearer Token (Authorization: Bearer <token>)
**/search/**API Key Header (API_SEARCH_TOKEN)
**/anchor-text/**API Key Header (API_SEARCH_TOKEN)
**/webhook/**Webhook Key Header (WEBHOOK_KEY)
Ngày cập nhật 2026-03-30 03:19:40
Trước
Nghiệp vụ & Luồng Tìm kiếm
Tiếp theo
User Guide
Built with