system-prompts-and-models-o.../Bolt.new/Backend-Architecture-Guidelines.txt
Jason Kneen e7b75d0bcd Bolt.new design and backend docs
Part 1 of many to come.
2025-04-24 03:58:42 +01:00

1745 lines
39 KiB
Plaintext

# Backend Architecture Guidelines
This document contains comprehensive guidelines for creating robust, scalable, and maintainable backend systems.
## Architecture Philosophy
Build backend systems that are:
- **Scalable and Resilient** - Able to handle growing loads and recover from failures
- **Secure by Design** - Security integrated at every level, not added as an afterthought
- **Maintainable** - Clean architecture that's easy to understand and extend
- **Performance Optimized** - Efficient resource utilization and response times
- **Observable** - Comprehensive logging, monitoring, and debugging capabilities
## Core Architecture Principles
### Clean Architecture
- **Layer Separation**
- Controllers/Routes (API endpoints)
- Services (business logic)
- Data Access (repository pattern)
- Domain Models (entities)
- Infrastructure (external services, databases)
- **Dependency Inversion**
- High-level modules don't depend on low-level modules
- Both depend on abstractions
- Abstractions don't depend on details
- Details depend upon abstractions
- **Single Responsibility**
- Each module has one reason to change
- Functions do one thing well
- Classes encapsulate cohesive functionality
- Services manage specific domains
- **Domain-Driven Design**
- Business logic in the domain layer
- Ubiquitous language shared with stakeholders
- Bounded contexts to isolate domains
- Aggregates to enforce invariants
### API Design
- **RESTful Principles**
- Resource-oriented endpoints
- Appropriate HTTP methods
- Proper status codes
- Hypermedia links where appropriate
- Version management
- **GraphQL Considerations**
- Schema-first development
- Resolver optimization
- Query complexity analysis
- Batching and caching
- Authorization directives
- **API Versioning**
- URL path versioning (`/v1/resources`)
- Accept header versioning
- Content negotiation
- Deprecation strategy
- Documentation of changes
- **Contract First**
- OpenAPI/Swagger documentation
- Schema validation
- Consumer-driven contracts
- Integration tests against spec
- Automated documentation
### Statelessness and Scaling
- **Horizontal Scaling**
- Stateless services
- Load balancing
- Session management via tokens
- No server affinity
- Container orchestration
- **Vertical Scaling**
- Resource allocation
- Performance profiling
- Memory optimization
- CPU utilization
- I/O efficiency
- **Microservices Considerations**
- Service boundaries
- Inter-service communication
- API gateways
- Service discovery
- Circuit breaking
- **Monolith Optimization**
- Modular architecture
- Clear boundaries
- Resource isolation
- Deployment strategies
- Scaling bottleneck identification
## Database and Data Management
### Schema Design
- **Relational Database**
- Normalization (3NF baseline)
- Foreign key constraints
- Indexing strategy
- Query optimization
- Transaction boundaries
- **NoSQL Database**
- Data access patterns
- Denormalization strategy
- Eventual consistency
- Partition keys
- Compound indexes
- **Migration Strategy**
- Version control for schema
- Forward-only migrations
- Rollback planning
- Zero-downtime updates
- Data validation
- **Entity Relationships**
- One-to-one
- One-to-many
- Many-to-many
- Polymorphic relationships
- Self-referential relationships
### Data Access Patterns
- **Repository Pattern**
- Entity-specific repositories
- Query abstraction
- Transaction support
- Caching integration
- Error handling
- **Object-Relational Mapping**
- Entity mapping
- Lazy/eager loading
- Change tracking
- Query generation
- Performance considerations
- **Query Optimization**
- Execution plans
- Index utilization
- N+1 query prevention
- Batch operations
- Connection pooling
- **Data Caching**
- Cache invalidation
- TTL strategies
- Distributed caching
- Cache warming
- Stale-while-revalidate
### Data Integrity and Validation
- **Input Validation**
- Request schema validation
- Type checking
- Business rule enforcement
- Cross-field validation
- Sanitization
- **Output Validation**
- Response schema conformance
- Content security
- Sensitive data redaction
- Consistent formatting
- Pagination metadata
- **Data Constraints**
- Database constraints
- Application-level validation
- Cross-service consistency
- Idempotency guarantees
- State transition rules
- **Error Cases**
- Input validation errors
- Business rule violations
- Resource not found
- Conflict resolution
- Server capability limits
## Security Implementation
### Authentication
- **User Identity**
- Credential storage
- Password policies
- Multi-factor authentication
- Account lockout
- Password reset
- **JWT Implementation**
- Token structure
- Signing algorithms
- Expiration strategy
- Refresh mechanism
- Revocation strategy
- **OAuth/OIDC**
- Authorization flows
- Provider integration
- Scope management
- Token validation
- User info endpoints
- **API Authentication**
- API keys
- Client credentials
- Certificate-based
- IP whitelisting
- Rate limiting
### Authorization
- **Role-Based Access**
- Role definition
- Permission mapping
- Role hierarchy
- Default deny
- Least privilege
- **Attribute-Based Access**
- Policy evaluation
- Context awareness
- Dynamic permissions
- Environmental conditions
- Temporal constraints
- **Resource Ownership**
- Multi-tenancy
- User-based isolation
- Team/organization access
- Delegation model
- Ownership transfer
- **Permission Enforcement**
- Controller/middleware level
- Service layer enforcement
- Data access filtering
- Object-level security
- Field-level security
### Data Protection
- **Encryption**
- Data at rest
- Data in transit
- Key management
- Rotation policies
- Algorithm selection
- **PII Handling**
- Classification
- Minimization
- Anonymization
- Pseudonymization
- Retention policies
- **Secrets Management**
- Environment variables
- Vault services
- Access control
- Audit logging
- Rotation strategy
- **Database Security**
- Network isolation
- Access controls
- Query parameterization
- Connection security
- Auditing
### Security Posture
- **Vulnerability Management**
- Dependency scanning
- Static analysis
- Dynamic testing
- Penetration testing
- Responsible disclosure
- **Security Headers**
- Content Security Policy
- CORS configuration
- XSS protection
- CSRF prevention
- Clickjacking protection
- **Rate Limiting**
- Request throttling
- Account limits
- IP-based limiting
- Graduated response
- Breach detection
- **Audit Logging**
- Security events
- Access attempts
- Administrative actions
- Data modifications
- System changes
## Error Handling and Resilience
### Error Management
- **Standardized Errors**
- Error classification
- Status code mapping
- Error codes
- User messages
- Developer details
- **Exception Handling**
- Try-catch patterns
- Async error handling
- Middleware interception
- Global error handlers
- Service-specific handling
- **Graceful Degradation**
- Fallback strategies
- Default behaviors
- Partial content responses
- Circuit breakers
- Bulkhead pattern
- **Retry Logic**
- Exponential backoff
- Jitter implementation
- Maximum attempts
- Idempotency guarantees
- Failure reporting
### Resilience Patterns
- **Circuit Breaker**
- Failure threshold
- Recovery timeout
- Half-open state
- Health monitoring
- Circuit isolation
- **Bulkhead Pattern**
- Resource isolation
- Thread pools
- Connection limitations
- Request prioritization
- Failure containment
- **Timeouts**
- Connection timeouts
- Read timeouts
- Write timeouts
- Service timeouts
- Cascade prevention
- **Rate Limiters**
- Request throttling
- Token bucket algorithm
- Leaky bucket algorithm
- Fixed/sliding window
- Adaptive strategies
### Recovery Strategies
- **Disaster Recovery**
- Backup strategy
- Restore procedures
- Recovery time objectives
- Recovery point objectives
- Failover systems
- **Data Consistency**
- Outbox pattern
- Saga pattern
- Eventual consistency
- Two-phase commit
- Compensating transactions
- **Self-Healing**
- Health checks
- Automatic restarts
- Replication
- State reconciliation
- Data repair
- **Chaos Engineering**
- Failure injection
- Load testing
- Network degradation
- Resource exhaustion
- Recovery validation
## Performance Optimization
### Response Time
- **Caching Strategy**
- Response caching
- Object caching
- Computation caching
- Cache hierarchy
- Invalidation triggers
- **Query Optimization**
- Indexing strategy
- Query planning
- Result limiting
- Join optimization
- Execution analysis
- **Async Processing**
- Background jobs
- Message queues
- Scheduled tasks
- Event-driven architecture
- Long-running processes
- **I/O Management**
- Connection pooling
- Batch operations
- Stream processing
- File I/O optimization
- Network I/O efficiency
### Resource Utilization
- **Memory Management**
- Memory profiling
- Leak detection
- Object pooling
- Garbage collection tuning
- Buffer management
- **CPU Optimization**
- Thread allocation
- Worker processes
- Computation distribution
- Algorithm efficiency
- Hot path optimization
- **Database Efficiency**
- Connection pooling
- Query optimization
- Read/write splitting
- Sharding
- Replication strategy
- **Network Efficiency**
- Payload compression
- Request batching
- Keep-alive connections
- Response streaming
- Protocol selection
### Scaling Strategies
- **Horizontal Scaling**
- Stateless design
- Load balancing
- Session management
- Data partitioning
- Service discovery
- **Vertical Scaling**
- Resource allocation
- Hardware optimization
- Application tuning
- Server configuration
- Database sizing
- **Caching Layers**
- Client-side cache
- CDN integration
- API gateway cache
- Application cache
- Database cache
- **Read/Write Splitting**
- Command Query Responsibility Segregation
- Read replicas
- Write sharding
- Cache read optimization
- Eventual consistency model
## Observability and Monitoring
### Logging
- **Log Levels**
- Error: System failures
- Warn: Potential issues
- Info: System events
- Debug: Development details
- Trace: Detailed execution flow
- **Log Structure**
- Timestamp
- Severity
- Service/component
- Correlation ID
- Context information
- **Log Storage**
- Centralized collection
- Retention policies
- Access controls
- Search capabilities
- Archival strategy
- **Log Analysis**
- Pattern detection
- Anomaly identification
- Performance insights
- Error investigation
- Audit capabilities
### Metrics
- **System Metrics**
- CPU utilization
- Memory usage
- Disk I/O
- Network throughput
- Connection count
- **Application Metrics**
- Request rate
- Response time
- Error rate
- Concurrent users
- Business transactions
- **Database Metrics**
- Query performance
- Connection utilization
- Index efficiency
- Lock contention
- Storage growth
- **Custom Business Metrics**
- Conversion rates
- User engagement
- Feature usage
- Business KPIs
- Revenue indicators
### Tracing
- **Distributed Tracing**
- Trace context propagation
- Span collection
- Service mapping
- Latency analysis
- Dependency visualization
- **Transaction Tracking**
- Request lifecycle
- Service boundaries
- Error propagation
- Resource utilization
- External calls
- **Performance Profiling**
- Hotspot identification
- Method-level timing
- Resource consumption
- Lock contention
- I/O blocking
- **User Journey Tracking**
- Session correlation
- Flow visualization
- Conversion funnels
- Abandonment points
- Experience metrics
### Alerting
- **Alert Configuration**
- Threshold definition
- Duration conditions
- Composite alerts
- Priority levels
- Notification channels
- **Alert Management**
- Escalation policies
- On-call rotations
- Alert grouping
- Suppression rules
- Maintenance windows
- **Alert Response**
- Playbooks
- Automated remediation
- Incident classification
- Resolution tracking
- Post-mortem analysis
- **Business Alerting**
- KPI thresholds
- Trend deviations
- Conversion drops
- Revenue impacts
- Customer experience degradation
## Testing Strategy
### Test Types
- **Unit Testing**
- Function/method testing
- Component isolation
- Mock dependencies
- State verification
- Edge case coverage
- **Integration Testing**
- Service interaction
- API contracts
- Database integration
- External service mocking
- Environment setup
- **System Testing**
- End-to-end workflows
- Real environment
- Data flow validation
- UI integration
- Cross-service functionality
- **Performance Testing**
- Load testing
- Stress testing
- Endurance testing
- Spike testing
- Scalability testing
### Test Implementation
- **Test-Driven Development**
- Write tests first
- Red-green-refactor cycle
- Continuous test execution
- Test coverage goals
- Regression prevention
- **Behavior-Driven Development**
- Specification by example
- Shared understanding
- Business-centric language
- Acceptance criteria
- Feature validation
- **Test Organization**
- Test hierarchy
- Descriptive naming
- Setup and teardown
- Shared fixtures
- Test isolation
- **Test Automation**
- CI/CD integration
- Parallel execution
- Selective testing
- Test reporting
- Failure analysis
### Test Data Management
- **Test Data Creation**
- Factories/builders
- Realistic data
- Randomization
- Edge cases
- Invalid data
- **Database Fixtures**
- Known state setup
- Test isolation
- Transactional tests
- Cleanup procedures
- Data versioning
- **Mocking and Stubbing**
- External dependencies
- Service virtualization
- Response simulation
- Behavior verification
- State verification
- **Property-Based Testing**
- Generative testing
- Invariant checking
- Random inputs
- Edge case discovery
- Shrinking to minimal examples
## Deployment and Operations
### CI/CD Pipeline
- **Continuous Integration**
- Automated builds
- Test execution
- Static analysis
- Security scanning
- Artifact generation
- **Continuous Delivery**
- Environment promotion
- Configuration management
- Deployment approval
- Release notes
- Rollback capability
- **Automated Testing**
- Unit test suite
- Integration tests
- E2E testing
- Performance verification
- Security validation
- **Code Quality Gates**
- Test coverage
- Static analysis
- Duplicate detection
- Complexity metrics
- Vulnerability scanning
### Infrastructure as Code
- **Environment Definition**
- Infrastructure templates
- Configuration scripts
- Network setup
- Resource allocation
- Security groups
- **Configuration Management**
- Environment variables
- Feature flags
- Secrets handling
- Parameter stores
- Configuration versioning
- **Deployment Strategies**
- Blue/green deployment
- Canary releases
- Feature flagging
- A/B testing
- Rolling updates
- **Containerization**
- Image building
- Registry management
- Orchestration
- Scaling policies
- Service discovery
### Operation Management
- **Incident Response**
- Alert triage
- Escalation procedures
- Communication channels
- Resolution tracking
- Post-incident review
- **Runbooks**
- Common operations
- Troubleshooting guides
- Recovery procedures
- Maintenance tasks
- Emergency protocols
- **Capacity Planning**
- Resource monitoring
- Growth forecasting
- Scaling thresholds
- Cost optimization
- Performance benchmarks
- **Change Management**
- Change requests
- Risk assessment
- Approval workflow
- Implementation plans
- Verification procedures
## Code Organization
### Project Structure
- **Directory Organization**
- Feature-based grouping
- Layer-based separation
- Config isolation
- Test proximity
- Documentation location
- **Module System**
- Clear dependencies
- Interface definitions
- Circular dependency prevention
- Encapsulation
- Public APIs
- **Naming Conventions**
- Consistent patterns
- Descriptive names
- Purpose indication
- Abbreviation avoidance
- Version indicators
- **Configuration Management**
- Environment separation
- Defaults and overrides
- Validation
- Documentation
- Secret handling
### Coding Standards
- **Style Guidelines**
- Formatting rules
- Naming conventions
- Comment practices
- Module organization
- Code documentation
- **Code Quality**
- Complexity limits
- Function size
- Class responsibility
- Coupling metrics
- Duplication prevention
- **Documentation**
- API documentation
- Implementation notes
- Architecture documentation
- Decision records
- Operation guides
- **Version Control**
- Commit messages
- Branch strategy
- Pull request process
- Code review standards
- Merge requirements
## Implementation Examples
### Express.js API Implementation
```typescript
// src/controllers/userController.ts
import { Request, Response, NextFunction } from 'express';
import { UserService } from '../services/userService';
import { CreateUserDto, UpdateUserDto } from '../dtos/userDtos';
export class UserController {
constructor(private userService: UserService) {}
async getUsers(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const users = await this.userService.findAll();
res.status(200).json(users);
} catch (error) {
next(error);
}
}
async getUserById(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const id = parseInt(req.params.id);
const user = await this.userService.findById(id);
if (!user) {
res.status(404).json({ message: 'User not found' });
return;
}
res.status(200).json(user);
} catch (error) {
next(error);
}
}
async createUser(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const userData: CreateUserDto = req.body;
const newUser = await this.userService.create(userData);
res.status(201).json(newUser);
} catch (error) {
next(error);
}
}
async updateUser(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const id = parseInt(req.params.id);
const userData: UpdateUserDto = req.body;
const updatedUser = await this.userService.update(id, userData);
if (!updatedUser) {
res.status(404).json({ message: 'User not found' });
return;
}
res.status(200).json(updatedUser);
} catch (error) {
next(error);
}
}
async deleteUser(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const id = parseInt(req.params.id);
const deleted = await this.userService.delete(id);
if (!deleted) {
res.status(404).json({ message: 'User not found' });
return;
}
res.status(204).send();
} catch (error) {
next(error);
}
}
}
```
### Service Layer Implementation
```typescript
// src/services/userService.ts
import { User } from '../models/user';
import { UserRepository } from '../repositories/userRepository';
import { CreateUserDto, UpdateUserDto } from '../dtos/userDtos';
import { NotFoundError, ValidationError } from '../utils/errors';
export class UserService {
constructor(private userRepository: UserRepository) {}
async findAll(): Promise<User[]> {
return this.userRepository.findAll();
}
async findById(id: number): Promise<User | null> {
return this.userRepository.findById(id);
}
async create(userData: CreateUserDto): Promise<User> {
// Validate data
this.validateUserData(userData);
// Check if email already exists
const existingUser = await this.userRepository.findByEmail(userData.email);
if (existingUser) {
throw new ValidationError('Email already registered');
}
// Create new user
return this.userRepository.create(userData);
}
async update(id: number, userData: UpdateUserDto): Promise<User | null> {
// Validate data
this.validateUserData(userData, false);
// Check if user exists
const user = await this.userRepository.findById(id);
if (!user) {
throw new NotFoundError('User not found');
}
// Check email uniqueness if changing email
if (userData.email && userData.email !== user.email) {
const existingUser = await this.userRepository.findByEmail(userData.email);
if (existingUser) {
throw new ValidationError('Email already registered');
}
}
// Update user
return this.userRepository.update(id, userData);
}
async delete(id: number): Promise<boolean> {
return this.userRepository.delete(id);
}
private validateUserData(data: CreateUserDto | UpdateUserDto, isCreating = true): void {
const errors: string[] = [];
if (isCreating && !data.email) {
errors.push('Email is required');
}
if (data.email && !this.isValidEmail(data.email)) {
errors.push('Invalid email format');
}
if (isCreating && !data.password) {
errors.push('Password is required');
}
if (data.password && data.password.length < 8) {
errors.push('Password must be at least 8 characters long');
}
if (errors.length > 0) {
throw new ValidationError(errors.join(', '));
}
}
private isValidEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
}
```
### Repository Pattern Implementation
```typescript
// src/repositories/userRepository.ts
import { db } from '../config/database';
import { User } from '../models/user';
import { CreateUserDto, UpdateUserDto } from '../dtos/userDtos';
import { hashPassword } from '../utils/auth';
export class UserRepository {
async findAll(): Promise<User[]> {
return db.users.findMany({
select: {
id: true,
name: true,
email: true,
role: true,
createdAt: true,
updatedAt: true,
},
});
}
async findById(id: number): Promise<User | null> {
return db.users.findUnique({
where: { id },
select: {
id: true,
name: true,
email: true,
role: true,
createdAt: true,
updatedAt: true,
},
});
}
async findByEmail(email: string): Promise<User | null> {
return db.users.findUnique({
where: { email },
select: {
id: true,
name: true,
email: true,
role: true,
createdAt: true,
updatedAt: true,
},
});
}
async create(userData: CreateUserDto): Promise<User> {
const hashedPassword = await hashPassword(userData.password);
return db.users.create({
data: {
name: userData.name,
email: userData.email,
password: hashedPassword,
role: userData.role || 'USER',
},
select: {
id: true,
name: true,
email: true,
role: true,
createdAt: true,
updatedAt: true,
},
});
}
async update(id: number, userData: UpdateUserDto): Promise<User | null> {
const data: any = {
name: userData.name,
email: userData.email,
role: userData.role,
};
// Only hash password if it's included in the update
if (userData.password) {
data.password = await hashPassword(userData.password);
}
// Remove undefined values
Object.keys(data).forEach(key => data[key] === undefined && delete data[key]);
return db.users.update({
where: { id },
data,
select: {
id: true,
name: true,
email: true,
role: true,
createdAt: true,
updatedAt: true,
},
});
}
async delete(id: number): Promise<boolean> {
try {
await db.users.delete({
where: { id },
});
return true;
} catch (error) {
// If no rows were affected, user didn't exist
if (error.code === 'P2025') {
return false;
}
throw error;
}
}
}
```
### Error Handling Middleware
```typescript
// src/middleware/errorHandler.ts
import { Request, Response, NextFunction } from 'express';
import { ValidationError, NotFoundError, AuthorizationError } from '../utils/errors';
import logger from '../utils/logger';
export function errorHandler(
err: Error,
req: Request,
res: Response,
next: NextFunction
) {
// Log all errors
logger.error({
message: err.message,
stack: err.stack,
method: req.method,
path: req.path,
ip: req.ip,
userId: req.user?.id,
});
// Handle specific error types
if (err instanceof ValidationError) {
return res.status(400).json({
status: 'error',
message: err.message,
code: 'VALIDATION_ERROR',
});
}
if (err instanceof NotFoundError) {
return res.status(404).json({
status: 'error',
message: err.message,
code: 'NOT_FOUND',
});
}
if (err instanceof AuthorizationError) {
return res.status(403).json({
status: 'error',
message: err.message,
code: 'FORBIDDEN',
});
}
// Handle unexpected errors
const isDevelopment = process.env.NODE_ENV === 'development';
return res.status(500).json({
status: 'error',
message: 'Internal server error',
code: 'SERVER_ERROR',
...(isDevelopment && {
detail: err.message,
stack: err.stack,
}),
});
}
```
### Authentication Implementation
```typescript
// src/middleware/authenticate.ts
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
import { UserService } from '../services/userService';
import { AuthorizationError } from '../utils/errors';
interface TokenPayload {
userId: number;
role: string;
iat: number;
exp: number;
}
export function authenticate(
requiredRoles: string[] = []
) {
return async (req: Request, res: Response, next: NextFunction) => {
try {
// Get token from authorization header
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
throw new AuthorizationError('Authentication required');
}
const token = authHeader.split(' ')[1];
// Verify token
let payload: TokenPayload;
try {
payload = jwt.verify(
token,
process.env.JWT_SECRET!
) as TokenPayload;
} catch (err) {
throw new AuthorizationError('Invalid token');
}
// Check token expiration
const now = Math.floor(Date.now() / 1000);
if (payload.exp < now) {
throw new AuthorizationError('Token expired');
}
// Check role if required
if (requiredRoles.length > 0 && !requiredRoles.includes(payload.role)) {
throw new AuthorizationError('Insufficient permissions');
}
// Get user and attach to request
const userService = new UserService();
const user = await userService.findById(payload.userId);
if (!user) {
throw new AuthorizationError('User not found');
}
// Attach user to request object
req.user = user;
next();
} catch (error) {
next(error);
}
};
}
```
### Custom Error Classes
```typescript
// src/utils/errors.ts
export class ValidationError extends Error {
constructor(message: string) {
super(message);
this.name = 'ValidationError';
Object.setPrototypeOf(this, ValidationError.prototype);
}
}
export class NotFoundError extends Error {
constructor(message: string) {
super(message);
this.name = 'NotFoundError';
Object.setPrototypeOf(this, NotFoundError.prototype);
}
}
export class AuthorizationError extends Error {
constructor(message: string) {
super(message);
this.name = 'AuthorizationError';
Object.setPrototypeOf(this, AuthorizationError.prototype);
}
}
export class DatabaseError extends Error {
constructor(message: string) {
super(message);
this.name = 'DatabaseError';
Object.setPrototypeOf(this, DatabaseError.prototype);
}
}
export class ServiceError extends Error {
constructor(message: string) {
super(message);
this.name = 'ServiceError';
Object.setPrototypeOf(this, ServiceError.prototype);
}
}
```
## Libraries and Tools
### Core Dependencies
- **Web Framework**
- Express.js
- Fastify
- NestJS
- Koa
- **Database Access**
- Prisma
- TypeORM
- Sequelize
- Knex
- **Validation**
- Joi
- Zod
- class-validator
- Yup
- **Authentication**
- Passport.js
- jsonwebtoken
- bcrypt
- OAuth libraries
### Development Tools
- **Testing**
- Jest
- Mocha/Chai
- SuperTest
- Cypress
- k6
- **Linting & Formatting**
- ESLint
- Prettier
- TypeScript
- Husky (pre-commit hooks)
- lint-staged
- **Documentation**
- Swagger/OpenAPI
- JSDoc
- Postman collections
- Markdown documentation
- Architecture Decision Records (ADRs)
- **Monitoring**
- Prometheus
- Grafana
- Datadog
- New Relic
- Sentry
## Best Practices Checklist
### Development Checklist
- [ ] Use TypeScript with strict mode
- [ ] Document all APIs with OpenAPI/Swagger
- [ ] Write comprehensive tests (unit, integration, E2E)
- [ ] Automate CI/CD pipeline
- [ ] Implement request validation
- [ ] Set up logging and monitoring
- [ ] Use consistent error handling
- [ ] Configure linting and code formatting
- [ ] Implement authentication and authorization
- [ ] Set up database migrations
### Security Checklist
- [ ] Use HTTPS for all communications
- [ ] Implement proper authentication
- [ ] Apply authorization on all endpoints
- [ ] Validate all input data
- [ ] Use parameterized queries
- [ ] Sanitize output to prevent XSS
- [ ] Apply rate limiting
- [ ] Set security headers
- [ ] Handle secrets securely
- [ ] Scan dependencies for vulnerabilities
### Production Readiness
- [ ] Configure proper logging
- [ ] Set up monitoring and alerts
- [ ] Implement health checks
- [ ] Configure CI/CD pipeline
- [ ] Document deployment procedures
- [ ] Create runbooks for common operations
- [ ] Set up backup and restore procedures
- [ ] Plan for scaling
- [ ] Document API contracts
- [ ] Create incident response plan
## Code Examples
### Express.js Application Setup
```typescript
// src/app.ts
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import compression from 'compression';
import rateLimit from 'express-rate-limit';
import { errorHandler } from './middleware/errorHandler';
import { notFoundHandler } from './middleware/notFoundHandler';
import { requestLogger } from './middleware/requestLogger';
import routes from './routes';
const app = express();
// Middleware
app.use(helmet()); // Security headers
app.use(cors()); // CORS handling
app.use(compression()); // Response compression
app.use(express.json()); // Parse JSON bodies
app.use(express.urlencoded({ extended: true })); // Parse URL-encoded bodies
app.use(requestLogger); // Log all requests
// Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // 100 requests per IP
standardHeaders: true,
legacyHeaders: false,
message: 'Too many requests from this IP, please try again later',
});
app.use(limiter);
// Routes
app.use('/api', routes);
// Error handling
app.use(notFoundHandler);
app.use(errorHandler);
export default app;
```
### API Route Definition
```typescript
// src/routes/userRoutes.ts
import { Router } from 'express';
import { UserController } from '../controllers/userController';
import { UserService } from '../services/userService';
import { UserRepository } from '../repositories/userRepository';
import { authenticate } from '../middleware/authenticate';
import { validateRequest } from '../middleware/validateRequest';
import { createUserSchema, updateUserSchema } from '../validation/userSchemas';
const router = Router();
const userRepository = new UserRepository();
const userService = new UserService(userRepository);
const userController = new UserController(userService);
router.get('/',
authenticate(['ADMIN']),
(req, res, next) => userController.getUsers(req, res, next)
);
router.get('/:id',
authenticate(),
(req, res, next) => userController.getUserById(req, res, next)
);
router.post('/',
validateRequest(createUserSchema),
(req, res, next) => userController.createUser(req, res, next)
);
router.put('/:id',
authenticate(),
validateRequest(updateUserSchema),
(req, res, next) => userController.updateUser(req, res, next)
);
router.delete('/:id',
authenticate(['ADMIN']),
(req, res, next) => userController.deleteUser(req, res, next)
);
export default router;
```
### Dependency Injection Setup
```typescript
// src/config/container.ts
import { Container } from 'inversify';
import { TYPES } from './types';
import { UserController } from '../controllers/userController';
import { UserService } from '../services/userService';
import { UserRepository } from '../repositories/userRepository';
import { DatabaseConnection } from '../config/database';
import { Logger } from '../utils/logger';
const container = new Container();
// Infrastructure
container.bind<DatabaseConnection>(TYPES.DatabaseConnection).to(DatabaseConnection).inSingletonScope();
container.bind<Logger>(TYPES.Logger).to(Logger).inSingletonScope();
// Repositories
container.bind<UserRepository>(TYPES.UserRepository).to(UserRepository).inSingletonScope();
// Services
container.bind<UserService>(TYPES.UserService).to(UserService).inSingletonScope();
// Controllers
container.bind<UserController>(TYPES.UserController).to(UserController).inSingletonScope();
export { container };
```
### Testing Example
```typescript
// src/services/__tests__/userService.test.ts
import { UserService } from '../userService';
import { UserRepository } from '../../repositories/userRepository';
import { ValidationError, NotFoundError } from '../../utils/errors';
// Mock the repository
jest.mock('../../repositories/userRepository');
describe('UserService', () => {
let userService: UserService;
let userRepository: jest.Mocked<UserRepository>;
beforeEach(() => {
userRepository = new UserRepository() as jest.Mocked<UserRepository>;
userService = new UserService(userRepository);
});
afterEach(() => {
jest.clearAllMocks();
});
describe('create', () => {
it('should create a user with valid data', async () => {
// Arrange
const userData = {
name: 'John Doe',
email: 'john@example.com',
password: 'password123',
};
userRepository.findByEmail.mockResolvedValue(null);
userRepository.create.mockResolvedValue({
id: 1,
...userData,
role: 'USER',
createdAt: new Date(),
updatedAt: new Date(),
});
// Act
const result = await userService.create(userData);
// Assert
expect(userRepository.findByEmail).toHaveBeenCalledWith(userData.email);
expect(userRepository.create).toHaveBeenCalledWith(userData);
expect(result).toHaveProperty('id', 1);
expect(result).toHaveProperty('name', userData.name);
expect(result).toHaveProperty('email', userData.email);
});
it('should throw ValidationError if email already exists', async () => {
// Arrange
const userData = {
name: 'John Doe',
email: 'john@example.com',
password: 'password123',
};
userRepository.findByEmail.mockResolvedValue({
id: 1,
name: 'Existing User',
email: userData.email,
role: 'USER',
createdAt: new Date(),
updatedAt: new Date(),
});
// Act & Assert
await expect(userService.create(userData)).rejects.toThrow(ValidationError);
expect(userRepository.create).not.toHaveBeenCalled();
});
it('should throw ValidationError if email is invalid', async () => {
// Arrange
const userData = {
name: 'John Doe',
email: 'invalid-email',
password: 'password123',
};
// Act & Assert
await expect(userService.create(userData)).rejects.toThrow(ValidationError);
expect(userRepository.findByEmail).not.toHaveBeenCalled();
expect(userRepository.create).not.toHaveBeenCalled();
});
});
describe('update', () => {
it('should update a user with valid data', async () => {
// Arrange
const userId = 1;
const userData = {
name: 'Updated Name',
};
userRepository.findById.mockResolvedValue({
id: userId,
name: 'Original Name',
email: 'user@example.com',
role: 'USER',
createdAt: new Date(),
updatedAt: new Date(),
});
userRepository.update.mockResolvedValue({
id: userId,
name: 'Updated Name',
email: 'user@example.com',
role: 'USER',
createdAt: new Date(),
updatedAt: new Date(),
});
// Act
const result = await userService.update(userId, userData);
// Assert
expect(userRepository.findById).toHaveBeenCalledWith(userId);
expect(userRepository.update).toHaveBeenCalledWith(userId, userData);
expect(result).toHaveProperty('id', userId);
expect(result).toHaveProperty('name', 'Updated Name');
});
it('should throw NotFoundError if user does not exist', async () => {
// Arrange
const userId = 999;
const userData = {
name: 'Updated Name',
};
userRepository.findById.mockResolvedValue(null);
// Act & Assert
await expect(userService.update(userId, userData)).rejects.toThrow(NotFoundError);
expect(userRepository.update).not.toHaveBeenCalled();
});
});
});
```
## Best Practices
### Code Structure Best Practices
- Keep files small and focused on a single responsibility
- Use consistent naming conventions across the codebase
- Group related functionality together
- Separate business logic from infrastructure concerns
- Maintain clear dependency boundaries
### API Design Best Practices
- Use nouns for resource endpoints
- Keep URLs clean and simple
- Use HTTP methods appropriately
- Return appropriate status codes
- Document all endpoints
### Security Best Practices
- Never trust client input
- Implement proper authentication and authorization
- Follow the principle of least privilege
- Keep dependencies up to date
- Run regular security scans
### Performance Best Practices
- Implement appropriate caching
- Optimize database queries
- Use async/await for I/O operations
- Monitor and optimize bottlenecks
- Consider pagination for large data sets
### Testing Best Practices
- Write tests at multiple levels (unit, integration, system)
- Use test doubles (mocks, stubs, spies) appropriately
- Aim for high code coverage
- Test happy paths and edge cases
- Incorporate testing into the development workflow