1. Tool
Proxy Tool
  • Tổng quan cấu trúc hệ thống
  • Bussiness | Logic
    • Logic nghiệp vụ
  • Project
    • Tool
      • Tổng quan
      • Tài liệu API
      • Architecture
        • User Guide
        • Database Schema
        • System Architecture
        • Code Structure
      • Public API
        • Auth
          • Đăng nhập
          • Đăng ký người dùng
          • Lấy thông tin cá nhân hiện tại
        • Users
          • Danh sách người dùng
          • Tạo người dùng mới (Admin)
        • Proxies
          • Danh sách tất cả Proxy
          • Thêm Proxy hàng loạt
          • Nhập proxy từ file Excel/CSV
        • Get proxy
          • Lấy một Proxy trống (Client Tool)
        • Webhooks
          • Trả lại Proxy sau khi dùng
        • Info
          • Thông tin hệ thống (Root)
          • Kiểm tra tình trạng hệ thống
          • Xem tệp nhật ký (Logs)
      • Deployment
        • Local
        • Staging
        • Product
  • Schemas
    • CreateUser
    • Proxy
  1. Tool

Tổng quan

Proxy Service Tool — Technical Documentation#

Version: 1.0.0
Runtime: Bun >= 1.2.5
Framework: ElysiaJS
Database: MongoDB 8
Cache: Redis 6.2

Table of Contents#

1.
Usage Guide (Local Development)
2.
Database Schema
3.
System Architecture
4.
Code Structure

1. Usage Guide (Local Development)#

1.1 Prerequisites#

ToolVersionNotes
Bun>= 1.2.5Primary runtime & package manager
Docker DesktopLatestFor MongoDB & Redis containers
GitAnySource control

1.2 Clone & Install#

1.3 Environment Configuration#

Copy the example environment file and edit your values:
Key variables:
VariableDescriptionExample
PORTHTTP server port33033
NODE_ENVRuntime environmentdevelopment
API_KEYJWT signing secretyour-secret-key
ALLOWED_API_KEYStatic API key for machine-to-machine clientssha256-hash-value
IP_ALLOWEDComma-separated IP whitelist for /get-proxy and /webhook127.0.0.1,10.0.0.5
DB_MONGO_HOSTMongoDB host (localhost for local, proxy_service_mongodb inside Docker)localhost
DB_MONGO_PORTMongoDB port27017
DB_MONGO_USERNAMEMongoDB root usernameroot
DB_MONGO_PASSWORDMongoDB root passwordsecret
DB_MONGO_DATABASEDatabase nameproxy-tool-mongodb
PROXY_USE_MAXMax concurrent leases per single proxy3
WEBHOOK_RETURN_PROXYBase URL consumers use to return a proxyhttp://127.0.0.1:33034/webhook/return-proxy
KIOT_API_KEYKiotProxy API token (optional integration)kiot-token
API_KIOT_PROXY_PACKAGEKiotProxy package list endpointhttps://api.kiotproxy.com/api/public/packages
API_KIOT_PROXY_KEYKiotProxy key list endpointhttps://api.kiotproxy.com/api/public/keys
KIOT_PROXY_ROTATE_URLKiotProxy rotation URL basehttps://api.kiotproxy.com/api/v1/proxies/new?key=
ZING_PROXY_TOKENZingProxy auth token (optional integration)zing-token
API_ZING_PROXY_ALLZingProxy active proxies endpointhttps://api.zingproxy.com/proxy/get-all-active-proxies
LOG_LEVELLog verbosity: error, warn, info, debuginfo
LOG_WRITE_TO_FILEWrite logs to storage/log/true
RUNTIMERuntime hint for AOT optimizationbun

1.4 Start Infrastructure#

Option A — Local dev (only infra in Docker, recommended):
Ports exposed to host:
MongoDB: localhost:33027
Redis: localhost:33025
Make sure .env uses:
DB_MONGO_HOST=localhost
REDIS_HOST=localhost
Option B — Full Docker stack (app + infra):
App will be reachable at http://localhost:33033 (or PORT value in .env).

1.5 Run Development Server#

App: http://localhost:33033
Swagger UI: http://localhost:33033/swagger
Bun Inspector/Debugger: localhost:4000/debugger
Hot-reload is enabled via --watch. Any file change restarts the server automatically.

1.6 Build & Compile#

1.7 Code Quality#

1.8 Scripts Summary#

ScriptCommandDescription
devbun run devHot-reload dev server + debugger
buildbun run buildBundle to ./dist
compilebun run compileStandalone binary ./dist/main
cleanbun run cleanRemove ./dist
formatbun run formatPrettier
lintbun run lintOXLint

1.9 First-time Admin Setup#

Register the first user:
Login to retrieve JWT token:
Use the token field from the response as Authorization: Bearer <token> on all protected routes.

2. Database Schema#

Database type: MongoDB 8
ODM: Mongoose + Typegoose (decorator-based class definitions)
All collections use timestamps: true — createdAt and updatedAt are auto-managed by Mongoose.

2.1 Collection: proxies#

Main collection. Each document represents one rotating proxy entry managed by the system.
FieldTypeRequiredDefaultDescription
_idstring (ObjectId hex)YESauto-generatedUnique document identifier
ipstringYES—Current IP/hostname of the proxy server (e.g. 123.45.67.89). Updated after each rotation
portnumberYES—HTTP port of the proxy server (e.g. 8080). Updated after each rotation
usernamestringYES—Auth username for the proxy. Updated after each rotation
passwordstringYES—Auth password for the proxy. Updated after each rotation
area"global" or "vn"YES—Geographic scope. "vn" = Vietnam-specific proxies; "global" = international
rotate_urlstring (URI)YES—URL to call to rotate (refresh) this proxy's IP. Provider-specific endpoint
rotate_timenumber—60Rotation interval in seconds between automatic rotations
auth_tokenstring or null—nullBearer token sent in Authorization header when calling rotate_url (if provider requires it)
ip_publicstring or null—nullPublicly visible IP after the last successful rotation, verified via api.ipify.org
is_activeboolean—trueWhether proxy is enabled and eligible for lease assignment
is_errorboolean—falsetrue if the last rotation or IP verification failed
is_rotatingboolean—falseConcurrency lock. Set to true while the cron is rotating this proxy. Prevents duplicate rotations
disable_auto_rotateboolean—falseIf true, cron skips the rotation step and only verifies the current IP
next_rotateDate—now + 60sTimestamp when proxy becomes eligible for the next rotation cycle
last_used_atDate or null—nullTimestamp when this proxy was last leased to a consumer
expired_atDate or null—nullSubscription expiry from the provider. Set during import
in_usenumber—0Number of currently active leases. Incremented on GET /api/get-proxy, decremented via return webhook
used_countnumber—0Total lease count in the current rotation cycle. Resets to 0 after a successful rotation
proxy_usedProxyUsed[]—[]Embedded array of active lease records. Cleared on rotation
webhook_urlstring or null—nullAuto-set when leased: {WEBHOOK_RETURN_PROXY}/{id}?key={key}. Consumer must call this URL to release the proxy
call_webhook_countnumber—0Counter for failed outbound webhook call attempts
statusnumber (enum)—0 (PENDING)Internal status: 0=PENDING, 1=PROCESSING, 2=COMPLETED
status_codenumber——HTTP status code from the last rotation API call
responsestring——Raw response body from the last rotation call (for debugging)
regionstring—""Geographic region label from provider (e.g. "HCM", "HN")
package_namestringYES—Denormalized display name from the proxy_packages collection
proxy_package_idstring (ref → proxy_packages._id)YES—Foreign key to the parent package
created_bystring (ref → users._id)——ID of the user who created this record
updated_bystring (ref → users._id)——ID of the user who last updated this record
createdAtDateauto—Mongoose-managed creation timestamp
updatedAtDateauto—Mongoose-managed last-update timestamp
Embedded sub-document: proxy_used[] (ProxyUsed)
FieldTypeDescription
ipstringIP address of the consumer holding this lease
keystringUnique lease key (ObjectId hex). Required to release the proxy via the webhook
timeDateTimestamp when the lease was granted

2.2 Collection: proxy_packages#

A subscription package offered by a proxy provider (e.g. "KiotProxy 4G VN Monthly").
FieldTypeRequiredDefaultDescription
_idstring (ObjectId hex)YESauto-generatedUnique identifier
codestringYES (unique)—Business key for the package. Convention: KiotProxy_<provider_code> for KiotProxy; ZingProxy_Pack for ZingProxy
namestringYES—Human-readable package name (e.g. "4G VN Tháng")
pricenumberYES—Monthly price in VND or provider currency
notestring—""Optional notes or description
proxy_provider_idstring (ref → proxy_providers._id)YES—Foreign key to the parent provider
is_activeboolean—truePackage is active and visible
created_bystring (ref → users._id)——ID of the user who created this record
updated_bystring (ref → users._id)——ID of the user who last updated this record
createdAtDateauto—Mongoose-managed creation timestamp
updatedAtDateauto—Mongoose-managed last-update timestamp

2.3 Collection: proxy_providers#

Top-level entity representing a proxy vendor/service provider.
FieldTypeRequiredDefaultDescription
_idstring (ObjectId hex)YESauto-generatedUnique identifier
namestringYES (unique)—Provider display name (e.g. "KiotProxy", "ZingProxy")
accountstringYES (unique)—Account name or username used on the provider's platform
domainstringYES (unique)—Provider website domain (e.g. "https://kiotproxy.com")
is_activeboolean—trueProvider is active and usable
created_bystring (ref → users._id)——ID of the user who created this record
updated_bystring (ref → users._id)——ID of the user who last updated this record
createdAtDateauto—Mongoose-managed creation timestamp
updatedAtDateauto—Mongoose-managed last-update timestamp

2.4 Collection: users#

Internal admin users who authenticate via JWT to manage the system.
FieldTypeRequiredDefaultDescription
_idstring (ObjectId hex)YESauto-generatedUnique identifier
emailstringYES (unique)—Email address used as login credential. Validated by regex
usernamestringYES (unique)—Display name
passwordstringYES—bcrypt-hashed password (cost factor = 4). Never stored in plaintext
createdAtDateauto—Mongoose-managed creation timestamp
updatedAtDateauto—Mongoose-managed last-update timestamp

2.5 Entity Relationships#

users._id
  └─> created_by / updated_by  (referenced across all collections)

proxy_providers._id
  └─> proxy_packages.proxy_provider_id

proxy_packages._id
  └─> proxies.proxy_package_id

proxies._id
  └─> proxy_used[]  (embedded array — active lease records)

3. System Architecture#

3.1 High-Level Diagram#

┌─────────────────────────────────────────────────────────────────┐
│                       Consumer Services                         │
│           (other microservices that need a proxy)               │
└──────────────────┬──────────────────────────┬───────────────────┘
                   │                          │
         GET /api/get-proxy?area=    POST /webhook/return-proxy/:id?key=
         (API Key + IP whitelist)    (return lease when done)
                   │                          │
                   v                          v
┌─────────────────────────────────────────────────────────────────┐
│                Proxy Service Tool  (ElysiaJS / Bun)             │
│                            PORT: 33033                          │
│                                                                 │
│   ┌───────────────┐  ┌──────────────────────┐  ┌────────────┐  │
│   │  Auth Routes  │  │    Admin Routes       │  │  Public    │  │
│   │  POST /login  │  │  /api/proxies         │  │  API       │  │
│   │  GET  /me     │  │  /api/proxy_packages  │  │            │  │
│   │  POST /register│ │  /api/proxy_providers │  │ /api/      │  │
│   │               │  │  /api/users           │  │  get-proxy │  │
│   │  (no auth)    │  │                       │  │            │  │
│   └───────────────┘  │  Auth: JWT Bearer     │  │ /webhook/  │  │
│                      └──────────────────────┘  │  return-   │  │
│                                                 │  proxy/:id │  │
│                                                 │            │  │
│                                                 │ Auth: API  │  │
│                                                 │ Key + IP   │  │
│                                                 └────────────┘  │
│                                                                 │
│   ┌──────────────────────────────────────────────────────────┐  │
│   │                  Background Cron Jobs                    │  │
│   │  proxy-cron-rotate  (every 10s)                          │  │
│   │    GetManyCanRotate(20) -> rotateProxy() -> checkIP()    │  │
│   │    -> save new ip/port/ip_public                         │  │
│   │  zing-proxy-cron  (every 12h)                            │  │
│   │    -> fetch ZingProxy active list -> auto-import         │  │
│   └──────────────────────────────────────────────────────────┘  │
└─────────────────────────────┬───────────────────────────────────┘
                              │
                 ┌────────────┴────────────┐
                 │                         │
          ┌──────────────┐         ┌──────────────┐
          │  MongoDB 8   │         │  Redis 6.2   │
          │  Port: 27017 │         │  Port: 6379  │
          │  (datastore) │         │  (reserved)  │
          └──────────────┘         └──────────────┘

┌─────────────────────────────────────────────────────────────────┐
│                   External Proxy Providers                      │
│  ┌───────────────────────┐   ┌───────────────────────────────┐ │
│  │      KiotProxy        │   │         ZingProxy             │ │
│  │  api.kiotproxy.com    │   │   api.zingproxy.com           │ │
│  │  - List packages      │   │   - List active proxies       │ │
│  │  - List keys          │   │   - Rotate via URL            │ │
│  │  - Rotate via URL     │   │                               │ │
│  └───────────────────────┘   └───────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

3.2 Authentication Layers#

The service has three separate authentication strategies:
LayerUsed ByMechanismRequired Header
JWT BearerAdmin users (Swagger, Frontend)JWT signed with API_KEY, expires in 14 daysAuthorization: Bearer <token>
Static API KeyMachine-to-machine admin clientsRaw key matched against ALLOWED_API_KEY env varAuthorization: <allowed_api_key>
API Key + IP WhitelistConsumer microservices (/get-proxy, /webhook)Key must match ALLOWED_API_KEY AND request IP must be in IP_ALLOWEDAuthorization: <allowed_api_key> from whitelisted IP

3.3 Proxy Lifecycle#

[Admin] POST /api/proxies
  -> Proxy created in DB: is_active=true, in_use=0, is_error=false

        ↓ Cron every 10s

[Cron] GetManyCanRotate(20)
  Filter: is_active=true AND is_rotating=false AND (
    next_rotate expired AND (is_error=true OR used_count > 0 OR in_use=0)
  )
  Lock: set is_rotating=true

  -> rotateProxy(proxy)
     GET rotate_url  (optional: Authorization: Bearer auth_token)
     Parse new ip/port/username/password from response

  -> checkIP(proxy)  [up to 3 retries, 5s between each]
     Fetch https://api.ipify.org via the proxy
     Compare new ip_public to old value

  If SUCCESS:
    ip_public = new IP
    next_rotate = now + rotate_time seconds
    in_use = 0, used_count = 0, proxy_used = []
    is_error = false, status_code = 200

  If FAIL:
    is_error = true, response = "Check IP failed", status_code = 500

  -> is_rotating = false -> save()

[Consumer] GET /api/get-proxy?area=vn
  -> getOneFree(consumerIP, area)  [mutex-protected]
     Filter: is_active=true, is_rotating=false,
             in_use < PROXY_USE_MAX, used_count < PROXY_USE_MAX,
             next_rotate > (now - 4min) OR used_count = 0
     Sort by: used_count ASC, last_used_at ASC
  -> in_use += 1, used_count += 1
  -> Append ProxyUsed { ip: consumerIP, key: uuid, time: now }
  -> last_used_at = now
  -> webhook_url = WEBHOOK_RETURN_PROXY/{id}?key={key}
  -> Return { ip, port, username, password, auth_token, webhook_url, ... }

[Consumer] Uses the proxy for its HTTP requests...

[Consumer] POST /webhook/return-proxy/{id}?key={key}
  -> ReturnProxy(id, consumerIP, key)  [mutex-protected]
     Remove matching entry from proxy_used
     in_use -= 1
     -> save()

3.4 Proxy Import Flows#

Manual Excel Import (POST /api/proxies/import)#

1.
Upload .xlsx file via multipart form
2.
Parse first sheet rows with xlsx library
3.
Normalize column headers (lowercase + underscored)
4.
Validate required fields: host, port, area, rotate_url, provider, package_code, expired_at
5.
Resolve proxy_package_id by matching provider name + package_code against DB
6.
Bulk-create proxy records

KiotProxy Auto-Import (POST /api/proxies/import-kiot)#

1.
Fetch package catalog from API_KIOT_PROXY_PACKAGE
2.
Fetch active keys from API_KIOT_PROXY_KEY (using Api-token: KIOT_API_KEY header)
3.
Auto-create KiotProxy provider record if not exists
4.
For each package: auto-create proxy_package if not exists (code: KiotProxy_<code>)
5.
Skip keys with expirationAt < now
6.
Skip keys already in DB (deduplicate by rotate_url)
7.
Create proxies with is_error=true, next_rotate=now (forces immediate rotation on first cron run)

ZingProxy Auto-Import (POST /api/proxies/import-zing or cron every 12h)#

1.
Fetch all active proxies from API_ZING_PROXY_ALL
2.
Auto-create ZingProxy provider + ZingProxy_Pack package if not exist
3.
Import new proxies

4. Code Structure#

tool/
├── src/
│   ├── index.ts                     # Entry point
│   │                                # - Connect MongoDB
│   │                                # - Register Swagger, routes, error handler
│   │                                # - Start Bun HTTP server
│   │
│   ├── api/
│   │   ├── index.ts                 # Route groups:
│   │   │                            #   apiRoutes    prefix: /api
│   │   │                            #   webhookRoutes prefix: /webhook
│   │   │
│   │   ├── auth/
│   │   │   └── auth.controller.ts   # POST /api/login
│   │   │                            # GET  /api/me
│   │   │                            # POST /api/register
│   │   │                            # No auth required
│   │   │
│   │   ├── user/
│   │   │   ├── user.controller.ts   # GET  /api/users/users
│   │   │   │                        # POST /api/users/users
│   │   │   │                        # PUT  /api/users/users/:id
│   │   │   │                        # DEL  /api/users/users/:id
│   │   │   ├── user.service.ts      # findAll, findOne, create, update, delete
│   │   │   ├── user.model.ts        # Collection: users
│   │   │   └── user.dto.ts          # CreateUserSchema {username, email, password}
│   │   │
│   │   ├── proxy/
│   │   │   ├── proxy.controller.ts  # GET    /api/proxies?get_full=
│   │   │   │                        # POST   /api/proxies
│   │   │   │                        # PUT    /api/proxies/:id
│   │   │   │                        # POST   /api/proxies/bulk-delete
│   │   │   │                        # DEL    /api/proxies/:id
│   │   │   │                        # POST   /api/proxies/import
│   │   │   │                        # POST   /api/proxies/import-kiot
│   │   │   │                        # POST   /api/proxies/import-zing
│   │   │   │                        # POST   /api/proxies/drop
│   │   │   │                        # Cron:  proxy-cron-rotate (10s)
│   │   │   │                        # Cron:  zing-proxy-cron (12h)
│   │   │   │
│   │   │   ├── proxy.service.ts     # Core service (all proxy business logic)
│   │   │   │                        # getOneFree(), ReturnProxy()     <- mutex
│   │   │   │                        # GetManyCanRotate(), UpdateIsRotating()
│   │   │   │                        # handleImportKiotProxy(), handleImportZingProxy()
│   │   │   │                        # processProxyImport() (Excel)
│   │   │   │
│   │   │   ├── proxy.cron.ts        # CronProxy class
│   │   │   │                        # start() -> runProcess()
│   │   │   │                        # processRotateProxy(): rotate + IP check flow
│   │   │   │                        # rotateProxy(): calls rotate_url
│   │   │   │                        # runWebhook(): outbound webhook callbacks
│   │   │   │
│   │   │   ├── proxy.model.ts       # Collection: proxies
│   │   │   │                        # Enum: Status (PENDING/PROCESSING/COMPLETED)
│   │   │   │                        # Interface: ProxyUsed, ProxyResponse
│   │   │   │                        # toProxyResponse() / toFullProxyResponse()
│   │   │   │
│   │   │   └── proxy.dto.ts         # CreateProxySchema
│   │   │                            # UpdateProxySchema
│   │   │                            # ImportProxySchema
│   │   │
│   │   ├── proxy_package/
│   │   │   ├── proxy_package.controller.ts  # GET  /api/proxy_packages
│   │   │   │                                # POST /api/proxy_packages
│   │   │   │                                # PUT  /api/proxy_packages/:id
│   │   │   │                                # POST /api/proxy_packages/bulk-delete
│   │   │   │                                # DEL  /api/proxy_packages/:id
│   │   │   │
│   │   │   ├── proxy_package.service.ts     # getAll, getById, getByCode, create, update, delete
│   │   │   │                                # getKiotPackages() - fetch from KiotProxy API
│   │   │   │                                # getKiotKeys()     - fetch from KiotProxy API
│   │   │   │                                # getOrCreateZingPackage()
│   │   │   │
│   │   │   ├── proxy_package.model.ts       # Collection: proxy_packages
│   │   │   │                                # Interfaces: KiotProxyKey, KiotProxyPackage,
│   │   │   │                                #             KiotProxyResponse, KiotProxyKeyResponse
│   │   │   │
│   │   │   └── proxy_package.dto.ts         # CreateProxyPackageSchema
│   │   │                                    # UpdateProxyPackageSchema
│   │   │
│   │   ├── proxy_provider/
│   │   │   ├── proxy_provider.controller.ts # GET  /api/proxy_providers
│   │   │   │                                # POST /api/proxy_providers
│   │   │   │                                # PUT  /api/proxy_providers/:id
│   │   │   │                                # POST /api/proxy_providers/bulk-delete
│   │   │   │                                # DEL  /api/proxy_providers/:id
│   │   │   │
│   │   │   ├── proxy_provider.service.ts    # findAll, getById, create, update, delete
│   │   │   │                                # getOrCreateKiotProvider()
│   │   │   │                                # getOrCreateZingProvider()
│   │   │   │
│   │   │   ├── proxy_provider.model.ts      # Collection: proxy_providers
│   │   │   └── proxy_provider.dto.ts        # CreateProxyProviderSchema, UpdateProxyProviderSchema
│   │   │
│   │   ├── get-proxy/
│   │   │   └── get-proxy.controller.ts      # GET /api/get-proxy?area=
│   │   │                                    # Auth: API Key + IP whitelist
│   │   │                                    # -> proxyServices.getOneFree(clientIP, area)
│   │   │
│   │   ├── webhook/
│   │   │   └── webhook.controller.ts        # POST /webhook/return-proxy/:id?key=
│   │   │                                    # Auth: API Key + IP whitelist
│   │   │                                    # -> proxyServices.ReturnProxy(id, ip, key)
│   │   │
│   │   └── test/
│   │       └── test.controller.ts           # Simple test/ping endpoint
│   │
│   ├── services/                            # Shared infrastructure services
│   │   ├── check-proxy/
│   │   │   ├── checkIP.ts                   # Verify proxy by fetching api.ipify.org/api.myip.com
│   │   │   │                                # Returns resolved public IP or null
│   │   │   └── checkRegion.ts               # Detect geographic region of a proxy IP
│   │   │
│   │   └── webhook/
│   │       ├── index.ts                     # callbackWebhook(): HTTP POST to consumer's URL
│   │       └── configs.ts                   # Webhook timeout / retry config
│   │
│   ├── config/
│   │   └── database/
│   │       └── mongodb.config.ts            # connectDatabase(): Mongoose connection setup
│   │
│   └── utils/
│       ├── index.ts                         # Re-exports: logger, createElysia, env
│       ├── env.ts                           # Parse & validate all environment variables
│       ├── createElysia.ts                  # Three Elysia factory functions:
│       │                                    # createElysia()             -> no auth
│       │                                    # createElysiaWithAuth()     -> JWT Bearer middleware
│       │                                    # createElysiaWithAllowed()  -> API Key + IP whitelist
│       ├── logger.ts                        # Structured logger (file + console, child scopes)
│       ├── error.middleware.ts              # APIError class + global Elysia error handler plugin
│       ├── file/                            # File utility helpers
│       └── number/                          # Number utility helpers
│
├── .docker/
│   └── dev/
│       └── Dockerfile                       # Dev Dockerfile (Bun base image)
│
├── docker-compose.yml                       # Full stack:
│                                            # proxy_service_tool   IP: 11.0.5.10  port: 33033
│                                            # proxy_service_mongodb IP: 11.0.5.11  port: 33027
│                                            # proxy_service_redis             port: 33025
│                                            # Network: bridge 11.0.5.0/24
│
├── storage/
│   └── log/                                 # Runtime log files (gitignored)
│
├── .env.example                             # Environment variable template
├── package.json                             # Project manifest & scripts
├── tsconfig.json                            # TypeScript config + path aliases:
│                                            # @api      -> src/api
│                                            # @utils    -> src/utils
│                                            # @services -> src/services
│                                            # @/        -> src/
└── .oxlintrc.json                           # OXLint linting rule configuration

4.1 Key Design Patterns#

PatternLocationPurpose
Mutex (async-mutex)proxy.service.ts — getOneFree(), ReturnProxy(), GetManyCanRotate()Prevent race conditions when multiple concurrent requests compete for proxy lease slots
Elysia Factory Functionsutils/createElysia.tsKeep Elysia instance setup DRY by injecting the correct auth middleware per security tier
Typegoose DecoratorsAll *.model.ts filesType-safe Mongoose schemas without duplicating TypeScript interfaces
DTO Schema as Single SourceAll *.dto.ts filest.Object() validates at request time; TypeScript type derived via typeof Schema.static — no duplication
Service SingletonEnd of each *.service.tsexport const proxyServices = new ProxyServices() — one shared instance per process
Child LoggersEach service classlogger.child("proxy") scopes log entries with a service tag for easy filtering
Cron co-located with Controllerproxy.controller.tsKeeps cron lifecycle bound to the route module that owns the domain logic
Ngày cập nhật 2026-03-30 03:08:55
Trước
Logic nghiệp vụ
Tiếp theo
Tài liệu API
Built with