Next.js 16 TypeScript Prisma 7
Agent-Optimized v3.0

TECH.MD — Tài liệu Kỹ thuật
& Quy tắc Phát triển

Tài liệu chuẩn dành cho AI Agents & Developers. Toàn bộ quy tắc kiến trúc, UI/UX, bảo mật và quy trình làm việc trong một file duy nhất.

Tháng 4/2026
21 Sections
Production-Ready
Cập nhật liên tục
Checklist 4 bước bắt buộc trước khi code
TUYỆT ĐỐI BẮT BUỘC: Không bỏ qua bất kỳ bước nào trong quy trình này. Áp dụng cho mọi phiên làm việc.
1
Phân tích codebase
Đọc schema.prisma và các types.ts hiện có. Không tạo type mới nếu đã tồn tại.
2
Lên kế hoạch trước khi code
Mô tả danh sách file sẽ tạo/sửa. Tuân theo cấu trúc modules/[feature]/.
3
Hỏi kiến trúc với Owner
Xác định xem có nên tách module/package riêng không. Xem Rule #8 — Code Standards.
4
Triển khai từng file nhỏ
Viết code từng file, không vượt 250 dòng / file. Xem Rule #9 — File Size Limit.
Hệ thống Lõi — Core Infrastructure
Runtime & Package
Node.js ≥ 22.x (LTS) pnpm v9.x Workspaces Turborepo v2.x
Ngôn ngữ
TypeScript v5.x
Strict Mode = true — Không ngoại lệ
Cấu trúc Monorepo
Thư mụcChứa gìVí dụ
apps/*Ứng dụng chạy đượcweb, admin, app
packages/*Packages dùng chungui, db, api, crypto, config
Frontend & Giao diện
Framework
Next.js v16.2 (App Router) React 19
Styling
Tailwind CSS v4.2
Native config architecture. Ưu tiên tính năng native.
UI Components
Radix UI (Headless) shadcn/ui (React 19) Lucide React
Visualization & UX
recharts @dnd-kit/core lenis
Font bắt buộc: Be Vietnam Pro — load qua next/font/google. Khai báo tại layout.tsx cho toàn bộ dự án.
Dark Mode: Dùng custom ThemeProvider từ components/providers.tsx. KHÔNG dùng next-themes — inject <script> vào React tree, crash hydration iOS Safari/React 19.
API & Tầng Giao tiếp Dữ liệu
API Layer
tRPC v11
End-to-End Type Safety
Real-time
socket.io / tRPC Subscriptions
SSE cho Live Notifications
State Client
Zustand v5
KHÔNG dùng Redux
Validation
Zod
Schema DB + Form + API
Serialization
SuperJSON
Date, Map, Set qua network
Email
Resend
System + Marketing email
Cơ sở Dữ liệu & Lưu trữ
ORM
Prisma v7.7
Dùng Query Compiler mới để tối ưu hiệu năng
Database
PostgreSQL
Row Level Security (RLS) bắt buộc
Storage
Cloudflare R2
S3 Compatible API. No Egress Fee.
Xác thực & Bảo mật
Authentication
Auth.js (NextAuth v5 Core 3)
OAuth: Google, GitHub
Credentials: Argon2 / Bcryptjs
Authorization
RBAC bắt buộc
Role: Admin / Editor / Viewer
Kiểm soát đến từng action, không chỉ dừng ở Login
XSS Protection: Bắt buộc dùng DOMPurify cho mọi nội dung user-generated được render vào DOM.
Kiến trúc Multi-Tenant
Chiến lược Database
Single Schema + Row Level Security (RLS). Nhận diện khách thuê qua tenant_id (UUID) trong mọi bảng nghiệp vụ.
BảngCác trường chính
Tenantid, name, domain, custom_domain, theme_config (JSON), features (String[])
Userid, email, role (OWNER | STAFF), tenant_id
Orderid, status, amount, metadata (JSON), tenant_id
Middleware Logic (src/middleware.ts)
// 1. Bóc tách hostname từ HTTP request // 2. Nhận diện: subdomain hay custom domain? // 3. Truy xuất tenant_id từ Cache/DB // 4. Rewrite URL → /[tenantId]/dashboard/... hoặc /[tenantId]/store/...
Quy tắc Viết Code dành cho Agent
  • 01
    Type Safety — Tuyệt đối không dùng any
    Mọi dữ liệu từ API phải có Schema Zod. Strict Mode = true toàn dự án.
  • 02
    Server Components mặc định
    Mặc định dùng React Server Components (RSC). Chỉ dùng 'use client' khi thực sự cần tương tác UI.
  • 03
    Error Handling chuẩn
    Dùng error.tsx của Next.js + Error Formatting của tRPC để bắt và hiển thị lỗi.
  • 04
    Git: Conventional Commits
    Ghi commit tuân theo chuẩn Conventional Commits: feat, fix, chore, refactor, docs...
  • 05
    Environment Variables — Schema duy nhất
    Cấm gọi process.env.ABC rải rác. Bắt buộc dùng env.ts + @t3-oss/env-nextjs validate bằng Zod. Throw Error ngay khi build/start nếu thiếu biến.
  • 06
    Rate Limiting & Debounce
    Mọi input Tìm kiếm / Filter / Lookup phải wrap qua Debounce 300–500ms. Ngăn bão request khi gõ phím liên tục.
  • 07
    Sitemap tự động cập nhật (SEO)
    Mọi route mới tạo ra — kể cả route động — đều phải tự động cập nhật vào sitemap.ts. Mỗi URL phải có mô tả chuẩn SEO.
  • 08
    Hỏi kiến trúc trước khi làm tính năng mới
    Dừng lại hỏi user: có nên tách module/package/component riêng không? Giữ sạch code, dễ bảo trì.
  • 09
    File Size Limit — Tối đa 250 dòng / file
    Nếu vượt → tách ngay:
    • UI quá dài → extract sub-components vào components/
    • Logic quá dài → extract Custom Hooks vào hooks/
    • API calls quá dài → extract vào services/ hoặc queries.ts
    • File cũ vi phạm → đề xuất Refactoring trước khi thêm tính năng mới
  • 10
    Routing: SEO vs Internal
    Public / SEO: Folder Routing (Clean URL) — app/products/[slug]/page.tsx. Tuyệt đối không dùng ?id=123 cho trang cần SEO.
    Admin / Dashboard: Query Params (?c=16238&view=history) — SPA-like navigation.
Quy tắc Thiết kế & UX/UI
Tuyệt đối không dùng Emoji làm biểu tượng. 100% phải dùng SVG Icons — khuyến nghị lucide-react.
Tuyệt đối không dùng <select> mặc định của HTML. Xây dựng Custom Select Component bằng Radix UI hoặc State + Framer Motion.
Cấm window.confirm()alert(). Dùng Inline Confirmation hoặc Custom Modal Overlay.
Quy tắcVấn đềGiải pháp đúng
Responsive Mobile-FirstThiết kế vỡ trên MobileCấm giá trị kích thước tĩnh cứng nhắc
Contrast & Dark ModeTương phản thấp, không AccessibleCSS Variables, không hardcode màu
Scrollbar Layout ShiftModal mở/đóng dịch content 15–17pxpadding-right = scrollbarWidth khi overflow: hidden
Clipboard Fallbacknavigator.clipboard bị chặn trong WebViewFallback <textarea> ẩn + execCommand('copy')
Typography Card TitleFont quá bold gây khó đọctext-xl font-bold text-neutral-700 dark:text-neutral-300
Scrollbar GutterContent dịch khi scrollbar xuất/ẩnscrollbar-gutter: stable trên html, body
Data Tables MobileWord wrap lộn xộn trên mobileoverflow-x-auto + whitespace-nowrap + min-w-[...]
Infinite ScrollDOM collapse khi hàng trăm recordsStrict Pagination (10 items/page)
Scrollbar Shift Fix (mọi Modal/Drawer)
useEffect(() => { const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth; document.body.style.overflow = "hidden"; document.body.style.paddingRight = `${scrollbarWidth}px`; return () => { document.body.style.overflow = "auto"; document.body.style.paddingRight = ""; }; }, []);
Header & Navigation Signature
  • Header sticky với backdrop-saturate-150 backdrop-blur-xl bg-background/60
  • Avatar fallback: 1 chữ cái nền bg-blue-600 nếu không load được ảnh
  • Dropdown Avatar dùng createPortal + getBoundingClientRect để tránh z-index/overflow issues
  • Mobile: Horizontal Scrollable Pager thay cho hamburger menu
Zero-Trust Backend & Module Isolation
Quy tắc Vàng: Mọi Business Logic phải thực thi tại Server. Frontend chỉ là Presentation Layer.
  • CẤM Authorization tại Client (if (user.role === 'admin') showDeleteButton)
  • CẤM tính toán giá, tồn kho, điểm thưởng tại Client rồi gửi lên Server
  • CẤM dùng ID từ request body mà không verify ownership (IDOR Attack)
  • Mọi API/Server Action bắt đầu bằng: Authentication → Authorization → Logic
Feature-based Module Structure
apps/web/modules/ users/ actions.ts ← Server Actions (write/delete/edit) queries.ts ← Server-side data fetching schemas.ts ← Zod validation schemas types.ts ← TypeScript types (module scope) components/ ← UI chỉ thuộc module này projects/ ← Tương tự admin/ ← Tương tự
Mẫu Server Action chuẩn
"use server"; export async function deleteProject(projectId: string) { // Bước 1: Xác thực danh tính const session = await auth(); if (!session?.user) throw new Error("Unauthorized"); // Bước 2: Kiểm tra quyền sở hữu (chống IDOR) const project = await db.project.findFirst({ where: { id: projectId, ownerId: session.user.id }, }); if (!project) throw new Error("Forbidden"); // Bước 3: Thực thi logic nghiệp vụ await db.project.delete({ where: { id: projectId } }); }
Component Patterns & UI Standards
RowActions — Kebab Menu bắt buộc
Mọi bảng có ≥ 2 actions bắt buộc dùng RowActions với nút ⋮.
Built-in: Escape/Click-outside close, flip-up tự động, z-index 9999, iOS ghost-click guard.
ConfirmDialog bắt buộc khi xóa/sửa
Mọi thao tác Delete/Edit phải qua ConfirmDialog trước khi thực thi.
Variants: danger (đỏ) / warning (vàng) / info (xanh)
Toast sau mỗi Action
Sau mọi onConfirm phải gọi toast.success() hoặc toast.warning().
<Toaster /> đặt 1 lần trong root layout.
EmptyState Component
Khi list trả về length === 0, bắt buộc render: Icon + Text thân thiện + CTA Button.
Loading Skeleton
Cấm <div>Loading...</div>. Phải dùng Suspense + Skeleton trùng khớp layout gốc kèm shimmer effect.
Form Management
Cấm useState thuần cho form phức tạp. Bắt buộc: react-hook-form + zodResolver. Lỗi inline với viền đỏ.
iOS Safari — Tất cả Bug đã xác nhận
BugTriệu chứngGiải pháp đúngTránh
Auto-zoom inputFont-size < 16px → Safari zoom trangfont-size: max(16px, 1em)Không dùng user-scalable=no
Ghost Click ModalTap row → modal open → tap đầu tiên bị nuốtisReady guard 350ms + pointer-events:noneRender modal tức thì tại tọa độ tap
Double-tap ZoomWeb page phóng to khi chạm đúptouch-action: manipulation globalKhông xử lý → vỡ UI
Dev Mode + CloudflareToàn bộ onClick chết trên device thậtpnpm build && pnpm startpnpm dev qua Cloudflare Tunnel
next-themes inject scriptClick toàn trang chết trên iOS/React 19Custom ThemeProvider không inject scriptDùng next-themes với React 19
SVG absorbing clicksTap icon không ăn lệnh của buttonpointer-events: none trên SVGĐể mặc định trên SVG
Viewport Meta chuẩn
export const viewport: Viewport = { width: "device-width", initialScale: 1, // KHÔNG đặt maximumScale/userScalable // → iOS click bug trên position:fixed! };
Global CSS bắt buộc
/* globals.css */ input, select, textarea { font-size: max(16px, 1em); } button, a, [role="button"] { touch-action: manipulation; } html, body { scrollbar-gutter: stable; }
iOS Ghost Click Guard (350ms)
const [isReady, setIsReady] = useState(false); useEffect(() => { const t = setTimeout(() => setIsReady(true), 350); return () => clearTimeout(t); }, []); // Trên modal card — SVG phải có pointer-events: none <div style={{ pointerEvents: isReady ? 'auto' : 'none' }}> {/* modal content */} </div>
Loading Skeleton & Priority Queue Loading
Checklist khi thêm Route mới
1
Thêm item vào menuGroups[] trong Sidebar.tsx
2
Tạo thư mục app/[locale]/[route]/
3
Tạo loading.tsx — KHÔNG được bỏ qua
import { PageSkeleton } from ".../PageSkeleton";
Chọn variant: overview / chat / generic
4
Tạo page.tsx
5
Áp dụng Priority Queue 4-tier nếu có API calls
Priority Queue 4-Tier Loading
Tier 1
0ms
Clock, Calendar, dữ liệu tĩnh
Render ngay
Tier 2
100ms
Permission check, auth
Không block UI
Tier 3
~500ms
API call quan trọng nhất
Skeleton hiện
Tier 4
1s+
Geocoding, metadata phụ
Load sau Tier 3
Panel / Overlay Positioning (Không Layout Shift)
position: absolute; right: 0 anchor vào parent gần nhất có position != static — không phải cạnh phải màn hình!
Layout Tree SAI
outer-wrapper └── content-column (position: relative) ← SAI ├── [nội dung trang] └── Panel (position: absolute; right: 0) ← anchor vào column!
Layout Tree ĐÚNG
outer-wrapper (position: relative; width: 100%) ├── content-column │ ← KHÔNG có position: relative │ └── [nội dung trang] └── Panel (position: absolute; top:0; right:0) ← SIBLING, KHÔNG PHẢI CON
  • Panel phải là SIBLING của content column, không phải con
  • Content column KHÔNG thay maxWidth hay margin khi panel mở/đóng
  • Outer wrapper PHẢI có position: relative
  • Panel dùng position: absolute (không phải fixed) trừ backdrop toàn màn hình
Mở rộng E-Commerce & Bán hàng
Dynamic Theme Variables
Cấm hardcode màu trong JSX. Quy hoạch về biến CSS: --primary, --secondary, --accent, --destructive.
Cart State Engine
Zustand + persist middleware. Optimistic Update: cộng số lượng ngay trên UI, gửi request ngầm sau. Cấm Context API cho giỏ hàng.
Core Web Vitals
Cấm thẻ <img> thô. 100% dùng next/image. Hero Banner: priority={true}. List images: loading="lazy" + responsive sizes.
Product Variants URL
URL chuẩn SEO: [locale]/[category]/[product]. Đổi biến thể dùng Search Params + scroll:false — không reload page.
AI Workspace Compatibility
MCP Architecture
AI Tools thành khối độc lập, linh hoạt cắm/thay thế model (DeepSeek, OpenAI, Gemini). Không lock-in 1 provider.
Vercel AI SDK Streaming
Output stream chunk-by-chunk. Render Markdown + Code Blocks ngay lập tức. Cấm user chờ 10s mới xổ ra toàn bộ text.
Persistence State
Lịch sử hội thoại lưu DB. Multi-session handling. User truy cập nhanh lịch sử qua sidebar.
Quy trình Siêu tốc cho Agency / Freelance
1
Template Lõi (Nhân bản)
Thiết lập 1 Next.js + Tailwind chuẩn SEO, Glassmorphism, điểm Lighthouse tuyệt đối. Dùng làm vũ khí hạng nặng.
2
One-File Config
Toàn bộ ngữ liệu tĩnh trong config.json: Tên, Menu, Hình ảnh, Màu, Tọa độ, Social links.
3
Triển khai trong 5 phút
Copy thư mục gốc → sửa config.json → Build → Bàn giao. Nhân bản không mất sức.
Mobile Testing qua Cloudflare Tunnel
Bắt buộc: Luôn dùng Production Build khi test qua Cloudflare Tunnel. Dev Mode dùng eval() và WebSocket HMR — iOS Safari block cả hai!
pnpm build # Build tối ưu, loại bỏ eval() và HMR pnpm start -- --port 5000 # Chạy production server cloudflared tunnel --url http://localhost:5000 # Sau đó mới tunnel
Phân biệt lỗi code vs lỗi môi trường
  • Desktop OK, iPhone qua Cloudflare KHÔNG OK → Chạy pnpm build trước
  • iPhone qua IP WiFi nội bộ OK → 100% lỗi Dev Mode + Cloudflare
  • Cả WiFi nội bộ cũng KHÔNG OK → Mới bắt đầu debug code React
UTF-8 Encoding — Quy tắc bắt buộc
MỨC ĐỘ NGHIÊM TRỌNG CAO: Vi phạm gây hỏng toàn bộ ký tự tiếng Việt. Đã xảy ra trên 3 cases thực tế.
CẤM dùng trong PowerShell
Add-Content -Path "file.md" -Value "nội dung" echo "nội dung" >> file.md "nội dung" | Out-File file.md # Mặc định Windows-1252 → hỏng tiếng Việt
ĐÚNG — Ghi tường minh UTF-8
[System.IO.File]::WriteAllText( "file.md", $content, [System.Text.Encoding]::UTF8 ) # Hoặc dùng file tool của Agent
.gitattributes bảo vệ toàn dự án
* text=auto eol=lf *.md text eol=lf *.ts text eol=lf *.tsx text eol=lf *.css text eol=lf *.json text eol=lf
Zero-Cost Database Backup Strategy
Không phụ thuộc 100% vào Vendor. Vercel Cron bị giới hạn bộ nhớ <50MB và timeout — CSDL lớn sẽ crash OOM.
Worker
GitHub Actions — RAM ảo đến 7GB. Cài pg_dump qua apt-get.
Output
Nén | gzip -9 rồi upload .gz vào Cloudflare R2 qua aws s3 cp.
Security
Toàn bộ credentials trong GitHub Actions Secrets. Tách biệt server App và server Backup.
Zero-Knowledge Crypto Architecture
Memory-Only Key
Cấm lưu secretKey xuống localStorage, cookies, IndexDB. Zustand giữ key trên RAM. Đóng tab → key bốc hơi. Miễn nhiễm XSS.
Dual-Salt PBKDF2
210,000 vòng lặp băm nát mật khẩu. 2 bộ Salt: auth_verify cho server, pepper+userId cho local. Blind Server + AES-GCM.
AAD Anti-Swap
AES-256-GCM nhúng additionalData = "${item.id}:${userId}". Tráo Ciphertext sang ID khác → giải mã fail, trả về null.
Quy trình Khởi tạo Module mới (GitNexus Standard)
Nhận lệnh "Tạo module mới" → TUYỆT ĐỐI KHÔNG CODE NGAY. Bắt buộc qua bước "Project Topology Research".
1
Reusability Check
Query các hàm/component có chung công năng trước. Tìm xem đã có IconBtn.tsx, relativeTime()... chưa?
2
Đọc SKILL.md của module tương tự
Sao chép đúng Design Pattern và Naming Convention của dự án.
3
Impact Analysis
Dùng gitnexus_impact kiểm tra Blast Radius nếu sửa shared Component/Hook.
4
Báo cáo Implementation Plan
Phác thảo kế hoạch → User xác nhận → mới lập trình.
Xuất cho AI Agent
Đã copy vào clipboard!