xiaohongshu
xiaohongshu
backend-service-patterns
Architect scalable backend services using layered architecture, dependency injection, middleware patterns, service classes, and separation of concerns. Use when building API services, implementing business logic layers, creating service classes, setting up middleware chains, implementing dependen...
Full skill instructions
Use when: Designing backend architecture, implementing APIs, handling business logic, managing microservices, or building serverless functions.
// ✅ Routes Layer - HTTP endpoints
// routes/users.ts
import express from 'express';
import { UserController } from '../controllers/UserController';
const router = express.Router();
const userController = new UserController();
router.get('/users', userController.list);
router.post('/users', userController.create);
router.get('/users/:id', userController.get);
export default router;
// ✅ Controller Layer - Request/response handling
// controllers/UserController.ts
import { Request, Response } from 'express';
import { UserService } from '../services/UserService';
import { CreateUserSchema } from '../schemas/user';
export class UserController {
private userService = new UserService();
list = async (req: Request, res: Response) => {
try {
const users = await this.userService.listUsers({
page: parseInt(req.query.page as string) || 1,
limit: parseInt(req.query.limit as string) || 20
});
res.json(users);
} catch (error) {
res.status(500).json({ error: 'Failed to fetch users' });
}
};
create = async (req: Request, res: Response) => {
try {
const validated = CreateUserSchema.parse(req.body);
const user = await this.userService.createUser(validated);
res.status(201).json(user);
} catch (error) {
res.status(400).json({ error: error.message });
}
};
}
// ✅ Service Layer - Business logic
// services/UserService.ts
import { UserRepository } from '../repositories/UserRepository';
import { EmailService } from './EmailService';
export class UserService {
private userRepo = new UserRepository();
private emailService = new EmailService();
async createUser(data: CreateUserInput) {
// Business logic here
const existingUser = await this.userRepo.findByEmail(data.email);
if (existingUser) {
throw new Error('Email already exists');
}
const hashedPassword = await bcrypt.hash(data.password, 10);
const user = await this.userRepo.create({
...data,
passwordHash: hashedPassword
});
// Send welcome email asynchronously
await this.emailService.sendWelcome(user.email);
return user;
}
async listUsers(params: { page: number; limit: number }) {
return await this.userRepo.findMany({
skip: (params.page - 1) * params.limit,
take: params.limit
});
}
}
// ✅ Repository Layer - Data access
// repositories/UserRepository.ts
import { prisma } from '../db';
export class UserRepository {
async create(data: CreateUserData) {
return await prisma.user.create({ data });
}
async findByEmail(email: string) {
return await prisma.user.findUnique({ where: { email } });
}
async findMany(params: { skip: number; take: number }) {
return await prisma.user.findMany(params);
}
}
// ✅ Constructor injection for testability
export class OrderService {
constructor(
private orderRepo: OrderRepository,
private paymentService: PaymentService,
private emailService: EmailService
) {}
async processOrder(orderId: string) {
const order = await this.orderRepo.findById(orderId);
const payment = await this.paymentService.charge(order);
await this.emailService.sendReceipt(order, payment);
return payment;
}
}
// Easy to mock in tests
const mockOrderRepo = {
findById: jest.fn().mockResolvedValue({ id: '1', total: 100 })
};
const mockPaymentService = {
charge: jest.fn().mockResolvedValue({ id: 'pay_123' })
};
const service = new OrderService(mockOrderRepo, mockPaymentService, mockEmailService);
// ✅ Abstract data access behind interface
interface IUserRepository {
create(data: CreateUserData): Promise<User>;
findById(id: string): Promise<User | null>;
update(id: string, data: UpdateUserData): Promise<User>;
delete(id: string): Promise<void>;
}
// PostgreSQL implementation
export class PostgresUserRepository implements IUserRepository {
async create(data: CreateUserData) {
return await prisma.user.create({ data });
}
async findById(id: string) {
return await prisma.user.findUnique({ where: { id } });
}
// ... other methods
}
// MongoDB implementation (easy to swap)
export class MongoUserRepository implements IUserRepository {
async create(data: CreateUserData) {
return await User.create(data);
}
// ... other methods
}
// ✅ Encapsulate business logic
export class OrderService {
async placeOrder(userId: string, items: OrderItem[]) {
// Validate inventory
for (const item of items) {
const product = await this.productRepo.findById(item.productId);
if (product.stock < item.quantity) {
throw new InsufficientStockError(item.productId);
}
}
// Calculate total
const total = items.reduce((sum, item) => sum + item.price * item.quantity, 0);
// Apply discount
const discount = await this.discountService.calculateDiscount(userId, total);
// Create order
const order = await this.orderRepo.create({
userId,
items,
subtotal: total,
discount,
total: total - discount,
status: 'pending'
});
// Reserve inventory
for (const item of items) {
await this.inventoryService.reserve(item.productId, item.quantity);
}
// Queue payment processing
await this.paymentQueue.add({ orderId: order.id });
return order;
}
}
// ✅ Create objects based on conditions
interface PaymentProvider {
charge(amount: number, currency: string): Promise<PaymentResult>;
}
class StripeProvider implements PaymentProvider {
async charge(amount: number, currency: string) {
return await stripe.charges.create({ amount, currency });
}
}
class PayPalProvider implements PaymentProvider {
async charge(amount: number, currency: string) {
return await paypal.payment.create({ amount, currency });
}
}
class PaymentProviderFactory {
static create(provider: string): PaymentProvider {
switch (provider) {
case 'stripe':
return new StripeProvider();
case 'paypal':
return new PayPalProvider();
default:
throw new Error(`Unknown provider: ${provider}`);
}
}
}
// Usage
const provider = PaymentProviderFactory.create(user.preferredPaymentMethod);
await provider.charge(100, 'USD');
// ✅ Swap algorithms at runtime
interface ShippingStrategy {
calculateCost(weight: number, distance: number): number;
}
class StandardShipping implements ShippingStrategy {
calculateCost(weight: number, distance: number) {
return weight * 0.5 + distance * 0.1;
}
}
class ExpressShipping implements ShippingStrategy {
calculateCost(weight: number, distance: number) {
return weight * 1.0 + distance * 0.3;
}
}
class OvernightShipping implements ShippingStrategy {
calculateCost(weight: number, distance: number) {
return weight * 2.0 + distance * 0.5;
}
}
class ShippingCalculator {
constructor(private strategy: ShippingStrategy) {}
calculate(weight: number, distance: number) {
return this.strategy.calculateCost(weight, distance);
}
}
// Usage
const calculator = new ShippingCalculator(new ExpressShipping());
const cost = calculator.calculate(10, 500);
// ✅ Decouple components with events
import { EventEmitter } from 'events';
class OrderEvents extends EventEmitter {
static CREATED = 'order.created';
static PAID = 'order.paid';
static SHIPPED = 'order.shipped';
static CANCELLED = 'order.cancelled';
}
const orderEvents = new OrderEvents();
// Listeners
orderEvents.on(OrderEvents.CREATED, async (order) => {
await emailService.sendOrderConfirmation(order);
await analyticsService.trackOrderCreated(order);
});
orderEvents.on(OrderEvents.PAID, async (order) => {
await inventoryService.deductStock(order.items);
await shippingService.createShipment(order);
});
// Emit events
export class OrderService {
async createOrder(data: CreateOrderData) {
const order = await this.orderRepo.create(data);
orderEvents.emit(OrderEvents.CREATED, order);
return order;
}
async markAsPaid(orderId: string) {
const order = await this.orderRepo.update(orderId, { status: 'paid' });
orderEvents.emit(OrderEvents.PAID, order);
return order;
}
}
// ✅ Single entry point for multiple services
import express from 'express';
import { createProxyMiddleware } from 'http-proxy-middleware';
const app = express();
// Route to different services
app.use('/api/users', createProxyMiddleware({
target: 'http://user-service:3001',
changeOrigin: true
}));
app.use('/api/orders', createProxyMiddleware({
target: 'http://order-service:3002',
changeOrigin: true
}));
app.use('/api/payments', createProxyMiddleware({
target: 'http://payment-service:3003',
changeOrigin: true
}));
// Add authentication, rate limiting, logging here
app.use(authMiddleware);
app.use(rateLimiter);
app.use(logger);
// ✅ HTTP/REST communication
export class UserService {
private orderServiceUrl = process.env.ORDER_SERVICE_URL;
async getUserWithOrders(userId: string) {
const user = await this.userRepo.findById(userId);
// Call order service
const response = await fetch(`${this.orderServiceUrl}/orders?userId=${userId}`);
const orders = await response.json();
return { ...user, orders };
}
}
// ✅ Message queue communication (async)
import { Queue } from 'bullmq';
const emailQueue = new Queue('emails', {
connection: { host: 'redis', port: 6379 }
});
// Producer (User Service)
export class UserService {
async createUser(data: CreateUserData) {
const user = await this.userRepo.create(data);
// Async notification
await emailQueue.add('welcome', {
userId: user.id,
email: user.email
});
return user;
}
}
// Consumer (Email Service)
import { Worker } from 'bullmq';
const worker = new Worker('emails', async (job) => {
if (job.name === 'welcome') {
await sendWelcomeEmail(job.data.email);
}
});
// ✅ Prevent cascading failures
import CircuitBreaker from 'opossum';
const options = {
timeout: 3000, // If function takes > 3s, trigger failure
errorThresholdPercentage: 50, // When 50% of requests fail...
resetTimeout: 30000 // ...open circuit for 30s
};
const breaker = new CircuitBreaker(callExternalAPI, options);
breaker.fallback(() => {
return { data: null, fromCache: true }; // Fallback response
});
breaker.on('open', () => {
console.log('Circuit breaker opened - too many failures');
});
async function callExternalAPI() {
const response = await fetch('https://external-api.com/data');
return response.json();
}
// Usage
try {
const data = await breaker.fire();
} catch (error) {
// Circuit is open or request failed
}
// ✅ AWS Lambda handler
import { APIGatewayProxyHandler } from 'aws-lambda';
export const handler: APIGatewayProxyHandler = async (event) => {
try {
const body = JSON.parse(event.body || '{}');
// Business logic
const result = await processOrder(body);
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify(result)
};
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify({ error: error.message })
};
}
};
// ✅ Vercel Edge Function
export const config = {
runtime: 'edge'
};
export default async function handler(request: Request) {
const data = await processData();
return new Response(JSON.stringify(data), {
headers: { 'content-type': 'application/json' }
});
}
// ✅ Initialize outside handler (persists across invocations)
import { PrismaClient } from '@prisma/client';
// Created once, reused across warm invocations
const prisma = new PrismaClient();
export const handler = async (event) => {
// This runs on every invocation
const users = await prisma.user.findMany();
return { statusCode: 200, body: JSON.stringify(users) };
};
// ✅ Lazy initialization
let connection: Connection | null = null;
async function getConnection() {
if (!connection) {
connection = await createConnection();
}
return connection;
}
export const handler = async (event) => {
const conn = await getConnection();
// Use connection
};
// ✅ BullMQ job processing
import { Queue, Worker } from 'bullmq';
const videoQueue = new Queue('video-processing', {
connection: { host: 'redis', port: 6379 }
});
// Add jobs
export class VideoService {
async uploadVideo(file: File) {
const video = await this.videoRepo.create({
filename: file.name,
status: 'pending'
});
// Queue processing job
await videoQueue.add('transcode', {
videoId: video.id,
inputPath: file.path
}, {
attempts: 3, // Retry up to 3 times
backoff: {
type: 'exponential',
delay: 5000 // 5s, 10s, 20s
}
});
return video;
}
}
// Worker process
const worker = new Worker('video-processing', async (job) => {
if (job.name === 'transcode') {
await transcodeVideo(job.data.videoId, job.data.inputPath);
// Update progress
job.updateProgress(50);
await generateThumbnail(job.data.videoId);
job.updateProgress(100);
}
}, {
connection: { host: 'redis', port: 6379 },
concurrency: 5 // Process 5 jobs concurrently
});
worker.on('completed', (job) => {
console.log(`Job ${job.id} completed`);
});
worker.on('failed', (job, err) => {
console.error(`Job ${job.id} failed:`, err);
});
// ✅ Cron jobs with node-cron
import cron from 'node-cron';
// Run every day at midnight
cron.schedule('0 0 * * *', async () => {
await cleanupExpiredSessions();
await generateDailyReport();
});
// Run every 5 minutes
cron.schedule('*/5 * * * *', async () => {
await checkPaymentStatus();
});
// ✅ Or use BullMQ repeat
await queue.add('daily-report', {}, {
repeat: {
pattern: '0 0 * * *' // Cron expression
}
});
// ✅ Environment-based config
export const config = {
port: parseInt(process.env.PORT || '3000'),
database: {
url: process.env.DATABASE_URL,
poolSize: parseInt(process.env.DB_POOL_SIZE || '10')
},
redis: {
host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT || '6379')
},
jwt: {
secret: process.env.JWT_SECRET,
expiresIn: '1h'
}
};
// Validate required vars on startup
const required = ['DATABASE_URL', 'JWT_SECRET'];
for (const key of required) {
if (!process.env[key]) {
throw new Error(`Missing required environment variable: ${key}`);
}
}
// ✅ Health check endpoint
app.get('/health', async (req, res) => {
const health = {
uptime: process.uptime(),
timestamp: Date.now(),
status: 'ok',
checks: {
database: 'ok',
redis: 'ok'
}
};
try {
await prisma.$queryRaw`SELECT 1`;
} catch (error) {
health.status = 'degraded';
health.checks.database = 'error';
}
try {
await redis.ping();
} catch (error) {
health.status = 'degraded';
health.checks.redis = 'error';
}
const statusCode = health.status === 'ok' ? 200 : 503;
res.status(statusCode).json(health);
});
Architecture:
□ Clear separation of concerns (routes/controllers/services/repos)
□ Dependency injection for testability
□ Business logic in service layer (not controllers)
□ Data access abstracted in repositories
□ No database queries in controllers
API Design:
□ RESTful endpoints
□ Proper HTTP methods and status codes
□ Input validation on all endpoints
□ Pagination for lists
□ API versioning strategy
Error Handling:
□ Try/catch in all async functions
□ Meaningful error messages
□ Proper error status codes
□ Error logging with context
□ No sensitive data in error responses
Performance:
□ Database queries optimized
□ Connection pooling configured
□ Caching strategy implemented
□ Background jobs for heavy operations
□ Rate limiting on public endpoints
Security:
□ Authentication required
□ Authorization checks
□ Input sanitization
□ SQL injection prevention
□ CORS configured properly
Monitoring:
□ Health check endpoint
□ Logging configured
□ Metrics collected
□ Error tracking (Sentry, etc.)
□ Performance monitoring
Remember: Great backend services are maintainable, testable, scalable, and resilient. Design for failure, optimize for readability.
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience