Giao diện
Kiến trúc nội bộ
Bức tranh cho người sửa core: mỗi package build ra gì, phụ thuộc thế nào, app sản phẩm nạp chúng ra sao và một request đi qua những đâu. Góc nhìn của team sản phẩm: Kiến trúc.
Package và cách build
| Package | Build bằng | Sản phẩm publish | Ai dùng |
|---|---|---|---|
@tasco/theme | unbuild | dist/ + styles/base.css (không qua build) | ui, composables, layer, docs, mcp lúc sinh dữ liệu |
@tasco/utils | unbuild | dist/ | ui, composables, ai, layer |
@tasco/composables | unbuild, nuxt/vue là external | dist/ | layer (auto-import) |
@tasco/ui | vite build (lib) + vite-plugin-dts gộp d.ts + gen-component-meta.mjs | dist/index.js, ui.css, index.d.ts, component-meta.json | layer, playground, docs, app sản phẩm, mcp lúc sinh dữ liệu |
@tasco/ai | unbuild, 4 entry: ., /server, /prompts, /eval | dist/ | app sản phẩm (tuỳ chọn) |
@tasco/nuxt-layer-base | không bundle — build chỉ chạy nuxi prepare để có type | Source: nuxt.config.ts, app/, server/, tasco.d.ts | app sản phẩm extends |
@tasco/cli | không build | bin/, templates/ | npx @tasco/cli |
@tasco/mcp | tsx scripts/generate.ts rồi unbuild | dist/, data/*.json, bin/ | AI tooling của dev |
@tasco/eslint-config, @tasco/tsconfig | không build | File cấu hình | mọi package và app |
Turborepo chạy build, typecheck, test, dev sau ^build của package phụ thuộc — nên luôn chạy qua pnpm build hoặc pnpm turbo run … --filter=… thay vì gọi thẳng trong từng thư mục.
Phụ thuộc
┌──────────┐ ┌──────────┐
│ theme │ │ utils │ TS thuần, không Vue/Nuxt
└────┬─────┘ └────┬─────┘
┌─────────────┼──────────────┼──────────────┐
▼ ▼ ▼ ▼
┌──────────┐ ┌────────────┐ ┌──────────┐ ┌─────────┐
│ ui │ │ composables│ │ ai │ │ mcp │ (theme, ui chỉ lúc sinh dữ liệu)
│ + antdv │ │ + Nuxt │ │ + vue/h3 │ └─────────┘
└────┬─────┘ └─────┬──────┘ └────┬─────┘
└──────┬───────┘ │ tuỳ chọn
▼ ▼
┌────────────────┐ ┌──────────────┐
│nuxt-layer-base │──────▶│ app sản phẩm │
└────────────────┘extends└──────────────┘Ràng buộc (vi phạm là từ chối MR — xem Quy ước code):
utilsvàthemekhông phụ thuộc Vue hay Nuxt — dùng lại được ở script, server, test thuần.composableskhông phụ thuộcui: composable nào cần antdv (useConfirm,useErrorHandler) đặt ở@tasco/ui.- Chỉ
@tasco/ui, layer, Storybook preview và theme của docs được important-design-vue. aikhông nằm trong layer — app bật tính năng AI thì tự cài.- Tối đa hai tầng Nuxt layer:
nuxt-layer-base→ app.
App sản phẩm nạp framework thế nào
- App
extends: ['@tasco/nuxt-layer-base']. Layer publish source: Nuxt đọcnuxt.config.ts,app/,server/của layer như một phần của app. - Layer khai
build.transpile: ['@tasco/ui', '@tasco/composables']— cài từ registry, hai package này nằm trongnode_modulesvà sẽ bị Nitro externalize (lỗiERR_MODULE_NOT_FOUNDkhi dev SSR) nếu không transpile. - Composable vào app qua preset
importscủa layer; componentC*qua plugin01.ui(app.use(TascoUI)); type của component toàn cục vàRouteMetaquatasco.d.ts. @ant-design-vue/nuxtđăng kýa-*toàn cục cho layer;@nuxt/fontstự host font.
Trong monorepo, playground và docs dùng workspace:* nên nạp thẳng thư mục package — một lỗi chỉ xuất hiện khi cài từ registry (thiếu files, thiếu transpile, thiếu @types/node) sẽ không lộ ra ở đây. Test của @tasco/cli (tests/template.test.mjs) khoá một số lỗi loại này.
Luồng runtime
Mở một trang
Trình duyệt ──GET /orders──▶ Nitro
routeRules '/**' ssr:false → trả HTML khung (lang="vi"), không render component
Trình duyệt tải JS
plugin 01.ui app.use(TascoUI)
plugin 02.auth GET /auth/session → useState('tasco:auth:user'); provide $tascoAuth
plugin 03.permission directive v-can
plugin 04.error errorHandler + vue:error → handleError; provide $tascoError
middleware auth.global chưa đăng nhập → /auth/login?redirect=/orders
middleware permission.global thiếu quyền trong meta → throw 403
app.vue ConfigProvider(theme, vi_VN) + <style id="tasco-vars"> + data-theme
layouts/default.vue CAppLayout + menu đã lọc quyền + NuxtErrorBoundary
pages/orders.vue useTable(fetcher) → useApi('/orders')Gọi backend
useApi ──$fetch /api/orders──▶ server/api/[...].ts
getTascoSession(event) giải mã cookie tasco_session
xoá authorization, cookie của client
gắn Bearer nếu token còn hạn
proxyRequest → apiProxyTarget/orders
◀── response nguyên trạng ──
lỗi HTTP ──▶ onResponseError → toAppError → throw AppError
──▶ trang tự bắt ($tascoError) hoặc errorHandler toàn cục → message / notification / chuyển trang đăng nhậpĐăng nhập
/auth/login (trang) → TascoLoginForm
GET /auth/clients danh sách ứng dụng (IAM clients)
POST /auth/otp/send chỉ với Telegram → transactionId
POST /auth/login IAM login-v1 → token; userInfo (POST, header authorization không Bearer)
seal { user tối thiểu, accessToken, expiresAt } vào cookie httpOnly 8 giờ
→ useAuth cập nhật user → navigateTo(redirect đã lọc)
Mỗi lần app khởi động: GET /auth/session gọi lại userInfo để lấy roles/permissions mớiCookie chỉ giữ token và định danh vì giới hạn 4KB; roles và permissions (có thể hàng trăm mục) luôn lấy tươi.
Theme
tokens.ts ──getAntdTheme(mode)──▶ ConfigProvider (token toàn cục + thuật toán sáng/tối của antdv)
──cssVars(mode)───────▶ biến --tasco-* trong <head> ──▶ style scoped của C*, CSS của app, base.css
base.css ──────────────────────▶ phần antdv 4 bỏ qua theme.components: bảng, mật độ, chữ màu ở chế độ tối
useThemeMode (cookie tasco:theme) ──▶ đổi mode ──▶ app.vue tính lại cả hai nhánhDữ liệu sinh lúc build
| Sinh ra | Từ | Bằng | Dùng ở |
|---|---|---|---|
packages/ui/dist/component-meta.json | JSDoc, defineSlots trong *.vue | vue-component-meta | Bảng API trong docs (<ApiTable>), docs-coverage, @tasco/mcp |
packages/mcp/data/*.json | component-meta.json và re-export antdv của ui, token, docs/**/*.md (kèm demo), CLAUDE.md | scripts/generate.ts | Tool của @tasco/mcp |
docs/.vitepress/theme/tokens.generated.css | cssVarsText | gen-tokens.mjs | Biến --tasco-* trong site docs |
docs/reference/api/*.md | TSDoc của 4 package TS | TypeDoc (gen-api.mjs) | Khu Tra cứu |
docs/reference/changelog.md | CHANGELOG.md các package, .changeset/*.md | gen-changelog.mjs | Trang Changelog |
Không sửa tay file sinh — sửa nguồn rồi build lại.
Muốn đổi … thì sửa ở đâu
| Muốn | Sửa | Xem |
|---|---|---|
| Màu, font, mật độ | packages/theme/src/tokens.ts, styles/base.css | Đổi design token |
| Thêm component | packages/ui/src/components/ + đăng ký 3 chỗ | Thêm component C* |
| Thêm composable, helper | packages/composables/src/, packages/utils/src/ | Thêm composable & util |
| Luồng đăng nhập, BFF | packages/nuxt-layer-base/server/ | Route BFF |
| Khoá cấu hình mới | runtimeConfig trong nuxt.config.ts của layer + trang tra cứu | Biến môi trường |
| Thứ tự khởi động, xử lý lỗi toàn cục | packages/nuxt-layer-base/app/plugins/ | API của layer |
| Dự án mới sinh ra gì | packages/cli/templates/app/ | CLI create-tasco-app |
Ràng buộc từ công nghệ bên ngoài
Một số lựa chọn kiến trúc ở trên (CSR mặc định, style qua base.css, cookie chỉ giữ token) đến từ giới hạn của antdv, IAM và GitLab registry — danh sách gotcha: Nợ kỹ thuật › Khác với gotcha.