# Hướng dẫn cho AI agent

> Chỉ mục máy đọc, bản Markdown của từng bài và lời nhắc cài đặt cho AI agent lập trình như Lovable, Cursor, Claude Code.

Trang này dành cho AI agent lập trình — Lovable, Cursor, Claude Code, Copilot và các agent khác — và cho người giao việc cài đặt cho chúng. Mọi nội dung ở đây đều có bản Markdown thuần, để agent đọc được mà không cần trình duyệt.

## Tài liệu cho máy đọc

| URL | Nội dung |
|---|---|
| `https://belvador.dev/llms.txt` | Chỉ mục mọi trang bằng tiếng Anh và tiếng Việt, kèm tóm tắt một dòng (theo bố cục [llmstxt.org](https://llmstxt.org)) |
| `https://belvador.dev/llms-full.txt` | Mọi trang dạng Markdown trong một tệp, tiếng Anh trước rồi tiếng Việt |
| `https://belvador.dev/api/public/docs/<locale>/<slug>` | Một trang dạng Markdown, ví dụ `/api/public/docs/vi/sdk/tanstack-start` |
| `https://belvador.dev/api/public/docs/<locale>/index` | Chỉ mục của một ngôn ngữ (`en` hoặc `vi`) |
| `https://belvador.dev/api/public/docs/<locale>/full` | Mọi trang của một ngôn ngữ trong một tệp |

Mỗi trang tài liệu cũng có nút **Sao chép Markdown** và liên kết **Bản Markdown**. Bản Markdown được tạo từ cùng nguồn với trang, kể cả code cài đặt, nên không bao giờ khác với nội dung người đọc thấy. Các URL này công khai, không cần đăng nhập và không trả về dữ liệu tài khoản nào.

## Quy tắc khi cài Belvador vào ứng dụng

1. **Lấy DSN từ người dùng.** DSN nằm trên trang project trong Belvador. Không bao giờ tự bịa, không dùng lại DSN của project khác. Một ứng dụng = một project = một DSN, dùng chung cho phần trình duyệt và phần máy chủ.
2. **Cài đúng phiên bản**: `@belvador/<gói>@0.6.1`. Với ứng dụng JavaScript, không thêm gói SDK `@sentry/*` nào — gói Belvador đã mang engine được rà soát. (Dùng `@sentry/cli` trong CI cho [source map](https://belvador.dev/vi/docs/source-maps) thì được.)
3. **Giữ nguyên những gì ứng dụng đang làm.** Thêm vào `src/server.ts`, `src/start.ts` và file router hiện có; không thay thế. Giữ middleware hiện có đúng thứ tự, và thêm middleware của Belvador **cuối cùng**.
4. **Không làm yếu bảo mật.** Gộp `https://ingest.belvador.dev` vào `connect-src` hiện có; không xoá hay thay Content-Security-Policy, chống CSRF, xác thực hay header bảo mật.
5. **Gỡ cài đặt Sentry cũ** (`Sentry.init`, `@sentry/*`) để lỗi không bị báo hai lần.
6. **Không đụng bí mật.** Không đọc, in, ghi log hay commit bí mật. Không đặt token, mật khẩu hay email người dùng vào tag, ngữ cảnh hoặc message. DSN không phải bí mật; token upload thì có — chúng thuộc về biến bí mật của CI.
7. **Không đổi logic nghiệp vụ.** Chỉ thêm phần theo dõi lỗi.
8. **Kiểm từng môi trường** bằng phép kiểm kết nối trong lời nhắc cài đặt (xem [Kiểm tra kết nối](https://belvador.dev/vi/docs/sdk/verify)). Chỉ báo xong khi từng kết quả là `verified` — hoặc kết quả đọc lại có đủ mọi phép kiểm. Nếu kết quả là `problem` hoặc `unconfirmed`, đưa nguyên dòng `[belvador] verify …` hoặc kết quả đọc lại cho người dùng. Xoá code kiểm tạm sau đó.

## Lời nhắc cài đặt

Đây là các lời nhắc mà ứng dụng Belvador hiển thị ở mục **Dán vào AI agent**. Thay DSN mẫu bằng DSN của project — ứng dụng điền sẵn giúp bạn.

### TanStack Start / Lovable

````text
@belvador/tanstack-start

Runtime: browser+workers

react: ^18.0.0 || ^19.0.0

@tanstack/react-router: ^1.168.0

@tanstack/react-start: ^1.168.0

Cloudflare Workers: nodejs_compat

Cài đặt
Thêm gói vào ứng dụng.
```bash
npm install @belvador/tanstack-start@0.6.1
```

Khởi tạo
Khởi tạo càng sớm càng tốt. Dữ liệu cá nhân và thông tin đăng nhập bị loại bỏ trước khi gửi.
src/instrument.ts
```typescript
import { init } from "@belvador/tanstack-start/client";

// Imported first by src/start.ts and src/router.tsx. Runs only in the browser.
if (typeof window !== "undefined") {
  init({
    dsn: "https://<public-key>@ingest.belvador.dev/<project-id>",
    release: import.meta.env.VITE_APP_VERSION, // your build or commit id
    environment: import.meta.env.MODE,
  });
}
```

Trình duyệt
Import ./instrument ở dòng đầu tiên và báo lỗi trang qua defaultOnCatch. Hàm này chỉ chạy ở nơi có error component.
src/router.tsx
```typescript
import "./instrument"; // first line, before the route tree
import { withBelvadorRouter } from "@belvador/tanstack-start/client";

// In getRouter(): wrap the options you already pass to createRouter.
// createRouter(withBelvadorRouter({ routeTree, ...yourOptions }))
// It reports route errors, calls your own defaultOnCatch after that, and adds
// TanStack's error component only if you set no defaultErrorComponent.
```

Máy chủ (Cloudflare Workers)
Bọc điểm vào máy chủ: mỗi request một phạm vi riêng, lỗi vẫn được ném tiếp, response giữ nguyên. Cần cờ nodejs_compat (app Lovable đã có).
src/server.ts
```typescript
import handler from "@tanstack/react-start/server-entry";
import { withBelvador } from "@belvador/tanstack-start/server";

// Requires Cloudflare Workers with nodejs_compat enabled.
// If src/server.ts already exists, wrap its default export instead of `handler`.
// vite.config.ts needs tanstackStart: { server: { entry: "server" } } (Lovable apps have it).
export default withBelvador(
  (env: { BELVADOR_DSN?: string; BELVADOR_RELEASE?: string }) => ({
    dsn: env.BELVADOR_DSN ?? "https://<public-key>@ingest.belvador.dev/<project-id>",
    release: env.BELVADOR_RELEASE,
  }),
  handler,
);
```

Middleware
Đặt ở cuối mỗi danh sách để thấy lỗi server function và server route trước khi middleware trang lỗi xử lý.
src/start.ts
```typescript
import "./instrument"; // first line: the browser loads start.ts before the router
import { createStart } from "@tanstack/react-start";
import { belvadorFunctionMiddleware, belvadorRequestMiddleware } from "@belvador/tanstack-start";

export const startInstance = createStart(() => ({
  // Last in each list, after your own middleware.
  requestMiddleware: [/* …your middleware, */ belvadorRequestMiddleware],
  functionMiddleware: [/* …your middleware, */ belvadorFunctionMiddleware],
}));
```

Content Security Policy
Nếu ứng dụng có header CSP, cho phép địa chỉ nhận lỗi trong connect-src.
```text
connect-src 'self' https://ingest.belvador.dev;
```

Kiểm trình duyệt
Chứng minh lỗi bắt bằng code và lỗi không bắt ở trình duyệt tới đúng project này, rồi đọc lại kết quả từ Belvador.
```typescript
import { verifyIntegration } from "@belvador/tanstack-start/client";

// Run once after setup or deploy (for example behind a debug flag), never on every page load.
// The console shows one expected "Belvador verification (uncaught)" error — that is the test.
const result = await verifyIntegration();
// result.outcome: "verified" | "problem" | "unconfirmed"; the console prints one summary line.
```

Kiểm máy chủ
Chứng minh code máy chủ chạy trong middleware của Belvador và lỗi của nó tới đúng project này.
src/routes/api/verify-belvador.ts
```typescript
import { createFileRoute } from "@tanstack/react-router";
import { verifyIntegration } from "@belvador/tanstack-start/server";

// Temporary: open /api/verify-belvador once after deploying, then delete this file.
// It must run inside belvadorRequestMiddleware (src/start.ts) — that is part of the check.
export const Route = createFileRoute("/api/verify-belvador")({
  server: {
    handlers: {
      GET: async () => Response.json(await verifyIntegration()),
    },
  },
});
```

Đọc lại kết quả
Dùng id app đã in ra. Kết quả liệt kê phép kiểm nào đã tới node.
```bash
curl -s "https://ingest.belvador.dev/api/<project-id>/verification/bv1_<id printed by your app>/?sentry_key=<public-key>"
```

Trước khi báo xong
Chạy phép kiểm cho mọi môi trường ở trên. Chỉ báo xong khi từng kết quả là verified (hoặc kết quả đọc lại có đủ mọi phép kiểm). Nếu kết quả là problem hoặc unconfirmed, đưa nguyên dòng "[belvador] verify …" hoặc kết quả đọc lại cho người dùng. Không bao giờ xoá middleware, trang lỗi hay header bảo mật sẵn có để phép kiểm qua.

Theo dõi việc chạy ngầm
Hỏi người dùng cần theo dõi cron job, hàng đợi hay worker nào — không tự đoán. Dùng withMonitor (SDK Belvador), API crons của Sentry SDK, hoặc check-in qua HTTP. Chạy thử mỗi job một lần và chỉ báo xong khi trang Monitor của Belvador thấy lượt đó. Trình duyệt không bao giờ gửi check-in.
````

### React

````text
@belvador/react

Runtime: browser

react: ^18.0.0 || ^19.0.0

Cài đặt
Thêm gói vào ứng dụng.
```bash
npm install @belvador/react@0.6.1
```

Khởi tạo
Khởi tạo càng sớm càng tốt. Dữ liệu cá nhân và thông tin đăng nhập bị loại bỏ trước khi gửi.
src/instrument.ts
```typescript
import { init } from "@belvador/react";

init({
  dsn: "https://<public-key>@ingest.belvador.dev/<project-id>",
  release: import.meta.env.VITE_APP_VERSION, // your build or commit id
  environment: import.meta.env.MODE,
});
```

Import đầu tiên
Đặt nó là dòng import đầu tiên của file entry. Các import chạy trước phần còn lại của file, nên lỗi xảy ra lúc các module của app đang nạp chỉ được báo khi Belvador đã khởi động trước đó.
src/main.tsx
```tsx
import "./instrument"; // first line: starts Belvador before App's modules load
import { createRoot } from "react-dom/client";
import { ErrorBoundary } from "@belvador/react";

import App from "./App";

const root = document.getElementById("root");
if (!root) throw new Error("Root element missing");
createRoot(root).render(
  <ErrorBoundary fallback={<p>Something went wrong.</p>}>
    <App />
  </ErrorBoundary>,
);
```

Content Security Policy
Nếu ứng dụng có header CSP, cho phép địa chỉ nhận lỗi trong connect-src.
```text
connect-src 'self' https://ingest.belvador.dev;
```

Kiểm trình duyệt
Chứng minh lỗi bắt bằng code và lỗi không bắt ở trình duyệt tới đúng project này, rồi đọc lại kết quả từ Belvador.
```typescript
import { verifyIntegration } from "@belvador/react";

// Run once after setup or deploy (for example behind a debug flag), never on every page load.
// The console shows one expected "Belvador verification (uncaught)" error — that is the test.
const result = await verifyIntegration();
// result.outcome: "verified" | "problem" | "unconfirmed"; the console prints one summary line.
```

Đọc lại kết quả
Dùng id app đã in ra. Kết quả liệt kê phép kiểm nào đã tới node.
```bash
curl -s "https://ingest.belvador.dev/api/<project-id>/verification/bv1_<id printed by your app>/?sentry_key=<public-key>"
```

Trước khi báo xong
Chạy phép kiểm cho mọi môi trường ở trên. Chỉ báo xong khi từng kết quả là verified (hoặc kết quả đọc lại có đủ mọi phép kiểm). Nếu kết quả là problem hoặc unconfirmed, đưa nguyên dòng "[belvador] verify …" hoặc kết quả đọc lại cho người dùng. Không bao giờ xoá middleware, trang lỗi hay header bảo mật sẵn có để phép kiểm qua.

Theo dõi việc chạy ngầm
Hỏi người dùng cần theo dõi cron job, hàng đợi hay worker nào — không tự đoán. Dùng withMonitor (SDK Belvador), API crons của Sentry SDK, hoặc check-in qua HTTP. Chạy thử mỗi job một lần và chỉ báo xong khi trang Monitor của Belvador thấy lượt đó. Trình duyệt không bao giờ gửi check-in.
````

Với các môi trường khác, làm theo chính trang hướng dẫn: [Trình duyệt](https://belvador.dev/vi/docs/sdk/browser), [Cloudflare Workers](https://belvador.dev/vi/docs/sdk/cloudflare), [Node.js](https://belvador.dev/vi/docs/sdk/node), [Python](https://belvador.dev/vi/docs/sdk/python).

### Traces và logs OpenTelemetry

Ứng dụng hiển thị một lời nhắc cho mỗi runtime đã chứng nhận ở **Cài đặt project → Khoá ingest → Cài bằng AI agent**, điền sẵn endpoint của project và để chỗ giữ thay cho khoá. Lời nhắc cho Node.js:

````text
OpenTelemetry traces and logs → Belvador: Node.js

traces: supported (Belvador certification run 2026-10-24)
logs: supported (Belvador certification run 2026-10-24), records carry trace_id/span_id
Tested with: node 22.23.4, @opentelemetry/sdk-node 0.300.0, @opentelemetry/auto-instrumentations-node 0.82.0, pino 10.4.0
Guide: https://belvador.dev/vi/docs/otel/node

Mục tiêu
Gửi traces và logs OpenTelemetry của dịch vụ này tới Belvador qua OTLP/HTTP. Giữ nguyên SDK lỗi đang có (Belvador hoặc Sentry).

Trước khi sửa
Xác định runtime và phiên bản, kiểu module (CommonJS hay ES modules với Node.js), framework, cách app khởi động ở production và nơi chạy. Tìm phần khởi tạo OpenTelemetry, tracing của Sentry hoặc của nhà cung cấp khác đã có. Nếu đã có thứ tạo span, thêm Belvador làm đích xuất cho phần đó; nếu không rõ bên nào làm chủ tracing, hãy hỏi người dùng. Không bao giờ đọc, in hay commit bí mật — dùng chỗ giữ khoá.

Quy tắc
Mỗi tiến trình một tracer provider; không thêm SDK hay lớp bọc handler thứ hai cũng tạo span. Không đổi xác thực, thứ tự middleware hay logic nghiệp vụ. Không bật thu thân request/response, header, cookie, giá trị query hay nội dung tin nhắn GenAI. Để metrics tắt. Khoá ingest là bí mật phía máy chủ: chỉ trong biến môi trường hoặc kho bí mật, không bao giờ trong code trình duyệt hay biến môi trường công khai. Không dùng OpenTelemetry trên trình duyệt. Giữ cơ chế gom lô của exporter; không bao giờ chờ xuất dữ liệu trong từng request.

Biến môi trường
Đặt các biến này ở nơi app chạy (khoá để trong kho bí mật). Dùng tên thật của dịch vụ và môi trường của bản triển khai.
```bash
export OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.belvador.dev/otlp/<project-id>
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer%20<your-ingest-key>
export OTEL_TRACES_EXPORTER=otlp
export OTEL_LOGS_EXPORTER=otlp
export OTEL_METRICS_EXPORTER=none
export OTEL_SERVICE_NAME=my-service
export OTEL_RESOURCE_ATTRIBUTES=deployment.environment.name=production
```

Công thức đã chứng nhận
Làm đúng các bước này; đây là các bước lần chứng nhận của Belvador chạy. Chỉ đổi tên file, lệnh khởi động và tên dịch vụ cho hợp với project, và ghim phiên bản gói như phần còn lại của project.

```bash
npm install @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node
```

```bash
export OTEL_SEMCONV_STABILITY_OPT_IN=http
export OTEL_NODE_RESOURCE_DETECTORS=env,host,os
node --require @opentelemetry/auto-instrumentations-node/register app.js
```

```bash
export OTEL_SEMCONV_STABILITY_OPT_IN=http
export OTEL_NODE_RESOURCE_DETECTORS=env,host,os
node --experimental-loader=@opentelemetry/instrumentation/hook.mjs --import @opentelemetry/auto-instrumentations-node/register app.mjs
```

Kiểm chứng
Chạy app trên máy với các biến đã đặt và gửi một request. Xác nhận trang Traces của Belvador có một trace với span server và span client, trang Logs có một dòng log cùng trace ID. Sau đó nhờ người dùng bấm "Kiểm kết nối OTLP" ở tab Kết nối của project. Không gửi dữ liệu thử vào production nếu người dùng chưa cho phép.

Báo cáo
Liệt kê các file đã sửa, các gói đã thêm kèm phiên bản chính xác, cách tắt (bỏ OTEL_EXPORTER_OTLP_ENDPOINT hoặc gỡ cờ khởi động), môi trường và loại dữ liệu đã thực sự thấy tới, và những gì chưa kiểm.
````

Các runtime khác có cùng quy tắc và dùng công thức của runtime đó: [Python](https://belvador.dev/vi/docs/otel/python), [Go](https://belvador.dev/vi/docs/otel/go), [Java](https://belvador.dev/vi/docs/otel/java), [Deno](https://belvador.dev/vi/docs/otel/deno), [Collector](https://belvador.dev/vi/docs/otel/collector).

## Kiểm tra trước khi báo “xong”

| Kiểm tra | Kết quả mong đợi |
|---|---|
| Đã cài gói | `@belvador/<gói>` bản 0.6.1 trong `package.json`, không có `@sentry/*` |
| Khởi tạo trình duyệt | Chạy một lần, sớm; dùng DSN của người dùng; có release và environment |
| Máy chủ (TanStack Start) | `src/server.ts` bọc entry thật bằng `withBelvador`; đã bật `nodejs_compat` |
| Middleware (TanStack Start) | Hai middleware của Belvador nằm cuối danh sách của chúng |
| CSP | `connect-src` có `https://ingest.belvador.dev`; không xoá gì khác |
| Kiểm trình duyệt | Phép kiểm kết nối từ trình duyệt là `verified` (hoặc kết quả đọc lại có `delivery` và `uncaught`) |
| Kiểm máy chủ | Phép kiểm máy chủ là `verified` — đã chạy trong middleware của Belvador — hoặc kết quả đọc lại có `delivery` |
| Dọn dẹp | Đã xoá route hoặc code kiểm tạm; build và kiểm tra kiểu đều qua |

## Giới hạn cần nói với người dùng

- Lỗi ứng dụng đã bắt và xử lý sẽ không được gửi, trừ khi gọi `captureException`.
- Lỗi trong loader của route TanStack Start khi render trên máy chủ chỉ được báo một lần từ máy chủ, kèm stack phía máy chủ, khi router được bọc bằng `withBelvadorRouter({ routeTree })`; không bọc thì lỗi chỉ đến từ trình duyệt.
- Bộ lọc xoá dữ liệu nhạy cảm thường gặp theo tên và mẫu; không thể nhận ra mọi bí mật.
- Nhận được event ID không chứng minh event đã được lưu — hãy kiểm tra project trong Belvador.

## Những điều agent hay hiểu sai về sản phẩm

- Belvador theo dõi **lỗi**, **lượt chạy của việc chạy ngầm** (monitor), **kiểm tra uptime** và **SLO**, đồng thời lưu **trace và log** gửi qua OpenTelemetry ([OpenTelemetry](https://belvador.dev/vi/docs/otel/overview)). SDK Belvador không tự tạo span; trace đến từ SDK OpenTelemetry hoặc Collector. Không có session replay — xem [Bảng năng lực theo runtime](https://belvador.dev/vi/docs/reference/capabilities).
- Chỉ thêm monitor cho job người dùng chỉ định. Hãy hỏi cron job, hàng đợi hay worker nào quan trọng; không bọc mọi hàm. Monitor chỉ coi là xong khi lượt chạy hiện trên trang Monitor.
- Khách hàng **không** tự cài máy chủ: Belvador tạo node trong project Hetzner của khách ngay từ ứng dụng. Không có bước SSH hay Docker.
- Node lưu sự kiện lỗi, trace và log; cơ sở dữ liệu của Belvador chỉ lưu metadata.
- Cảnh báo dùng bot Telegram, Slack webhook hoặc email riêng của từng workspace, hoặc [webhook có chữ ký](https://belvador.dev/vi/docs/alerts/webhooks) gửi tới endpoint riêng của workspace.
- Belvador có **máy chủ MCP** tại `https://api.belvador.dev/mcp` (OAuth hoặc token) và bản chạy cục bộ `npx -y @belvador/mcp@0.6.0`. Agent đọc được issue, event, trace, log, monitor và tài liệu này; người dùng cài trong **Cài đặt → AI agent** — xem [Kết nối AI agent qua MCP](https://belvador.dev/vi/docs/mcp). Không dùng MCP thì agent gọi [REST API](https://belvador.dev/vi/docs/reference/api) bằng token cá nhân hoặc token service. Khoá, thành viên, nơi nhận cảnh báo và thay đổi node luôn chờ một người duyệt trên belvador.dev. Đừng bao giờ bảo người dùng dán token vào khung chat — hãy đọc từ biến môi trường `BELVADOR_TOKEN`.
