Giao diện
Viết tài liệu
Site này là VitePress trong thư mục docs/, build cùng monorepo và deploy từ main. Tài liệu viết theo kiểu docs-as-code: ví dụ là file chạy thật, bảng API sinh từ source, CI chặn khi tài liệu lệch code (RFC 0003).
Xem trước
bash
pnpm turbo run dev --filter=docs # http://localhost:5173/v2/ — turbo build @tasco/* trước
pnpm turbo run build --filter=docs # như CI: báo link hỏng, thiếu TSDocKhông có bản xem trước theo MR — người review tự chạy lệnh trên.
Trang đặt ở đâu
| Khu | Thư mục | Người đọc | Loại nội dung |
|---|---|---|---|
| Bắt đầu | docs/start/ | Team sản phẩm mới | Học: làm theo từng bước |
| Hướng dẫn | docs/guide/ | Team sản phẩm | Làm: giải quyết một việc cụ thể |
| Component | docs/components/ | Team sản phẩm | Tra cứu + ví dụ cho từng component |
| UI/UX | docs/design/ | Designer, BA, dev | Hiểu: quy tắc giao diện |
| Tra cứu | docs/reference/ | Mọi người | Tra cứu: bảng, chữ ký, không giải thích dài |
| Phát triển core | docs/core/ | Team core | Quy trình và kiến trúc nội bộ |
Mỗi trang một việc. Trang vừa hướng dẫn vừa liệt kê đủ mọi tuỳ chọn thì tách phần liệt kê sang khu Tra cứu và dẫn link.
Thêm trang mới: thêm mục vào sidebar trong docs/.vitepress/config.ts. Đổi hoặc xoá URL đã phát hành: thêm dòng chuyển hướng vào docs/deploy/_redirects — link cũ trong app, CLAUDE.md của sản phẩm và bookmark phải còn vào được.
Giọng văn
- Tiếng Việt, câu ngắn, chủ động, nói thẳng việc cần làm: "Đặt
NUXT_SESSION_SECRETở production", không "Bạn nên cân nhắc việc thiết lập…". - Viết cho người đang làm việc: câu đầu trang nói trang giúp làm gì; bảng cho thông tin tra cứu; checklist cho việc cần rà soát.
- Nói vì sao khi quy tắc không hiển nhiên — người đọc làm đúng lâu hơn khi hiểu lý do.
- Không viết điều code không làm. Chưa chắc thì đọc source hoặc chạy thử trước khi viết.
- Thuật ngữ: giữ tên API và khái niệm kỹ thuật phổ biến bằng tiếng Anh trong
code(runtimeConfig,middleware,slot); dùng từ Việt cho khái niệm chung (phân quyền, phiên đăng nhập, bộ lọc, trang danh sách).
Cấu trúc trang
- Một
#tiêu đề trang; mục##,###. Tiêu đề là danh từ hoặc việc cần làm, không đánh số. - Mỗi mục
##/###đọc được khi đứng riêng:search_docscủa@tasco/mcptrả cho AI từng mục, không kèm phần trên của trang. Tiêu đề mục nói rõ chủ đề ("Chặn nút theo quyền", không phải "Cách 2"); câu đầu không viết "như trên". - Trang kết thúc bằng mục Liên quan, 2–4 link kèm một câu vì sao nên đọc.
- Link trong site viết đường dẫn tuyệt đối, không đuôi
.md:[Chặn theo quyền](/guide/auth/guard). Không thêm/v2/— VitePress tự thêm base. - Ghi chú nổi bật dùng khối của VitePress:
::: info,::: tip,::: warning,::: danger. Tối đa một, hai khối mỗi trang — nhiều khối thì không khối nào nổi bật.
Trang component
Mọi trang trong docs/components/<tên-kebab>/index.md theo cùng thứ tự:
- Mở đầu — một câu component làm gì; Dùng khi / Không dùng khi (kèm component nên dùng thay).
- Ví dụ — mỗi trường hợp một mục có demo: cơ bản, từng biến thể chính, từng trạng thái (disabled, loading, rỗng, lỗi), ít nhất một ví dụ ghép thực tế (
useTable,CForm, phân quyền). - API —
<ApiTable component="CTên" />. - Giao diện — biến CSS đang dùng (
<TokenTable prefix="…" />), class BEM được phép ghi đè. - Khả năng tiếp cận — bàn phím, nhãn, focus.
- Lưu ý — lỗi hay gặp, lỗi
[@tasco/ui]component tự ném khi dùng sai. - Liên quan.
Trang xong khi: bảng API không còn ô "Thiếu mô tả"; demo chỉ dùng C* và composable công khai; một người không viết trang làm theo được.
Claude Code: skill /doc-component <Tên> đọc source, test, story rồi soạn nháp trang và demo theo đúng thứ tự trên. Nháp là điểm bắt đầu — người mở MR đọc lại từng câu và chạy thử từng demo.
API mới trong một major
Docs /v2/ build từ main, nên mô tả cả API đã merge mà chưa phát hành — người đọc còn ở bản cũ hơn sẽ gọi hàm không tồn tại. Mục mô tả API thêm trong một bản minor gắn nhãn phiên bản ở heading, hoặc ở cuối dòng bảng khi API chỉ chiếm một dòng:
md
### Bằng `ref` <Badge type="tip" text="từ 2.1" />- Số phiên bản là bản minor sẽ chứa thay đổi (bản đang phát hành cộng một minor), không đổi sau khi phát hành.
- Chỉ gắn cho API người dùng framework gọi trực tiếp; thay đổi nội bộ và trang khu Phát triển core thì không.
- Anchor của heading không đổi vì VitePress bỏ qua thẻ khi sinh anchor;
@tasco/mcpđưa chữ trong nhãn vào tên mục để AI biết API cần bản nào.
Demo chạy thật
md
<demo src="./demos/closable.vue" />Plugin demo-plugin.ts render file .vue chạy thật và hiện code đọc từ chính file đó, nên code hiển thị không thể lệch code chạy.
| Quy tắc | Vì sao |
|---|---|
File đặt trong demos/ cạnh trang, tên kebab-case | Demo.vue nạp mọi **/demos/*.vue |
Chỉ dùng C*, primitive và composable export từ @tasco/ui, @tasco/utils | ESLint của docs chặn ant-design-vue như ở app sản phẩm |
Không dùng API của Nuxt (useApi, definePageMeta, navigateTo) | VitePress không có runtime Nuxt — ví dụ cần Nuxt viết thành code block |
| Comment đầu file nói demo minh hoạ điều gì | Người đọc bấm "Xem code" thấy ngay ý chính |
| Ví dụ dài hơn 10 dòng là file demo, không viết trong markdown | Được vue-tsc và ESLint kiểm |
Component thương hiệu dùng trong demo phải có trong docs/.vitepress/env.d.ts | vue-tsc kiểm demo như code app |
Demo render trong <ClientOnly> vì antdv render phía server kém; chữ và code block của trang vẫn render tĩnh nên tìm kiếm không bị ảnh hưởng.
Component dùng được trong markdown
| Cú pháp | Hiển thị |
|---|---|
<demo src="./demos/x.vue" /> | Demo chạy thật + nút xem code |
<ApiTable component="CTag" /> | Props, sự kiện, slot từ component-meta.json |
<TokenTable prefix="color-success" /> | Token theo tiền tố; :prefixes="['card-', 'form-']" nhiều tiền tố; on="page" đo tương phản trên nền trang |
<ContrastPairs /> | Bảng cặp chữ/nền từ contrastPairs |
Component C* cũng dùng thẳng được trong markdown (bọc <ClientOnly>), như ở trang Tổng quan bộ C*.
Phần tự sinh — sửa nguồn, không sửa trang
| Nội dung | Nguồn cần sửa |
|---|---|
| Bảng API component | JSDoc của prop, defineEmits, defineSlots trong packages/ui/src/components/*.vue |
| Trang Tra cứu package TS | TSDoc trong packages/{composables,utils,theme,ai}/src |
| Bảng token, cặp tương phản | packages/theme/src/tokens.ts, contrast-pairs.ts |
| Changelog | Changeset của từng MR |
| Quy ước code, Nợ kỹ thuật | CLAUDE.md |
Dữ liệu search_docs, read_doc, get_component của @tasco/mcp | Chính trang docs và JSDoc — sinh lại khi build package |
Nhúng một đoạn của CLAUDE.md (hoặc file markdown khác) vào trang: bọc đoạn đó bằng <!-- #region ten-vung --> … <!-- #endregion ten-vung --> trong file nguồn, rồi đặt dòng include trong trang, đường dẫn tính từ file trang:
md
<!--@include: ../../duong-dan/file-nguon.md#ten-vung-->Include chạy cả trong code block
VitePress thay mọi dòng @include trước khi đọc markdown, kể cả dòng nằm trong code block. Muốn hiển thị cú pháp include như ví dụ trên thì dùng đường dẫn không tồn tại — VitePress giữ nguyên dòng khi không đọc được file.
Bẫy khi viết markdown cho VitePress
Trang markdown được biên dịch thành template Vue:
{{ … }}bị hiểu là biểu thức Vue ở mọi chỗ ngoài code block — kể cả trong code inline. Không có biến trùng tên thì trang hiện rỗng, có ký tự lạ thì build hỏng. Bọc đoạn văn đó bằng khối::: v-pre…:::.
- Thẻ lạ ngoài code (
<Tên>,<đối tượng>) bị hiểu là component. Viết trong`code`hoặc bỏ dấu<>. - Bảng có ký tự
|trong code: viết\|.
Quy tắc nội dung — site công khai
Site docs không đặt sau đăng nhập, nên:
- Không bao giờ đưa token, secret, mật khẩu, cookie thật, kể cả đã hết hạn.
- Host IAM, gateway, backend trong ví dụ dùng
example.com(https://iam.example.com/cop). Chỉ ghi host thật khi người đọc bắt buộc phải cấu hình đúng host đó — hiện chỉ có registry GitLab. - Không đưa tên người, số điện thoại, dữ liệu khách hàng thật vào ví dụ và ảnh chụp.
CI kiểm tra gì
| Kiểm tra | Fail khi |
|---|---|
pnpm lint (docs) | Demo import ant-design-vue, vi phạm rule Vue |
pnpm typecheck (docs) | Demo sai kiểu, dùng component chưa khai trong env.d.ts |
pnpm build (docs) | Link nội bộ hỏng, export package TS thiếu TSDoc, template Vue trong markdown lỗi |
pnpm test (docs) | Script sinh changelog hoặc trang API sai |
docs-coverage --strict | Component thiếu trang hoặc thiếu mô tả; khoá runtimeConfig chưa có trong trang tra cứu |
check-mcp-links | Link docs trong dữ liệu @tasco/mcp trỏ tới trang hoặc mục không có trong bản build |
Link tới mục trong trang (#ten-muc) không được kiểm — bấm thử trước khi mở MR. Mã mục là tiêu đề bỏ dấu viết thường nối gạch ngang, riêng chữ đ giữ nguyên; tiêu đề có đ thì đặt mã riêng: ## Quyền đóng góp {#quyen-dong-gop}.
Checklist MR tài liệu
Mục "Tài liệu" và "Ảnh chụp" trong template MR (.gitlab/merge_request_templates/Default.md) là bản rút gọn của danh sách này — MR đổi API công khai chỉ xong khi có JSDoc, trang docs, demo, changeset và mục Migration nếu breaking.
- [ ] Trang ở đúng khu, có trong sidebar; URL đổi thì có
_redirects. - [ ] Đã đọc source hoặc chạy thử điều được viết.
- [ ] Demo chạy ở cả chế độ sáng và tối; MR đổi giao diện có ảnh chụp trước/sau.
- [ ] Mục
##/###đọc được khi đứng riêng. - [ ] Không có host thật (trừ registry), token, dữ liệu cá nhân.
- [ ]
pnpm turbo run build --filter=docskhông lỗi.
Liên quan
- RFC 0003 — lý do của cấu trúc và công cụ.
- Thêm component C* — trang docs là một phần của component.
- Release & phiên bản docs — docs theo major.