Docs · Developers

Hướng dẫn cho dev: clone dự án & phát triển template

Tài liệu này dành cho dev muốn:

  1. 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.
  2. 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ệnhViệc
com dev -p 3001Chạy cổng khác
com dev --target zaloChạy dạng Zalo Mini App
com syncLấ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.sqlChạy migration rồi sync schema
com test / com test --watchTest (DB PGlite in-memory, không cần mock)
com typecheck, com lint --fixKiể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/.tsx củ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ới seed.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ườngGhi chú
categoryDù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.
iconlanding | store | components
accentblue | emerald | indigo
modulesID module trong prebuilt-modules/packs/ (ví dụ ecom-core, news-core, auth-core)
listedfalse để ẩn khỏi store nhưng vẫn cài được (như shadcnui)
author / sourceTê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:

  1. Trong showcase.preview.tsx: giữ export default function ... và mọi import dạng @/.... Nếu dùng react-query thì bọc QueryClientProvider ngay trong file (xem packs/ecom2/showcase.preview.tsx).
  2. Không chép components/ui, lib, hooks (đã có trong shadcnui) hay modules/... (đã có trong module) vào pack.
  3. Viết pack.json, thêm copyright.md nếu template dựa trên thiết kế của người khác.
  4. 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 initPGLite trong dynamic-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 repo pglite (bun run build:wasm). Hoặc viết SQL đơn giản hơn: tránh config || $1::jsonb, và đổi Date sang chuỗi ISO trước khi truyền làm tham số.

4. Sửa template có sẵn

  1. Dựng dự án làm việc như mục 3.1.
  2. 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
    
  3. 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.json hợp lệ; category dùng tên có sẵn (hoặc đã thêm bản dịch).
  • preview/main.webp có, 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.md ghi đúng designer gốc.
  • com typecheck sạch trong dự án làm việc; Live preview ở /start khô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.