Tài liệu này dành cho dev muốn:
- Clone một dự án đã tạo trên web (ví dụ tạo từ Kho template ở
/start) về máy để code tiếp, rồi đẩy lại lên cloud. - Phát triển một template mới (hoặc sửa template có sẵn) trên máy bằng CLI
com, rồi đưa vào Kho template của NATA.
Công cụ dùng là CLI com trong repo com.ai.vn-framework (engine dev viết bằng Rust, chạy App Router kiểu Next.js, có sẵn PostgreSQL nhúng @pglite/core).
0. Cài CLI com
Cách nhanh nhất: tải bộ cài cho macOS, Windows hoặc Linux ở trang Download. Bộ cài có sẵn Bun và engine Rust, không cần Node hay npm.
Hoặc build từ mã nguồn. Yêu cầu: Bun ≥ 1.2 và Rust toolchain.
cd ~/Documents/GitHub/com.ai.vn-framework bun install bun run build:local # build engine Rust (compiler-rs) + CLI cho máy hiện tại bun link # đăng ký lệnh `com` (alias: `cai`, `aivn`) com --version com doctor # kiểm tra Bun, engine, cổng, .env
Đăng nhập (cần cho clone, push, publish):
com login # mở trình duyệt đăng nhập Google com whoami
1. Clone một dự án về máy
Mỗi dự án trên web là một View có ID. ID nằm trên URL editor: /views/<viewId>.
com clone <viewId> ./my-app # tải mã nguồn, tự sinh package.json / tsconfig.json cd my-app com dev # http://localhost:3000, hot reload
Các lệnh hay dùng trong lúc làm:
| Lệnh | Việc |
|---|---|
com dev -p 3001 | Chạy cổng khác |
com dev --target zalo | Chạy dạng Zalo Mini App |
com sync | Lấy schema DB → types/db.d.ts, schema.sql, cập nhật AGENTS.md và dependency |
com migrate "<sql>" hoặc com migrate file.sql | Chạy migration rồi sync schema |
com test / com test --watch | Test (DB PGlite in-memory, không cần mock) |
com typecheck, com lint --fix | Kiểm tra kiểu, lint |
com pkg add <tên> | Thêm package (kho package dùng chung, không cần node_modules) |
com push (hoặc com save) | Lưu thay đổi lên cloud, chưa publish (--dry-run để xem trước) |
com publish [viewId] | Publish lên production |
Clone về là code thật của dự án: sửa ở máy,
com pushđể web editor thấy cùng nội dung.
2. Cấu trúc một template (pack)
Template nằm ở web/app/modules/prebuilt/prebuilt-components/packs/<id>/. Chỉ cần thêm thư mục là template tự hiện trong Kho template (/start, trang chủ), modal UI Studio của editor và tool AI install_ui_pack, vì registry.ts tự quét packs/*/pack.json.
packs/<id>/ pack.json # bắt buộc — thông tin hiển thị trên store showcase.preview.tsx # bắt buộc — trang demo; khi tạo dự án sẽ thành app/page.tsx components/<id>/... # UI của template (đặt trong thư mục riêng để không đè file của dự án) features/... # (tuỳ chọn) hook/state gọi tới module backend seed.sql # (tuỳ chọn) dữ liệu mẫu, chạy SAU migration của module preview/main.webp # (tuỳ chọn) ảnh bìa trên store; thêm 1.webp, 2.webp… cho gallery design/*.png # (tuỳ chọn) ảnh thiết kế gốc để tham khảo — KHÔNG được đóng gói copyright.md # (tuỳ chọn) link nguồn thiết kế + tên designer
Những gì được đóng gói vào dự án khi người dùng chọn template:
- Mọi file
.ts/.tsxcủa pack (trừ*.preview.tsx), giữ nguyên đường dẫn tương đối. showcase.preview.tsx→app/page.tsx.- Thư viện nền shadcn/ui (
packs/shadcnui:components/ui/*,lib/utils.ts,hooks/*). Pack không cần tự chép; file trùng tên trong pack sẽ thắng. - File và migration của các module backend khai báo trong
pack.json→modules(lấy từprebuilt-modules/packs/<module>/templates/), rồi tớiseed.sql.
pack.json mẫu:
{
"name": "Hat Store",
"description": "Một câu mô tả ngắn hiện trên thẻ và trong modal preview.",
"category": "E-Commerce",
"tags": ["Store", "Cart", "Checkout"],
"icon": "store",
"accent": "emerald",
"modules": ["ecom-core"],
"order": 2,
"source": { "name": "\"Ecommerce Website\" by Awe Design Studio on Dribbble", "url": "https://dribbble.com/shots/..." },
"license": "MIT",
"copyright": "© 2026 ..."
}
| Trường | Ghi chú |
|---|---|
category | Dùng lại tên có sẵn để gom nhóm và có bản dịch: Corporate, E-Commerce, SaaS, Productivity, Food & Drink, Games. Danh mục mới cần thêm key templateStore.category.<Tên> vào web/app/modules/locale/translations/*.ts. |
icon | landing | store | components |
accent | blue | emerald | indigo |
modules | ID module trong prebuilt-modules/packs/ (ví dụ ecom-core, news-core, auth-core) |
listed | false để ẩn khỏi store nhưng vẫn cài được (như shadcnui) |
author / source | Tên designer trên thẻ lấy từ author.name, không có thì tách từ source.name ("Tên shot" by <Designer> on Dribbble) |
Quy ước import trong code template — giống hệt dự án tạo bằng com create:
@/components/ui/...,@/lib/utils— shadcn/ui.@/components/<id>/...,@/features/...— code của chính template.@/modules/<domain>— server actions của module backend.import { db } from "core"— chỉ dùng trong module backend (Kysely + PostgreSQL).
3. Phát triển template mới bằng com
Vì template dùng đúng cấu trúc của một dự án com, cách nhanh nhất là dựng một dự án rỗng, code và chạy thật ở đó, rồi chép sang pack.
3.1. Dựng dự án làm việc
com create tpl-coffee # Next.js + Clean Architecture + PGlite nhúng cd tpl-coffee
Chép thư viện nền shadcn/ui của NATA vào để giống môi trường khi cài template:
NATA=~/Documents/GitHub/NATA/web/app/modules/prebuilt
cp -R $NATA/prebuilt-components/packs/shadcnui/{components,lib,hooks} .
Nếu template cần module backend (ví dụ ecom-core), chép module và migration vào:
cp -R $NATA/prebuilt-modules/packs/ecom-core/templates/{modules,features,app} . # thư mục nào có thì chép
mkdir -p migrations
cp $NATA/prebuilt-modules/packs/ecom-core/templates/planners/designs/migrations/*.sql migrations/01_ecom.sql
core tự chạy schema.sql rồi mọi file migrations/*.sql (theo thứ tự tên) khi khởi động.
3.2. Code template
components/<id>/... # các section: navbar, hero, footer…; nội dung/ảnh gom vào content.ts features/<id>/... # hook gọi server action (react-query) migrations/99_seed.sql # dữ liệu mẫu — sau này thành seed.sql của pack app/page.tsx # ghép các section — sau này thành showcase.preview.tsx
com dev # xem trực tiếp, hot reload com test # test module với DB thật in-memory com typecheck
DB dev nằm ở data/app.db. Muốn chạy lại migration + seed từ đầu: xoá data/app.db rồi com dev.
Mẹo:
- Gom toàn bộ chữ, link, ảnh vào
components/<id>/content.tsđể người dùng đổi thương hiệu dễ. - Không dùng nguyên tên thương hiệu, logo hay ảnh có bản quyền trong thiết kế tham khảo. Đổi tên; ảnh lấy từ Unsplash và ghi tên tác giả ảnh ở footer.
- Tách section thành từng file nhỏ; tránh thư viện ngoài nếu không thật cần (preview chạy trong trình duyệt).
3.3. Đóng gói vào NATA
PACK=~/Documents/GitHub/NATA/web/app/modules/prebuilt/prebuilt-components/packs/<id> mkdir -p $PACK/preview $PACK/design cp -R components/<id> $PACK/components/ cp -R features/<id> $PACK/features/ # nếu có cp migrations/99_seed.sql $PACK/seed.sql # nếu có cp app/page.tsx $PACK/showcase.preview.tsx
Rồi:
- Trong
showcase.preview.tsx: giữexport default function ...và mọi import dạng@/.... Nếu dùng react-query thì bọcQueryClientProviderngay trong file (xempacks/ecom2/showcase.preview.tsx). - Không chép
components/ui,lib,hooks(đã có trongshadcnui) haymodules/...(đã có trong module) vào pack. - Viết
pack.json, thêmcopyright.mdnếu template dựa trên thiết kế của người khác. - Chụp ảnh preview (1440px, dạng webp, mỗi ảnh < 200KB) vào
preview/main.webp,preview/1.webp…:cwebp -q 80 shot.png -o $PACK/preview/main.webp
3.4. Kiểm tra trong NATA
cd ~/Documents/GitHub/NATA/web npm run dev # rồi mở http://localhost:3003/start
- Template hiện trên store với đúng ảnh, tên designer, danh mục.
- Preview → Live chạy được. Module và seed chạy trên DB WASM trong trình duyệt, qua
initPGLitetrongdynamic-rerender/tools/pglite.ts. - Use template → đặt tên → dự án tạo ra mở được trong editor.
- Nếu engine WASM (
@pglite/core/wasm) báo lỗi với câu SQL nào đó, build lại engine trong repopglite(bun run build:wasm). Hoặc viết SQL đơn giản hơn: tránhconfig || $1::jsonb, và đổiDatesang chuỗi ISO trước khi truyền làm tham số.
4. Sửa template có sẵn
- Dựng dự án làm việc như mục 3.1.
- Chép code của pack vào:
cp -R $PACK/components $PACK/features . 2>/dev/null cp $PACK/showcase.preview.tsx app/page.tsx cp $PACK/seed.sql migrations/99_seed.sql 2>/dev/null
- Sửa và chạy
com dev, xong thì chép ngược lại như mục 3.3.
Hoặc sửa thẳng trong packs/<id>/ và xem bằng Live preview ở /start. Cách này nhanh với thay đổi nhỏ về giao diện.
5. Checklist trước khi merge
-
pack.jsonhợp lệ;categorydùng tên có sẵn (hoặc đã thêm bản dịch). -
preview/main.webpcó, nhẹ, đúng là ảnh chụp template (không phải mockup có logo của người khác). - Không còn tên thương hiệu thật trong thiết kế gốc; ảnh có ghi nguồn.
-
source/copyright.mdghi đúng designer gốc. -
com typechecksạch trong dự án làm việc; Live preview ở/startkhông lỗi console. - Bản mobile 390px không tràn ngang.
- Tạo thử một dự án từ template và mở được trong editor.