Chuyển tới nội dung chính

Docusaurus — Documentation Website

Tổng quan (Overview)

RAC sử dụng Docusaurus v3 để chuyển đổi toàn bộ tài liệu Markdown trong repo thành một static website có thể tìm kiếm, điều hướng và sử dụng offline. Website được tự động build và deploy lên Cloudflare Pages mỗi khi có commit vào main.

irp/ services/ templates/ tools/
↓ symlinks
website/docs/
↓ Docusaurus build
website/build/
↓ Wrangler (GitLab CI)
Cloudflare Pages → docs.nexa.mobi

Cấu trúc thư mục (Directory Structure)

website/ ← Docusaurus project root
├── docusaurus.config.js ← Cấu hình chính: plugins, themes, navbar
├── sidebars.js ← Định nghĩa sidebar cho 4 section
├── package.json ← Dependencies (Node.js)
├── docs/ ← Symlinks trỏ về nội dung thật
│ ├── irp → ../../irp/
│ ├── services → ../../services/
│ ├── templates→ ../../templates/
│ ├── tools → ../../tools/
│ └── resilience_as_code_architecture_plan.md → ../../resilience_as_code_architecture_plan.md
├── static/
│ └── img/runbooks/ ← Static assets (SVG diagrams, images)
└── src/
├── pages/index.js ← Landing page
└── css/custom.css ← Custom styles

Docusaurus cần đọc file từ một thư mục nằm bên trong project (website/docs/). Thay vì copy tài liệu (tạo ra hai source of truth) hoặc trỏ path: '../' về toàn bộ repo root (gây lỗi EMFILE — quá nhiều file descriptors để watch), RAC dùng symlinks trong website/docs/ trỏ chính xác về các thư mục nội dung.

Kèm theo cấu hình webpack resolve.symlinks: false để webpack không resolve symlink về đường dẫn thật (tránh lỗi metadata undefined khi render page).


Plugins đã cài đặt

Loại: Theme
Cấu hình: themes array trong docusaurus.config.js

Build search index tại compile time — không cần external service, hoạt động offline. Hỗ trợ cả tiếng Anh và tiếng Việt.

// docusaurus.config.js
themes: [
['@easyops-cn/docusaurus-search-local', {
hashed: true,
language: ['en', 'vi'],
docsRouteBasePath: '/',
indexBlog: false,
}],
],

Lưu ý: Search không hoạt động trong npm run start (dev server). Phải chạy npm run build && npm run serve để test search locally.


2. @docusaurus/theme-mermaid — Diagram-as-Code

Loại: Theme
Cài đặt: npm install @docusaurus/theme-mermaid

Render Mermaid diagrams trực tiếp trong Markdown — không cần export ảnh. Hỗ trợ: sequenceDiagram, flowchart, erDiagram, gantt, gitGraph, v.v.

// docusaurus.config.js
markdown: { mermaid: true },
themes: ['@docusaurus/theme-mermaid'],

Cách dùng trong .md / .mdx:

```mermaid
sequenceDiagram
participant SRE
participant DB as PostgreSQL
SRE->>DB: systemctl stop postgresql
DB-->>SRE: Service stopped ✓
```

Khi nào dùng Mermaid:

  • Sequence diagrams (tương tác giữa các service/người)
  • Flowcharts đơn giản
  • Git branching diagrams
  • ER diagrams cho data model

3. docusaurus-plugin-drawio — Interactive Draw.io Diagrams

Loại: Plugin
Cài đặt: npm install docusaurus-plugin-drawio

Render file .drawio trực tiếp trong page — interactive zoom, pan, layer switching. Yêu cầu file có extension .mdx (cần JSX import syntax).

// docusaurus.config.js
plugins: [['drawio', {}]],

Cách dùng trong .mdx:

import Drawio from '@theme/Drawio';
import myDiagram from '!!raw-loader!./my-diagram.drawio';

<Drawio content={myDiagram} toolbar="zoom layers" />

Lưu ý quan trọng:

  • File .drawio phải nằm cùng thư mục với file .mdx để import relative path hoạt động qua symlinks.
  • Chỉ dùng .mdx extension (không phải .md) khi cần embed Drawio hoặc bất kỳ JSX component nào.
  • File .drawio là XML — có thể mở trực tiếp tại app.diagrams.net để chỉnh sửa.

Khi nào dùng Drawio vs Mermaid:

Tiêu chíMermaidDrawio
Cú phápCode (text-based)GUI (drag & drop)
Phù hợp choSequence, flowchart đơn giảnArchitecture complex, custom layout
Git diffDễ reviewXML khó đọc
Cần .mdx?Không

4. docusaurus-plugin-copy-page-button — Copy Page as Markdown

Loại: Plugin
Cài đặt: npm install docusaurus-plugin-copy-page-button

Thêm nút "Copy page" vào sidebar TOC — copy toàn bộ nội dung page thành Markdown để paste vào AI tool (ChatGPT, Claude, v.v.).

plugins: [
['docusaurus-plugin-copy-page-button', {
// Chỉ bật copy và view — ẩn link AI tools (site nội bộ, không public)
enabledActions: ['copy', 'view'],
}],
],

5. docusaurus-plugin-llms — LLM/AI Consumption Files

Loại: Plugin
Cài đặt: npm install docusaurus-plugin-llms

Tự động sinh /llms.txt (index) và /llms-full.txt (toàn bộ nội dung) tại build time theo chuẩn llmstxt.org. AI agent và LLM tools có thể truy cập toàn bộ RAC documentation qua hai file này.

plugins: [
['docusaurus-plugin-llms', {
generateLLMsTxt: true,
generateLLMsFullTxt: true,
docsDir: 'docs',
title: 'Resilience as Code — RAC Documentation',
excludeImports: true,
removeDuplicateHeadings: true,
}],
],

URL sau khi deploy:

  • https://docs.nexa.mobi/llms.txt — Index với links
  • https://docs.nexa.mobi/llms-full.txt — Toàn bộ content (dùng cho RAG)

6. docusaurus-plugin-image-zoom — Image Zoom

Loại: Plugin
Cài đặt: npm install docusaurus-plugin-image-zoom

Click vào bất kỳ ảnh nào trong .markdown để zoom full-screen (dùng medium-zoom).

// Thêm vào plugins[]
'docusaurus-plugin-image-zoom',

// Thêm vào themeConfig
zoom: {
selector: '.markdown img',
background: { light: 'rgb(255,255,255)', dark: 'rgb(30,30,30)' },
},

7. docusaurus-graph — Knowledge Graph

Loại: Plugin
Cài đặt: npm install docusaurus-graph

Render một trang /graph interactive cho phép xem toàn bộ mối quan hệ giữa các tài liệu RAC dưới dạng node-edge graph. Mỗi document là một node; field calls trong frontmatter tạo directed edge từ document đó đến document được gọi.

// docusaurus.config.js
plugins: [
['docusaurus-graph', {
docsDir: 'docs',
buildDir: 'build',
referencesTag: 'calls', // tên field trong frontmatter
sourcesTag: 'called_by', // reverse-link field (không bắt buộc phải điền)
}],
],

// themeConfig.navbar.items
{ to: '/graph', label: 'Graph', position: 'right' },

Cách thêm relationship cho một document mới:

---
type: Runbook
title: "My New Runbook"
# ... frontmatter khác ...
calls:
- payment-gateway
- escalation-policy
---

Định dạng node IDdocusaurus-graph dùng basename của file (không có extension, không có đường dẫn) làm node ID:

File thậtNode ID trong calls
irp/runbooks/restart-database.mdxrestart-database
services/payment-gateway.mdpayment-gateway
irp/policies/escalation-policy.mdescalation-policy

Lưu ý quan trọng: docusaurus-graph dùng basename làm ID, không phải đường dẫn đầy đủ. Điều này có nghĩa là hai file cùng tên trong các thư mục khác nhau sẽ được coi là một node duy nhất (collision). Vì vậy, khi tạo runbook/playbook mới cho production, hãy đặt tên file unique (ví dụ: restart-payment-gateway-pods.md thay vì example.md). Các file tên example.mdindex.md không nên được dùng trong calls.

Relationship hierarchy hiện tại của RAC:

example (playbook)
→ restart-database (runbook) → payment-gateway (service)
→ escalation-policy (policy)
→ payment-gateway (service)

Plugin tự inject button: docusaurus-graph tự thêm nút "Graph view" vào góc phải trên của navbar — không cần thêm navbar item thủ công.

Quy ước bảo trì:

  • Chỉ cần khai báo calls trên document gọi (caller) — không cần called_by trên document được gọi.
  • docusaurus-graph tự suy ra chiều ngược lại khi render graph.
  • Validator (validate.py) không kiểm tra giá trị trong calls — là basename, không phải markdown path.

TODO — Auto-extract graph edges từ inline markdown links: Hiện tại calls được khai báo thủ công trong frontmatter, nhưng các file .md đã có đầy đủ relationship thông qua inline links [text](path.md) trong prose. Implement một trong hai hướng:

  • Option A (validate.py post-pass): Thêm một bước vào validate.py để parse tất cả [text](path.md) links trong body, suy ra basename của target file, và tự động ghi vào field calls trong frontmatter — đồng bộ calls với thực tế của prose.
  • Option B (custom Docusaurus plugin): Viết plugin riêng thay thế docusaurus-graph — đọc markdown body của mỗi doc trong quá trình build, extract links bằng regex, xây dựng graph data mà không cần frontmatter calls. Zero maintenance overhead phía content.

Option B được ưu tiên vì không tạo ra hai source of truth (frontmatter + prose). Tham khảo website/docusaurus.config.js comment cho context đầy đủ.


Chạy locally (Local Development)

cd website

# Dev server (hot reload, search không hoạt động)
npm run start

# Production build + local preview (search hoạt động đầy đủ)
npm run build && npm run serve

# Xóa cache khi gặp lỗi lạ
npm run clear

Dev server và EMFILE error trên macOS: Nếu gặp lỗi EMFILE: too many open files, cài watchman:

brew install watchman

CI/CD — Cloudflare Pages (GitLab CI)

Mỗi push lên bất kỳ branch nào sẽ trigger job deploy-docs trong .gitlab-ci.yml.

Luồng deploy

git push → GitLab CI trigger
→ node:22-alpine container
→ cd website && npm ci
→ npm run build (Docusaurus → website/build/)
→ npx wrangler pages deploy build
--project-name=$CF_PAGES_PROJECT_NAME
--branch=$CI_COMMIT_REF_SLUG
BranchLoại deploymentURL
mainProductiondocs.nexa.mobi
Bất kỳ branch khácPreview<branch-slug>.rac-docs.pages.dev

CI/CD Variables (GitLab Settings → CI/CD → Variables)

VariableMô tảLưu ý
CLOUDFLARE_API_TOKENAPI token với quyền "Cloudflare Pages: Edit"Bỏ chọn Protected để dùng trên feature branches
CLOUDFLARE_ACCOUNT_IDAccount ID từ Cloudflare dashboardBỏ chọn Protected
CF_PAGES_PROJECT_NAMETên project trên Cloudflare Pages (vd: rac-docs)Bỏ chọn Protected

Tạo Cloudflare Pages project (lần đầu)

cd website
npx wrangler pages project create rac-docs
# Production branch: main

Thêm nội dung mới (Adding Content)

Thêm tài liệu thông thường (.md)

Tạo file trong irp/, services/, templates/, hoặc tools/ — Docusaurus tự động pick up qua symlinks. Không cần cấu hình thêm.

Nếu file nằm trong thư mục đã có trong autogenerated sidebar → tự động xuất hiện.
Nếu không → thêm vào website/sidebars.js thủ công.

Thêm tài liệu có JSX/Mermaid/Drawio (.mdx)

Dùng extension .mdx khi file cần:

  • Import JSX component (<Drawio>, custom component)
  • Sử dụng Mermaid (thực ra .md cũng hoạt động với Mermaid)
---
type: Runbook
title: "My Runbook"
# ... frontmatter như bình thường
---

import Drawio from '@theme/Drawio';
import diagram from '!!raw-loader!./my-diagram.drawio';

## Architecture

<Drawio content={diagram} toolbar="zoom layers" />

## Sequence

```mermaid
sequenceDiagram
A->>B: Hello

### Thêm ảnh tĩnh

Đặt ảnh vào `website/static/img/` và reference bằng absolute path:

```markdown
![Alt text](/img/runbooks/my-diagram.svg)

Ảnh trong website/static/ được serve tại root URL — không đi qua symlinks.


Lưu ý kỹ thuật (Technical Notes)

Validator và static assets

tools/validate/validate.py chỉ kiểm tra links trỏ đến file .md/.mdx. Links đến ảnh (/img/...) hoặc file khác không bị validate — đây là behavior có chủ đích vì static assets không phải RAC documents.

Docusaurus đăng ký doc file theo symlink path (website/docs/irp/index.md). Webpack mặc định resolve symlink về real path (irp/index.md) — dẫn đến mismatch làm props.content.metadata trả về undefined trên mọi page. Plugin nội bộ fix-symlink-resolution set resolve: { symlinks: false } để giữ path nhất quán.

Build luôn sinh [WARNING] Docusaurus found broken links cho:

  • Template placeholder links (/services/tên-service.md) — intentional
  • Links đến Python source files (.py) trong tools docs — không được serve
  • Đây là warnings, không phải errors — build vẫn [SUCCESS]
X

Graph View