Skip to content

Kiến trúc

Toàn bộ hệ thống chạy trên hạ tầng biên của Cloudflare; không có máy chủ nào cần trực.

                    ┌──────────────────────────┐
   Trình duyệt ───▶ │  www.chuyenchon.com      │
                    │  Cloudflare Pages        │
                    │  HTML tĩnh + SPA React   │
                    └───────────┬──────────────┘
                                │  fetch /v1/*  (CORS)

                    ┌──────────────────────────┐
                    │  api.chuyenchon.com      │
                    │  Cloudflare Worker (Hono)│
                    └───────────┬──────────────┘
                                │  binding DB

                    ┌──────────────────────────┐
                    │  Cloudflare D1 (SQLite)  │
                    │  bảng thực thể + FTS5    │
                    └──────────────────────────┘

   docs.chuyenchon.com — Cloudflare Pages (VitePress), độc lập hoàn toàn

Vì sao tách API thành Worker riêng

Có thể đặt /api/* ngay trong Pages Functions, nhưng tách ra đem lại:

  • Một tên miền ổn định cho mọi client về sau (web, ứng dụng di động, đối tác) — đúng vai trò "API Gateway" trong đề bài.
  • Vòng đời triển khai độc lập: sửa truy vấn không cần build lại toàn bộ frontend.
  • Bước prerender gọi được API như một client bên ngoài — chính là điều cần để sinh HTML tĩnh.

Chi phí phải trả là CORS, xử lý ở src/index.ts bằng danh sách ALLOWED_ORIGINS.

Ba tầng dữ liệu

TầngNơi chạyTrách nhiệm
D1CloudflareLưu trữ, ràng buộc, chỉ mục FTS5
WorkerBiênLọc, phân trang, ghép quan hệ, đặt Cache-Control
Trình duyệtMáy người dùngTanStack Query giữ cache trong phiên, hydrate từ HTML tĩnh

Worker đặt Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=86400 cho dữ liệu công khai, nên phần lớn request được phục vụ từ cache biên chứ không chạm D1.

Ngân sách hiệu năng

  • Mỗi endpoint chi tiết dùng một db.batch() thay vì nhiều lượt truy vấn nối tiếp.
  • Danh sách luôn có LIMIT, per_page chặn trần ở 100.
  • Chỉ mục tìm kiếm dựng sẵn (bảng search_docs + search_fts) thay vì LIKE trên nhiều bảng.

Biến môi trường

BiếnNơi dùngGhi chú
ALLOWED_ORIGINSWorkerDanh sách origin, phân tách bằng dấu phẩy
ADMIN_TOKENWorker (secret)Bearer token cho /v1/admin/*
VITE_API_BASEWeb (build)Gốc API; để trống khi dev để dùng proxy của Vite
VITE_SITE_URLWeb (build)Dùng cho canonical và sitemap

Tài liệu nội bộ dự án Chuyên Chọn.