Decisions - ntphiep/zhesen-main GitHub Wiki
Có 5 quyết định đã nghiên cứu. Mục 1 tới 3 và mục 5 đã chốt, gồm 2 về hạ tầng, 1 về bố cục trang chi tiết từ và 1 về tên miền; mục 4 về Cloudflare chờ owner quyết. Mỗi mục ghi kết luận, số đo dẫn tới kết luận đó, phần đã làm, và điều kiện phải xem lại.
Quyết định 2026-09-22. Trạng thái: đã làm, cutover 2026-09-23 (issue #57). Project
Supabase Cloud cvltsyoweddhpkomuevz giữ nguyên, đóng băng, tới 2026-10-23 làm đường
rollback.
Vấn đề là dung lượng. Gói Free của Supabase cho 500 MB; chạm trần thì database chuyển sang
chế độ chỉ đọc cho tới khi xuống dưới 475 MB. Database đang ở 455 MB, trong đó dữ liệu từ
điển khoảng 197 MB và hai index PGroonga chiếm 91 MB cố định. Mở rộng vốn tiếng Anh (issue
#36) hay nạp thêm bất kỳ nguồn nào đều bị chặn. Triệu chứng thứ hai cùng gốc: gói Free cho
0,5 GB RAM, shared_buffers 224 MB không giữ nổi 455 MB, nên tám lượt tra tiếng Việt gửi
đồng thời thì sáu lượt trả statement timeout (issue #7).
| Phương án | Dung lượng | Search tiếng Trung | Tháng | Sửa code |
|---|---|---|---|---|
| Supabase Pro | 8 GB | giữ PGroonga | 25 USD tiền mặt | 0 |
| EC2 Seoul chạy Supabase self-hosted | tuỳ đĩa | giữ PGroonga | 23 tới 38 USD, credit trả | 0 |
| RDS Postgres | tuỳ đĩa | mất PGroonga, viết lại; vẫn cần một máy cho auth và PostgREST | khoảng 40 USD | 9 file |
| Aurora Serverless v2 | tuỳ | mất PGroonga | từ 73 USD | 9 file |
Chọn EC2 vì ba điều. Credit AWS 163,70 USD trả tiền máy được khoảng bảy tháng, Pro thì không
dùng credit được. App chỉ đọc NEXT_PUBLIC_SUPABASE_URL và anon key, nên chạy nguyên bộ
Supabase bằng Docker trên EC2 là đổi một biến môi trường, không sửa code, giữ PGroonga, auth
và RLS. Máy riêng cho phép cài thêm thứ khác về sau. Marketplace bị loại vì credit không trả;
Aurora bị loại vì giá.
graph LR
V["Vercel icn1 Seoul"] --> CF["CloudFront, HTTPS"]
CF -->|"VPC origin"| E["EC2 Seoul: Envoy, GoTrue, PostgREST,<br/>Postgres 17.6 với PGroonga"]
E -.-> S3["S3, pg_dump hằng ngày"]
Đã làm trước đó, giữ nguyên: nghiên cứu 2026-09-16 đo lex.search tốn 46,3 ms trong
Postgres trong khi người dùng chờ 319 tới 582 ms, nguyên nhân là function Vercel ở Washington
còn database ở Seoul. vercel.json đã pin function về icn1 Seoul. Kết luận "không chuyển
database" hôm đó dựa trên dung lượng 383 MB còn chỗ; điều kiện xem lại là vượt 450 MB, đã tới.
Xem lại khi: credit hết, dự kiến khoảng tháng 4 năm 2027. Lúc đó so tiền mặt cho EC2 với Supabase Pro 25 USD. Cost Explorer ghi khoảng 38 USD/tháng trong 30 ngày tới 2026-10-08, nên credit có thể hết khoảng 2027-01-31 (suy luận); mục 4 so các phương án.
Nghiên cứu 2026-09-17, cập nhật 2026-09-26. Trạng thái: bước 1 đã làm, bước 2 và 3 chưa làm.
App đang hotlink thẳng vào upload.wikimedia.org. Chuyển sang S3 ap-northeast-2 đặt sau
CloudFront nhanh hơn rõ rệt, nhưng nó biến zhesen từ bên nhúng thành bên phân phối lại, nên
phải làm phần ghi công trước.
| Phương án | TTFB từ Việt Nam | Chi phí ở mức tăng trưởng |
|---|---|---|
| Giữ Wikimedia (đang chạy) | 167 ms khi nóng, 411 ms khi nguội | 0 USD |
| S3 Seoul trực tiếp | 277 ms | 0,112 USD |
| S3 Seoul sau CloudFront (khuyến nghị) | 32,3 ms khi cache hit | 0,007 USD |
| Supabase Storage | chưa đo được | 0 USD, nhưng ăn vào hạn mức egress của từ điển |
Chi phí không phân biệt được phương án nào: cả bốn đều dưới 0,12 USD một tháng. Chỉ có hai thứ quyết định.
-
Latency. CloudFront phục vụ từ PoP Hà Nội, nhanh hơn Wikimedia 379 ms khi file nguội.
Trạng thái nguội mới là thường gặp: 20 trên 25 file đo được
age = 0. -
Giấy phép. 647 trên 699 file có
AttributionRequired = truetheo Commons API, nên phải ghi công trước khi phân phối lại. Cộtlex.pronunciations.attributioncó từ migration0003nhưng không chỗ nào đọc nó.
Bước 1 đã làm theo cách rẻ hơn dự tính. Sau khi nạp đủ tiếng Anh, số bản ghi tăng từ 699 lên 96.765, nên gọi Commons API cho từng file không còn hợp lý. Mọi chỗ phát bản ghi, gồm trang một từ, sổ tay và các trang luyện tập, có link "nguồn" tới trang file trên Wikimedia Commons, nơi ghi tác giả và giấy phép (issue #29). CC BY-SA 4.0 mục 3(a)(2) chấp nhận ghi công bằng một link tới nguồn chứa thông tin đó (legalcode).
Thứ tự làm, bước một là bắt buộc:
graph TD
A["1. Link tới trang file trên Commons<br/>ở mỗi bản ghi: đã làm"] --> B["2. Copy file sang S3 ap-northeast-2<br/>dựng CloudFront distribution"]
B --> C["3. Migration ghi lại audio_url<br/>đổi media-src trong next.config.ts"]
A -.->|"nếu không làm bước 1"| X["Giữ nguyên Wikimedia"]
style A fill:#fff3cd,stroke:#b8860b
style X fill:#fde2e2,stroke:#c0392b
Xem lại khi: người dùng thật bắt đầu nhận HTTP 429 từ Wikimedia, lúc đó chuyển ngay và bỏ điều kiện làm bước 1 trước, vì khi đó nút phát âm đang hỏng chứ không phải chậm. Hoặc khi dự án bắt đầu tự sinh audio, vì lúc đó cần object store dù sao đi nữa.
Quyết định 2026-09-26, cập nhật 2026-09-27. Trạng thái: đã làm. Bản vẽ ở
Figma, frame A2 · Desktop 1440 và
A2 · Phone 390; ba frame A, B, C phía trên là các hướng đã so trước khi chọn.
Trang cũ đặt 3 nghĩa đầu theo thứ tự từ điển gốc, nên nghĩa thứ tư của take là "bắt bóng" trong cricket. Ví dụ nằm tách khỏi nghĩa. Bốn khối từ liên quan lặp nhau: take up nằm cả ở "Cụm từ chứa từ này" lẫn "Từ cùng gốc". Ở 1440 px cột phải hết sớm và bỏ trống nửa dưới trang.
| Vùng | Nội dung |
|---|---|
| Đầu trang | Từ, trình độ, phát âm, nút lưu, một dòng nối 5 nghĩa chính, nút nhảy tới từng từ loại, Ví dụ và Từ liên quan |
| Cột trái | Nghĩa nhóm theo từ loại. Mỗi từ loại hiện 5 nghĩa hay dùng nhất, mỗi nghĩa kèm 1 ví dụ của chính nó. Phần còn lại mở ngay tại chỗ. Cuối cột là "Ví dụ khác", 3 câu |
| Cột phải | Dạng từ trên một dòng, Từ liên quan chia tab và bỏ mục trùng, Ngôn ngữ khác, Ngữ pháp, Trợ lý |
| Điện thoại | Một cột: đầu trang, nghĩa, dạng từ, ví dụ, từ liên quan, ngôn ngữ khác, ngữ pháp, trợ lý |
Trang rộng 1296 px thay vì 1024 (issue #50, chỉ trang một từ). Trỏ chuột, focus hoặc chạm vào
một từ thì trang của từ đó được tải trước, và link hiện chấm chờ trong lúc tải. Không dùng
khung chờ loading.tsx: khung đó làm từ không tồn tại trả mã 200 thay vì 404.
Bảng trên mô tả bố cục mặc định, giờ gọi là "Tổng quan". Trang có thêm nút chọn ba bố cục:
Tổng quan, Song ngữ (từ và nghĩa tiếng Việt song song, không chia cột trái phải) và Cổ điển
(bảng và mục theo thứ tự từ điển giấy). Lựa chọn nhớ theo trình duyệt
(components/lookup/WordLayouts.tsx). Một bố cục thứ tư, "Nhiều cột", mở từ liên quan thành
cột riêng cạnh trang, bị bỏ theo yêu cầu owner vì thừa so với ba bố cục kia; trình duyệt nào
còn nhớ lựa chọn đó rơi về Tổng quan.
Hai phần cần dữ liệu mới. "Nghĩa hay dùng nhất" đọc cột lex.senses.sense_frequency, trước
nay để trống. "Ví dụ của chính nghĩa đó" đọc lex.examples.sense_id: câu từ Wiktionary đã có
cột này, câu từ Tatoeba thì chưa. Trong 17.427 từ tiếng Anh trình độ A1 tới B2, 12.692 từ đã có
ít nhất một ví dụ gắn nghĩa. AI router của project xếp nghĩa, gắn các câu Tatoeba vào nghĩa và
viết nghĩa tiếng Việt còn thiếu. Azure Translator dịch những câu ví dụ trang hiện ra. Câu từ
Cambridge chưa dùng tới khi kiểm tra xong licence. Từ chưa qua bước này vẫn hiện đúng: nghĩa
theo thứ tự cũ, ví dụ gom vào "Ví dụ khác".
Xem lại khi: mở rộng bước dữ liệu ra C1, C2 hoặc sang tiếng Tây Ban Nha. Tiếng Tây Ban Nha hiện chưa có câu ví dụ nào.
Nghiên cứu ngày 2026-10-13, đang chờ owner quyết. Chi tiết, script và số đo nằm ở file
1-cloudflare.md trong folder ~/W/zhesen-docs/2026-10-research/ trên máy của owner.
Không chuyển zhesen sang Cloudflare lúc này. Phần tốn tiền là backend: Postgres với PGroonga, GoTrue, PostgREST, 2 router AI và các batch job. Cloudflare không chạy được phần nào trong số đó. App đang miễn phí trên Vercel Hobby và AWS đang trả bằng credit, nên không sản phẩm Cloudflare nào làm hoá đơn hiện tại thấp hơn. Đo từ Việt Nam, cả 2 đều trả lời từ Hồng Kông hoặc Singapore, Cloudflare trong 135 tới 195 ms và Vercel trong 163 ms.
Có 3 dịch vụ miễn phí của Cloudflare đáng dùng khi có tên miền. DNS quản lý tên miền ở chế độ DNS-only, vì Vercel khuyên không đặt reverse proxy phía trước. Tunnel kèm Access đóng dashboard của 9router và OmniRoute. Turnstile chống bot ở trang đăng ký.
Trần ISR write của Hobby cạn sớm vì 2 lý do. Mỗi deployment có ISR cache riêng, tức cache trang đã render của Vercel, và CI deploy production 138 lần trong 30 ngày. Ở nhịp đó mỗi deploy chỉ còn chỗ render khoảng 241 trang trước khi cạn trần tháng. Một lượt crawl toàn bộ 213.089 URL trong sitemap tốn 4,3 tới 6,4 lần trần đó. Vì vậy gom deploy production còn 1 lần mỗi ngày, chặn crawler huấn luyện AI và đọc trang Usage trước khi nộp sitemap. Hobby cũng chỉ cho dùng phi thương mại, nên bán bất cứ thứ gì cần rời Hobby.
| Phương án sau khi hết credit | USD/tháng | Giờ công | Được bán | 12 tháng, USD |
|---|---|---|---|---|
| Giữ Hobby và EC2 như hiện tại | 38,00 | 0 | không | 342 |
| Hobby và EC2 Savings Plan 1 năm | 25,29 | 0,5 tới 1 | không | 235 |
| Vercel Pro và EC2 Savings Plan | 45,29 | 1 tới 2 | có | 483 |
| Workers và EC2 Savings Plan | 30,38 | 16 tới 40 | có | 659 |
| Hobby và OVH VPS-2 | 8,50 | 20 tới 44 | không | 512 |
next start và backend trên 1 OVH VPS-2, sau proxy Cloudflare |
8,50 | 30 tới 64 | có | 752 |
| Như trên, trên Oracle Always Free A1 | 0 | 34 tới 74 | có | 720 |
Tổng 12 tháng tính giờ công 10 USD/giờ và giả định credit còn 3 tháng. Khi credit hết, thử
Oracle Always Free A1 một lần; không được thì chọn OVH VPS-2 sau khi xác nhận kỳ thanh toán.
EC2 Savings Plan chỉ hợp khi owner chấp nhận cam kết 12 tháng. Khi bán, chọn Vercel Pro nếu
backend còn ở EC2, hoặc tự chạy next start nếu backend đã sang VPS. Rời AWS phải viết lại
phần admin, gồm 9 file và 1.642 dòng gọi AWS.
Next.js đã lên 16.3.8 ngày 2026-10-14, sửa lỗ hổng critical chạy code từ xa qua class
ImageResponse của next/og và 6 lỗ hổng khác. 16.3.8 cũng là bản thấp nhất mà OpenNext,
adapter chạy Next.js trên Workers, nhận.
Xem lại khi owner đọc trang Billing, Credits của AWS, 6 tuần trước ngày credit hết, hoặc khi bắt đầu bán.
Chốt ngày 2026-10-13 (issue #89). Chi tiết và các bước nối vào Vercel nằm ở file
2-ten-mien.md trong cùng folder.
Owner đăng ký zhesen.net tại Mắt Bão ngày 2026-10-13, hạn tới 2027-10-13.
zhesen.net là tên chính, chạy HTTPS trên Vercel từ 2026-10-13. DNS đặt ở Cloudflare chế độ
DNS-only. www.zhesen.net và zhesen-main.vercel.app chuyển 308 về zhesen.net, trừ đường dẫn /api
của tên cũ mà SNS alert và script revalidate còn gọi (commit 7050fbc).
Owner mua thêm zhesen.xyz, zhesen.cloud và zhesen.io.vn cùng ngày. Cả 3 không có nội dung riêng: DNS đặt ở Cloudflare và Vercel chuyển 308 mọi host của chúng về zhesen.net.
Xem lại khi mở rộng ra ngoài Việt Nam, hoặc trước hạn gia hạn 2027-10-13.