feat: add comprehensive NodeJS development skills and rules
Based on Planner and Memory Manager analysis: New Skills (8): - nodejs-express-patterns: App structure, routing, middleware - nodejs-security-owasp: OWASP Top 10 security practices - nodejs-testing-jest: Unit/integration tests, mocking - nodejs-auth-jwt: JWT authentication, OAuth, sessions - nodejs-error-handling: Error classes, middleware, async handlers - nodejs-middleware-patterns: Auth, validation, rate limiting - nodejs-db-patterns: SQLite, PostgreSQL, MongoDB patterns - nodejs-npm-management: package.json, scripts, dependencies New Rules: - nodejs.md: Code style, security, best practices Updated: - backend-developer.md: Added skills reference table Milestone: #48 NodeJS Development Coverage Related: Planner & Memory Manager analysis results
This commit is contained in:
271
.kilo/rules/nodejs.md
Normal file
271
.kilo/rules/nodejs.md
Normal file
@@ -0,0 +1,271 @@
|
||||
# NodeJS Development Rules
|
||||
|
||||
Essential rules for Node.js backend development.
|
||||
|
||||
## Code Style
|
||||
|
||||
- Use `const` and `let`, never `var`
|
||||
- Use arrow functions for callbacks
|
||||
- Use async/await instead of callbacks
|
||||
- Use template literals for string interpolation
|
||||
- Use object destructuring
|
||||
- Use spread operator for objects/arrays
|
||||
|
||||
```javascript
|
||||
// ✅ Good
|
||||
const { id, name } = req.body;
|
||||
const user = { ...req.body, createdAt: new Date() };
|
||||
const users = await User.findAll();
|
||||
|
||||
// ❌ Bad
|
||||
var id = req.body.id;
|
||||
const user = Object.assign({}, req.body, { createdAt: new Date() });
|
||||
User.findAll().then(users => {});
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Always use try/catch with async/await
|
||||
- Use centralized error handling middleware
|
||||
- Never catch and swallow errors
|
||||
- Use custom AppError classes
|
||||
- Log errors with context
|
||||
|
||||
```javascript
|
||||
// ✅ Good
|
||||
try {
|
||||
const user = await User.findById(id);
|
||||
if (!user) throw new NotFoundError('User');
|
||||
res.json({ user });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
||||
// ❌ Bad
|
||||
User.findById(id).then(user => {
|
||||
if (!user) return res.status(404).json({ error: 'Not found' });
|
||||
res.json({ user });
|
||||
}).catch(err => {}); // Swallowing error
|
||||
```
|
||||
|
||||
## Async Code
|
||||
|
||||
- Always use async/await
|
||||
- Never mix callbacks and promises
|
||||
- Use Promise.all for parallel operations
|
||||
- Use async middleware wrapper
|
||||
|
||||
```javascript
|
||||
// ✅ Good
|
||||
const [users, posts] = await Promise.all([
|
||||
User.findAll(),
|
||||
Post.findAll()
|
||||
]);
|
||||
|
||||
// ❌ Bad
|
||||
let users;
|
||||
User.findAll().then(u => { users = u; });
|
||||
console.log(users); // undefined
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
- Always validate and sanitize input
|
||||
- Use parameterized queries
|
||||
- Never expose sensitive data
|
||||
- Use HTTPS in production
|
||||
- Set security headers with helmet
|
||||
- Rate limit public endpoints
|
||||
|
||||
```javascript
|
||||
// ✅ Good
|
||||
const user = await db.query('SELECT * FROM users WHERE id = ?', [id]);
|
||||
app.use(helmet());
|
||||
|
||||
// ❌ Bad
|
||||
const user = await db.query(`SELECT * FROM users WHERE id = ${id}`);
|
||||
// SQL injection vulnerable
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
- Never store passwords in plain text
|
||||
- Use bcrypt for password hashing
|
||||
- Use short-lived access tokens
|
||||
- Use refresh tokens
|
||||
- Use httpOnly cookies
|
||||
- Never put secrets in JWT payload
|
||||
|
||||
```javascript
|
||||
// ✅ Good
|
||||
const hashedPassword = await bcrypt.hash(password, 12);
|
||||
const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET, { expiresIn: '1h' });
|
||||
|
||||
// ❌ Bad
|
||||
const hashedPassword = password; // No hash
|
||||
const token = jwt.sign({ password: user.password }, 'secret'); // Secret in payload
|
||||
```
|
||||
|
||||
## Express Best Practices
|
||||
|
||||
- Use express.Router() for route organization
|
||||
- Keep route handlers thin
|
||||
- Validate at route level
|
||||
- Put error handlers last
|
||||
- Use middleware for cross-cutting concerns
|
||||
|
||||
```javascript
|
||||
// ✅ Good
|
||||
// routes/users.js
|
||||
const router = express.Router();
|
||||
router.get('/', authenticate, validate, controller.list);
|
||||
|
||||
// app.js
|
||||
app.use('/api/users', routes.users);
|
||||
app.use(errorHandler); // Last middleware
|
||||
|
||||
// ❌ Bad
|
||||
app.get('/api/users', async (req, res) => {
|
||||
// All logic in route
|
||||
});
|
||||
```
|
||||
|
||||
## Database
|
||||
|
||||
- Use connection pooling
|
||||
- Close connections gracefully
|
||||
- Use transactions for writes
|
||||
- Index frequently queried fields
|
||||
- Use migrations for schema changes
|
||||
|
||||
```javascript
|
||||
// ✅ Good
|
||||
await db.transaction(async (trx) => {
|
||||
await trx('users').insert(user);
|
||||
await trx('profiles').insert(profile);
|
||||
});
|
||||
|
||||
// ❌ Bad
|
||||
async function createUser(data) {
|
||||
const user = await db('users').insert(data);
|
||||
// No transaction, partial data on error
|
||||
await Profile.create({ userId: user.id });
|
||||
}
|
||||
```
|
||||
|
||||
## Logging
|
||||
|
||||
- Use structured logging (pino, winston)
|
||||
- Log levels: error, warn, info, debug
|
||||
- Include request ID for tracing
|
||||
- Log errors with stack traces
|
||||
- Don't log sensitive data
|
||||
|
||||
```javascript
|
||||
// ✅ Good
|
||||
logger.info({ userId, action: 'login', ip: req.ip });
|
||||
|
||||
// ❌ Bad
|
||||
console.log('User logged in:', user); // Logs entire user including password
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
- Write tests for critical paths
|
||||
- Use Jest or Mocha
|
||||
- Mock external dependencies
|
||||
- Aim for 80%+ coverage
|
||||
- Test edge cases
|
||||
|
||||
```javascript
|
||||
// ✅ Good
|
||||
describe('UserService', () => {
|
||||
it('should create user with hashed password', async () => {
|
||||
const user = await service.create({ email, password });
|
||||
expect(user.password).not.toBe(password);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Environment
|
||||
|
||||
- Use .env for secrets
|
||||
- Never commit secrets
|
||||
- Use different configs for environments
|
||||
- Validate required env vars
|
||||
|
||||
```javascript
|
||||
// ✅ Good
|
||||
const config = {
|
||||
db: {
|
||||
url: process.env.DATABASE_URL
|
||||
}
|
||||
};
|
||||
|
||||
if (!config.db.url) {
|
||||
throw new Error('DATABASE_URL is required');
|
||||
}
|
||||
|
||||
// ❌ Bad
|
||||
const config = {
|
||||
db: {
|
||||
url: 'postgres://user:pass@localhost/db' // Hardcoded
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Package Management
|
||||
|
||||
- Use exact versions in production
|
||||
- Run npm audit regularly
|
||||
- Update dependencies regularly
|
||||
- Remove unused dependencies
|
||||
|
||||
```bash
|
||||
# ✅ Good
|
||||
npm audit
|
||||
npx depcheck
|
||||
|
||||
# ❌ Bad
|
||||
# Never running security audit
|
||||
# Many unused dependencies
|
||||
```
|
||||
|
||||
## Performance
|
||||
|
||||
- Use streaming for large files
|
||||
- Cache frequently accessed data
|
||||
- Use connection pooling
|
||||
- Implement pagination
|
||||
- Compress responses
|
||||
|
||||
```javascript
|
||||
// ✅ Good
|
||||
app.use(compression());
|
||||
app.get('/users', paginated, controller.list);
|
||||
|
||||
// ❌ Bad
|
||||
app.get('/users', async (req, res) => {
|
||||
const users = await User.findAll(); // All users at once
|
||||
res.json(users);
|
||||
});
|
||||
```
|
||||
|
||||
## Clean Code
|
||||
|
||||
- No magic numbers, use constants
|
||||
- Meaningful variable names
|
||||
- One function, one responsibility
|
||||
- Comments only for "why", not "what"
|
||||
- DRY principle
|
||||
|
||||
```javascript
|
||||
// ✅ Good
|
||||
const MAX_LOGIN_ATTEMPTS = 5;
|
||||
const isLocked = user.loginAttempts >= MAX_LOGIN_ATTEMPTS;
|
||||
|
||||
// ❌ Bad
|
||||
if (user.loginAttempts >= 5) { // Magic number
|
||||
// ...
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user