ADR-0003. Render PDF HKD chính thức bằng Typst
| Trường | Giá trị |
|---|---|
| Status | Accepted |
| Date | 2026-03-30 |
| Deciders | ledger-team |
| Supersedes | — |
Bối cảnh
- Sổ HKD là biểu mẫu chính thức của nhà nước với bố cục chặt: header chính xác, khối chữ ký, quy ước số/ngày Việt Nam, bảng nhiều trang, và biến thể dọc/ngang theo từng mẫu.
- Cùng dữ liệu đã validate cũng phải tạo một XLSX sửa được (xử lý riêng bởi ExcelJS).
- Chúng ta cần PDF ổn định pixel, sẵn-in mà designer có thể lặp lại không cần recompile service.
Quyết định
Chúng ta sẽ render PDF bằng Typst qua @myriaddreamin/typst-ts-node-compiler. Template nằm dạng source .typ trong resources/templates/ (6 mẫu + common.typ dùng chung); PdfGeneratorService khởi tạo lazy một NodeCompiler duy nhất, inject dữ liệu đã validate dưới dạng shadow file (data.json), và render. Mỗi instance consumer có instance service riêng, nên path shadow-file cố định không bị chia sẻ đồng thời. File previews/ độc lập cho phép typst compile để debug bố cục không cần full pipeline.
Hệ quả
| Ưu | Nhược |
|---|---|
| Template hướng markup, kiểm soát version; lặp nhanh | Ngôn ngữ mới cho team so với HTML/CSS |
| Bảng nhiều trang native, typography chính xác, nhúng font | Compiler là phụ thuộc native; cần font đóng gói |
Macro common.typ dùng chung giữ 6 mẫu nhất quán | Cô lập shadow-file dựa vào giả định một-service-mỗi-consumer |
Preview --root . cho phép kiểm tra trực quan nhanh | Một lỗi compile yêu cầu thay instance compiler |
Phương án đã cân nhắc
| Phương án | Ưu | Nhược | Vì sao loại |
|---|---|---|---|
| Headless Chromium (HTML→PDF) | HTML/CSS quen thuộc | Runtime nặng, phân trang mong manh, bộ nhớ lớn | Quá nặng cho render batch; kiểm soát phân trang kém |
| LaTeX | Typography xuất sắc | Toolchain nặng, chậm, khó template từ JSON | Vận hành vụng |
| Thư viện PDF (pdf-lib / PDFKit) | JS thuần | Bố cục thủ công cho bảng nhiều trang phức tạp | Quá thấp tầng cho bố cục đa-mẫu chính thức |
Tham chiếu
ledger/src/services/generators/pdf-generator.service.tsledger/resources/templates/(common.typ,s1a-hkd.typ..s2e-hkd.typ)- HKD Templates