Add Quick Reference and Common Mistakes sections to 14 skills

Enhanced skills with practical quick reference tables and common mistakes:

Skills updated:
- database-prisma: CRUD patterns, schema types, query examples
- caching-patterns: TTL guidelines, key patterns, cache layers
- observability-monitoring: Log levels, metrics, health checks
- middleware-patterns: Middleware order, async patterns, imports
- error-handling-patterns: Error classes, response format, codes
- repository-pattern: BaseRepository methods, query options
- deployment-kubernetes: kubectl commands, resource sizing
- configuration-management: Config types, Zod validation
- event-driven-architecture: Kafka concepts, event structure
- performance-optimization: Profiling, connection pooling
- service-layer-patterns: Layer responsibilities, DI patterns
- data-consistency-patterns: Saga patterns, idempotency
- inter-service-communication: Protocol selection, client setup
- cicd-advanced-patterns: Deployment strategies, rollback

All sections include:
- Quick Reference tables with practical patterns
- Common Mistakes with BAD/GOOD code examples
- Essential commands and imports

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Ho Ngoc Hai
2026-01-01 11:05:36 +07:00
parent 2cfe903ebb
commit a0dda79478
14 changed files with 1004 additions and 3 deletions

View File

@@ -275,6 +275,51 @@ async getWithCache(key: string): Promise<Data | null> {
- Review cache key patterns for efficiency
- Consider L1 cache hit rate (should be high)
## Quick Reference
| Cache Layer | Speed | Capacity | TTL | Scope |
|-------------|-------|----------|-----|-------|
| **L1 (Memory)** | <1ms | 10k keys | 60s-5min | Per instance |
| **L2 (Redis)** | <5ms | Large | Configurable | Shared |
**TTL Guidelines:**
| Data Type | TTL | Example |
|-----------|-----|---------|
| Session data | 15-60min | User sessions |
| Permissions | 5min | RBAC cache |
| User profiles | 10min | Profile data |
| Config | 30min | Feature flags |
| Static data | 1-2hr | Reference data |
**Key Patterns:**
```typescript
// Entity
`user:${userId}`
`session:${sessionId}`
// Entity + Sub-resource
`user:${userId}:permissions`
`user:${userId}:roles`
// List/Collection
`users:list:page:${page}`
`products:category:${categoryId}`
```
**Essential Operations:**
```typescript
// Get/Set
await cache.get<T>(key);
await cache.set(key, value, ttl);
// Get or fetch
await cache.getOrSet(key, fetchFn, ttl);
// Invalidate
await cache.del(key);
await cache.invalidatePattern('user:123:*');
```
## Resources
- [Multi-Layer Cache](../../services/iam-service/src/core/cache/multi-layer-cache.ts) - Multi-layer cache implementation

View File

@@ -440,6 +440,74 @@ jobs:
5. **Health Checks**: Monitor health continuously
6. **Gates**: Use deployment gates for critical deployments
## Common Mistakes
1. **No Rollback Plan**: Can't recover from failed deployment
```yaml
# ✅ Always have rollback command ready
kubectl rollout undo deployment/service
```
2. **Skipping Smoke Tests**: Catching issues too late
```yaml
# ✅ Run smoke tests immediately after deploy
- name: Smoke Tests
run: ./scripts/smoke-tests.sh
```
3. **100% Traffic Switch**: All-or-nothing failures
```yaml
# ❌ BAD: Immediate full switch
# ✅ GOOD: Gradual rollout (10% → 50% → 100%)
```
4. **No Health Monitoring**: Missing deployment issues
```yaml
# ✅ Monitor health after deployment
- name: Monitor Health
run: kubectl rollout status deployment/service --timeout=5m
```
## Quick Reference
| Strategy | Risk | Downtime | Resource Cost |
|----------|------|----------|---------------|
| **Blue-Green** | Low | Zero | 2x (temporary) |
| **Canary** | Low | Zero | +10-20% |
| **Rolling** | Medium | Zero | 1x |
| **Recreate** | High | Yes | 1x |
**Deployment Commands:**
```bash
# Apply deployment
kubectl apply -f kubernetes/
# Check rollout status
kubectl rollout status deployment/service
# Rollback
kubectl rollout undo deployment/service
# Canary traffic split (Istio)
kubectl apply -f virtualservice-canary.yaml
```
**GitHub Actions Triggers:**
```yaml
on:
push:
branches: [main] # Deploy to prod
tags: ['v*'] # Release
pull_request:
branches: [main] # PR checks
```
**Deployment Gates:**
```
Build → Test → Security Scan → Deploy Staging
→ Smoke Tests → Manual Approval → Deploy Prod
```
## Resources
- [Kubernetes Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)

View File

@@ -406,6 +406,84 @@ export function getAppConfig() {
5. **Reloading**: Support dynamic reloading where possible
6. **Monitoring**: Monitor configuration changes
## Common Mistakes
1. **Not Validating Config**: App crashes with cryptic errors
```typescript
// ❌ BAD: No validation
const port = process.env.PORT;
// ✅ GOOD: Validate at startup
const config = AppConfigSchema.parse(process.env);
```
2. **Committing Secrets**: Exposing credentials
```bash
# ❌ BAD: Secrets in code
JWT_SECRET=my-secret-key
# ✅ GOOD: Use .env.example with placeholders
JWT_SECRET=<your-jwt-secret>
```
3. **Feature Flags Without Fallback**: Breaking when flag not found
```typescript
// ❌ BAD: No fallback
if (await featureFlags.isEnabled('new-feature')) { ... }
// ✅ GOOD: Default to disabled
if (await featureFlags.isEnabled('new-feature') ?? false) { ... }
```
4. **Inconsistent Env Naming**: Confusion across environments
```bash
# ❌ BAD: Inconsistent
DB_URL, DATABASE_CONNECTION, postgres_url
# ✅ GOOD: Consistent pattern
DATABASE_URL, REDIS_URL, KAFKA_URL
```
## Quick Reference
| Config Type | Source | Example |
|-------------|--------|---------|
| **Static** | Environment vars | `DATABASE_URL` |
| **Dynamic** | Config service | `rate_limit_threshold` |
| **Secrets** | K8s Secrets/Vault | `JWT_SECRET` |
| **Feature Flags** | Database | `new_checkout_flow` |
**Environment Variable Naming:**
```bash
# Pattern: SERVICE_CATEGORY_NAME
DATABASE_URL # Connection strings
REDIS_HOST # Service hosts
JWT_SECRET # Secrets (use K8s secrets)
LOG_LEVEL # Configuration
FEATURE_NEW_UI # Feature flags
```
**Zod Validation Pattern:**
```typescript
const ConfigSchema = z.object({
port: z.coerce.number().default(3000),
nodeEnv: z.enum(['development', 'staging', 'production']),
databaseUrl: z.string().url(),
logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
});
export const config = ConfigSchema.parse(process.env);
```
**Feature Flag Check Pattern:**
```typescript
// Simple check
const enabled = await featureFlags.isEnabled('feature-key');
// With user context (for gradual rollout)
const enabled = await featureFlags.isEnabled('feature-key', userId);
```
## Resources
- [Feature Flags Pattern](https://martinfowler.com/articles/feature-toggles.html)

View File

@@ -692,6 +692,85 @@ describe('OrderProcessingSaga', () => {
});
```
## Common Mistakes
1. **No Compensation Logic**: Saga steps without rollback
```typescript
// ❌ BAD: No compensation
steps: [{ execute: () => createOrder() }]
// ✅ GOOD: Always define compensation
steps: [{
execute: () => createOrder(),
compensate: (ctx) => cancelOrder(ctx.orderId)
}]
```
2. **Missing Idempotency**: Duplicate processing on retry
```typescript
// ❌ BAD: Creates duplicate
await createPayment(orderId);
// ✅ GOOD: Idempotent check
const existing = await findPayment(idempotencyKey);
if (existing) return existing;
await createPayment(orderId);
```
3. **Ignoring Partial Failures**: Not handling step failures
```typescript
// ❌ BAD: No error handling
await step1(); await step2(); await step3();
// ✅ GOOD: Saga orchestration
await sagaOrchestrator.execute(context);
```
4. **No Version Field**: Concurrent update conflicts
```prisma
// ✅ Add version for optimistic locking
model Entity {
version Int @default(1)
}
```
## Quick Reference
| Pattern | Use Case | Complexity |
|---------|----------|------------|
| **Saga (Orchestrated)** | Complex multi-step workflows | High |
| **Saga (Choreography)** | Simple event-driven flows | Medium |
| **Outbox Pattern** | Guaranteed event publishing | Medium |
| **Idempotency** | Retry-safe operations | Low |
| **Optimistic Lock** | Concurrent updates | Low |
**Saga Steps:**
```
Execute: Step1 → Step2 → Step3 → Complete
Compensate: ← Step2.undo ← Step1.undo (on failure)
```
**Idempotency Key Pattern:**
```typescript
const key = `${operation}:${userId}:${hash(requestData)}`;
await idempotencyHandler.execute(key, () => operation());
```
**Optimistic Lock Query:**
```typescript
await prisma.entity.update({
where: { id, version: currentVersion },
data: { ...updates, version: { increment: 1 } }
});
```
**Consistency Models:**
| Model | Latency | Use Case |
|-------|---------|----------|
| **Strong** | High | Financial transactions |
| **Eventual** | Low | Read models, analytics |
| **Causal** | Medium | User sessions |
## Resources
- [Saga Pattern](https://microservices.io/patterns/data/saga.html) - Saga pattern overview

View File

@@ -476,4 +476,107 @@ describe('UserRepository', () => {
- Keep migrations small and focused
- Test migrations before production
- Backup before major changes
- Monitor query performance
- Monitor query performance
## Common Mistakes
1. **N+1 Query Problem**: Fetching related data in a loop
```typescript
// ❌ BAD: N+1 queries
const users = await prisma.user.findMany();
for (const user of users) {
const posts = await prisma.post.findMany({ where: { authorId: user.id } });
}
// ✅ GOOD: Include relations
const users = await prisma.user.findMany({
include: { posts: true }
});
```
2. **No Indexes**: Missing indexes on frequently queried columns
```prisma
// ❌ BAD: No index
model User {
email String @unique
createdAt DateTime @default(now())
}
// ✅ GOOD: Add index for queries
model User {
email String @unique
createdAt DateTime @default(now())
@@index([createdAt])
}
```
3. **Raw Queries Without Parameters**: SQL injection risk
```typescript
// ❌ BAD: SQL injection risk
prisma.$queryRawUnsafe(`SELECT * FROM users WHERE email = '${email}'`);
// ✅ GOOD: Parameterized query
prisma.$queryRaw`SELECT * FROM users WHERE email = ${email}`;
```
4. **Not Using Transactions**: Data inconsistency risk
```typescript
// ❌ BAD: No transaction
await prisma.account.update({ where: { id: from }, data: { balance: { decrement: amount } } });
await prisma.account.update({ where: { id: to }, data: { balance: { increment: amount } } });
// ✅ GOOD: Use transaction
await prisma.$transaction([
prisma.account.update({ where: { id: from }, data: { balance: { decrement: amount } } }),
prisma.account.update({ where: { id: to }, data: { balance: { increment: amount } } })
]);
```
5. **Exposing Internal IDs**: Leaking database structure
```typescript
// ❌ BAD: Exposing auto-increment ID
model User { id Int @id @default(autoincrement()) }
// ✅ GOOD: Use CUID or UUID
model User { id String @id @default(cuid()) }
```
## Quick Reference
| Operation | Prisma Command |
|-----------|----------------|
| **Create migration** | `npx prisma migrate dev --name <name>` |
| **Apply migrations** | `npx prisma migrate deploy` |
| **Reset database** | `npx prisma migrate reset` |
| **Generate client** | `npx prisma generate` |
| **Open Prisma Studio** | `npx prisma studio` |
| **Seed database** | `npx prisma db seed` |
**Common Query Patterns:**
```typescript
// Find unique
await prisma.user.findUnique({ where: { id } });
// Find with relations
await prisma.user.findMany({ include: { posts: true } });
// Select specific fields
await prisma.user.findMany({ select: { id: true, email: true } });
// Pagination
await prisma.user.findMany({ skip: 10, take: 10 });
// Transaction
await prisma.$transaction(async (tx) => { /* operations */ });
```
**Schema Field Types:**
| Type | PostgreSQL | Description |
|------|------------|-------------|
| `String` | TEXT | Variable-length string |
| `Int` | INTEGER | 32-bit integer |
| `BigInt` | BIGINT | 64-bit integer |
| `Float` | DOUBLE PRECISION | Floating point |
| `Boolean` | BOOLEAN | True/false |
| `DateTime` | TIMESTAMP | Date and time |
| `Json` | JSONB | JSON data |

View File

@@ -484,4 +484,88 @@ kubectl describe pod pod-name -n goodgo | grep -A 5 Limits
6. **Monitoring**
- Expose metrics endpoint
- Set up alerts for critical issues
- Monitor resource usage and performance
- Monitor resource usage and performance
## Common Mistakes
1. **No Resource Limits**: Pods consuming all node resources
```yaml
# ❌ BAD: No limits
containers:
- name: app
image: app:latest
# ✅ GOOD: Set limits
containers:
- name: app
image: app:latest
resources:
requests: { memory: "256Mi", cpu: "250m" }
limits: { memory: "512Mi", cpu: "500m" }
```
2. **Missing Health Checks**: K8s can't detect unhealthy pods
```yaml
# ✅ Always add liveness and readiness probes
livenessProbe:
httpGet: { path: /health, port: 3000 }
initialDelaySeconds: 30
readinessProbe:
httpGet: { path: /ready, port: 3000 }
initialDelaySeconds: 5
```
3. **Hardcoded Secrets**: Exposing sensitive data
```yaml
# ❌ BAD: Hardcoded
env:
- name: DB_PASSWORD
value: "secret123"
# ✅ GOOD: Use secrets
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef: { name: db-secrets, key: password }
```
4. **Using `latest` Tag**: Unpredictable deployments
```yaml
# ❌ BAD
image: app:latest
# ✅ GOOD
image: app:v1.2.3
```
## Quick Reference
| Resource | Command |
|----------|---------|
| **Apply manifests** | `kubectl apply -f kubernetes/` |
| **Get pods** | `kubectl get pods -n goodgo` |
| **Get logs** | `kubectl logs -f deployment/app -n goodgo` |
| **Scale** | `kubectl scale deployment/app --replicas=5` |
| **Rollback** | `kubectl rollout undo deployment/app` |
| **Port forward** | `kubectl port-forward svc/app 3000:80` |
| **Exec into pod** | `kubectl exec -it pod-name -- /bin/sh` |
**Resource Sizing Guidelines:**
| Service Type | Memory Request | Memory Limit | CPU Request | CPU Limit |
|--------------|----------------|--------------|-------------|-----------|
| Microservice | 256Mi | 512Mi | 250m | 500m |
| API Gateway | 512Mi | 1Gi | 500m | 1000m |
| Database | 1Gi | 2Gi | 500m | 1000m |
**Health Check Defaults:**
```yaml
livenessProbe:
initialDelaySeconds: 30 # Wait for app startup
periodSeconds: 10 # Check every 10s
failureThreshold: 3 # Restart after 3 failures
readinessProbe:
initialDelaySeconds: 5 # Start checking early
periodSeconds: 5 # Check frequently
failureThreshold: 3 # Remove from LB after 3 failures
```

View File

@@ -312,6 +312,50 @@ Standardized error response format:
**Problem**: Stack traces visible in API responses
**Solution**: Ensure production environment checks are in place. Use error middleware to filter stack traces.
## Quick Reference
| Error Class | Status | When to Use |
|-------------|--------|-------------|
| `NotFoundError` | 404 | Resource not found |
| `BadRequestError` | 400 | Invalid request |
| `ValidationError` | 422 | Input validation failed |
| `UnauthorizedError` | 401 | Auth required |
| `ForbiddenError` | 403 | Access denied |
| `ConflictError` | 409 | Duplicate/conflict |
| `RateLimitError` | 429 | Too many requests |
| `InternalServerError` | 500 | Server error |
**Error Response Format:**
```typescript
{
success: false,
error: {
code: "RESOURCE_001",
message: "User not found",
details?: { /* validation details */ }
},
timestamp: "2024-01-01T00:00:00.000Z"
}
```
**Common Error Codes:**
| Code | Category | Description |
|------|----------|-------------|
| `AUTH_001` | Auth | Unauthorized |
| `AUTH_003` | Auth | Invalid token |
| `VALIDATION_001` | Validation | Validation failed |
| `RESOURCE_001` | Resource | Not found |
| `RESOURCE_002` | Resource | Already exists |
| `DB_001` | Database | Database error |
| `SYS_001` | System | Internal error |
**Essential Imports:**
```typescript
import { NotFoundError, ValidationError, ConflictError } from '../errors/http-error';
import { ErrorCode } from '../errors/error-codes';
import { asyncHandler } from '../middlewares/async.middleware';
```
## Resources
- [Error Classes](../../services/iam-service/src/errors/http-error.ts) - Base error classes

View File

@@ -1581,6 +1581,101 @@ eventSource.addEventListener('user.created', (event) => {
});
```
## Common Mistakes
1. **Blocking on Publish**: Slowing down request handlers
```typescript
// ❌ BAD: Await in request handler
await eventPublisher.publish('user.created', event);
res.json({ success: true });
// ✅ GOOD: Fire and forget with error logging
eventPublisher.publish('user.created', event)
.catch(err => logger.error('Failed to publish', { err }));
res.json({ success: true });
```
2. **No Idempotency**: Duplicate event processing issues
```typescript
// ❌ BAD: No duplicate check
async handle(event) {
await createUser(event.data);
}
// ✅ GOOD: Check for duplicates
async handle(event) {
if (await this.isProcessed(event.eventId)) return;
await createUser(event.data);
await this.markProcessed(event.eventId);
}
```
3. **Missing Partition Key**: Events for same entity out of order
```typescript
// ❌ BAD: No partition key
await publish('user.updated', event);
// ✅ GOOD: Use entity ID as partition key
await publish('user.updated', event, { partitionKey: userId });
```
4. **No Dead Letter Queue**: Lost events on failure
```typescript
// ✅ Always implement DLQ for failed events
after maxRetries → send to topic.dlq
```
## Quick Reference
| Concept | Description |
|---------|-------------|
| **Topic** | Named stream of events (e.g., `user.created`) |
| **Partition** | Division of topic for parallelism |
| **Consumer Group** | Consumers sharing workload |
| **Offset** | Position in partition |
**Event Structure:**
```typescript
{
eventId: "uuid", // Unique identifier
eventType: "user.created", // Event type
eventVersion: "1.0.0", // Schema version
timestamp: "ISO-8601", // When published
source: "auth-service", // Publisher service
correlationId: "uuid", // Request trace ID
data: { ... } // Event payload
}
```
**Topic Naming:**
```
{domain}.{action}
user.created
order.placed
payment.processed
```
**Essential Commands:**
```bash
# List topics
kafka-topics --list --bootstrap-server localhost:9092
# Create topic
kafka-topics --create --topic user.created --partitions 3
# Consume from beginning
kafka-console-consumer --topic user.created --from-beginning
```
**KafkaJS Quick Setup:**
```typescript
import { Kafka } from 'kafkajs';
const kafka = new Kafka({ brokers: ['localhost:9092'], clientId: 'my-app' });
const producer = kafka.producer();
const consumer = kafka.consumer({ groupId: 'my-group' });
```
## Resources
- [KafkaJS Documentation](https://kafka.js.org/) - Node.js Kafka client

View File

@@ -1079,6 +1079,86 @@ describe('Service Communication E2E', () => {
});
```
## Common Mistakes
1. **No Service Authentication**: Unsecured internal calls
```typescript
// ❌ BAD: No auth header
await client.get('/api/users');
// ✅ GOOD: Include service auth
await client.get('/api/users', {
headers: { 'x-service-auth': process.env.INTERNAL_API_KEY }
});
```
2. **Missing Timeouts**: Hanging requests
```typescript
// ❌ BAD: No timeout
await axios.get(url);
// ✅ GOOD: Set timeout
await axios.get(url, { timeout: 5000 });
```
3. **No Circuit Breaker**: Cascade failures
```typescript
// ✅ Use circuit breaker for external calls
await circuitBreaker.fire(() => serviceClient.get('/api/users'));
```
4. **Hardcoded Service URLs**: Breaks in different environments
```typescript
// ❌ BAD
const url = 'http://user-service:5000';
// ✅ GOOD
const url = process.env.USER_SERVICE_URL;
```
## Quick Reference
| Protocol | Use Case | Latency | Complexity |
|----------|----------|---------|------------|
| **REST** | External APIs, CRUD | Medium | Low |
| **gRPC** | Internal high-perf | Low | High |
| **GraphQL** | Flexible queries | Medium | Medium |
**Protocol Selection:**
```
External/Public API → REST
Internal service-to-service → gRPC
Complex data fetching → GraphQL
Real-time streaming → gRPC/WebSocket
```
**HTTP Client Setup:**
```typescript
import axios from 'axios';
const client = axios.create({
baseURL: process.env.SERVICE_URL,
timeout: 5000,
headers: { 'x-service-auth': process.env.INTERNAL_API_KEY }
});
```
**gRPC Client Setup:**
```typescript
const client = new GrpcClient({
protoPath: './proto/service.proto',
serviceName: 'UserService',
serverUrl: 'localhost:50051'
});
```
**Essential Headers:**
| Header | Purpose |
|--------|---------|
| `x-service-auth` | Internal authentication |
| `x-correlation-id` | Request tracing |
| `x-request-id` | Request identification |
## Resources
- [gRPC Documentation](https://grpc.io/docs/) - Official gRPC documentation

View File

@@ -264,6 +264,47 @@ export const requestLogger = (req: Request, res: Response, next: NextFunction) =
**Problem**: Unhandled promise rejections in async middleware
**Solution**: Use `asyncHandler` wrapper or wrap async code in try-catch with `next(error)`.
## Quick Reference
**Middleware Order (Critical):**
```
1. Security (helmet, cors)
2. Rate Limiting
3. Correlation ID
4. Body Parsing (json, urlencoded)
5. Request Logging
6. Metrics
7. Routes
8. Error Handling (LAST)
```
| Middleware Type | Signature | When to Use |
|-----------------|-----------|-------------|
| **Standard** | `(req, res, next) => void` | Sync operations |
| **Async** | `async (req, res, next) => Promise<void>` | Async operations |
| **Error** | `(err, req, res, next) => void` | Error handling |
**Common Patterns:**
```typescript
// Async wrapper
const asyncHandler = (fn) => (req, res, next) =>
Promise.resolve(fn(req, res, next)).catch(next);
// Conditional middleware
const conditionalMiddleware = (condition, middleware) =>
condition ? middleware : (req, res, next) => next();
// Factory pattern
const authenticate = (options = {}) => async (req, res, next) => { /* ... */ };
```
**Essential Imports:**
```typescript
import { Request, Response, NextFunction } from 'express';
import { z, ZodError } from 'zod';
import { logger } from '@goodgo/logger';
```
## Resources
- [Correlation Middleware](../../services/iam-service/src/middlewares/correlation.middleware.ts)

View File

@@ -489,4 +489,97 @@ groups:
- Alert on symptoms, not causes
- Include runbook links in alerts
- Avoid alert fatigue with proper thresholds
- Test alerting rules regularly
- Test alerting rules regularly
## Common Mistakes
1. **Logging Sensitive Data**: Exposing PII in logs
```typescript
// ❌ BAD: Logging sensitive data
logger.info('User login', { email, password, token });
// ✅ GOOD: Sanitize sensitive fields
logger.info('User login', { email, userId });
```
2. **High Cardinality Labels**: Too many metric label values
```typescript
// ❌ BAD: userId as label (millions of values)
httpRequests.labels(method, route, userId).inc();
// ✅ GOOD: Low cardinality labels only
httpRequests.labels(method, route, statusCode).inc();
```
3. **No Correlation IDs**: Can't trace requests across services
```typescript
// ❌ BAD: No correlation
logger.info('Processing request');
// ✅ GOOD: Include correlation ID
logger.info('Processing request', { correlationId: req.headers['x-correlation-id'] });
```
4. **Wrong Log Levels**: Using ERROR for non-errors
```typescript
// ❌ BAD: Wrong level
logger.error('User not found'); // Not an error, expected case
// ✅ GOOD: Appropriate level
logger.info('User not found', { userId });
logger.error('Database connection failed', { error });
```
5. **No Health Checks**: Service status unknown
```typescript
// ❌ BAD: No health endpoint
// ✅ GOOD: Comprehensive health checks
app.get('/health/live', livenessCheck);
app.get('/health/ready', readinessCheck);
```
## Quick Reference
| Pillar | Tool | Endpoint |
|--------|------|----------|
| **Logs** | Winston/Loki | stdout → Loki |
| **Metrics** | Prometheus | `/metrics` |
| **Traces** | Jaeger | `http://jaeger:14268` |
**Log Levels:**
| Level | When to Use |
|-------|-------------|
| `error` | Errors requiring attention |
| `warn` | Potential issues, degradation |
| `info` | Business events, state changes |
| `debug` | Development details |
**Essential Metrics:**
```typescript
// Request rate
rate(http_requests_total[5m])
// Error rate
rate(http_requests_total{status=~"5.."}[5m])
// Latency (p95)
histogram_quantile(0.95, http_request_duration_seconds_bucket)
// Active connections
active_connections
```
**Health Check Endpoints:**
| Endpoint | Purpose | Used By |
|----------|---------|---------|
| `/health/live` | Is process running? | K8s liveness probe |
| `/health/ready` | Ready for traffic? | K8s readiness probe |
| `/health` | Full status | Monitoring |
**Essential Imports:**
```typescript
import { logger } from '@goodgo/logger';
import { Counter, Histogram, Gauge } from 'prom-client';
import { trace, SpanStatusCode } from '@opentelemetry/api';
```

View File

@@ -360,6 +360,96 @@ export class CacheOptimizer {
5. **Profiling**: Profile regularly to identify bottlenecks
6. **Monitoring**: Monitor performance metrics continuously
## Common Mistakes
1. **N+1 Queries**: Fetching related data in loops
```typescript
// ❌ BAD: N+1
for (const user of users) {
user.orders = await orderRepo.findByUserId(user.id);
}
// ✅ GOOD: Use include
const users = await userRepo.findAll({ include: { orders: true } });
```
2. **No Connection Pooling**: Creating new connections per request
```typescript
// ❌ BAD: No pooling
const client = new PrismaClient(); // per request
// ✅ GOOD: Reuse singleton
import { prisma } from './db'; // shared instance
```
3. **Missing Indexes**: Slow queries on frequently searched columns
```prisma
// ✅ Add indexes in schema
@@index([createdAt])
@@index([userId, status])
```
4. **Unbounded Queries**: Fetching all data without limits
```typescript
// ❌ BAD
const all = await repo.findAll();
// ✅ GOOD
const page = await repo.findAll({ take: 100, skip: offset });
```
## Quick Reference
| Metric | Target | Alert Threshold |
|--------|--------|-----------------|
| **Response Time (p95)** | <200ms | >500ms |
| **Memory Usage** | <70% | >85% |
| **CPU Usage** | <60% | >80% |
| **Query Time** | <50ms | >200ms |
**Profiling Commands:**
```bash
# CPU profiling
node --prof app.js
node --prof-process isolate-*.log > profile.txt
# Memory snapshot
node --inspect app.js # Use Chrome DevTools
# Clinic.js
npx clinic doctor -- node app.js
npx clinic flame -- node app.js
```
**Prisma Query Optimization:**
```typescript
// Select only needed fields
await prisma.user.findMany({ select: { id: true, email: true } });
// Use include for relations
await prisma.user.findMany({ include: { posts: true } });
// Batch operations
await prisma.$transaction([...operations]);
// Raw query for complex cases
await prisma.$queryRaw`SELECT ... FROM ...`;
```
**Connection Pool Config:**
```bash
# In DATABASE_URL
?connection_limit=20&pool_timeout=10
```
**Performance Checklist:**
- [ ] Add database indexes for frequent queries
- [ ] Use pagination for list endpoints
- [ ] Implement caching for hot data
- [ ] Enable connection pooling
- [ ] Profile and monitor regularly
- [ ] Use batch operations for bulk updates
## Resources
- [Node.js Performance](https://nodejs.org/en/docs/guides/simple-profiling/)

View File

@@ -213,6 +213,60 @@ const usersWithRoles = await userRepository.findAll({
**Problem**: Slow queries or N+1 query problems
**Solution**: Use `include` to fetch related data in single query. Use `select` to limit fields. Add database indexes.
## Quick Reference
**BaseRepository Methods:**
| Method | Returns | Description |
|--------|---------|-------------|
| `findById(id)` | `T \| null` | Find by primary key |
| `findByUnique(field, value)` | `T \| null` | Find by unique field |
| `findAll(options)` | `T[]` | Find with filters |
| `create(data)` | `T` | Create entity |
| `update(id, data)` | `T` | Update entity |
| `delete(id)` | `void` | Delete entity |
| `count(where)` | `number` | Count entities |
| `exists(id)` | `boolean` | Check existence |
| `transaction(cb)` | `R` | Execute transaction |
**Query Options:**
```typescript
// Pagination
{ skip: 0, take: 10 }
// Filtering
{ where: { isActive: true } }
// Sorting
{ orderBy: { createdAt: 'desc' } }
// Relations
{ include: { roles: true } }
// Field selection
{ select: { id: true, email: true } }
```
**Repository Template:**
```typescript
export class EntityRepository extends BaseRepository<Entity, CreateDto, UpdateDto> {
constructor(prisma: PrismaClient) {
super(prisma, 'entity');
}
// Custom query methods
async findByField(value: string): Promise<Entity | null> {
return this.prisma.entity.findUnique({ where: { field: value } });
}
}
```
**Essential Imports:**
```typescript
import { PrismaClient } from '@prisma/client';
import { BaseRepository, IRepository } from '../modules/common/repository';
import { DatabaseError } from '../errors/http-error';
```
## Resources
- [BaseRepository](../../services/iam-service/src/modules/common/repository.ts) - Base repository implementation

View File

@@ -195,6 +195,53 @@ export class FeatureModule {
4. **No Error Handling**: Not throwing appropriate errors
5. **Business Logic in Controllers**: Moving business logic to controllers
## Quick Reference
**Service Responsibilities:**
| Layer | Responsibility | Example |
|-------|----------------|---------|
| **Controller** | HTTP handling, validation | Parse request, send response |
| **Service** | Business logic | Validate rules, orchestrate |
| **Repository** | Data access | CRUD operations |
**Service Template:**
```typescript
export class EntityService {
constructor(
private repository: EntityRepository,
private cache?: CacheService
) {}
async findById(id: string): Promise<Entity> {
const entity = await this.repository.findById(id);
if (!entity) throw new NotFoundError('Entity');
return entity;
}
async create(data: CreateDto): Promise<Entity> {
// Business validation
await this.validateBusinessRules(data);
return this.repository.create(data);
}
}
```
**Dependency Injection Pattern:**
```typescript
// Module setup
const repository = new EntityRepository(prisma);
const service = new EntityService(repository, cacheService);
const controller = new EntityController(service);
```
**Common Patterns:**
| Pattern | When to Use |
|---------|-------------|
| **Caching** | Frequently accessed data |
| **Composition** | Complex operations across domains |
| **Validation** | Business rule enforcement |
| **Logging** | Audit and debugging |
## Resources
- [Feature Service](../../services/iam-service/src/modules/feature/feature.service.ts) - Example service implementation