⚡ Phần 5 · AI Skills · Mục 11

Skills — Copilot Instructions Chuyên Nghiệp

File .github/copilot-instructions.md là "bộ não" mà bạn nạp vào AI trước khi bắt đầu dự án — giúp Copilot luôn code đúng chuẩn, an toàn, và chuyên nghiệp cho mọi loại dự án.

🧠 Bắt buộc dùng
📋 Copy & dùng ngay
🔒 OWASP + Best Practices
🌐 Mọi loại dự án
7 Mục thực chiến
💡 1. Khái Niệm
Copilot Instructions là gì, cách hoạt động
📄 2. File Hoàn Chỉnh
Copy & dùng ngay cho mọi project
🔧 3. VS Code Setup
.instructions.md với YAML frontmatter
✅ 4. Kiểm Tra
Verify Skills đang hoạt động đúng
🎛 5. Tuỳ Chỉnh
Customize theo dự án cụ thể
📦 6. Templates
React, Express, Python templates sẵn dùng
⚡ 7. Workflow
Pair programming & daily AI workflow

⚡ Skills này dạy AI làm gì?

  • Luôn viết code production-ready — không phải code demo tạm bợ
  • Tự động tuân theo chuẩn bảo mật OWASP Top 10 trong mọi dự án
  • Code đúng naming convention, structure, và error handling pattern
  • Biết cách tổ chức project structure cho JavaScript, Python, React, Express
  • Viết test cases đúng chuẩn, commit message theo Conventional Commits
  • Trả lời và giải thích bằng tiếng Việt, code comment tiếng Việt nếu cần
1

Copilot Instructions Là Gì?

GitHub Copilot hỗ trợ file cấu hình đặc biệt: .github/copilot-instructions.md. Khi file này tồn tại trong repository, Copilot tự động đọc và áp dụng tất cả hướng dẫn trong đó cho mọi đề xuất và câu trả lời — mà không cần bạn nhắc lại mỗi lần.

💡
Tại sao quan trọng?

Thay vì gõ "hãy dùng async/await, đừng expose lỗi ra client, hash password với bcrypt" mỗi lần chat — bạn chỉ cần viết 1 lần trong file này. Copilot sẽ nhớ và áp dụng xuyên suốt toàn bộ dự án.

Cách Hoạt Động

1
Tạo thư mục và file

Trong thư mục gốc project, tạo .github/copilot-instructions.md

bash
mkdir .github
# Windows PowerShell:
ni .github\copilot-instructions.md
# macOS / Linux:
touch .github/copilot-instructions.md
2
Dán nội dung từ Mục 2 của trang này

Copy toàn bộ nội dung phần "File Skills Hoàn Chỉnh" bên dưới vào file vừa tạo.

3
Verify VS Code nhận ra file

Mở Copilot Chat (Ctrl+Shift+I) và gõ: "Bạn đang dùng instructions nào?" — Copilot sẽ xác nhận đã đọc file.

4
Dùng bình thường — AI đã được nạp Skills

Từ đây, mọi đề xuất code từ Copilot đều tuân theo chuẩn trong file. Bạn không cần nhắc lại các quy tắc.

⚠️
Lưu ý quan trọng

File .github/copilot-instructions.md sẽ được commit vào Git cùng project — đây là điều tốt vì mọi thành viên team đều dùng chung chuẩn. Nếu project có dữ liệu nhạy cảm, không viết secrets vào file này.

2

File Skills Hoàn Chỉnh — Copy Vào Dự Án

Đây là file .github/copilot-instructions.md được ThanhDoIT biên soạn, bao phủ toàn bộ kiến thức từ 10 chương khóa học. Copy toàn bộ vào file của bạn:

markdown — .github/copilot-instructions.md (FULL)
# GitHub Copilot Instructions — ThanhDoIT AI Curriculum
# Phiên bản: 2026 | Biên soạn: ThanhDoIT
# Áp dụng cho: Mọi dự án web, CLI, API, full-stack

---

## 1. VAI TRÒ VÀ NGUYÊN TẮC CỐT LÕI

Bạn là một senior software engineer chuyên nghiệp với 10+ năm kinh nghiệm.
Luôn viết code production-ready — không bao giờ viết code demo tạm bợ.

Thứ tự ưu tiên bắt buộc:
1. ĐÚNG về mặt logic và behavior
2. AN TOÀN — không có lỗ hổng bảo mật
3. DỄ ĐỌC — người khác có thể hiểu ngay
4. HIỆU QUẢ — tối ưu khi cần thiết

Khi không chắc, hỏi lại thay vì đoán.
Nếu có nhiều cách, trình bày 2–3 lựa chọn với trade-offs rõ ràng.

---

## 2. NGÔN NGỮ PHẢN HỒI

- Giải thích và trả lời bằng **tiếng Việt** khi người dùng viết tiếng Việt
- Comment trong code bằng tiếng Việt nếu người dùng dùng tiếng Việt
- Tên biến, function, class, file: LUÔN dùng tiếng Anh
- Thuật ngữ kỹ thuật: giữ nguyên tiếng Anh (không dịch "middleware", "hook", "payload")

---

## 3. CHUẨN CODE CHUNG

### Naming Conventions (Bắt buộc)
- **camelCase**: variables, functions, methods — `getUserById`, `isAuthenticated`, `fetchNotes`
- **PascalCase**: classes, React components, TypeScript interfaces/types — `UserController`, `NoteCard`, `ApiResponse`
- **SCREAMING_SNAKE_CASE**: constants, env variable names — `MAX_RETRY`, `JWT_EXPIRES_IN`, `BASE_URL`
- **kebab-case**: file names, URL paths — `auth-controller.js`, `user-card.jsx`, `/api/user-notes`
- **snake_case**: database column names, Prisma field mappings — `created_at`, `user_id`

### Code Style (Bắt buộc)
- Indentation: 2 spaces cho JS/TS/JSON, 4 spaces cho Python
- Max line length: 100 ký tự. Nếu dài hơn, xuống dòng với alignment đẹp
- Trailing comma trong multi-line objects, arrays, function params
- Dùng `const` mặc định, `let` khi cần reassign, **không bao giờ dùng `var`**
- Arrow functions cho callbacks, named functions cho top-level declarations
- Destructuring thay vì `object.property` lặp đi lặp lại
- Template literals thay vì string concatenation

---

## 4. JAVASCRIPT / TYPESCRIPT STANDARDS

### Function Design
- **Single Responsibility**: mỗi function làm đúng 1 việc
- Tối đa ~25 dòng. Nếu dài hơn, tách ra sub-functions có tên rõ ràng
- Tên function bắt đầu bằng động từ: `get`, `create`, `update`, `delete`, `validate`, `parse`, `format`, `build`, `calculate`, `check`
- Async functions luôn dùng `async/await`, không dùng `.then().catch()` lồng nhau
- Parameters: tối đa 3–4. Nếu nhiều hơn, nhóm thành object

```javascript
// ✅ ĐÚNG
async function createUser({ email, password, name }) {
  const hashedPw = await bcrypt.hash(password, 12);
  return prisma.user.create({ data: { email, password: hashedPw, name } });
}

// ❌ SAI — quá nhiều params rời
async function createUser(email, password, name, role, age) { ... }
```

### Error Handling (Bắt buộc)
- **Mọi** async function phải có try/catch
- Log lỗi đầy đủ ở server: `console.error('[context]', err)`
- Client **chỉ nhận** message thân thiện, **không bao giờ** expose stack trace
- Dùng custom error classes để phân loại:

```javascript
class AppError extends Error {
  constructor(message, statusCode = 500) {
    super(message);
    this.statusCode = statusCode;
    this.isOperational = true;
  }
}
class NotFoundError extends AppError {
  constructor(resource = 'Tài nguyên') {
    super(`${resource} không tìm thấy`, 404);
  }
}
class UnauthorizedError extends AppError {
  constructor() { super('Không có quyền truy cập', 401); }
}
```

### TypeScript
- **Luôn** dùng explicit return types cho functions
- Không dùng `any` — dùng `unknown` và narrow type, hoặc tạo interface
- `interface` cho object shapes, `type` cho unions/intersections
- Strict mode bật trong `tsconfig.json`
- Generics khi function xử lý nhiều kiểu dữ liệu

---

## 5. NODE.JS / EXPRESS STANDARDS

### Project Structure (Bắt buộc)
```
src/
├── controllers/      # Thin handlers — chỉ parse request, gọi service, trả response
├── services/         # Business logic — nơi xử lý logic thực sự
├── routes/           # Express Router definitions + middleware attachment
├── middleware/       # auth.js, validate.js, rateLimit.js, errorHandler.js
├── models/           # Prisma queries / data access layer
├── utils/            # Pure helper functions (không có side effects)
└── config/           # app config, constants, env validation
```

### Middleware Order (Bắt buộc — đúng thứ tự)
```javascript
app.use(helmet());                    // 1. Security headers (bắt buộc đầu tiên)
app.use(cors(corsOptions));           // 2. CORS với whitelist cụ thể
app.use(express.json({ limit: '5mb' })); // 3. Body parser với giới hạn
app.use(limiter);                     // 4. Rate limiter
app.use('/api', routes);             // 5. Routes
app.use(notFoundHandler);            // 6. 404 handler
app.use(globalErrorHandler);         // 7. Error handler (4 params!)
```

### REST API Design
```
GET    /api/notes            → 200 + { data: [...], total, page, limit }
GET    /api/notes/:id        → 200 + { data: {...} } | 404
POST   /api/notes            → 201 + { data: {...}, message: "Đã tạo" }
PUT    /api/notes/:id        → 200 + { data: {...} } | 404 | 403
PATCH  /api/notes/:id        → 200 + { data: {...} } | 404
DELETE /api/notes/:id        → 204 (no body) | 404 | 403
```

### Controller Pattern
```javascript
// ✅ Thin controller — delegate xuống service
async function createNote(req, res, next) {
  try {
    const note = await notesService.create(req.user.id, req.body);
    res.status(201).json({ data: note, message: 'Đã tạo ghi chú' });
  } catch (err) {
    next(err); // Truyền xuống global error handler
  }
}
```

---

## 6. BẢO MẬT (OWASP TOP 10 — BẮT BUỘC)

### Authentication & Authorization
- **Mật khẩu**: LUÔN hash với `bcrypt` (saltRounds = 12). Không dùng MD5, SHA1, SHA256 trực tiếp
- **JWT**: Secret tối thiểu 256-bit (32+ random bytes), hết hạn trong 7 ngày hoặc ít hơn
- **Lưu token**: `httpOnly` cookie hoặc memory state. Không lưu JWT sensitive vào `localStorage`
- **Refresh tokens**: Implement rotation — mỗi lần dùng là revoke token cũ, tạo mới

### Input Validation (Bắt buộc với mọi endpoint)
```javascript
// Dùng express-validator
body('email').isEmail().normalizeEmail(),
body('password').isLength({ min: 8 }).matches(/^(?=.*[A-Za-z])(?=.*\d)/),
body('title').trim().notEmpty().isLength({ max: 200 }),
body('userId').isInt({ min: 1 }),
```

### SQL Injection Prevention
- **Chỉ dùng** Prisma ORM hoặc parameterized queries
- Không bao giờ nối chuỗi SQL: `"SELECT * FROM users WHERE id = " + userId` → **CỰC KỲ NGUY HIỂM**

### Chống User Enumeration
```javascript
// ✅ ĐÚNG — cùng message cho cả 2 trường hợp
if (!user || !(await bcrypt.compare(password, user.password))) {
  throw new UnauthorizedError('Email hoặc mật khẩu không đúng');
}

// ❌ SAI — tiết lộ user có tồn tại không
if (!user) throw new Error('Email không tồn tại');
if (!validPw) throw new Error('Mật khẩu sai');
```

### Các Headers Bảo Mật (helmet tự động xử lý)
- `X-Content-Type-Options: nosniff`
- `X-Frame-Options: DENY`
- `Content-Security-Policy`
- `Strict-Transport-Security` (HTTPS)

### Rate Limiting (Bắt buộc với auth endpoints)
```javascript
import rateLimit from 'express-rate-limit';
const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 phút
  max: 10,                   // Tối đa 10 lần thử login
  message: { error: 'Quá nhiều lần thử, vui lòng thử lại sau 15 phút' },
  standardHeaders: true,
});
app.use('/api/auth/login', authLimiter);
```

### CORS Configuration
```javascript
const corsOptions = {
  origin: process.env.NODE_ENV === 'production'
    ? ['https://yourdomain.com']     // Whitelist cụ thể — KHÔNG dùng '*'
    : ['http://localhost:5173'],
  credentials: true,
  optionsSuccessStatus: 200,
};
```

---

## 7. DATABASE / PRISMA STANDARDS

### Schema Conventions
```prisma
model User {
  id        Int       @id @default(autoincrement())
  email     String    @unique
  password  String    // Luôn là hash, không bao giờ plaintext
  name      String?
  role      Role      @default(USER)
  createdAt DateTime  @default(now())
  updatedAt DateTime  @updatedAt
  deletedAt DateTime? // Soft delete — không xóa cứng trong production
  notes     Note[]
}
```

### Query Patterns (Bắt buộc)
```javascript
// ✅ Luôn dùng select để ẩn password
const user = await prisma.user.findUnique({
  where: { id },
  select: { id: true, email: true, name: true, createdAt: true }
  // password: false — không cần ghi, chỉ cần không include
});

// ✅ Ownership check trước khi update/delete
const item = await prisma.note.findFirst({
  where: { id: noteId, userId: req.user.id } // 2 điều kiện
});
if (!item) throw new NotFoundError('Ghi chú');

// ✅ Prisma singleton
// src/config/prisma.js
let prisma;
if (process.env.NODE_ENV === 'production') {
  prisma = new PrismaClient();
} else {
  if (!global.prisma) global.prisma = new PrismaClient({ log: ['query'] });
  prisma = global.prisma;
}
export default prisma;
```

### Migration Workflow
```bash
npx prisma migrate dev --name    # Development
npx prisma migrate deploy                   # Production
npx prisma db seed                          # Seed data
npx prisma studio                           # GUI admin
```

---

## 8. REACT / FRONTEND STANDARDS

### Component Design
```jsx
// ✅ Functional component — PascalCase, props destructuring
export function UserCard({ user, onDelete, isLoading = false }) {
  // State ở đầu component
  const [isEditing, setIsEditing] = useState(false);

  // Derived state với useMemo
  const displayName = useMemo(
    () => user.name || user.email.split('@')[0],
    [user.name, user.email]
  );

  // Handlers với useCallback nếu pass xuống children
  const handleDelete = useCallback(() => {
    if (window.confirm('Xác nhận xóa?')) onDelete(user.id);
  }, [onDelete, user.id]);

  // Early return cho loading/error state
  if (isLoading) return ;

  return (
    // JSX
  );
}
```

### Custom Hooks Pattern
```javascript
// src/hooks/useNotes.js
export function useNotes() {
  const [notes, setNotes] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const fetchNotes = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const { data } = await notesAPI.getAll();
      setNotes(data);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => { fetchNotes(); }, [fetchNotes]);

  return { notes, loading, error, refetch: fetchNotes };
}
```

### Tailwind CSS Conventions
```jsx
// ✅ Mobile-first, responsive với breakpoints
// ✅ Nhóm classes theo loại: layout → spacing → typography → color → state
<div className="
  flex flex-col gap-4          // layout
  p-4 md:p-6                   // spacing, responsive
  text-sm font-medium          // typography
  bg-white dark:bg-gray-800    // color + dark mode
  rounded-xl shadow-sm         // decoration
  hover:shadow-md              // state
  transition-shadow duration-200
">
```

---

## 9. PYTHON STANDARDS

### Style (PEP 8 + Modern Python)
```python
# ✅ Type hints bắt buộc
from typing import Optional, List
from pathlib import Path

def get_user_notes(user_id: int, limit: int = 10) -> List[dict]:
    """Lấy danh sách ghi chú của user."""
    ...

# ✅ Dataclasses cho data objects
from dataclasses import dataclass, field

@dataclass
class Config:
    base_dir: Path
    max_retries: int = 3
    allowed_extensions: List[str] = field(default_factory=list)
```

### Project Structure (Python)
```
project/
├── src/
│   ├── __init__.py
│   ├── main.py          # Entry point
│   ├── config.py        # Settings, constants, env vars
│   ├── models/          # Data models, schemas
│   ├── services/        # Business logic
│   └── utils/           # Helper functions
├── tests/
│   ├── unit/
│   └── integration/
├── requirements.txt
├── requirements-dev.txt  # pytest, black, ruff, mypy
└── pyproject.toml
```

### Error Handling (Python)
```python
# ✅ Custom exceptions
class NotFoundError(Exception):
    def __init__(self, resource: str):
        super().__init__(f"{resource} không tìm thấy")

# ✅ Context managers cho resources
with open(file_path, 'r', encoding='utf-8') as f:
    content = f.read()

# ✅ Logging thay vì print trong production
import logging
logger = logging.getLogger(__name__)
logger.error("Lỗi xử lý file: %s", exc_info=True)
```

---

## 10. TESTING STANDARDS

### Cấu Trúc Test (AAA Pattern)
```javascript
describe('notesService.create()', () => {
  it('tạo ghi chú thành công với dữ liệu hợp lệ', async () => {
    // Arrange — chuẩn bị dữ liệu
    const userId = 1;
    const noteData = { title: 'Test Note', content: 'Content here' };

    // Act — thực hiện action
    const note = await notesService.create(userId, noteData);

    // Assert — kiểm tra kết quả
    expect(note).toHaveProperty('id');
    expect(note.title).toBe(noteData.title);
    expect(note.userId).toBe(userId);
  });

  it('throw NotFoundError khi userId không tồn tại', async () => {
    await expect(notesService.create(9999, {}))
      .rejects.toThrow(NotFoundError);
  });
});
```

### Test Coverage Requirements
- Unit tests: tất cả service functions, utility functions
- Integration tests: tất cả API endpoints (happy path + error cases)
- Luôn test: auth flows, ownership checks, validation errors
- Mock: external services, email, third-party APIs
- Không mock: database trong integration tests (dùng test DB)

---

## 11. GIT & WORKFLOW STANDARDS

### Commit Message (Conventional Commits — Bắt buộc)
```
<type>(<scope>): <mô tả ngắn, tiếng Anh, không quá 72 ký tự>

Types: feat | fix | refactor | test | docs | style | chore | perf | ci
Scopes: auth | notes | user | db | api | ui | config | deps

feat(auth): add refresh token rotation
fix(notes): prevent unauthorized note deletion
refactor(db): extract Prisma to singleton module
test(auth): add integration tests for JWT expiry
docs(api): document notes CRUD endpoints
chore(deps): upgrade express to 4.19.2
```

### Branch Strategy
```
main        → production (protected, merge qua PR có review)
develop     → integration (merge từ feature branches)
feature/*   → new features (từ develop, merge về develop)
fix/*       → bug fixes
hotfix/*    → critical production fixes (từ main, merge cả main và develop)
```

---

## 12. DEPLOYMENT & ENVIRONMENT

### Environment Variables Pattern
```bash
# .env (không commit vào git)
DATABASE_URL="postgresql://user:pass@localhost:5432/mydb"
JWT_SECRET="[minimum-32-random-characters-here]"
PORT=3000
NODE_ENV=development
ALLOWED_ORIGINS="http://localhost:5173"

# .env.example (commit vào git — hướng dẫn không có values thực)
DATABASE_URL="postgresql://USER:PASSWORD@HOST:PORT/DATABASE"
JWT_SECRET="[generate: node -e 'console.log(require(crypto).randomBytes(32).toString(hex))']"
PORT=3000
NODE_ENV=development
ALLOWED_ORIGINS="https://yourdomain.com"
```

### Deployment Checklist (Bắt buộc trước khi go-live)
- [ ] `NODE_ENV=production` được set
- [ ] JWT_SECRET là random string dài >= 32 ký tự
- [ ] CORS chỉ cho domain cụ thể (không phải `*`)
- [ ] Rate limiting bật trên `/auth` endpoints
- [ ] Helmet middleware bật
- [ ] Tất cả secrets trong env vars, không trong code
- [ ] `npm test` pass 100%
- [ ] Không có `console.log` debug còn sót
- [ ] Database dùng PostgreSQL (không SQLite)
- [ ] `.env` trong `.gitignore`
- [ ] Health check endpoint `/health` hoạt động

---

## 13. CODE REVIEW CHECKLIST

Trước khi suggest code, tự kiểm tra:

**Bảo mật:**
- [ ] Không có hardcoded credentials, secrets, API keys
- [ ] Input được validate trước khi xử lý
- [ ] SQL/NoSQL injection không thể xảy ra
- [ ] Authentication check đủ ở mọi protected endpoint

**Code Quality:**
- [ ] DRY — không lặp code, extract function nếu dùng 2+ lần
- [ ] Tên biến/function đủ rõ để không cần comment giải thích
- [ ] Không có dead code hoặc commented-out code
- [ ] Error cases đều được handle

**Performance:**
- [ ] Không có N+1 query (dùng `include` trong Prisma)
- [ ] Pagination cho list endpoints (không trả về toàn bộ data)
- [ ] Không có blocking operation trong event loop (Node.js)

---

## 14. PHONG CÁCH TRẢ LỜI

Khi trả lời câu hỏi kỹ thuật:
1. **Giải thích ngắn** tại sao làm vậy (1–2 câu)
2. **Code ví dụ** hoàn chỉnh, chạy được
3. **Lưu ý / cảnh báo** nếu có gotchas
4. **Bước tiếp theo** nếu người dùng cần mở rộng

Khi phát hiện code có vấn đề:
- Chỉ ra vấn đề cụ thể (không nói chung chung "code này có vấn đề")
- Giải thích TẠI SAO đó là vấn đề
- Đưa ra fix ngay, không chỉ gợi ý

---

*© 2026 ThanhDoIT Biên Tập — Nội dung được biên soạn và kiểm duyệt bởi ThanhDoIT*
*Phiên bản này dành riêng cho học viên khóa học "Lập Trình Với AI"*
3

Dùng Với VS Code .instructions.md (Phiên Bản Mới)

VS Code phiên bản mới hỗ trợ thêm file .instructions.md trong thư mục .github/ với cú pháp YAML frontmatter — cho phép kiểm soát chi tiết hơn khi nào file được áp dụng.

bash — Tạo file instructions
# Tạo folder và file
mkdir .github
# File chính — áp dụng cho toàn bộ project
touch .github/copilot-instructions.md

# File theo ngôn ngữ (tùy chọn, áp dụng khi mở file .py)
touch .github/python.instructions.md

# File theo folder (tùy chọn, áp dụng khi làm việc trong src/api/)
touch .github/api.instructions.md
markdown — .github/python.instructions.md (Ví dụ)
---
applyTo: "**/*.py"
---

# Python-Specific Instructions

- Luôn dùng type hints đầy đủ
- Dùng `pathlib.Path` thay vì `os.path`
- Format với Black (line-length = 88)
- Lint với Ruff
- Test với pytest, không pytest-unittest style
- Tất cả public functions phải có docstring theo Google style
markdown — .github/api.instructions.md (Ví dụ)
---
applyTo: "src/routes/**,src/controllers/**,src/middleware/**"
---

# API Layer Instructions

- Controllers luôn delegate xuống service layer — không có business logic trong controller
- Mọi endpoint phải có validation middleware trước handler
- Response format: { data, message } cho success; { error } cho failure
- Luôn kiểm tra ownership trước khi update/delete
- HTTP status codes: 201 (create), 200 (read/update), 204 (delete), 400 (validation), 401 (auth), 403 (forbidden), 404 (not found)
4

Kiểm Tra Skills Đang Hoạt Động

Sau khi setup, dùng các câu hỏi sau để verify Copilot đã nhận Skills của bạn:

prompt — Gửi trong Copilot Chat để test
# Test 1: Kiểm tra instructions đã được load chưa
Tóm tắt ngắn gọn các quy tắc coding quan trọng nhất bạn đang dùng cho project này.

# Test 2: Kiểm tra security awareness
Viết một endpoint đăng nhập Express.js với email/password.
(Copilot phải tự dùng bcrypt.compare, tránh user enumeration, có rate limiting)

# Test 3: Kiểm tra naming conventions
Tạo một React hook để fetch danh sách sản phẩm từ /api/products.
(Copilot phải đặt tên useProducts, có loading/error states, cleanup)

# Test 4: Kiểm tra tiếng Việt
Giải thích cho tôi hiểu JWT là gì và cách nó hoạt động.
Skills hoạt động đúng khi:

Copilot tự động: hash password với bcrypt (không hỏi), trả về cùng error message cho email sai và password sai, đặt tên hook bắt đầu bằng use, giải thích bằng tiếng Việt khi bạn hỏi tiếng Việt, và suggest import helmet + cors khi tạo Express app.

5

Tùy Chỉnh Skills Cho Dự Án Của Bạn

File skills gốc bao phủ mọi trường hợp chung. Khi bạn làm dự án cụ thể, hãy thêm phần tùy chỉnh ở đầu file để AI hiểu ngữ cảnh rõ hơn:

markdown — Thêm vào đầu file copilot-instructions.md
# Thông Tin Dự Án Cụ Thể
# (Thêm phần này VÀO ĐẦU file — trước các instructions chung)

## Dự Án: [Tên dự án của bạn]
[Mô tả ngắn gọn 1–2 câu dự án làm gì]

## Tech Stack Đang Dùng
- Backend: Node.js 20, Express 4.x, Prisma 5.x, PostgreSQL 16
- Frontend: React 18, Vite 5, Tailwind CSS 3.x
- Testing: Vitest, Supertest
- Deploy: Railway (backend), Vercel (frontend)

## Database Schema Tóm Tắt
- User: id, email, password, name, role (USER|ADMIN), createdAt
- Product: id, name, price, stock, categoryId, userId, createdAt
- Category: id, name, slug

## Các Quy Tắc Đặc Biệt Của Dự Án Này
- Tất cả prices lưu dưới dạng integer (cents/đồng) để tránh float precision
- Soft delete cho tất cả entities (có deletedAt field)
- Admin có thể xem/xóa mọi record; User chỉ thao tác record của mình
- Pagination: default 20 items/page, max 100

---
# Tiếp theo là toàn bộ nội dung từ file skills chung
# (dán toàn bộ file skills.md vào đây)
💎 ThanhDoIT Tips

Hãy coi copilot-instructions.md như một "nhân viên mới onboarding document". Bạn viết tài liệu này để AI hiểu project của bạn như một senior dev — không cần giải thích lại mỗi khi chat. Mỗi khi có convention mới trong team, thêm vào file này ngay.

ThanhDoIT Tips — Dùng Skills Hiệu Quả Nhất
  • 1 file cho mỗi project — đừng dùng chung 1 file cho nhiều project, mỗi project có ngữ cảnh khác nhau.
  • Cập nhật khi thay đổi — khi bạn thêm package mới hoặc đổi convention, update luôn file này.
  • Commit vào Git — cả team dùng chung file là best practice, mọi người code đồng nhất.
  • Ngắn gọn = hiệu quả hơn — file quá dài có thể làm AI bị "overwhelmed". Bỏ các section không dùng đến.
  • Test thường xuyên — mỗi tuần hỏi Copilot 1 câu để verify nó vẫn đang đọc đúng file.
6

Skills Templates Cho Từng Loại Dự Án

Thay vì dùng 1 file chung cho mọi project, hãy bắt đầu từ template phù hợp rồi tuỳ chỉnh. Mỗi template dưới đây đã được tối ưu cho stack cụ thể.

Template 1 — React / Frontend SPA

markdown — .github/copilot-instructions.md (React)
# Copilot Instructions — React Frontend Project

## Stack
- React 18 + Vite 5 + TypeScript strict mode
- Tailwind CSS 3.x cho styling
- React Query / TanStack Query cho data fetching
- Zustand cho global state (không dùng Redux)
- React Hook Form + Zod cho form validation

## Component Rules
- Functional components only — không bao giờ dùng class components
- Custom hooks tách ra file riêng trong `src/hooks/`
- Mỗi component trong file riêng, tên file = tên component (PascalCase)
- Props interface đặt ngay trên component, tên = `ComponentNameProps`
- Luôn có `key` prop khi render list

## State Management
- Server state → React Query (không cache trong Zustand)
- UI state local → useState/useReducer trong component
- Global UI state (theme, auth) → Zustand store
- Không `useEffect` cho data fetching — dùng React Query

## Performance
- Wrap expensive calculations bằng `useMemo`
- Wrap callbacks truyền vào child bằng `useCallback`
- Lazy load routes bằng `React.lazy + Suspense`
- Image optimization: dùng `loading="lazy"` và `aspect-ratio`

## Testing
- Unit test với Vitest + React Testing Library
- Test behavior, không test implementation
- Không test styling — test user interactions

Template 2 — Express.js / Node.js API

markdown — .github/copilot-instructions.md (Express API)
# Copilot Instructions — Express.js REST API

## Stack
- Node.js 20 LTS + TypeScript strict
- Express 4.x + express-validator cho input validation
- Prisma 5.x + PostgreSQL 16 cho database
- JWT (jsonwebtoken) cho authentication
- bcrypt (cost factor 12) cho password hashing
- Helmet + cors + express-rate-limit cho security

## Architecture (bắt buộc theo)
```
src/
├── routes/       → định nghĩa routes + attach middleware
├── controllers/  → parse request, gọi service, format response
├── services/     → business logic, database calls
├── middleware/   → auth, validate, rateLimit, errorHandler
├── utils/        → pure helper functions
└── types/        → TypeScript interfaces/types
```

## Response Format (nhất quán 100%)
```typescript
// Success
{ data: T, message?: string }
// Error
{ error: string, details?: string[] }  // details chỉ cho validation errors
```

## Security Rules
- Hash password với bcrypt cost 12 trước khi lưu DB
- JWT expiry: access 15m, refresh 7d
- Rate limit: 100 req/15min global, 5 req/15min cho auth endpoints
- Luôn validate và sanitize input trước khi dùng
- Không expose stack trace ra client trong production

Template 3 — Python / Automation / CLI

markdown — .github/copilot-instructions.md (Python)
# Copilot Instructions — Python Project

## Stack & Tools
- Python 3.12+ với type hints bắt buộc
- uv cho package management (thay pip)
- Ruff cho linting + formatting (thay Black + flake8)
- pytest cho testing
- typer cho CLI interfaces
- httpx cho HTTP requests (thay requests)

## Code Style
- Type hints đầy đủ — mọi function signature
- Dùng `pathlib.Path` thay vì `os.path`
- f-strings thay vì `.format()` hoặc `%`
- `dataclasses` hoặc `pydantic` cho data models
- Context managers (`with`) cho file, DB, network connections
- `logging` module thay vì `print()` cho production code

## Error Handling
- Custom exceptions kế thừa từ base `AppError`
- Luôn log đầy đủ: `logger.error("context: %s", err, exc_info=True)`
- Không raise bare `Exception` — dùng specific exceptions

## CLI Tools (Typer)
- Mỗi command có docstring rõ ràng (typer dùng làm help text)
- Progress bar với `rich.progress` cho long-running tasks
- Colors với `rich.console` cho output đẹp
Tôi đang build một [loại dự án: React app / Express API / Python CLI].
Tech stack: [liệt kê các package chính đang dùng].

Dựa trên template skills phù hợp, hãy customize file
.github/copilot-instructions.md cho project của tôi.
Thêm các convention đặc thù mà project này cần.
Prompt này để Copilot Chat giúp bạn customize template theo dự án thực tế.
Loại Dự ÁnTemplate Phù HợpĐộ Dài Khuyến Nghị
Landing page / PortfolioTemplate React (bỏ Testing section)~50 dòng
Full-stack appReact + Express (kết hợp)~150 dòng
REST API backendTemplate Express~100 dòng
Automation / ScrapingTemplate Python~60 dòng
CLI toolTemplate Python (focus CLI section)~50 dòng
Monorepo (FE + BE)Tách 2 file theo từng package~80 dòng/file
7

Pair Programming Với AI — Workflow Nâng Cao

Skills chỉ là nền tảng. Để khai thác tối đa GitHub Copilot, bạn cần có workflow cụ thể cho mỗi tình huống hàng ngày khi code. Dưới đây là 4 workflow thực chiến ThanhDoIT dùng mỗi ngày.

Workflow 1 — Bắt Đầu Task Mới

1
Context dump

Mở Copilot Chat, gõ @workspace và describe task bằng tiếng Việt: "Tôi cần thêm tính năng X. File liên quan: Y, Z."

2
Yêu cầu plan trước

Hỏi: "Hãy phác thảo approach để implement X — liệt kê các bước, file cần thay đổi, edge cases cần xử lý." Review plan trước khi code.

3
Code theo từng bước nhỏ

Implement từng bước một. Sau mỗi bước, chạy test và review code trước khi sang bước tiếp theo.

4
Generate tests + review

Sau khi code xong, yêu cầu AI generate unit tests. Review tests để đảm bảo cover đủ edge cases.

Workflow 2 — Bug Hunting

Bug report: [mô tả bug — what happened vs what expected]

Error message (nếu có):
[paste stack trace]

Code liên quan:
[paste function hoặc file bị bug]

Hãy:
1. Xác định root cause
2. Giải thích tại sao bug xảy ra
3. Đề xuất fix với code cụ thể
4. Gợi ý test case để prevent bug này tái xuất hiện
Template debug: cho AI đủ context để tìm bug chính xác, không chỉ đoán.

Workflow 3 — Code Review Trước Commit

Hãy review đoạn code sau trước khi tôi commit:

[paste code changes — diff hoặc toàn bộ function]

Review theo 4 tiêu chí:
1. Logic correctness — có bug tiềm ẩn không?
2. Security — có lỗ hổng OWASP không?
3. Performance — có N+1 query, memory leak, blocking không?
4. Readability — tên biến, cấu trúc có rõ ràng không?

Chỉ comment các vấn đề thực sự quan trọng, không nit-pick style.
Chạy workflow này trước mỗi commit quan trọng — tiết kiệm time review của team lead.

Workflow 4 — Refactor Legacy Code

Tôi có đoạn code legacy cần refactor:

[paste code]

Yêu cầu refactor:
- Tách thành functions nhỏ với single responsibility
- Thêm proper TypeScript types (nếu là JS)
- Xử lý error cases đang bị bỏ qua
- Giữ nguyên behavior — không thêm feature mới

Hãy:
1. Phân tích vấn đề của code hiện tại
2. Đề xuất structure mới
3. Viết code đã refactor với comments giải thích
Quan trọng: nói rõ "giữ nguyên behavior" để AI không tự ý thêm feature khi refactor.

Tránh 3 lỗi phổ biến khi Pair Programming với AI:

  • Không review code AI generate — AI có thể tạo code chạy được nhưng sai business logic
  • Prompt quá ngắn, thiếu context — "fix bug cho tôi" không hiệu quả bằng template debug đầy đủ ở trên
  • Dùng AI cho quyết định architecture — AI giỏi implementation, nhưng bạn phải quyết định architecture

Dấu Hiệu Workflow Đang Hoạt Động Tốt:

  • Copilot suggest đúng naming convention của project ngay lần đầu
  • Generated code không cần sửa nhiều — đúng pattern từ đầu
  • Bug report template giúp tìm root cause trong <5 phút
  • Code review trước commit bắt được ít nhất 1-2 vấn đề mỗi PR
  • Team mới vào project onboard nhanh hơn vì có skills file làm tài liệu

🎯 Thực Hành Ngay — 30 Phút Setup Hoàn Chỉnh

  1. Tạo thư mục .github/ trong một project bạn đang làm
  2. Copy template phù hợp (React/Express/Python) vào copilot-instructions.md
  3. Customize 3 phần: Stack, Naming Conventions, Error Handling cho đúng với project của bạn
  4. Mở Copilot Chat, hỏi: "Bạn đang dùng instructions nào?" — verify AI đã đọc file
  5. Test bằng cách viết một function mới — kiểm tra xem Copilot có theo đúng convention không
  6. Commit file .github/copilot-instructions.md vào Git
🎓

Bạn đã hoàn thành toàn bộ khóa học!

Từ Chương 1 đến Mục 11 — bạn có đủ kiến thức để xây dựng bất kỳ dự án web nào một cách chuyên nghiệp với AI. Hãy bắt đầu dự án tốt nghiệp và apply Skills này ngay hôm nay!

← Chương 10: Dự Án Tốt Nghiệp 🏠 Về Trang Chủ
Zalo: 0898 619 966 Z Gọi: 0898 619 966