NĐ-LARK-PG-DIR — Prerequisites + Kế hoạch tổng thể POC Thông báo tuyển dụng
NĐ-LARK-PG-DIR — Prerequisites + Kế hoạch tổng thể POC
Trạng thái: DRAFT chờ Huyên duyệt Tác giả: Claude Desktop (phiên Lark 6, 2026-04-13) Mục tiêu file: Bổ sung phần thiếu cho 3 file GPT đã viết trong
lark_PG_Dir/. KHÔNG sửa file gốc của GPT. File này là pre-flight + roadmap chi tiết để các phiên sau đọc 1 lần là đủ context, không phải lội lại lịch sử chat. Lý do tồn tại: Token-saving. Mỗi lần phiên mới mà phải search KB + đọc lại ngữ cảnh lan man rất tốn token. File này gói toàn bộ context cần thiết vào 1 chỗ, các phiên sau chỉ cầnget_document1 call.
0. Cách dùng file này
Phiên mới vào:
get_document knowledge/dev/lark/lark_PG_Dir/nd-lark-pg-dir-prerequisites-v1.md← file này- Đọc Section 9 (Trạng thái hiện tại) trước — biết đang ở đâu
- Đọc Section 6 (Việc nhóm A vs B) — biết phải làm gì tiếp
- Chỉ đọc các section khác khi cần chi tiết
Không cần search KB lan man. Không cần đọc lịch sử chat. File này là single source of truth cho POC này.
1. Mục tiêu POC (cụ thể, đo được)
Sinh tự động 1 file PDF "Thông báo tuyển dụng" từ data Lark Base 88, hiển thị trên Nuxt tại domain donhang.incomex..., chạy theo cron 30 phút/lần trong giờ làm việc Hà Nội.
Tiêu chí thành công:
- 1 record trong bảng tổng hợp Lark (Huyên sẽ tạo) → tự động sinh ra 1 PDF trong vòng tối đa 30 phút
- PDF hiển thị được trên Nuxt
donhang.incomex...dưới dạng bảng matrix 3-5 cột (mã đơn, ngày, trạng thái, link tải PDF) - Toàn bộ pipeline READ-only từ phía Lark (không write back)
- Có cờ tắt nhanh nếu xảy ra sự cố
- Có Dual-trigger theo hiến pháp Incomex
KHÔNG nằm trong scope POC:
- Không sync 2 chiều
- Không thiết kế generic connector cho 18 Base
- Không hiểu toàn bộ Lark
- Không đụng automation Lark
- Không ký số PDF chuẩn pháp lý (chỉ render dấu đỏ/chữ ký dạng ảnh)
- Không sửa Lark production
2. Bối cảnh (gốc lý do làm POC này)
POC này sinh ra do 5 phiên Lark trước (Lark 1 → Lark 6) đã thử "hiểu toàn bộ Lark trước khi làm gì" — bất khả với SaaS đóng. Hướng đi mới (Huyên chốt phiên Lark 6):
"Mục tiêu thấp hơn. Kết nối một vài dữ liệu sang PG → Directus → PDF render → Nuxt. Quá trình tự động hoàn toàn."
Nguyên nhân thực tế: Lark hiện đang sinh thông báo tuyển dụng (đăng đơn hàng tuyển TTS theo luật) qua 1 cơ chế đã hỏng từ 29/07/2025 (Base "Thông báo đơn hàng" còn 87 record cũ, không sinh thêm). POC này không phải để fix Lark — mà là xây tuyến mới song song, không phụ thuộc Lark còn hỏng.
3. Kiến trúc tổng thể (đã được Huyên duyệt nguyên tắc, chờ duyệt chi tiết)
[Lark Base 88 - Phái cử (CORE, 80 bảng)]
app_token: YSIkb8PxOaNaozs2vwalOOcagkf
│
│ Bảng tổng hợp (Huyên tạo, table_id sẽ báo sau)
│ ─ Huyên tự fill data từ nhiều bảng/Base về 1 chỗ
│ ─ Pipeline KHÔNG cần filter/join cross-table
│
│ Cổng 2 READ (lark-client, polling cron)
│ Identity: app "For Gem" (cli_a785d634437a502f)
│ Scope: bitable READ verified P3
│ Cron: 30 phút/lần, 8h-18h GMT+7
│ Dual-trigger theo hiến pháp Incomex
▼
[PostgreSQL 16 trên VPS Contabo]
├─ lark_jobs (cấu hình job: base_token, table_id, field whitelist)
├─ lark_job_runs (mỗi lần chạy = 1 run, có status, rows_fetched)
├─ lark_raw_records (JSONB, không mất bit nào, idempotent theo source_record_id)
├─ lark_document_rows (canonical, cột thật, dùng để render)
├─ lark_pdf_outputs (track file output, status render)
└─ cron_flags (cờ tắt nhanh dual-trigger)
│
│ Directus expose collection
▼
[Directus CMS]
├─ Collection lark_document_rows (read-only mirror PG)
└─ Files collection (lưu PDF output, có metadata + permission)
│
│ Cron quét row mới → render
▼
[Gotenberg container Docker]
Input: HTML template + data merged
Output: PDF
│
▼
[Directus Files] ← lưu PDF output
│
▼
[Nuxt 3 tại donhang.incomex...]
Trang list: bảng matrix 3-5 cột (mã đơn, ngày, trạng thái, link PDF)
Click → tải PDF từ Directus Files
Luồng cũ Directus → Nuxt vẫn chạy song song, không bị POC này ảnh hưởng.
4. Tài sản đã có sẵn (KHÔNG phải build mới)
| # | Tài sản | Vị trí | Trạng thái |
|---|---|---|---|
| 1 | Base 88 - Phái cử (core, 80 bảng) | app_token YSIkb8PxOaNaozs2vwalOOcagkf |
✅ Active production, edit cuối 13/04/2026 14:57 bởi Nhung.PTH |
| 2 | App "For Gem" Lark | cli_a785d634437a502f | ✅ Đã invite vào toàn bộ 18 Base |
| 3 | LARK_APP_ID + LARK_APP_SECRET | GSM project github-chatgpt-ggcloud |
✅ Sẵn sàng |
| 4 | lark-client toolkit | /opt/incomex/lark-client/ |
✅ Phase 2 test 8/8 PASS (2026-04-11) |
| 5 | LarkCore + LarkReader | trong lark-client | ✅ Read-only, có rate limit + audit |
| 6 | CLI commands | schema list/dump/summarize, audit tail |
✅ Sẵn sàng |
| 7 | 15/15 READ endpoint Bitable v1 | verified P3 (cong2-p6-final-report) | ✅ |
| 8 | PostgreSQL 16 | VPS Contabo, Docker | ✅ DUY NHẤT |
| 9 | Directus CMS | VPS Contabo, Docker | ✅ |
| 10 | Nuxt 3 | VPS Contabo, Docker | ✅ |
| 11 | Domain donhang.incomex... |
Đã trỏ về VPS | ✅ Huyên đã setup |
| 12 | Schema Đơn hàng - Chính thức | tblh7nrQpK8TqIs2, 234 fields |
✅ Có trong lark-base-88-data-flow.md |
| 13 | Schema TTS - Thông tin | tblKnzaih6154r2e, 233 fields |
✅ Có trong lark-base-88-data-flow.md |
| 14 | Schema Nghiệp đoàn | tblG18kR9aFhWrJW, 87 fields |
✅ Có trong lark-base-88-data-flow.md |
| 15 | Blueprint 80 bảng Base 88 | lark-base-88-phai-cu-blueprint.md |
✅ Phân nhóm A-O |
| 16 | Registry 18 Base | lark-base-registry.md |
✅ Có app_token đầy đủ |
→ Không cần build mới gì ở tầng reader/storage. Chỉ cần ráp.
5. Quyết định kỹ thuật đã chốt
| # | Quyết định | Lý do |
|---|---|---|
| 1 | PDF engine: Gotenberg | API REST sẵn, Docker container, render HTML+CSS bằng Chromium, hỗ trợ tốt: con dấu đỏ overlay (CSS absolute), bảng phức tạp, header/footer, font Unicode tiếng Việt, MIT license. Ứng cử viên dự phòng nếu Gotenberg fail: Typst |
| 2 | Reader: Cổng 2 (lark-client/LarkReader) | Read-only, đã verified, có audit + rate limit |
| 3 | Cron: 30 phút/lần, 8h-18h GMT+7 | Huyên chốt. Nghỉ qua đêm, sáng 8h chạy tiếp |
| 4 | Dual-trigger theo hiến pháp Incomex | Bắt buộc. Cần verify lại Điều mấy quy định Dual-trigger trước khi implement (xem Section 10 Open Questions) |
| 5 | Storage PDF: Directus Files collection | Có metadata + permission sẵn, Nuxt đã đọc Directus rồi, không cần thêm credential storage. Đề xuất, chờ Huyên duyệt |
| 6 | Template engine merge data: Handlebars | Node native, đơn giản nhất, đủ dùng. Chờ Huyên duyệt |
| 7 | Template HTML lưu trong git Nuxt repo | Versioning qua git commit. Chờ Huyên duyệt |
| 8 | Mapping format: YAML, dùng field_id (KHÔNG dùng tên) | Tên field Lark có thể đổi, field_id không đổi |
| 9 | Schema PG: dùng đúng 5 bảng GPT đề xuất trong nd-lark-mvp |
Không sửa, không thêm |
| 10 | POC chỉ đọc 1 table tổng hợp Huyên tạo | Không filter, không join cross-table phía pipeline. Cắt độ phức tạp |
6. Việc cần làm — chia 2 nhóm
Nhóm A — Làm được NGAY (không phụ thuộc bảng tổng hợp Huyên tạo)
| # | Việc | Ai làm | Estimate | Trạng thái |
|---|---|---|---|---|
| A1 | File này (nd-lark-pg-dir-prerequisites-v1.md) |
Claude Desktop | 30 phút | 🟡 đang viết |
| A2 | Setup Gotenberg container Docker trên VPS | Claude Code CLI | 15 phút | ⏳ |
| A3 | Tạo 5 bảng PG schema theo nd-lark-mvp (lark_jobs, lark_job_runs, lark_raw_records, lark_document_rows, lark_pdf_outputs) + bảng cron_flags |
Claude Code CLI qua DOT cặp A/B | 30 phút | ⏳ |
| A4 | Tạo Directus collection mirror PG (read-only) | Claude Code CLI qua DOT | 20 phút | ⏳ |
| A5 | Skeleton template HTML A4 (sườn, Huyên sẽ sửa khi có data thật) | Claude Desktop | 30 phút | ⏳ |
| A6 | Cron systemd 30 phút/lần 8h-18h GMT+7, đọc cờ từ cron_flags, dual-trigger | Claude Code CLI (sau khi verify hiến pháp) | 45 phút | ⏳ |
| A7 | Endpoint Nuxt skeleton tại donhang.incomex... |
Claude Code CLI | 30 phút | ⏳ |
Tổng nhóm A: ~3.5 giờ, có thể chạy song song nhiều việc.
Nhóm B — CHỜ Huyên báo table_id bảng tổng hợp
| # | Việc | Ai làm | Phụ thuộc |
|---|---|---|---|
| B1 | Mapping field Lark → PG column (YAML, field_id) | Claude Desktop | Huyên báo table_id + tên field |
| B2 | Tạo job config trong lark_jobs (base_token, source_table_id, field_whitelist) |
Claude Code CLI | B1 |
| B3 | Lần chạy đầu tiên end-to-end (Lark → PG → Directus → Gotenberg → PDF → Nuxt) | Claude Code CLI | B2 + nhóm A xong |
| B4 | Sửa template HTML cho khớp data thật + layout đúng PDF mẫu | Huyên + Claude Desktop | B3 |
| B5 | Hardtest end-to-end (1 record → PDF đúng, cron tự chạy đúng giờ, cờ tắt OK) | Claude Code CLI | B4 |
Tổng nhóm B: ~2-4 giờ, sequential.
7. Ràng buộc tuyệt đối (KHÔNG được vi phạm)
- Cổng 2 READ-only. KHÔNG dùng bất kỳ tool write nào của Cổng 2 trong toàn bộ POC. Nếu cần verify quyền, dùng
lark-client schema listhoặcLarkReader.list_tables. - KHÔNG đụng Lark production (Base 88 đang chạy, edit cuối hôm nay 13/04/2026).
- KHÔNG sync 2 chiều, KHÔNG write-back.
- Mọi DOT ghi (cấp B) phải có DOT kiểm tra (cấp A) theo nguyên tắc Huyên đã chốt.
- §0-AE: Không báo DONE nếu chưa verify.
- Smoke test sau mọi deploy.
- Dual-trigger theo hiến pháp Incomex (Điều cần verify).
- GSM = SSOT cho secrets — không hardcode token.
- §0-AU: Không hardcode (path, URL, token).
8. Mapping schema PG (draft, theo nd-lark-mvp của GPT)
8.1 lark_jobs
CREATE TABLE lark_jobs (
job_code TEXT PRIMARY KEY,
base_token TEXT NOT NULL,
source_table_id TEXT NOT NULL,
source_view_id TEXT,
field_whitelist JSONB NOT NULL, -- [{lark_field_id, lark_field_name, pg_column, type, required}]
document_type TEXT NOT NULL, -- 'thong_bao_tuyen_dung'
status TEXT NOT NULL DEFAULT 'active', -- 'active' | 'paused'
schedule_mode TEXT NOT NULL DEFAULT 'cron', -- 'cron' | 'manual'
notes TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
8.2 lark_job_runs
CREATE TABLE lark_job_runs (
run_id BIGSERIAL PRIMARY KEY,
job_code TEXT NOT NULL REFERENCES lark_jobs(job_code),
trigger_source TEXT NOT NULL, -- 'cron_primary' | 'cron_backup' | 'manual'
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
finished_at TIMESTAMPTZ,
status TEXT NOT NULL DEFAULT 'running', -- 'running' | 'success' | 'failed' | 'skipped'
rows_fetched INTEGER DEFAULT 0,
rows_new INTEGER DEFAULT 0,
rows_updated INTEGER DEFAULT 0,
error_log TEXT
);
8.3 lark_raw_records
CREATE TABLE lark_raw_records (
id BIGSERIAL PRIMARY KEY,
run_id BIGINT NOT NULL REFERENCES lark_job_runs(run_id),
job_code TEXT NOT NULL,
source_record_id TEXT NOT NULL,
raw_jsonb JSONB NOT NULL,
fetched_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(job_code, source_record_id, fetched_at)
);
CREATE INDEX idx_raw_records_lookup ON lark_raw_records(job_code, source_record_id);
8.4 lark_document_rows (canonical)
CREATE TABLE lark_document_rows (
row_id BIGSERIAL PRIMARY KEY,
job_code TEXT NOT NULL,
source_record_id TEXT NOT NULL,
document_type TEXT NOT NULL,
-- Cột canonical sẽ được điền sau khi Huyên báo bảng tổng hợp
-- Ví dụ cho thong_bao_tuyen_dung:
-- ma_don_hang TEXT,
-- ten_xi_nghiep TEXT,
-- nganh_nghe TEXT,
-- ngay_ban_hanh DATE,
-- ...
payload_jsonb JSONB, -- phần linh hoạt cho field chưa biết
render_status TEXT NOT NULL DEFAULT 'pending', -- 'pending' | 'rendering' | 'rendered' | 'failed'
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(job_code, source_record_id, document_type)
);
8.5 lark_pdf_outputs
CREATE TABLE lark_pdf_outputs (
output_id BIGSERIAL PRIMARY KEY,
row_id BIGINT NOT NULL REFERENCES lark_document_rows(row_id),
source_record_id TEXT NOT NULL,
document_type TEXT NOT NULL,
directus_file_id UUID, -- UUID file trong Directus Files collection
file_name TEXT,
file_size_bytes BIGINT,
rendered_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
status TEXT NOT NULL DEFAULT 'success', -- 'success' | 'failed'
error_log TEXT
);
8.6 cron_flags (mới, cho dual-trigger + tắt nhanh)
CREATE TABLE cron_flags (
flag_key TEXT PRIMARY KEY,
flag_value BOOLEAN NOT NULL,
description TEXT,
updated_at TIMESTAMPTZ DEFAULT NOW(),
updated_by TEXT
);
INSERT INTO cron_flags VALUES
('lark_pdf_pipeline_enabled', TRUE, 'Cờ tắt nhanh toàn bộ pipeline POC'),
('lark_pdf_trigger_primary', TRUE, 'Cờ trigger chính (cron 30 phút)'),
('lark_pdf_trigger_backup', TRUE, 'Cờ trigger backup (dual-trigger theo hiến pháp)');
9. Trạng thái hiện tại (cập nhật mỗi phiên)
Phiên Lark 6, 2026-04-13, 15:30 GMT+7:
- File này đang được tạo (A1)
- Việc nhóm A (A2-A7) ⏳ chưa bắt đầu
- Việc nhóm B ⏳ chờ Huyên báo table_id bảng tổng hợp
- Open Questions: chưa verify Điều mấy của hiến pháp về Dual-trigger
Cần Huyên quyết để đi tiếp:
- Duyệt file này có ổn không? Nội dung đã đầy đủ chưa?
- Duyệt Storage = Directus Files, Template engine = Handlebars, Template lưu git Nuxt?
- Cho phép Claude Desktop search KB tìm Điều hiến pháp về Dual-trigger?
- Khi Huyên tạo xong bảng tổng hợp → báo table_id + tên các field cần đọc (text plain, dán vào chat hoặc file mới
nd-lark-pg-dir-source-table-info-v1.md)
10. Open Questions (cần verify, không tự đoán)
| # | Câu hỏi | Cách verify | Khi nào |
|---|---|---|---|
| Q1 | Điều mấy của hiến pháp Incomex quy định Dual-trigger? Cơ chế chính xác là gì (1 chính + 1 backup? 2 độc lập + dedup?) | agent-data:search_knowledge với query "dual trigger điều" và "hiến pháp dual" |
Trước A6 |
| Q2 | Directus có Files collection sẵn không, hay cần tạo? Permission default ra sao? | Kiểm tra Directus admin UI | Trước A4 |
| Q3 | Nuxt có sẵn route engine cho subdomain donhang.incomex... không, hay cần config riêng? |
Kiểm tra Nuxt config + nginx VPS | Trước A7 |
| Q4 | Gotenberg version nào dùng? Latest stable hay LTS? | Check Docker Hub gotenberg/gotenberg |
Trước A2 |
| Q5 | Bảng tổng hợp Huyên tạo sẽ là bảng MỚI hay 1 bảng có sẵn (như Đơn hàng - Chính thức)? | Hỏi Huyên | Trước B1 |
| Q6 | Tên 8 cột template thông báo tuyển dụng cụ thể là gì? | Phân tích PDF mẫu Huyên gửi (đã có) + map sang field Lark | Trước B1 |
11. Tham khảo chéo
knowledge/dev/lark/lark_PG_Dir/README.md— README nhóm tài liệuknowledge/dev/lark/lark_PG_Dir/nd-lark-pg-dir-short-plan-v1-gpt.md— Plan ngắn của GPTknowledge/dev/lark/lark_PG_Dir/nd-lark-mvp-lark-to-pg-to-pdf-v1-gpt.md— MVP detail của GPT (schema PG 5 bảng nguồn)knowledge/dev/lark/lark_PG_Dir/nd-lark-pg-dir-pdf-engine-decision-v1-gpt.md— Quyết định Gotenbergknowledge/dev/lark/lark-base-registry.md— 18 Base + app_tokenknowledge/dev/lark/lark-base-88-phai-cu-blueprint.md— Blueprint 80 bảng Base 88knowledge/dev/lark/lark-base-88-data-flow.md— Schema 3 bảng core + 12 link fieldknowledge/dev/lark/lark-client-architecture.md— lark-client toolkit docknowledge/dev/lark/cong2-p6-final-report— Kết quả P6 verify Cổng 2
12. Lịch sử file
| Rev | Ngày | Người | Thay đổi |
|---|---|---|---|
| 1 | 2026-04-13 | Claude Desktop (phiên Lark 6) | Khởi tạo. Tổng hợp 6 phiên Lark trước + 3 file GPT + KB Lark sẵn có. Mục đích: token-saving cho phiên sau. |
EOF