1. Search tool
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 tool

Tổng quan

Search Tool — Tools Technical Documentation#

Stack: Bun >= 1.2.5 · TypeScript · Elysia v1.2 · Puppeteer + Rebrowser + Stealth · Mongoose/Typegoose · MongoDB · @elysiajs/cron
Service name: search-tool
Default port: 33033
Version: 2.0.6

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
Bun>= 1.2.5
Node.js20+ (dùng khi Puppeteer cần)
Docker & Docker ComposeLatest
Google ChromeInstalled system-wide
Lưu ý: Dự án ưu tiên chạy bằng Bun runtime thay vì Node.js thuần. Một số tính năng Chrome launch dùng chrome-launcher nên Chrome phải được cài trên máy.

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

Bước 1 — Vào thư mục project Tools và copy file môi trường:
Bước 2 — Cấu hình .env: Chỉnh sửa theo hướng dẫn mục 1.3.
Bước 3 — Khởi động MongoDB bằng Docker:
Bước 4 — Cài dependencies:
Bước 5 — Chạy development server (hot-reload):
Server sẽ khởi động tại http://localhost:33033
Bước 6 — Kiểm tra:
GET http://localhost:33033/
# Trả về: { name: "Search tool", version: "2.0.6", environment: "development", browserSession: 0 }

GET http://localhost:33033/health
# Trả về: { status: "ok", time: "...", uptime: ... }

GET http://localhost:33033/swagger
# Swagger UI tự động tạo từ Elysia

1.3 Build & Deploy#


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

BiếnVí dụMô tả
PORT33033Port HTTP server lắng nghe
NODE_ENVdevelopmentMôi trường chạy (development / production)
API_KEY#!6f1!0...API Key bảo vệ các endpoint nội bộ
IP_ALLOWED127.0.0.1,11.0.3.11Danh sách IP được phép gọi (whitelist)
WEBHOOK_API_KEY255d00cc...Secret key xác thực webhook callback từ API server
GET_PROXY_APIhttp://127.0.0.1:33034/api/get-proxyURL endpoint để lấy proxy từ API server
PROXY_API_KEY(nếu cần)API key cho endpoint GET_PROXY_API
DB_MONGO_HOSTsearch_tool_mongodbHost MongoDB
DB_MONGO_PORT27017Port MongoDB
DB_MONGO_USERNAMErootUsername MongoDB
DB_MONGO_PASSWORDPwDev123Password MongoDB
DB_MONGO_DATABASEsearch-tool-toolsTên database MongoDB
CRON_SEARCH_LIMIT10Số tác vụ search chạy đồng thời tối đa
CRON_TASK_LIMIT14Số tác vụ proxy check chạy đồng thời tối đa
BROWSER_LIMIT_PER_PROCESS1Số browser session mỗi process
BROWSER_LIMIT22Tổng số Chrome sessions tối đa. Công thức mặc định: (CRON_SEARCH_LIMIT + CRON_TASK_LIMIT) * BROWSER_LIMIT_PER_PROCESS
SEARCH_API_KEY(cần điền)API key cho searchapi.io
SEARCH_API_URLhttps://searchapi.io/api/v1/searchURL của Search API bên ngoài
LOG_LEVELinfoMức log: error, warn, info, debug
LOG_SERVICEappTên service mặc định trong log
LOG_TIMESTAMPtrueCó gắn timestamp vào log hay không
LOG_COLORIZEDtrueCó format màu cho console log
LOG_WRITE_TO_FILEtrueCó ghi log ra file không
LOG_WRITE_TO_CONSOLEtrueCó xuất log ra console không
LOG_DIRstorage/logThư mục chứa log files
RUNTIMEbunRuntime sử dụng (bun hoặc node)

2. Database Schema (MongoDB)#

Dự án chỉ dùng MongoDB với Mongoose/Typegoose.

Collection: searches#

Lưu danh sách task tìm kiếm keyword Google cần thực hiện.
FieldKiểuBắt buộcMô tả
_idString (ObjectID hex)YesID task
keywordStringYesTừ khoá cần tìm kiếm
result_numNumberYesSố kết quả tối đa cần lấy
deviceNumberYesThiết bị: 0 = Desktop, 1 = Mobile
device_osNumberYesOS: 0 = Windows/Android, 1 = MacOS/iOS
engineNumberYesCông cụ tìm kiếm (xem enum Engine)
webhook_urlString (URI)YesURL để gửi kết quả về sau khi hoàn thành
proxy_urlString (URI)YesURL proxy để gọi lấy proxy từ API server
call_webhook_countNumberNoSố lần đã gọi webhook, mặc định 0
proxyObjectNoThông tin proxy đang dùng: {host, port, username, password}
search_dataObjectNoKết quả tìm kiếm (xem Search Data bên dưới)
statusNumberNo0 = PENDING, 1 = PROCESSING, 2 = COMPLETED
result_statusNumberNo0 = UNKNOWN, -1 = ERROR, -2 = NOT_FOUND, -3 = CAPTCHA, 1 = SUCCESS
search_youtubeBooleanNoTìm kiếm kết quả YouTube, mặc định true
search_imageBooleanNoTìm kiếm kết quả hình ảnh, mặc định true
geo_locationObjectNoVị trí địa lý: {latitude, longitude}
retry_countNumberNoSố lần retry do lỗi thông thường, mặc định 0
captcha_retry_countNumberNoSố lần retry do captcha, mặc định 0
device_os_retry_countNumberNoSố lần retry do thay đổi OS, mặc định 0
createdAtDatetimeAutoThời điểm tạo (Typegoose TimeStamps)
updatedAtDatetimeAutoThời điểm cập nhật
Cấu trúc search_data:
{
  "ads": [
    { "url": "https://...", "rank": 1 }
  ],
  "search": [
    { "url": "https://...", "rank": 1, "title": "...", "description": "..." }
  ]
}
Enum Engine (Device.Engine):
0 = Google VN
1 = Google (quốc tế)
2 = Coc Coc
Enum Status:
0 = PENDING (chờ xử lý)
1 = PROCESSING (đang xử lý)
2 = COMPLETED (đã hoàn thành)
Enum ResultStatus:
0 = UNKNOWN (chưa biết)
-1 = ERROR (lỗi xử lý)
-2 = NOT_FOUND (không tìm thấy kết quả)
-3 = CAPTCHA (bị chặn bởi captcha)
1 = SUCCESS (thành công)

Collection: proxies#

Lưu danh sách proxy cần rotate/kiểm tra định kỳ.
FieldKiểuBắt buộcMô tả
_idString (ObjectID hex)YesID proxy task
webhook_urlString (URI)YesURL gửi kết quả rotate về
statusNumberNo0 = PENDING, 1 = PROCESSING, 2 = COMPLETED
status_codeNumberNoHTTP status code từ lần rotate gần nhất
responseStringNoResponse body từ rotate URL
is_errorBooleanNotrue nếu rotate gặp lỗi
rotate_urlStringYesURL endpoint để trigger rotate IP
ip_publicStringNoIP public sau khi rotate
auth_tokenStringNoToken xác thực nhà cung cấp proxy
regionStringNoRegion của proxy
call_webhook_countNumberNoSố lần đã gọi webhook
disable_auto_rotateBooleanNotrue = tắt tự động rotate
ipStringNoIP của proxy
portNumberNoPort của proxy
usernameStringNoUsername xác thực
passwordStringNoPassword xác thực
createdAtDatetimeAutoThời điểm tạo
updatedAtDatetimeAutoThời điểm cập nhật

Collection: search_anchor_texts#

Lưu danh sách task tìm kiếm anchor text cho từng domain.
FieldKiểuBắt buộcMô tả
_idString (ObjectID hex)YesID task
anchor_keyArray[String]YesDanh sách từ khoá anchor cần tìm trên trang
domainStringYesDomain cần crawl anchor text
webhook_urlString (URI)YesURL để gửi kết quả về
proxy_urlString (URI)YesURL để lấy proxy từ API server
call_webhook_countNumberNoSố lần đã gọi webhook
proxyObjectNoProxy đang sử dụng: {host, port, username, password}
search_dataObjectNoKết quả anchor text (xem bên dưới)
statusNumberNo0 = PENDING, 1 = PROCESSING, 2 = COMPLETED
result_statusNumberNo0 = UNKNOWN, -1 = ERROR, -2 = NOT_FOUND, -3 = CAPTCHA, 1 = SUCCESS
createdAtDatetimeAutoThời điểm tạo
updatedAtDatetimeAutoThời điểm cập nhật
Cấu trúc search_data:
{
  "url": "https://example.com",
  "anchor_text": [
    { "key": "casino", "link": "https://...", "element": "a" }
  ]
}

3. System Architecture#

+------------------------------------------------------------------+
|                  SEARCH TOOL (Bun + Elysia)                      |
|                        Port: 33033                               |
|                                                                  |
|  Entry Point: src/index.ts                                       |
|  - connectDatabase() -> MongoDB                                  |
|  - Clean tmp/user-data folder                                    |
|  - Start Elysia server                                           |
|                                                                  |
|  +--------------------+  +-----------------------------------+   |
|  |  Swagger UI        |  |  API Routes (/api/*)              |   |
|  |  /swagger          |  |                                   |   |
|  +--------------------+  |  /api/searches   (Search Tasks)   |   |
|                          |  /api/proxies    (Proxy Tasks)    |   |
|  +--------------------+  |  /api/search-anchor-texts         |   |
|  |  Health Endpoints   |  |  /api/test       (Dev/Debug)     |   |
|  |  GET /              |  +-----------------------------------+   |
|  |  GET /health        |                                         |
|  |  GET /logs          |                                         |
|  +--------------------+                                          |
|                                                                  |
|  +-------------------------------------------------------------+ |
|  |  Cron Jobs (Every Second)                                   | |
|  |                                                             | |
|  |  search-cron          -> searchCron.start()                 | |
|  |  search-cron-webhook  -> searchCron.runWebhook()            | |
|  |  proxy-cron           -> crontProxy.start()                 | |
|  |  proxy-cron-webhook   -> crontProxy.runWebhook()            | |
|  |  anchor-text-cron     -> searchCron.start()                 | |
|  |  anchor-text-cron-webhook -> searchCron.runWebhook()        | |
|  +-------------------------------------------------------------+ |
|                                                                  |
|  +-------------------------------------------------------------+ |
|  |  Browser Manager                                            | |
|  |  - Manages Chrome sessions pool                             | |
|  |  - Max sessions: BROWSER_LIMIT (default 22)                | |
|  |  - Uses Puppeteer + Stealth plugin                          | |
|  |  - Ghost cursor for human-like mouse movement               | |
|  |  - Support Desktop/Mobile device emulation                  | |
|  +-------------------------------------------------------------+ |
+---+-------------------------------+-----------------------------+
    |                               |
    v                               v
+--------+                 +-------------------+
|MongoDB |                 |  External Services |
|(search-|                 |                   |
| tool-  |                 | - searchapi.io    |
| tools) |                 | - Search API      |
|        |                 |   (API Server)    |
|searches|                 | - Webhook URLs    |
|proxies |                 |   (API Server )   |
|search_ |                 +-------------------+
|anchor_ |
|texts   |
+--------+

Luồng xử lý Search Task#

API Server
  -> POST /api/searches (tạo task)
  -> Cron (every 1s) picks PENDING tasks up to CRON_SEARCH_LIMIT
  -> BrowserManager.newSession() -> Chrome launch
  -> Navigate to Google / Coc Coc
  -> Scrape search results (ads + organic)
  -> Update task status = COMPLETED, save search_data
  -> Webhook callback to webhook_url (API Server)
  -> API Server records result in keyword_results

Luồng xử lý Proxy Rotation#

API Server
  -> POST /api/proxies (tạo proxy task)
  -> Cron picks PENDING proxy tasks
  -> HTTP GET rotate_url (trigger IP rotation)
  -> Parse response, confirm ip_public
  -> Webhook callback to webhook_url
  -> API Server updates proxy record

4. Code Structure#

tools/
├── src/
│   ├── index.ts                        # Entry point chính
│   │   - connectDatabase()             # Kết nối MongoDB
│   │   - Clean tmp/user-data           # Dọn dẹp Chrome profile cũ
│   │   - Khởi tạo Elysia app
│   │   - Register Swagger, errorHandler
│   │   - Register routes (apiRoutes)
│   │   - Expose GET /, /health, /logs
│   │
│   ├── api/
│   │   ├── index.ts                    # Ghép tất cả route controllers
│   │   │                               # Prefix: /api
│   │   │
│   │   ├── search/
│   │   │   ├── search.controller.ts    # Routes: GET /, POST /, DELETE /, DELETE /:id
│   │   │   │                           # POST /reset-status-all, POST /reset-process-running
│   │   │   ├── search.dto.ts           # CreateSearchSchema, UpdateSearchSchema
│   │   │   ├── search.model.ts         # Mongoose model: Search (collection: searches)
│   │   │   ├── search.service.ts       # findAll, createMany, delete, deleteAll, resetStatus
│   │   │   └── search.cron.ts          # Cron logic: pick tasks, run browser, scrape, webhook
│   │   │
│   │   ├── proxy/
│   │   │   ├── proxy.controller.ts     # Routes: GET /, POST /, DELETE /, DELETE /:id
│   │   │   ├── proxy.dto.ts            # CreateProxySchema
│   │   │   ├── proxy.model.ts          # Mongoose model: Proxy (collection: proxies)
│   │   │   ├── proxy.service.ts        # findAll, create, delete, deleteAll, resetStatus
│   │   │   ├── proxy.cron.ts           # Cron: rotate proxy, call webhook
│   │   │   └── cron/                   # (sub-cron logic nếu có)
│   │   │
│   │   ├── search-anchor-text/
│   │   │   ├── search-anchor-text.controller.ts  # Routes: GET/, POST/, DELETE/, DELETE/:id
│   │   │   │                                       # POST /reset-status-all, reset-process-running
│   │   │   ├── search-anchor-text.dto.ts          # CreateSearchAnchorTextSchema, UpdateSearchAnchorTextSchema
│   │   │   ├── search-anchor-text.model.ts        # Mongoose model: SearchAnchorText
│   │   │   ├── search-anchor-text.service.ts      # CRUD + reset
│   │   │   └── search-anchor-text.cron.ts         # Cron: crawl anchor text, webhook
│   │   │
│   │   └── test/
│   │       └── test.controller.ts      # Debug endpoints:
│   │                                   # GET /test         -> open browser, go to google
│   │                                   # POST /test/proxy  -> return hardcoded proxy info
│   │                                   # GET /test/check-browser -> launch Chrome, screenshot
│   │                                   # DELETE /test/clear-browser-sessions
│   │
│   ├── config/
│   │   └── database/
│   │       └── mongodb.config.ts       # MongoDB connection setup (mongoose)
│   │
│   ├── services/
│   │   └── (shared services nếu có)
│   │
│   ├── types/
│   │   └── global/                     # Global type definitions
│   │
│   └── utils/
│       ├── createElysia.ts             # Factory tạo Elysia instance với cấu hình chuẩn
│       ├── env.ts                      # loadEnv() -> parse tất cả biến môi trường
│       ├── error.middleware.ts         # Global error handler (Elysia onError)
│       ├── index.ts                    # Re-export utils
│       ├── logger.ts                   # Logger với level, file rotation, colorize
│       ├── browser_manager/            # Quản lý Chrome browser pool
│       │   ├── index.ts                # BrowserManager class
│       │   ├── device.ts               # Device.Type, Device.Engine enums
│       │   └── ...                     # Session, page management
│       ├── captcha/                    # Captcha solving utilities
│       ├── file/                       # File utilities
│       └── number/                     # Number utilities
│
├── plugin/                             # Chrome extension files
│   ├── _locales/                       # Ngôn ngữ extension
│   ├── css/
│   ├── img/
│   ├── js/
│   └── sounds/
│
├── storage/
│   └── log/                            # Log files (tạo runtime)
│
├── tmp/                                # Temp folder (Chrome user-data, screenshots)
│
├── package.json                        # Dependencies
├── tsconfig.json                       # TypeScript config
├── .env.example                        # Template môi trường
├── docker-compose.yml                  # Docker MongoDB
└── .prettierrc.json                    # Code formatter config

Cron Job Strategy#

Tất cả cron chạy every second nhưng có bảo vệ:
protect: true trên webhook cron → chỉ 1 instance chạy tại 1 thời điểm
CRON_SEARCH_LIMIT / CRON_TASK_LIMIT giới hạn số task concurrent

Browser Management#

Pool-based: browserManager.sessionsCount theo dõi số session đang mở
Hard limit: BROWSER_LIMIT ngăn mở quá nhiều Chrome cùng lúc
Stealth: Dùng puppeteer-extra-plugin-stealth để bypass bot detection
Ghost cursor: Simulate mouse movement tự nhiên để qua anti-bot
Device emulation: Desktop (1920x1080) hoặc Mobile (iPhone 14 emulation)
Cleanup: tmp/user-data được xóa khi khởi động lại server
Ngày cập nhật 2026-03-30 03:15:45
Trước
Reset running process
Tiếp theo
User Guide
Built with