[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6JKEN69C26AFJSHJFPRPME9":3,"skill-same:01M6JKEN69C26AFJSHJFPRPME9":76},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":26,"publishedAt":47,"linkOnly":48,"markdownContent":49,"markdownBody":50,"frontMatter":51,"refName":53,"commitSha":54,"skillDirectory":55,"forksCount":56,"repositoryHtmlUrl":57,"repositoryHomepageUrl":58,"ownerHtmlUrl":59,"ownerBlogUrl":60,"ownerDescription":6,"updatedAt":61,"install":62,"resources":75},"01M6JKEN69C26AFJSHJFPRPME9","backend-patterns",null,"Backend architecture patterns, API design, database optimization, and server-side best practices for Node.js, Express, and Next.js API routes.","LongLeo287\u002FOmniClaw","LongLeo287","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F141803367?v=4","01M6JK75C62VCNZKR5BRZ386YV","LongLeo","01M6JK75GQ78TSP1ZPXNKK3MCH",9,"MIT","https:\u002F\u002Fgithub.com\u002FLongLeo287\u002FOmniClaw\u002Fblob\u002Fmain\u002Fbrain\u002Fknowledge\u002Frepositories\u002Feverything_claude_code\u002F.agents\u002Fskills\u002Fbackend_patterns\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",[27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],"patterns","backend","backend patterns","for","design","server-side","express","next","database optimization","node","js","Next.js","api","architecture patterns","Optimization","server","database","best practices","api design","architecture","2026-11-10 10:12:30",false,"---\nname: backend-patterns\ndescription: Backend architecture patterns, API design, database optimization, and server-side best practices for Node.js, Express, and Next.js API routes.\norigin: ECC\n---\n\n# Backend Development Patterns\n\nBackend architecture patterns and best practices for scalable server-side applications.\n\n## When to Activate\n\n- Designing REST or GraphQL API endpoints\n- Implementing repository, service, or controller layers\n- Optimizing database queries (N+1, indexing, connection pooling)\n- Adding caching (Redis, in-memory, HTTP cache headers)\n- Setting up background jobs or async processing\n- Structuring error handling and validation for APIs\n- Building middleware (auth, logging, rate limiting)\n\n## API Design Patterns\n\n### RESTful API Structure\n\n```typescript\n\u002F\u002F ✅ Resource-based URLs\nGET    \u002Fapi\u002Fmarkets                 # List resources\nGET    \u002Fapi\u002Fmarkets\u002F:id             # Get single resource\nPOST   \u002Fapi\u002Fmarkets                 # Create resource\nPUT    \u002Fapi\u002Fmarkets\u002F:id             # Replace resource\nPATCH  \u002Fapi\u002Fmarkets\u002F:id             # Update resource\nDELETE \u002Fapi\u002Fmarkets\u002F:id             # Delete resource\n\n\u002F\u002F ✅ Query parameters for filtering, sorting, pagination\nGET \u002Fapi\u002Fmarkets?status=active&sort=volume&limit=20&offset=0\n```\n\n### Repository Pattern\n\n```typescript\n\u002F\u002F Abstract data access logic\ninterface MarketRepository {\n  findAll(filters?: MarketFilters): Promise\u003CMarket[]>\n  findById(id: string): Promise\u003CMarket | null>\n  create(data: CreateMarketDto): Promise\u003CMarket>\n  update(id: string, data: UpdateMarketDto): Promise\u003CMarket>\n  delete(id: string): Promise\u003Cvoid>\n}\n\nclass SupabaseMarketRepository implements MarketRepository {\n  async findAll(filters?: MarketFilters): Promise\u003CMarket[]> {\n    let query = supabase.from('markets').select('*')\n\n    if (filters?.status) {\n      query = query.eq('status', filters.status)\n    }\n\n    if (filters?.limit) {\n      query = query.limit(filters.limit)\n    }\n\n    const { data, error } = await query\n\n    if (error) throw new Error(error.message)\n    return data\n  }\n\n  \u002F\u002F Other methods...\n}\n```\n\n### Service Layer Pattern\n\n```typescript\n\u002F\u002F Business logic separated from data access\nclass MarketService {\n  constructor(private marketRepo: MarketRepository) {}\n\n  async searchMarkets(query: string, limit: number = 10): Promise\u003CMarket[]> {\n    \u002F\u002F Business logic\n    const embedding = await generateEmbedding(query)\n    const results = await this.vectorSearch(embedding, limit)\n\n    \u002F\u002F Fetch full data\n    const markets = await this.marketRepo.findByIds(results.map(r => r.id))\n\n    \u002F\u002F Sort by similarity\n    return markets.sort((a, b) => {\n      const scoreA = results.find(r => r.id === a.id)?.score || 0\n      const scoreB = results.find(r => r.id === b.id)?.score || 0\n      return scoreA - scoreB\n    })\n  }\n\n  private async vectorSearch(embedding: number[], limit: number) {\n    \u002F\u002F Vector search implementation\n  }\n}\n```\n\n### Middleware Pattern\n\n```typescript\n\u002F\u002F Request\u002Fresponse processing pipeline\nexport function withAuth(handler: NextApiHandler): NextApiHandler {\n  return async (req, res) => {\n    const token = req.headers.authorization?.replace('Bearer ', '')\n\n    if (!token) {\n      return res.status(401).json({ error: 'Unauthorized' })\n    }\n\n    try {\n      const user = await verifyToken(token)\n      req.user = user\n      return handler(req, res)\n    } catch (error) {\n      return res.status(401).json({ error: 'Invalid token' })\n    }\n  }\n}\n\n\u002F\u002F Usage\nexport default withAuth(async (req, res) => {\n  \u002F\u002F Handler has access to req.user\n})\n```\n\n## Database Patterns\n\n### Query Optimization\n\n```typescript\n\u002F\u002F ✅ GOOD: Select only needed columns\nconst { data } = await supabase\n  .from('markets')\n  .select('id, name, status, volume')\n  .eq('status', 'active')\n  .order('volume', { ascending: false })\n  .limit(10)\n\n\u002F\u002F ❌ BAD: Select everything\nconst { data } = await supabase\n  .from('markets')\n  .select('*')\n```\n\n### N+1 Query Prevention\n\n```typescript\n\u002F\u002F ❌ BAD: N+1 query problem\nconst markets = await getMarkets()\nfor (const market of markets) {\n  market.creator = await getUser(market.creator_id)  \u002F\u002F N queries\n}\n\n\u002F\u002F ✅ GOOD: Batch fetch\nconst markets = await getMarkets()\nconst creatorIds = markets.map(m => m.creator_id)\nconst creators = await getUsers(creatorIds)  \u002F\u002F 1 query\nconst creatorMap = new Map(creators.map(c => [c.id, c]))\n\nmarkets.forEach(market => {\n  market.creator = creatorMap.get(market.creator_id)\n})\n```\n\n### Transaction Pattern\n\n```typescript\nasync function createMarketWithPosition(\n  marketData: CreateMarketDto,\n  positionData: CreatePositionDto\n) {\n  \u002F\u002F Use Supabase transaction\n  const { data, error } = await supabase.rpc('create_market_with_position', {\n    market_data: marketData,\n    position_data: positionData\n  })\n\n  if (error) throw new Error('Transaction failed')\n  return data\n}\n\n\u002F\u002F SQL function in Supabase\nCREATE OR REPLACE FUNCTION create_market_with_position(\n  market_data jsonb,\n  position_data jsonb\n)\nRETURNS jsonb\nLANGUAGE plpgsql\nAS $$\nBEGIN\n  -- Start transaction automatically\n  INSERT INTO markets VALUES (market_data);\n  INSERT INTO positions VALUES (position_data);\n  RETURN jsonb_build_object('success', true);\nEXCEPTION\n  WHEN OTHERS THEN\n    -- Rollback happens automatically\n    RETURN jsonb_build_object('success', false, 'error', SQLERRM);\nEND;\n$$;\n```\n\n## Caching Strategies\n\n### Redis Caching Layer\n\n```typescript\nclass CachedMarketRepository implements MarketRepository {\n  constructor(\n    private baseRepo: MarketRepository,\n    private redis: RedisClient\n  ) {}\n\n  async findById(id: string): Promise\u003CMarket | null> {\n    \u002F\u002F Check cache first\n    const cached = await this.redis.get(`market:${id}`)\n\n    if (cached) {\n      return JSON.parse(cached)\n    }\n\n    \u002F\u002F Cache miss - fetch from database\n    const market = await this.baseRepo.findById(id)\n\n    if (market) {\n      \u002F\u002F Cache for 5 minutes\n      await this.redis.setex(`market:${id}`, 300, JSON.stringify(market))\n    }\n\n    return market\n  }\n\n  async invalidateCache(id: string): Promise\u003Cvoid> {\n    await this.redis.del(`market:${id}`)\n  }\n}\n```\n\n### Cache-Aside Pattern\n\n```typescript\nasync function getMarketWithCache(id: string): Promise\u003CMarket> {\n  const cacheKey = `market:${id}`\n\n  \u002F\u002F Try cache\n  const cached = await redis.get(cacheKey)\n  if (cached) return JSON.parse(cached)\n\n  \u002F\u002F Cache miss - fetch from DB\n  const market = await db.markets.findUnique({ where: { id } })\n\n  if (!market) throw new Error('Market not found')\n\n  \u002F\u002F Update cache\n  await redis.setex(cacheKey, 300, JSON.stringify(market))\n\n  return market\n}\n```\n\n## Error Handling Patterns\n\n### Centralized Error Handler\n\n```typescript\nclass ApiError extends Error {\n  constructor(\n    public statusCode: number,\n    public message: string,\n    public isOperational = true\n  ) {\n    super(message)\n    Object.setPrototypeOf(this, ApiError.prototype)\n  }\n}\n\nexport function errorHandler(error: unknown, req: Request): Response {\n  if (error instanceof ApiError) {\n    return NextResponse.json({\n      success: false,\n      error: error.message\n    }, { status: error.statusCode })\n  }\n\n  if (error instanceof z.ZodError) {\n    return NextResponse.json({\n      success: false,\n      error: 'Validation failed',\n      details: error.errors\n    }, { status: 400 })\n  }\n\n  \u002F\u002F Log unexpected errors\n  console.error('Unexpected error:', error)\n\n  return NextResponse.json({\n    success: false,\n    error: 'Internal server error'\n  }, { status: 500 })\n}\n\n\u002F\u002F Usage\nexport async function GET(request: Request) {\n  try {\n    const data = await fetchData()\n    return NextResponse.json({ success: true, data })\n  } catch (error) {\n    return errorHandler(error, request)\n  }\n}\n```\n\n### Retry with Exponential Backoff\n\n```typescript\nasync function fetchWithRetry\u003CT>(\n  fn: () => Promise\u003CT>,\n  maxRetries = 3\n): Promise\u003CT> {\n  let lastError: Error\n\n  for (let i = 0; i \u003C maxRetries; i++) {\n    try {\n      return await fn()\n    } catch (error) {\n      lastError = error as Error\n\n      if (i \u003C maxRetries - 1) {\n        \u002F\u002F Exponential backoff: 1s, 2s, 4s\n        const delay = Math.pow(2, i) * 1000\n        await new Promise(resolve => setTimeout(resolve, delay))\n      }\n    }\n  }\n\n  throw lastError!\n}\n\n\u002F\u002F Usage\nconst data = await fetchWithRetry(() => fetchFromAPI())\n```\n\n## Authentication & Authorization\n\n### JWT Token Validation\n\n```typescript\nimport jwt from 'jsonwebtoken'\n\ninterface JWTPayload {\n  userId: string\n  email: string\n  role: 'admin' | 'user'\n}\n\nexport function verifyToken(token: string): JWTPayload {\n  try {\n    const payload = jwt.verify(token, process.env.JWT_SECRET!) as JWTPayload\n    return payload\n  } catch (error) {\n    throw new ApiError(401, 'Invalid token')\n  }\n}\n\nexport async function requireAuth(request: Request) {\n  const token = request.headers.get('authorization')?.replace('Bearer ', '')\n\n  if (!token) {\n    throw new ApiError(401, 'Missing authorization token')\n  }\n\n  return verifyToken(token)\n}\n\n\u002F\u002F Usage in API route\nexport async function GET(request: Request) {\n  const user = await requireAuth(request)\n\n  const data = await getDataForUser(user.userId)\n\n  return NextResponse.json({ success: true, data })\n}\n```\n\n### Role-Based Access Control\n\n```typescript\ntype Permission = 'read' | 'write' | 'delete' | 'admin'\n\ninterface User {\n  id: string\n  role: 'admin' | 'moderator' | 'user'\n}\n\nconst rolePermissions: Record\u003CUser['role'], Permission[]> = {\n  admin: ['read', 'write', 'delete', 'admin'],\n  moderator: ['read', 'write', 'delete'],\n  user: ['read', 'write']\n}\n\nexport function hasPermission(user: User, permission: Permission): boolean {\n  return rolePermissions[user.role].includes(permission)\n}\n\nexport function requirePermission(permission: Permission) {\n  return (handler: (request: Request, user: User) => Promise\u003CResponse>) => {\n    return async (request: Request) => {\n      const user = await requireAuth(request)\n\n      if (!hasPermission(user, permission)) {\n        throw new ApiError(403, 'Insufficient permissions')\n      }\n\n      return handler(request, user)\n    }\n  }\n}\n\n\u002F\u002F Usage - HOF wraps the handler\nexport const DELETE = requirePermission('delete')(\n  async (request: Request, user: User) => {\n    \u002F\u002F Handler receives authenticated user with verified permission\n    return new Response('Deleted', { status: 200 })\n  }\n)\n```\n\n## Rate Limiting\n\n### Simple In-Memory Rate Limiter\n\n```typescript\nclass RateLimiter {\n  private requests = new Map\u003Cstring, number[]>()\n\n  async checkLimit(\n    identifier: string,\n    maxRequests: number,\n    windowMs: number\n  ): Promise\u003Cboolean> {\n    const now = Date.now()\n    const requests = this.requests.get(identifier) || []\n\n    \u002F\u002F Remove old requests outside window\n    const recentRequests = requests.filter(time => now - time \u003C windowMs)\n\n    if (recentRequests.length >= maxRequests) {\n      return false  \u002F\u002F Rate limit exceeded\n    }\n\n    \u002F\u002F Add current request\n    recentRequests.push(now)\n    this.requests.set(identifier, recentRequests)\n\n    return true\n  }\n}\n\nconst limiter = new RateLimiter()\n\nexport async function GET(request: Request) {\n  const ip = request.headers.get('x-forwarded-for') || 'unknown'\n\n  const allowed = await limiter.checkLimit(ip, 100, 60000)  \u002F\u002F 100 req\u002Fmin\n\n  if (!allowed) {\n    return NextResponse.json({\n      error: 'Rate limit exceeded'\n    }, { status: 429 })\n  }\n\n  \u002F\u002F Continue with request\n}\n```\n\n## Background Jobs & Queues\n\n### Simple Queue Pattern\n\n```typescript\nclass JobQueue\u003CT> {\n  private queue: T[] = []\n  private processing = false\n\n  async add(job: T): Promise\u003Cvoid> {\n    this.queue.push(job)\n\n    if (!this.processing) {\n      this.process()\n    }\n  }\n\n  private async process(): Promise\u003Cvoid> {\n    this.processing = true\n\n    while (this.queue.length > 0) {\n      const job = this.queue.shift()!\n\n      try {\n        await this.execute(job)\n      } catch (error) {\n        console.error('Job failed:', error)\n      }\n    }\n\n    this.processing = false\n  }\n\n  private async execute(job: T): Promise\u003Cvoid> {\n    \u002F\u002F Job execution logic\n  }\n}\n\n\u002F\u002F Usage for indexing markets\ninterface IndexJob {\n  marketId: string\n}\n\nconst indexQueue = new JobQueue\u003CIndexJob>()\n\nexport async function POST(request: Request) {\n  const { marketId } = await request.json()\n\n  \u002F\u002F Add to queue instead of blocking\n  await indexQueue.add({ marketId })\n\n  return NextResponse.json({ success: true, message: 'Job queued' })\n}\n```\n\n## Logging & Monitoring\n\n### Structured Logging\n\n```typescript\ninterface LogContext {\n  userId?: string\n  requestId?: string\n  method?: string\n  path?: string\n  [key: string]: unknown\n}\n\nclass Logger {\n  log(level: 'info' | 'warn' | 'error', message: string, context?: LogContext) {\n    const entry = {\n      timestamp: new Date().toISOString(),\n      level,\n      message,\n      ...context\n    }\n\n    console.log(JSON.stringify(entry))\n  }\n\n  info(message: string, context?: LogContext) {\n    this.log('info', message, context)\n  }\n\n  warn(message: string, context?: LogContext) {\n    this.log('warn', message, context)\n  }\n\n  error(message: string, error: Error, context?: LogContext) {\n    this.log('error', message, {\n      ...context,\n      error: error.message,\n      stack: error.stack\n    })\n  }\n}\n\nconst logger = new Logger()\n\n\u002F\u002F Usage\nexport async function GET(request: Request) {\n  const requestId = crypto.randomUUID()\n\n  logger.info('Fetching markets', {\n    requestId,\n    method: 'GET',\n    path: '\u002Fapi\u002Fmarkets'\n  })\n\n  try {\n    const markets = await fetchMarkets()\n    return NextResponse.json({ success: true, data: markets })\n  } catch (error) {\n    logger.error('Failed to fetch markets', error as Error, { requestId })\n    return NextResponse.json({ error: 'Internal error' }, { status: 500 })\n  }\n}\n```\n\n**Remember**: Backend patterns enable scalable, maintainable server-side applications. Choose patterns that fit your complexity level.\n","# Backend Development Patterns\n\nBackend architecture patterns and best practices for scalable server-side applications.\n\n## When to Activate\n\n- Designing REST or GraphQL API endpoints\n- Implementing repository, service, or controller layers\n- Optimizing database queries (N+1, indexing, connection pooling)\n- Adding caching (Redis, in-memory, HTTP cache headers)\n- Setting up background jobs or async processing\n- Structuring error handling and validation for APIs\n- Building middleware (auth, logging, rate limiting)\n\n## API Design Patterns\n\n### RESTful API Structure\n\n```typescript\n\u002F\u002F ✅ Resource-based URLs\nGET    \u002Fapi\u002Fmarkets                 # List resources\nGET    \u002Fapi\u002Fmarkets\u002F:id             # Get single resource\nPOST   \u002Fapi\u002Fmarkets                 # Create resource\nPUT    \u002Fapi\u002Fmarkets\u002F:id             # Replace resource\nPATCH  \u002Fapi\u002Fmarkets\u002F:id             # Update resource\nDELETE \u002Fapi\u002Fmarkets\u002F:id             # Delete resource\n\n\u002F\u002F ✅ Query parameters for filtering, sorting, pagination\nGET \u002Fapi\u002Fmarkets?status=active&sort=volume&limit=20&offset=0\n```\n\n### Repository Pattern\n\n```typescript\n\u002F\u002F Abstract data access logic\ninterface MarketRepository {\n  findAll(filters?: MarketFilters): Promise\u003CMarket[]>\n  findById(id: string): Promise\u003CMarket | null>\n  create(data: CreateMarketDto): Promise\u003CMarket>\n  update(id: string, data: UpdateMarketDto): Promise\u003CMarket>\n  delete(id: string): Promise\u003Cvoid>\n}\n\nclass SupabaseMarketRepository implements MarketRepository {\n  async findAll(filters?: MarketFilters): Promise\u003CMarket[]> {\n    let query = supabase.from('markets').select('*')\n\n    if (filters?.status) {\n      query = query.eq('status', filters.status)\n    }\n\n    if (filters?.limit) {\n      query = query.limit(filters.limit)\n    }\n\n    const { data, error } = await query\n\n    if (error) throw new Error(error.message)\n    return data\n  }\n\n  \u002F\u002F Other methods...\n}\n```\n\n### Service Layer Pattern\n\n```typescript\n\u002F\u002F Business logic separated from data access\nclass MarketService {\n  constructor(private marketRepo: MarketRepository) {}\n\n  async searchMarkets(query: string, limit: number = 10): Promise\u003CMarket[]> {\n    \u002F\u002F Business logic\n    const embedding = await generateEmbedding(query)\n    const results = await this.vectorSearch(embedding, limit)\n\n    \u002F\u002F Fetch full data\n    const markets = await this.marketRepo.findByIds(results.map(r => r.id))\n\n    \u002F\u002F Sort by similarity\n    return markets.sort((a, b) => {\n      const scoreA = results.find(r => r.id === a.id)?.score || 0\n      const scoreB = results.find(r => r.id === b.id)?.score || 0\n      return scoreA - scoreB\n    })\n  }\n\n  private async vectorSearch(embedding: number[], limit: number) {\n    \u002F\u002F Vector search implementation\n  }\n}\n```\n\n### Middleware Pattern\n\n```typescript\n\u002F\u002F Request\u002Fresponse processing pipeline\nexport function withAuth(handler: NextApiHandler): NextApiHandler {\n  return async (req, res) => {\n    const token = req.headers.authorization?.replace('Bearer ', '')\n\n    if (!token) {\n      return res.status(401).json({ error: 'Unauthorized' })\n    }\n\n    try {\n      const user = await verifyToken(token)\n      req.user = user\n      return handler(req, res)\n    } catch (error) {\n      return res.status(401).json({ error: 'Invalid token' })\n    }\n  }\n}\n\n\u002F\u002F Usage\nexport default withAuth(async (req, res) => {\n  \u002F\u002F Handler has access to req.user\n})\n```\n\n## Database Patterns\n\n### Query Optimization\n\n```typescript\n\u002F\u002F ✅ GOOD: Select only needed columns\nconst { data } = await supabase\n  .from('markets')\n  .select('id, name, status, volume')\n  .eq('status', 'active')\n  .order('volume', { ascending: false })\n  .limit(10)\n\n\u002F\u002F ❌ BAD: Select everything\nconst { data } = await supabase\n  .from('markets')\n  .select('*')\n```\n\n### N+1 Query Prevention\n\n```typescript\n\u002F\u002F ❌ BAD: N+1 query problem\nconst markets = await getMarkets()\nfor (const market of markets) {\n  market.creator = await getUser(market.creator_id)  \u002F\u002F N queries\n}\n\n\u002F\u002F ✅ GOOD: Batch fetch\nconst markets = await getMarkets()\nconst creatorIds = markets.map(m => m.creator_id)\nconst creators = await getUsers(creatorIds)  \u002F\u002F 1 query\nconst creatorMap = new Map(creators.map(c => [c.id, c]))\n\nmarkets.forEach(market => {\n  market.creator = creatorMap.get(market.creator_id)\n})\n```\n\n### Transaction Pattern\n\n```typescript\nasync function createMarketWithPosition(\n  marketData: CreateMarketDto,\n  positionData: CreatePositionDto\n) {\n  \u002F\u002F Use Supabase transaction\n  const { data, error } = await supabase.rpc('create_market_with_position', {\n    market_data: marketData,\n    position_data: positionData\n  })\n\n  if (error) throw new Error('Transaction failed')\n  return data\n}\n\n\u002F\u002F SQL function in Supabase\nCREATE OR REPLACE FUNCTION create_market_with_position(\n  market_data jsonb,\n  position_data jsonb\n)\nRETURNS jsonb\nLANGUAGE plpgsql\nAS $$\nBEGIN\n  -- Start transaction automatically\n  INSERT INTO markets VALUES (market_data);\n  INSERT INTO positions VALUES (position_data);\n  RETURN jsonb_build_object('success', true);\nEXCEPTION\n  WHEN OTHERS THEN\n    -- Rollback happens automatically\n    RETURN jsonb_build_object('success', false, 'error', SQLERRM);\nEND;\n$$;\n```\n\n## Caching Strategies\n\n### Redis Caching Layer\n\n```typescript\nclass CachedMarketRepository implements MarketRepository {\n  constructor(\n    private baseRepo: MarketRepository,\n    private redis: RedisClient\n  ) {}\n\n  async findById(id: string): Promise\u003CMarket | null> {\n    \u002F\u002F Check cache first\n    const cached = await this.redis.get(`market:${id}`)\n\n    if (cached) {\n      return JSON.parse(cached)\n    }\n\n    \u002F\u002F Cache miss - fetch from database\n    const market = await this.baseRepo.findById(id)\n\n    if (market) {\n      \u002F\u002F Cache for 5 minutes\n      await this.redis.setex(`market:${id}`, 300, JSON.stringify(market))\n    }\n\n    return market\n  }\n\n  async invalidateCache(id: string): Promise\u003Cvoid> {\n    await this.redis.del(`market:${id}`)\n  }\n}\n```\n\n### Cache-Aside Pattern\n\n```typescript\nasync function getMarketWithCache(id: string): Promise\u003CMarket> {\n  const cacheKey = `market:${id}`\n\n  \u002F\u002F Try cache\n  const cached = await redis.get(cacheKey)\n  if (cached) return JSON.parse(cached)\n\n  \u002F\u002F Cache miss - fetch from DB\n  const market = await db.markets.findUnique({ where: { id } })\n\n  if (!market) throw new Error('Market not found')\n\n  \u002F\u002F Update cache\n  await redis.setex(cacheKey, 300, JSON.stringify(market))\n\n  return market\n}\n```\n\n## Error Handling Patterns\n\n### Centralized Error Handler\n\n```typescript\nclass ApiError extends Error {\n  constructor(\n    public statusCode: number,\n    public message: string,\n    public isOperational = true\n  ) {\n    super(message)\n    Object.setPrototypeOf(this, ApiError.prototype)\n  }\n}\n\nexport function errorHandler(error: unknown, req: Request): Response {\n  if (error instanceof ApiError) {\n    return NextResponse.json({\n      success: false,\n      error: error.message\n    }, { status: error.statusCode })\n  }\n\n  if (error instanceof z.ZodError) {\n    return NextResponse.json({\n      success: false,\n      error: 'Validation failed',\n      details: error.errors\n    }, { status: 400 })\n  }\n\n  \u002F\u002F Log unexpected errors\n  console.error('Unexpected error:', error)\n\n  return NextResponse.json({\n    success: false,\n    error: 'Internal server error'\n  }, { status: 500 })\n}\n\n\u002F\u002F Usage\nexport async function GET(request: Request) {\n  try {\n    const data = await fetchData()\n    return NextResponse.json({ success: true, data })\n  } catch (error) {\n    return errorHandler(error, request)\n  }\n}\n```\n\n### Retry with Exponential Backoff\n\n```typescript\nasync function fetchWithRetry\u003CT>(\n  fn: () => Promise\u003CT>,\n  maxRetries = 3\n): Promise\u003CT> {\n  let lastError: Error\n\n  for (let i = 0; i \u003C maxRetries; i++) {\n    try {\n      return await fn()\n    } catch (error) {\n      lastError = error as Error\n\n      if (i \u003C maxRetries - 1) {\n        \u002F\u002F Exponential backoff: 1s, 2s, 4s\n        const delay = Math.pow(2, i) * 1000\n        await new Promise(resolve => setTimeout(resolve, delay))\n      }\n    }\n  }\n\n  throw lastError!\n}\n\n\u002F\u002F Usage\nconst data = await fetchWithRetry(() => fetchFromAPI())\n```\n\n## Authentication & Authorization\n\n### JWT Token Validation\n\n```typescript\nimport jwt from 'jsonwebtoken'\n\ninterface JWTPayload {\n  userId: string\n  email: string\n  role: 'admin' | 'user'\n}\n\nexport function verifyToken(token: string): JWTPayload {\n  try {\n    const payload = jwt.verify(token, process.env.JWT_SECRET!) as JWTPayload\n    return payload\n  } catch (error) {\n    throw new ApiError(401, 'Invalid token')\n  }\n}\n\nexport async function requireAuth(request: Request) {\n  const token = request.headers.get('authorization')?.replace('Bearer ', '')\n\n  if (!token) {\n    throw new ApiError(401, 'Missing authorization token')\n  }\n\n  return verifyToken(token)\n}\n\n\u002F\u002F Usage in API route\nexport async function GET(request: Request) {\n  const user = await requireAuth(request)\n\n  const data = await getDataForUser(user.userId)\n\n  return NextResponse.json({ success: true, data })\n}\n```\n\n### Role-Based Access Control\n\n```typescript\ntype Permission = 'read' | 'write' | 'delete' | 'admin'\n\ninterface User {\n  id: string\n  role: 'admin' | 'moderator' | 'user'\n}\n\nconst rolePermissions: Record\u003CUser['role'], Permission[]> = {\n  admin: ['read', 'write', 'delete', 'admin'],\n  moderator: ['read', 'write', 'delete'],\n  user: ['read', 'write']\n}\n\nexport function hasPermission(user: User, permission: Permission): boolean {\n  return rolePermissions[user.role].includes(permission)\n}\n\nexport function requirePermission(permission: Permission) {\n  return (handler: (request: Request, user: User) => Promise\u003CResponse>) => {\n    return async (request: Request) => {\n      const user = await requireAuth(request)\n\n      if (!hasPermission(user, permission)) {\n        throw new ApiError(403, 'Insufficient permissions')\n      }\n\n      return handler(request, user)\n    }\n  }\n}\n\n\u002F\u002F Usage - HOF wraps the handler\nexport const DELETE = requirePermission('delete')(\n  async (request: Request, user: User) => {\n    \u002F\u002F Handler receives authenticated user with verified permission\n    return new Response('Deleted', { status: 200 })\n  }\n)\n```\n\n## Rate Limiting\n\n### Simple In-Memory Rate Limiter\n\n```typescript\nclass RateLimiter {\n  private requests = new Map\u003Cstring, number[]>()\n\n  async checkLimit(\n    identifier: string,\n    maxRequests: number,\n    windowMs: number\n  ): Promise\u003Cboolean> {\n    const now = Date.now()\n    const requests = this.requests.get(identifier) || []\n\n    \u002F\u002F Remove old requests outside window\n    const recentRequests = requests.filter(time => now - time \u003C windowMs)\n\n    if (recentRequests.length >= maxRequests) {\n      return false  \u002F\u002F Rate limit exceeded\n    }\n\n    \u002F\u002F Add current request\n    recentRequests.push(now)\n    this.requests.set(identifier, recentRequests)\n\n    return true\n  }\n}\n\nconst limiter = new RateLimiter()\n\nexport async function GET(request: Request) {\n  const ip = request.headers.get('x-forwarded-for') || 'unknown'\n\n  const allowed = await limiter.checkLimit(ip, 100, 60000)  \u002F\u002F 100 req\u002Fmin\n\n  if (!allowed) {\n    return NextResponse.json({\n      error: 'Rate limit exceeded'\n    }, { status: 429 })\n  }\n\n  \u002F\u002F Continue with request\n}\n```\n\n## Background Jobs & Queues\n\n### Simple Queue Pattern\n\n```typescript\nclass JobQueue\u003CT> {\n  private queue: T[] = []\n  private processing = false\n\n  async add(job: T): Promise\u003Cvoid> {\n    this.queue.push(job)\n\n    if (!this.processing) {\n      this.process()\n    }\n  }\n\n  private async process(): Promise\u003Cvoid> {\n    this.processing = true\n\n    while (this.queue.length > 0) {\n      const job = this.queue.shift()!\n\n      try {\n        await this.execute(job)\n      } catch (error) {\n        console.error('Job failed:', error)\n      }\n    }\n\n    this.processing = false\n  }\n\n  private async execute(job: T): Promise\u003Cvoid> {\n    \u002F\u002F Job execution logic\n  }\n}\n\n\u002F\u002F Usage for indexing markets\ninterface IndexJob {\n  marketId: string\n}\n\nconst indexQueue = new JobQueue\u003CIndexJob>()\n\nexport async function POST(request: Request) {\n  const { marketId } = await request.json()\n\n  \u002F\u002F Add to queue instead of blocking\n  await indexQueue.add({ marketId })\n\n  return NextResponse.json({ success: true, message: 'Job queued' })\n}\n```\n\n## Logging & Monitoring\n\n### Structured Logging\n\n```typescript\ninterface LogContext {\n  userId?: string\n  requestId?: string\n  method?: string\n  path?: string\n  [key: string]: unknown\n}\n\nclass Logger {\n  log(level: 'info' | 'warn' | 'error', message: string, context?: LogContext) {\n    const entry = {\n      timestamp: new Date().toISOString(),\n      level,\n      message,\n      ...context\n    }\n\n    console.log(JSON.stringify(entry))\n  }\n\n  info(message: string, context?: LogContext) {\n    this.log('info', message, context)\n  }\n\n  warn(message: string, context?: LogContext) {\n    this.log('warn', message, context)\n  }\n\n  error(message: string, error: Error, context?: LogContext) {\n    this.log('error', message, {\n      ...context,\n      error: error.message,\n      stack: error.stack\n    })\n  }\n}\n\nconst logger = new Logger()\n\n\u002F\u002F Usage\nexport async function GET(request: Request) {\n  const requestId = crypto.randomUUID()\n\n  logger.info('Fetching markets', {\n    requestId,\n    method: 'GET',\n    path: '\u002Fapi\u002Fmarkets'\n  })\n\n  try {\n    const markets = await fetchMarkets()\n    return NextResponse.json({ success: true, data: markets })\n  } catch (error) {\n    logger.error('Failed to fetch markets', error as Error, { requestId })\n    return NextResponse.json({ error: 'Internal error' }, { status: 500 })\n  }\n}\n```\n\n**Remember**: Backend patterns enable scalable, maintainable server-side applications. Choose patterns that fit your complexity level.\n",{"name":5,"origin":52,"description":7},"ECC","main","c173cdffe08e788a99b91928a831b476b8434838","brain\u002Fknowledge\u002Frepositories\u002Feverything_claude_code\u002F.agents\u002Fskills\u002Fbackend_patterns",0,"https:\u002F\u002Fgithub.com\u002FLongLeo287\u002FOmniClaw","https:\u002F\u002Fportfolio-longleo.vercel.app\u002Flabs\u002Fomniclaw.html","https:\u002F\u002Fgithub.com\u002FLongLeo287","https:\u002F\u002Fwww.facebook.com\u002FResourceRookie2023","2026-09-30 00:58:05",{"source":8,"skillName":5,"commands":63,"prompt":73,"zipAvailable":74},[64,67,70],{"tool":65,"command":66},"npx","npx skills add LongLeo287\u002FOmniClaw --skill backend-patterns",{"tool":68,"command":69},"bunx","bunx skills add LongLeo287\u002FOmniClaw --skill backend-patterns",{"tool":71,"command":72},"pnpm","pnpm dlx skills add LongLeo287\u002FOmniClaw --skill backend-patterns","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FLongLeo287\u002FOmniClaw\u002Fblob\u002Fmain\u002Fbrain\u002Fknowledge\u002Frepositories\u002Feverything_claude_code\u002F.agents\u002Fskills\u002Fbackend_patterns\u002FSKILL.md",true,[],[77,115,135,162,178,205],{"skillNo":78,"name":79,"nameZh":6,"description":80,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":81,"categories":82,"keywords":95,"publishedAt":47},"01M6JR0KQP4MHT32TN40D9CBFX","UI-UX Pro Max","Advanced UI\u002FUX analysis and generation skills with data-driven patterns. Python scripts (core.py, search.py) for systematic UI pattern extraction, design system generation, and component search from curated data sources.","https:\u002F\u002Fgithub.com\u002FLongLeo287\u002FOmniClaw\u002Fblob\u002Fmain\u002Fecosystem\u002Fui_components\u002Fui_ux_pro_max\u002FSKILL.md",[83,84,87,92],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":85,"categoryName":86,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":88,"categoryName":89,"taxonomyType":90,"taxonomyTypeDesc":91},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",{"categoryNo":93,"categoryName":94,"taxonomyType":90,"taxonomyTypeDesc":91},"01JBSEEDCAT000000000000033","数据分析师",[96,97,98,99,100,101,31,102,103,104,105,106,107,108,109,110,111,112,113,114],"ux","ui","ui ux pro max","max","pro","ui ux","component","search","analysis","team","rd","ui-ux","active","systematic","scripts","pattern extraction","sources","advanced","data-driven",{"skillNo":116,"name":117,"nameZh":6,"description":118,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":119,"categories":120,"keywords":122,"publishedAt":47},"01M6JR0EF5AEQHP2FSTB57H05P","shadcn-ui","Expert guidance for integrating and building applications with shadcn\u002Fui components, including component discovery, installation, customization, and best practices.","https:\u002F\u002Fgithub.com\u002FLongLeo287\u002FOmniClaw\u002Fblob\u002Fmain\u002Fecosystem\u002Fui_components\u002Fshadcn_ui\u002FSKILL.md",[121],{"categoryNo":88,"categoryName":89,"taxonomyType":90,"taxonomyTypeDesc":91},[123,97,124,125,102,126,44,127,128,105,129,130,131,108,132,133,134,30],"shadcn","shadcn ui","components","core","applications","discovery","customization","guidance","expert","installation","ui components","with",{"skillNo":136,"name":137,"nameZh":6,"description":138,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":139,"categories":140,"keywords":144,"publishedAt":47},"01M6JR08F51BEN17RHFYX65WVE","zustand_store_ts","Create Zustand stores with TypeScript, subscribeWithSelector middleware, and proper state\u002Faction separation. Use when building React state management, creating global stores, or implementing reactive state patterns with Zustand.","https:\u002F\u002Fgithub.com\u002FLongLeo287\u002FOmniClaw\u002Fblob\u002Fmain\u002Fecosystem\u002Fskills\u002Fzustand_store_ts\u002FSKILL.md",[141],{"categoryNo":142,"categoryName":143,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发",[145,146,147,148,149,150,151,152,153,154,155,156,157,27,158,159,134,160,161],"zustand store ts","zustand","store","typescript","microsoft","react","create","state management","state","react state management","management","global","use","separation","middleware","action","implementing",{"skillNo":163,"name":146,"nameZh":6,"description":164,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":165,"categories":166,"keywords":167,"publishedAt":47},"01M6JR00TDMVAFFCZXZ04AN7Q7","Zustand state management guide. Use when working with store code (src\u002Fstore\u002F**), implementing actions, managing state, or creating slices. Triggers on Zustand store development, state management questions, or action implementation.","https:\u002F\u002Fgithub.com\u002FLongLeo287\u002FOmniClaw\u002Fblob\u002Fmain\u002Fecosystem\u002Fskills\u002Fzustand\u002FSKILL.md",[],[146,168,152,169,153,170,171,155,172,157,173,174,175,147,134,176,177,160,161],"development","code","actions","src","guide","implementation","zustand state","triggers","questions","zustand state management",{"skillNo":179,"name":180,"nameZh":6,"description":181,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":182,"categories":183,"keywords":188,"publishedAt":47},"01M6JQZSWV4KWJP112G6XHEP44","youtube_summarizer","Automatically fetch YouTube video transcripts, generate structured summaries, and send full transcripts to messaging platforms. Detects YouTube URLs and provides metadata, key insights, and downloadable transcripts.","https:\u002F\u002Fgithub.com\u002FLongLeo287\u002FOmniClaw\u002Fblob\u002Fmain\u002Fecosystem\u002Fskills\u002Fyoutube_summarizer\u002FSKILL.md",[184,187],{"categoryNo":185,"categoryName":186,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000016","图像与多媒体",{"categoryNo":85,"categoryName":86,"taxonomyType":21,"taxonomyTypeDesc":22},[189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204],"youtube","youtube summarizer","summarizer","generate","metadata","messaging","Video","fetch","telegram","transcription","summarization","structured","full","insights","transcripts","summaries",{"skillNo":206,"name":207,"nameZh":6,"description":208,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":209,"categories":210,"keywords":211,"publishedAt":47},"01M6JQZN3QJB6B77JGKJD62DQT","youtube_clipper","YouTube 视频智能剪辑工具。下载视频和字幕，AI 分析生成精细章节（几分钟级别）， 用户选择片段后自动剪辑、翻译字幕为中英双语、烧录字幕到视频，并生成总结文案。 使用场景：当用户需要剪辑 YouTube 视频、生成短视频片段、制作双语字幕版本时。 关键词：视频剪辑、YouTube、字幕翻译、双语字幕、视频下载、clip video","https:\u002F\u002Fgithub.com\u002FLongLeo287\u002FOmniClaw\u002Fblob\u002Fmain\u002Fecosystem\u002Fskills\u002Fyoutube_clipper\u002FSKILL.md",[],[189,212,213,195,214,215,216,217,218,219,220,221,222,223,224,225,226],"clipper","youtube clipper","Bash","下载","视频","生成","关键词","翻译","read","write","clip","总结","工具","文案","sonnet"]