backend-developer
SKILL.md
Backend Developer
Expert guidance for building secure, scalable, and maintainable backend systems.
When to Use This Skill
- Designing REST or GraphQL APIs
- Creating database schemas
- Implementing authentication/authorization
- Writing business logic
- Setting up data validation
- Handling errors and logging
- Optimizing database queries
- Ensuring security best practices
API Design
REST API Principles
Resource Naming
Good:
GET /users # List users
GET /users/:id # Get user
POST /users # Create user
PUT /users/:id # Update user (full)
PATCH /users/:id # Update user (partial)
DELETE /users/:id # Delete user
GET /users/:id/orders # User's orders (nested resource)
GET /orders?userId=123 # Filter orders (query param)
Bad:
GET /getUsers
POST /createUser
GET /user/delete/:id
HTTP Status Codes
Success:
200 OK # Request succeeded
201 Created # Resource created
204 No Content # Success, no body (DELETE)
Client Errors:
400 Bad Request # Invalid request data
401 Unauthorized # Authentication required
403 Forbidden # Insufficient permissions
404 Not Found # Resource doesn't exist
409 Conflict # Resource conflict
422 Unprocessable Entity # Validation failed
Server Errors:
500 Internal Server Error # Unexpected error
502 Bad Gateway # Upstream service error
503 Service Unavailable # Temporarily down
Response Format
// Success response
{
"data": {
"id": "123",
"name": "John Doe",
"email": "john@example.com"
}
}
// List response with pagination
{
"data": [
{ "id": "1", "name": "Item 1" },
{ "id": "2", "name": "Item 2" }
],
"pagination": {
"page": 1,
"pageSize": 20,
"totalPages": 5,
"totalItems": 100
}
}
// Error response
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid input data",
"details": [
{ "field": "email", "message": "Invalid email format" },
{ "field": "password", "message": "Must be at least 8 characters" }
]
}
}
API Versioning
URL versioning (recommended for simplicity):
/api/v1/users
/api/v2/users
Header versioning:
Accept: application/vnd.api+json; version=1
Query parameter:
/api/users?version=1
Rate Limiting
Headers to include:
X-RateLimit-Limit: 100 # Max requests per window
X-RateLimit-Remaining: 95 # Remaining requests
X-RateLimit-Reset: 1609459200 # Window reset timestamp
Response when exceeded:
HTTP 429 Too Many Requests
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Retry after 60 seconds.",
"retryAfter": 60
}
}
Database Design
Schema Design Principles
- Normalization: Reduce redundancy (3NF for OLTP)
- Denormalization: Strategic for read performance
- Indexing: Based on query patterns
- Constraints: Enforce data integrity at DB level
Common Patterns
User Authentication Schema
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NULL -- Soft delete
);
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_deleted_at ON users(deleted_at) WHERE deleted_at IS NULL;
Soft Delete Pattern
-- Add deleted_at column
ALTER TABLE users ADD COLUMN deleted_at TIMESTAMP NULL;
-- Query active records
SELECT * FROM users WHERE deleted_at IS NULL;
-- Soft delete
UPDATE users SET deleted_at = CURRENT_TIMESTAMP WHERE id = ?;
-- Hard delete (if needed)
DELETE FROM users WHERE id = ? AND deleted_at IS NOT NULL;
Audit Trail
CREATE TABLE audit_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
table_name VARCHAR(100) NOT NULL,
record_id UUID NOT NULL,
action VARCHAR(20) NOT NULL, -- INSERT, UPDATE, DELETE
old_values JSONB,
new_values JSONB,
user_id UUID REFERENCES users(id),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_audit_record ON audit_logs(table_name, record_id);
CREATE INDEX idx_audit_user ON audit_logs(user_id);
Query Optimization
-- Use EXPLAIN ANALYZE to understand query plans
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = ?;
-- Cover queries with composite indexes
CREATE INDEX idx_orders_user_status ON orders(user_id, status);
-- Partial indexes for frequent filters
CREATE INDEX idx_orders_pending ON orders(created_at)
WHERE status = 'pending';
-- Avoid SELECT *
SELECT id, name, email FROM users WHERE id = ?; -- Good
SELECT * FROM users WHERE id = ?; -- Avoid
Authentication & Authorization
JWT Authentication Flow
1. Login Request:
POST /auth/login { email, password }
2. Validate credentials, generate tokens:
{
"accessToken": "eyJ...", // Short-lived (15-60 min)
"refreshToken": "abc...", // Long-lived (7-30 days)
"expiresIn": 3600
}
3. Access protected resources:
GET /api/users
Authorization: Bearer eyJ...
4. Refresh when expired:
POST /auth/refresh { refreshToken: "abc..." }
JWT Best Practices
// Token payload (keep minimal)
interface JwtPayload {
sub: string; // User ID
email: string; // For display
roles: string[]; // Authorization
iat: number; // Issued at
exp: number; // Expiration
}
// Security considerations:
// - Use RS256 (asymmetric) for distributed systems
// - Use HS256 (symmetric) for single service
// - Never store sensitive data in payload
// - Implement token blacklisting for logout
// - Use short expiration for access tokens
Role-Based Access Control (RBAC)
// Define permissions
const PERMISSIONS = {
users: {
create: 'users:create',
read: 'users:read',
update: 'users:update',
delete: 'users:delete',
},
orders: {
create: 'orders:create',
read: 'orders:read',
update: 'orders:update',
delete: 'orders:delete',
},
};
// Define roles
const ROLES = {
admin: [
'users:*', // All user permissions
'orders:*', // All order permissions
],
manager: [
'users:read',
'orders:*',
],
user: [
'orders:create',
'orders:read', // Own orders only
],
};
// Middleware example
function requirePermission(permission: string) {
return (req, res, next) => {
if (!hasPermission(req.user.roles, permission)) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
}
Input Validation
Validation Schema Example
// Using Zod
import { z } from 'zod';
const createUserSchema = z.object({
email: z.string().email('Invalid email'),
password: z.string()
.min(8, 'Password must be at least 8 characters')
.regex(/[A-Z]/, 'Must contain uppercase')
.regex(/[0-9]/, 'Must contain number'),
name: z.string().min(1).max(100),
age: z.number().int().min(18).optional(),
});
// Validate in controller
async function createUser(req, res) {
const result = createUserSchema.safeParse(req.body);
if (!result.success) {
return res.status(422).json({
error: {
code: 'VALIDATION_ERROR',
details: result.error.issues,
},
});
}
// Proceed with validated data
const user = await userService.create(result.data);
res.status(201).json({ data: user });
}
Sanitization
// Sanitize string inputs
function sanitizeString(input: string): string {
return input
.trim()
.replace(/[<>]/g, ''); // Basic XSS prevention
}
// Sanitize for SQL (use parameterized queries instead)
// NEVER do string concatenation for SQL
// Good: Parameterized query
const user = await db.query(
'SELECT * FROM users WHERE email = $1',
[email]
);
// Bad: String concatenation (SQL injection risk)
const user = await db.query(
`SELECT * FROM users WHERE email = '${email}'`
);
Error Handling
Error Classes
// Base application error
class AppError extends Error {
constructor(
public statusCode: number,
public code: string,
message: string,
public details?: unknown
) {
super(message);
this.name = 'AppError';
}
}
// Specific error types
class ValidationError extends AppError {
constructor(details: unknown) {
super(422, 'VALIDATION_ERROR', 'Validation failed', details);
}
}
class NotFoundError extends AppError {
constructor(resource: string) {
super(404, 'NOT_FOUND', `${resource} not found`);
}
}
class UnauthorizedError extends AppError {
constructor(message = 'Authentication required') {
super(401, 'UNAUTHORIZED', message);
}
}
class ForbiddenError extends AppError {
constructor(message = 'Insufficient permissions') {
super(403, 'FORBIDDEN', message);
}
}
Global Error Handler
function errorHandler(err: Error, req: Request, res: Response, next: NextFunction) {
// Log error
logger.error({
error: err.message,
stack: err.stack,
path: req.path,
method: req.method,
userId: req.user?.id,
});
// Handle known errors
if (err instanceof AppError) {
return res.status(err.statusCode).json({
error: {
code: err.code,
message: err.message,
details: err.details,
},
});
}
// Handle unknown errors
res.status(500).json({
error: {
code: 'INTERNAL_ERROR',
message: 'An unexpected error occurred',
},
});
}
Logging
Structured Logging
// Logger setup
const logger = {
info: (message: string, meta?: object) => {
console.log(JSON.stringify({
level: 'info',
message,
timestamp: new Date().toISOString(),
...meta,
}));
},
error: (message: string, meta?: object) => {
console.error(JSON.stringify({
level: 'error',
message,
timestamp: new Date().toISOString(),
...meta,
}));
},
};
// Request logging middleware
function requestLogger(req, res, next) {
const start = Date.now();
res.on('finish', () => {
logger.info('HTTP Request', {
method: req.method,
path: req.path,
statusCode: res.statusCode,
duration: Date.now() - start,
userId: req.user?.id,
});
});
next();
}
Security Best Practices
Security Checklist
- HTTPS only in production
- Parameterized queries for all database operations
- Input validation on all endpoints
- Rate limiting to prevent abuse
- CORS configuration restricted to allowed origins
- Secure headers (Helmet.js or equivalent)
- Password hashing with bcrypt/argon2
- Secrets management (environment variables, vault)
- Dependency scanning for vulnerabilities
- SQL injection prevention via ORM or parameterized queries
- XSS prevention via output encoding
Security Headers
// Essential security headers
app.use((req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-XSS-Protection', '1; mode=block');
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
res.setHeader('Content-Security-Policy', "default-src 'self'");
next();
});
Project Structure
src/
├── controllers/ # Request handlers
├── services/ # Business logic
├── repositories/ # Data access layer
├── models/ # Database models/entities
├── middleware/ # Express middleware
├── routes/ # Route definitions
├── validators/ # Request validation schemas
├── utils/ # Utility functions
├── types/ # TypeScript types
├── config/ # Configuration
└── app.ts # Application entry point
Output Artifacts
When this skill is activated, I can help create:
- API Endpoint Implementation: Controllers and routes
- Database Schema: Migrations and models
- Authentication System: JWT, sessions, OAuth
- Validation Schemas: Request validation
- Error Handling: Error classes and middleware
- Security Configuration: Headers, CORS, rate limiting
- API Documentation: OpenAPI/Swagger specs
Weekly Installs
2
Repository
navedanan/backg…-removerFirst Seen
10 days ago
Security Audits
Installed on
opencode2
gemini-cli2
claude-code2
github-copilot2
windsurf2
codex2