Files
OmniRoute/docs/i18n/vi/CONTRIBUTING.md
Diego Rodrigues de Sa e Souza b637350680 fix(docs): re-sync the 65 documentation mirror sets; section-level docs pipeline; drift gate blocking (#13940)
1,104 mirrors rewritten over five passes of run-translation on the 22-source core set: the 14 sources edited since their translation, the 322 mirrors that were still English copies, and the frontmatter the old extractor leaked into the newer locales' bodies. The pipeline now caches per-`## `-section hashes and retranslates only changed sections, never reuses a section that is still English, rebuilds English-copy / leaked mirrors even when the source is unchanged, merges the state on save (parallel runs), and the drift gate (scoped to the core set) is blocking. Final audit: 0 stale, 0 English copies, 0 leaked frontmatter across 1,430 core mirrors.

⚠️ base-red inherited: #12732
2026-09-17 02:55:31 -03:00

26 KiB

Contributing to OmniRoute (Tiếng Việt)

🌐 Languages: 🇺🇸 English · 🇪🇹 am · 🇸🇦 ar · 🇦🇿 az · 🇧🇬 bg · 🇧🇩 bn · 🇨🇿 cs · 🇩🇰 da · 🇩🇪 de · 🇬🇷 el · 🇪🇸 es · 🇪🇪 et · 🇮🇷 fa · 🇫🇮 fi · 🇫🇷 fr · 🇮🇪 ga · 🇮🇳 gu · 🇳🇬 ha · 🇮🇱 he · 🇮🇳 hi · 🇭🇷 hr · 🇭🇺 hu · 🇦🇲 hy · 🇮🇩 id · 🇳🇬 ig · 🇮🇹 it · 🇯🇵 ja · 🇬🇪 ka · 🇰🇭 km · 🇮🇳 kn · 🇰🇷 ko · 🇱🇹 lt · 🇱🇻 lv · 🇮🇳 ml · 🇮🇳 mr · 🇲🇾 ms · 🇲🇹 mt · 🇲🇲 my · 🇳🇵 ne · 🇳🇱 nl · 🇳🇴 no · 🇮🇳 or · 🇮🇳 pa · 🇵🇭 phi · 🇵🇱 pl · 🇵🇹 pt · 🇧🇷 pt-BR · 🇷🇴 ro · 🇷🇺 ru · 🇱🇰 si · 🇸🇰 sk · 🇸🇮 sl · 🇷🇸 sr · 🇸🇪 sv · 🇰🇪 sw · 🇮🇳 ta · 🇮🇳 te · 🇹🇭 th · 🇹🇷 tr · 🇺🇦 uk-UA · 🇵🇰 ur · 🇺🇿 uz · 🇳🇬 yo · 🇨🇳 zh-CN · 🇹🇼 zh-TW


Thank you for your interest in contributing! This guide covers everything you need to get started.


Thiết lập môi trường phát triển

Điều kiện tiên quyết

  • Node.js >=22.22.3 <23, hoặc >=24.0.0 <27 (khuyến nghị: 24 LTS)
  • npm 10+

Người dùng npm v11+ (Node 24+): Sau khi chạy npm install, hãy xác minh rằng các mô-đun native đã được cài đặt: node -e "require('better-sqlite3')". Nếu lệnh thất bại với MODULE_NOT_FOUND, hãy chạy npm approve-scripts better-sqlite3 && npm install. Xem Khắc phục sự cố.

  • Git

Sao chép kho lưu trữ & Cài đặt

git clone https://github.com/diegosouzapw/OmniRoute.git
cd OmniRoute
npm install

Biến môi trường

# Tạo tệp .env từ mẫu
cp .env.example .env

# Tạo các khóa bí mật bắt buộc
echo "JWT_SECRET=$(openssl rand -base64 48)" >> .env
echo "API_KEY_SECRET=$(openssl rand -hex 32)" >> .env

Các biến chính dành cho phát triển:

Biến Giá trị mặc định khi phát triển Mô tả
PORT 20128 Cổng máy chủ
NEXT_PUBLIC_BASE_URL http://localhost:20128 URL cơ sở cho frontend
JWT_SECRET (tạo ở trên) Khóa bí mật để ký JWT
INITIAL_PASSWORD CHANGEME Mật khẩu đăng nhập lần đầu
APP_LOG_LEVEL info Mức độ chi tiết của nhật ký

Cài đặt bảng điều khiển

Bảng điều khiển cung cấp các nút bật/tắt trên giao diện người dùng cho những tính năng cũng có thể được cấu hình thông qua biến môi trường:

Vị trí cài đặt Nút bật/tắt Mô tả
Cài đặt → Nâng cao Chế độ gỡ lỗi Bật nhật ký yêu cầu gỡ lỗi (giao diện người dùng)
Cài đặt → Chung Khả năng hiển thị thanh bên Hiện/ẩn các phần của thanh bên

Các cài đặt này được lưu trong cơ sở dữ liệu và duy trì qua các lần khởi động lại, đồng thời ghi đè các giá trị mặc định của biến môi trường khi được thiết lập.

Chạy cục bộ

# Chế độ phát triển (tải lại nóng)
npm run dev

# Bản dựng sản xuất
npm run build    # next build → .build/next/ sau đó assembleStandalone → dist/
npm run start

# Biên dịch nhanh chỉ dành cho backend/API đối với các thay đổi của người đóng góp
npm run build:contributor

# Bản dựng phát hành (dựng lại từ đầu + dấu kiểm HEAD — bắt buộc để triển khai)
npm run build:release   # rm -rf .build dist && build + ghi dist/BUILD_SHA

# Cấu hình cổng thường dùng
PORT=20128 NEXT_PUBLIC_BASE_URL=http://localhost:20128 npm run dev

Bản dựng dành cho người đóng góp chỉ thực hiện xác thực biên dịch: nó không lắp ráp bản phân phối độc lập hoặc dựng các tài nguyên đóng gói native tùy chọn. Hãy sử dụng bản dựng sản xuất thông thường khi bạn cần xác thực gói có thể phát hành.

Bố cục đầu ra bản dựng

Thư mục Nội dung Được theo dõi
src/ Mã nguồn ứng dụng (TypeScript / TSX)
.build/ Các tệp trung gian — đầu ra của next build (được git bỏ qua, distDir = .build/next) Không
dist/ Gói có thể phát hành — được lắp ráp bởi assembleStandalone (được git bỏ qua) Không

Quy trình dựng chỉ gồm một lượt:

npm run build
  └─ next build → .build/next/standalone  (đầu ra Next.js)
  └─ assembleStandalone()                 (sao chép bản độc lập + tệp tĩnh + công khai + tài nguyên native)
       └─ đầu ra: dist/                   (server.js, .next/static/, public/, node_modules/)

npm run build:release còn dọn sạch cả hai thư mục trước tiên và ghi dist/BUILD_SHA (= git rev-parse --short HEAD) làm dấu kiểm tính toàn vẹn khi triển khai.

npm run build:contributor sử dụng cấu hình dựng chỉ dành cho backend. Cấu hình này tạm thời thay thế các tệp giao diện người dùng của bảng điều khiển bằng tệp giả trong khi dựng, giữ nguyên các trình xử lý tuyến API và khôi phục các tệp gốc sau khi dựng. Hãy sử dụng npm run build cho các thay đổi ảnh hưởng đến giao diện người dùng của bảng điều khiển hoặc để xác thực đầy đủ bản phát hành; cấu hình dành cho người đóng góp không thay thế cho bản dựng phát hành.

Lưu ý khi triển khai lên VPS: thư mục image từ xa /usr/lib/node_modules/omniroute/app/ không thay đổi. Các kỹ năng triển khai dùng rsync để đồng bộ nội dung của dist/ vào thư mục đó. Chỉ đường dẫn đầu ra bản dựng trong kho lưu trữ được thay đổi (app/dist/).

Các URL mặc định:

  • Bảng điều khiển: http://localhost:20128/dashboard
  • API: http://localhost:20128/v1

Quy trình làm việc với Git

⚠️ KHÔNG BAO GIỜ commit trực tiếp vào main. Luôn sử dụng các nhánh tính năng.

Nhánh cơ sở của PR: nhắm đến nhánh release/vX.Y.Z đang hoạt động (không phải main). Xem docs/ops/BRANCHING_MODEL.md để biết mô hình mỗi bản phát hành một nhánh + gắn thẻ khi phát hành.

# Tạo nhánh từ đầu nhánh phát hành đang hoạt động (ví dụ: release/v3.8.49)
git fetch origin
git checkout -b feat/your-feature-name origin/release/v3.8.49
# ... thực hiện thay đổi ...
git commit -m "feat: mô tả thay đổi của bạn"
git push -u origin feat/your-feature-name
# Mở Pull Request với base = release/v3.8.49

Quy tắc đặt tên nhánh

Tiền tố Mục đích
feat/ Tính năng mới
fix/ Sửa lỗi
refactor/ Tái cấu trúc mã nguồn
docs/ Thay đổi tài liệu
test/ Bổ sung/sửa kiểm thử
chore/ Công cụ, CI, các phần phụ thuộc

Thông điệp commit

Tuân theo Conventional Commits:

feat: thêm circuit breaker cho các lệnh gọi đến nhà cung cấp
fix: xử lý trường hợp biên khi xác thực JWT secret
docs: cập nhật SECURITY.md với biện pháp bảo vệ PII
test: thêm các kiểm thử đơn vị về khả năng quan sát
refactor(db): hợp nhất các bảng giới hạn tốc độ

Phạm vi (v3.8): db, sse, oauth, dashboard, api, cli, docker, ci, mcp, a2a, memory, skills, cloud-agent, guardrails, compression, auto-combo, resilience, providers, executors, translator, domain, authz.


Chạy kiểm thử

# Tất cả kiểm thử (unit + vitest + ecosystem + e2e)
npm run test:all

# Một tệp kiểm thử duy nhất (trình chạy kiểm thử gốc của Node.js — hầu hết kiểm thử sử dụng cách này)
node --import tsx/esm --test tests/unit/your-file.test.ts

# Chỉ các kiểm thử đơn vị bị ảnh hưởng bởi thay đổi của bạn (cùng bộ chọn TIA như cổng CI, #8084)
npm run test:scoped            # các thay đổi trong commit gần nhất (hoặc cây làm việc)
npm run test:scoped:staged     # chỉ các thay đổi đã staged — phù hợp để chạy cùng pre-commit
npm run test:scoped:full       # xây dựng lại ánh xạ đồ thị nhập trước (sau khi thêm/di chuyển tệp)
# Mã thoát 1 + "run the full suite" có nghĩa là một tệp trung tâm (tsconfig, package.json, …) hoặc
# nguồn chưa được ánh xạ đã thay đổi — bộ chọn chuyển sang chế độ an toàn, không bao giờ âm thầm bỏ qua.

# Vitest (máy chủ MCP, autoCombo, bộ nhớ đệm)
npm run test:vitest

# Kiểm thử E2E (yêu cầu Playwright)
npm run test:e2e

# E2E cho các máy khách giao thức (phương thức truyền tải MCP, A2A)
npm run test:protocols:e2e

# Kiểm thử khả năng tương thích hệ sinh thái
npm run test:ecosystem

# Ngưỡng độ bao phủ: 60% câu lệnh/dòng/hàm/nhánh
npm run test:coverage
npm run coverage:report

# Kiểm tra lint + định dạng
npm run lint
npm run check

# Kiểm thử nhanh tổ hợp thực tế có kiểm soát với upstream (yêu cầu quyền truy cập VPS + tín dụng nhà cung cấp thực)
# Gọi các nhà cung cấp THỰC — tốn một ít chi phí. KHÔNG BAO GIỜ chạy trong CI. Bỏ qua an toàn nếu không có cổng kiểm soát.
# Yêu cầu: quyền truy cập ssh root@192.168.0.15 (nạp ảnh chụp nhanh DB chỉ đọc từ VPS).
RUN_COMBO_LIVE=1 npm run test:combo:live

# Kiểm thử nhanh trực tiếp VPS giai đoạn 3 — các tập lệnh Node ESM thuần túy, gọi trực tiếp máy chủ .15 đang hoạt động.
# Yêu cầu: quyền truy cập ssh root@192.168.0.15 (các tổ hợp được tạo/xóa qua SSH sqlite).
# Gọi các nhà cung cấp THỰC (chi phí nhỏ). Chỉ tạo/xóa các tổ hợp __live_test__*. KHÔNG BAO GIỜ chạy trong CI.
# REQUIRE_API_KEY=false trên .15 nên không cần khóa API, nhưng vẫn tuân theo COMBO_LIVE_BASE_URL / COMBO_LIVE_API_KEY nếu được đặt.
npm run test:combo:live:vps              # 7 kịch bản HTTP (ưu tiên/luân phiên/có trọng số/chi phí/hợp nhất/tự động + trạng thái)
npm run test:combo:live:vps:failover     # thêm một kịch bản chuyển đổi dự phòng thực giữa các nhà cung cấp (tổng cộng 8)

Ghi chú về độ bao phủ:

  • npm run test:coverage đo độ bao phủ mã nguồn cho bộ kiểm thử đơn vị chính, loại trừ tests/** và bao gồm open-sse/**
  • Các pull request phải duy trì ngưỡng độ bao phủ ở mức 60%+ đối với câu lệnh/dòng/hàm/nhánh
  • Nếu một PR thay đổi mã production trong src/, open-sse/, electron/ hoặc bin/, PR đó phải thêm hoặc cập nhật các kiểm thử tự động trong cùng PR
  • npm run coverage:report in báo cáo chi tiết theo từng tệp từ lần chạy độ bao phủ gần nhất
  • npm run test:coverage:legacy giữ lại chỉ số cũ để so sánh theo lịch sử
  • Xem docs/ops/COVERAGE_PLAN.md để biết lộ trình cải thiện độ bao phủ theo từng giai đoạn

Yêu cầu đối với Pull Request

Trước khi mở một PR, hãy sử dụng Quy trình chuẩn để đóng góp để chạy vòng lặp tập trung cho những gì bạn đã thay đổi. Toàn bộ bộ kiểm thử đơn vị (4 phân đoạn CI), Vitest, ngưỡng độ bao phủ 60%+ và bản dựng production thuộc trách nhiệm của CI — việc chạy chúng cục bộ không cung cấp thêm tín hiệu nào ngoài những gì các bước kiểm tra PR đã cung cấp, đồng thời trên các máy cấu hình thấp hơn, việc này có thể làm quá tải máy chủ (#8084):

  • Chạy các tệp kiểm thử bao phủ thay đổi của bạn: node --import tsx/esm --test tests/unit/<file>.test.ts
  • Chạy npm run lint
  • Thêm hoặc cập nhật các kiểm thử tự động trong cùng PR bất cứ khi nào mã production thay đổi
  • Liệt kê các tệp kiểm thử đã thay đổi hoặc được thêm vào trong phần mô tả PR khi mã production thay đổi
  • Kiểm tra kết quả SonarQube trên PR khi các secret của dự án được cấu hình trong CI

Trạng thái kiểm thử hiện tại: 122 tệp kiểm thử đơn vị bao phủ:

  • Các trình chuyển đổi nhà cung cấp và chuyển đổi định dạng
  • Giới hạn tốc độ, bộ ngắt mạch và khả năng phục hồi
  • Bộ nhớ đệm ngữ nghĩa, tính lũy đẳng, theo dõi tiến độ
  • Các thao tác cơ sở dữ liệu và schema (21 mô-đun DB)
  • Các luồng OAuth và xác thực
  • Xác thực endpoint API (Zod v4)
  • Các công cụ máy chủ MCP và thực thi phạm vi
  • Các hệ thống Memory và Skills

Phong cách mã nguồn

  • ESLint — Chạy npm run lint trước khi commit
  • Prettier — Tự động định dạng qua lint-staged khi commit (thụt lề 2 khoảng trắng, dấu chấm phẩy, dấu ngoặc kép, độ rộng 100 ký tự, dấu phẩy cuối theo es5)
  • TypeScript — Toàn bộ mã trong src/ sử dụng .ts/.tsx; open-sse/ sử dụng .ts/.js; viết tài liệu bằng TSDoc (@param, @returns, @throws)
  • Không dùng eval() — ESLint áp dụng các quy tắc no-eval, no-implied-eval, no-new-func
  • Xác thực bằng Zod — Sử dụng schema Zod v4 để xác thực toàn bộ đầu vào API
  • Quy tắc đặt tên: Tệp = camelCase/kebab-case, component = PascalCase, hằng số = UPPER_SNAKE

Xử lý lỗi / khối catch rỗng

Không bao giờ để một catch mà không giải thích. Hãy phân loại nó vào một trong hai nhóm (cụ thể hóa quy tắc nghiêm ngặt "không bao giờ âm thầm bỏ qua lỗi trong luồng SSE"):

  • Có chủ đích (hoạt động dọn dẹp/đo từ xa theo nỗ lực tối đa của chính chúng ta) — lỗi ở đây là điều được dự kiến và vô hại; thêm một dòng chú thích nêu lý do, không ghi log (quy ước này nhằm tránh việc ghi log cho mọi request gây nhiễu).

    } catch {} // việc đóng một controller đã đóng sau khi client ngắt kết nối là điều được dự kiến
    
  • Nên ghi log (mã bên ngoài/do bên gọi cung cấp, hoặc việc bỏ qua làm thay đổi luồng điều khiển) — giữ lại catch (không bao giờ để nó làm gián đoạn luồng) nhưng phát ra console.debug/warn có ngữ cảnh để lỗi có thể được phát hiện.

    } catch (e) {
      console.debug("[STREAM] onFailure callback error:", e);
    }
    

Xem open-sse/utils/stream.tsopen-sse/utils/streamHandler.ts để biết các ví dụ đã áp dụng.


Project Structure

src/                        # TypeScript (.ts / .tsx)
├── app/                    # Next.js 16 App Router
│   ├── (dashboard)/        # Dashboard pages (23 sections)
│   ├── api/                # API routes (51 directories)
│   └── login/              # Auth pages (.tsx)
├── domain/                 # Policy engine (policyEngine, comboResolver, costRules, etc.)
├── lib/                    # Core business logic (.ts)
│   ├── a2a/                # Agent-to-Agent v0.3 protocol server
│   ├── acp/                # Agent Communication Protocol registry
│   ├── compliance/         # Compliance policy engine
│   ├── db/                 # SQLite database layer (110 top-level modules + 130 migrations)
│   ├── memory/             # Persistent conversational memory
│   ├── oauth/              # OAuth providers, services, and utilities
│   ├── skills/             # Extensible skill framework
│   ├── usage/              # Usage tracking and cost calculation
│   └── localDb.ts          # Re-export layer only — never add logic here
├── middleware/              # Request middleware (promptInjectionGuard)
├── mitm/                   # MITM proxy (cert, DNS, target routing)
├── shared/
│   ├── components/         # React components (.tsx)
│   ├── constants/          # Provider definitions (329), MCP scopes, routing strategies
│   ├── utils/              # Circuit breaker, sanitizer, auth helpers
│   └── validation/         # Zod v4 schemas
└── sse/                    # SSE proxy pipeline

open-sse/                   # @omniroute/open-sse workspace
├── executors/              # 89 executor implementation modules
├── handlers/               # 11 request handlers (chat, responses, embeddings, images, etc.)
├── mcp-server/             # MCP server (107 tools, 3 transports, 32 scopes)
├── services/               # 178 top-level services (combo, autoCombo, rateLimitManager, etc.)
├── translator/             # Format translators (OpenAI ↔ Claude ↔ Gemini ↔ Responses ↔ Ollama)
├── transformer/            # Responses API transformer
└── utils/                  # 22 utility modules (stream, TLS, proxy, logging)

electron/                   # Electron desktop app (cross-platform)

tests/
├── unit/                   # Node.js test runner (122 test files)
├── integration/            # Integration tests
├── e2e/                    # Playwright tests
├── security/               # Security tests
├── translator/             # Translator-specific tests
└── load/                   # Load tests

docs/                       # Documentation
├── ARCHITECTURE.md         # System architecture
├── API_REFERENCE.md        # All endpoints
├── USER_GUIDE.md           # Provider setup, CLI integration
├── TROUBLESHOOTING.md      # Common issues
├── MCP-SERVER.md           # MCP server (107 tools)
├── A2A-SERVER.md           # A2A agent protocol
├── AUTO-COMBO.md           # Auto-combo engine
├── CLI-TOOLS.md            # CLI tools integration
├── COVERAGE_PLAN.md        # Test coverage improvement plan
├── openapi.yaml            # OpenAPI specification
└── adr/                    # Architecture Decision Records

Thêm Nhà cung cấp Mới

Bước 1: Đăng ký các Hằng số của Nhà cung cấp

Thêm vào src/shared/constants/providers.ts — được Zod xác thực khi mô-đun tải.

Bước 2: Thêm Executor (nếu cần logic tùy chỉnh)

Tạo executor trong open-sse/executors/your-provider.ts, kế thừa executor cơ sở.

Bước 3: Thêm Translator (nếu không dùng định dạng OpenAI)

Tạo các translator cho yêu cầu/phản hồi trong open-sse/translator/.

Bước 4: Thêm Cấu hình OAuth (nếu dựa trên OAuth)

Thêm thông tin xác thực OAuth trong src/lib/oauth/constants/oauth.ts và dịch vụ trong src/lib/oauth/services/.

Nếu nhà cung cấp thượng nguồn phân phối OAuth client_id/secret công khai hoặc khóa Firebase Web API bên trong CLI / gói trình duyệt công khai của họ, không nhúng dưới dạng chuỗi ký tự. Sử dụng resolvePublicCred() từ open-sse/utils/publicCreds.ts và thêm một mục byte đã che vào EMBEDDED_DEFAULTS. Quy trình bắt buộc đầy đủ được ghi lại trong docs/security/PUBLIC_CREDS.md.

Bên trong các handler/executor, thông báo lỗi gửi đến máy khách phải đi qua buildErrorBody() / sanitizeErrorMessage() từ open-sse/utils/error.ts — tuyệt đối không đưa trực tiếp err.stack hoặc err.message vào phần thân Response. Xem docs/security/ERROR_SANITIZATION.md.

Bước 5: Đăng ký các Mô hình

Thêm định nghĩa mô hình trong open-sse/config/providerRegistry.ts.

Bước 6: Thêm Kiểm thử

Viết các kiểm thử đơn vị trong tests/unit/, tối thiểu bao gồm:

  • Đăng ký nhà cung cấp
  • Chuyển đổi yêu cầu/phản hồi
  • Xử lý lỗi

Danh sách kiểm tra Pull Request

  • Các bài kiểm thử đều vượt qua (npm test)
  • Quá trình kiểm tra lint vượt qua (npm run lint)
  • Quá trình build thành công (npm run build)
  • Đã thêm kiểu TypeScript cho các hàm và interface công khai mới
  • Không có secret hoặc giá trị dự phòng được mã hóa cứng
  • Thông tin xác thực upstream công khai được nhúng thông qua resolvePublicCred() (xem docs/security/PUBLIC_CREDS.md), tuyệt đối không dùng giá trị literal
  • Phản hồi lỗi được xử lý thông qua buildErrorBody() / sanitizeErrorMessage() — không đưa stack trace thô vào nội dung phản hồi (xem docs/security/ERROR_SANITIZATION.md)
  • Các lệnh shell (exec / spawn) truyền giá trị runtime qua env, không thông qua nội suy chuỗi
  • Tất cả đầu vào đều được xác thực bằng schema Zod
  • Đã thêm fragment changelog vào changelog.d/{features|fixes|maintenance}/<PR>-<slug>.md cho các thay đổi ảnh hưởng đến người dùng (xem changelog.d/README.md) — không chỉnh sửa trực tiếp CHANGELOG.md; các fragment được tổng hợp khi phát hành và không bao giờ xung đột giữa các PR
  • Đã cập nhật tài liệu (nếu áp dụng)
  • Không tạo cảnh báo CodeQL / Secret-Scanning mới, hoặc mỗi cảnh báo đã được loại bỏ kèm lý do kỹ thuật có tham chiếu đến tài liệu docs/security/ liên quan
  • Các route tạo tiến trình con (/api/mcp/, /api/cli-tools/runtime/) được phân loại là isLocalOnlyPath() trong src/server/authz/routeGuard.ts — xem Quy tắc bắt buộc #15
  • Không có trailer Co-Authored-By trong thông điệp commit — các commit phải chỉ hiển thị danh tính Git của chủ sở hữu repository (Quy tắc bắt buộc #16)

Releasing

Releases are managed via the /generate-release workflow. When a new GitHub Release is created, the package is automatically published to npm via GitHub Actions.


Nhận trợ giúp