diff --git a/.cursor/skills/api-design/SKILL.md b/.cursor/skills/api-design/SKILL.md index 22230e1d..d7eb5933 100644 --- a/.cursor/skills/api-design/SKILL.md +++ b/.cursor/skills/api-design/SKILL.md @@ -485,6 +485,50 @@ export function errorHandler( - Document error responses - Version your documentation +## Common Mistakes + +1. **Using Verbs in URLs**: Non-RESTful endpoints + ``` + # ❌ BAD: Verb in URL + POST /api/v1/createUser + GET /api/v1/getUserById/123 + + # ✅ GOOD: RESTful resources + POST /api/v1/users + GET /api/v1/users/123 + ``` + +2. **Inconsistent Response Format**: Different structures for different endpoints + ```typescript + // ❌ BAD: Inconsistent + res.json({ user: data }); // One endpoint + res.json({ result: data }); // Another endpoint + + // ✅ GOOD: Consistent structure + res.json({ success: true, data }); // All endpoints + ``` + +3. **Wrong HTTP Status Codes**: Using 200 for errors + ```typescript + // ❌ BAD: 200 with error + res.status(200).json({ error: 'Not found' }); + + // ✅ GOOD: Appropriate status + res.status(404).json({ success: false, error: { code: 'NOT_FOUND', message: 'User not found' } }); + ``` + +4. **Missing Pagination**: Returning all records + ```typescript + // ❌ BAD: Returns everything + const users = await prisma.user.findMany(); + + // ✅ GOOD: Paginated + const users = await prisma.user.findMany({ + skip: (page - 1) * limit, + take: limit, + }); + ``` + ## Quick Reference | HTTP Method | Action | Idempotent | Status Codes | diff --git a/.cursor/skills/project-rules/SKILL.md b/.cursor/skills/project-rules/SKILL.md index 8398c685..3e1430db 100644 --- a/.cursor/skills/project-rules/SKILL.md +++ b/.cursor/skills/project-rules/SKILL.md @@ -248,6 +248,51 @@ docker-compose ps docker-compose up -d --build ``` +## Common Mistakes + +1. **Wrong Directory Structure**: Placing files in wrong locations + ``` + # ❌ BAD: Controllers outside modules + src/controllers/user.controller.ts + + # ✅ GOOD: Controllers inside modules + src/modules/user/user.controller.ts + ``` + +2. **Inconsistent Naming**: Mixing naming conventions + ```typescript + // ❌ BAD: Mixed naming + UserService.ts + user_repository.ts + userController.ts + + // ✅ GOOD: Consistent kebab-case + user.service.ts + user.repository.ts + user.controller.ts + ``` + +3. **Wrong Response Format**: Not following API response standard + ```typescript + // ❌ BAD: Inconsistent format + res.json({ user: data }); + res.json({ error: "Not found" }); + + // ✅ GOOD: Standard format + res.json({ success: true, data: user }); + res.json({ success: false, error: { code: 'NOT_FOUND', message: 'User not found' } }); + ``` + +4. **Missing Bilingual Comments**: Only one language + ```typescript + // ❌ BAD: English only + // Initialize database + + // ✅ GOOD: Bilingual + // EN: Initialize database connection + // VI: Khởi tạo kết nối database + ``` + ## Quick Reference | Category | Pattern/Standard | diff --git a/.cursor/skills/security/SKILL.md b/.cursor/skills/security/SKILL.md index df20b99b..47e74dff 100644 --- a/.cursor/skills/security/SKILL.md +++ b/.cursor/skills/security/SKILL.md @@ -789,6 +789,47 @@ export class SecurityIncidentService { } ``` +## Common Mistakes + +1. **Weak Password Hashing**: Using insufficient bcrypt rounds + ```typescript + // ❌ BAD: Low cost factor + const hash = await bcrypt.hash(password, 8); + + // ✅ GOOD: Use cost 12 + const hash = await bcrypt.hash(password, 12); + ``` + +2. **Storing Secrets in Code**: Hardcoded credentials + ```typescript + // ❌ BAD: Hardcoded secret + const JWT_SECRET = "my-secret-key"; + + // ✅ GOOD: Use environment variable + const JWT_SECRET = process.env.JWT_SECRET; + if (!JWT_SECRET) throw new Error('JWT_SECRET required'); + ``` + +3. **Missing Input Validation**: Not validating user input + ```typescript + // ❌ BAD: No validation + const user = await prisma.user.findUnique({ where: { id: req.params.id } }); + + // ✅ GOOD: Validate input + const schema = z.object({ id: z.string().cuid() }); + const { id } = schema.parse(req.params); + const user = await prisma.user.findUnique({ where: { id } }); + ``` + +4. **Logging Sensitive Data**: Exposing secrets in logs + ```typescript + // ❌ BAD: Logging password + logger.info('User login', { email, password }); + + // ✅ GOOD: Sanitize before logging + logger.info('User login', { email, password: '[REDACTED]' }); + ``` + ## Quick Reference | Security Area | Implementation | diff --git a/.cursor/skills/testing-patterns/SKILL.md b/.cursor/skills/testing-patterns/SKILL.md index 7316954e..5ea7e3a5 100644 --- a/.cursor/skills/testing-patterns/SKILL.md +++ b/.cursor/skills/testing-patterns/SKILL.md @@ -492,6 +492,49 @@ test('should paginate results', async () => { - [ ] Keep test data realistic - [ ] Clean up after tests +## Common Mistakes + +1. **Testing Implementation Details**: Tests break on refactoring + ```typescript + // ❌ BAD: Testing internal method + expect(service['privateMethod']()).toBe(true); + + // ✅ GOOD: Test public behavior + expect(await service.processOrder(order)).toEqual({ success: true }); + ``` + +2. **Shared Mutable State**: Tests affect each other + ```typescript + // ❌ BAD: Shared state + let counter = 0; + test('first', () => { counter++; expect(counter).toBe(1); }); + test('second', () => { expect(counter).toBe(0); }); // Fails! + + // ✅ GOOD: Reset in beforeEach + let counter: number; + beforeEach(() => { counter = 0; }); + ``` + +3. **Not Mocking External Services**: Tests are slow and flaky + ```typescript + // ❌ BAD: Real HTTP calls + const response = await fetch('https://api.example.com/data'); + + // ✅ GOOD: Mock external services + jest.spyOn(httpClient, 'get').mockResolvedValue({ data: mockData }); + ``` + +4. **Missing Edge Cases**: Only testing happy path + ```typescript + // ❌ BAD: Only success case + test('creates user', async () => { ... }); + + // ✅ GOOD: Include error cases + test('creates user', async () => { ... }); + test('throws on duplicate email', async () => { ... }); + test('validates email format', async () => { ... }); + ``` + ## Quick Reference | Test Type | Location | Speed | Mocking |