[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-a8d08023-3083-4ad0-be7d-29c6f664180c":3,"$fWZvxgyenSsEkkmLJhOlROmf0QFIIrj8FPGfIPI8RPm4":42},{"id":4,"title":5,"description":6,"categoryId":7,"moduleId":8,"tags":9,"prompt":10,"icon":11,"source":12,"sourceUrl":13,"authorId":14,"authorName":15,"isPublic":16,"stars":17,"runs":18,"createdAt":19,"updatedAt":19,"module":20,"category":27,"packages":33},"a8d08023-3083-4ad0-be7d-29c6f664180c","cc-skill-backend-patterns","后端架构模式、API设计、数据库优化以及Node.js、Express和Next.js API路由的服务端最佳实践。","cat_coding_backend","mod_coding","sickn33,coding","---\nname: cc-skill-backend-patterns\ndescription: \"Backend architecture patterns, API design, database optimization, and server-side best practices for Node.js, Express, and Next.js API routes.\"\nrisk: unknown\nsource: community\ndate_added: \"2026-02-27\"\n---\n\n# Backend Development Patterns\n\nBackend architecture patterns and best practices for scalable server-side applications.\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 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 user\n  }\n}\n\n\u002F\u002F Usage\nexport const DELETE = requirePermission('delete')(async (request: Request) => {\n  \u002F\u002F Handler with permission check\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\n## When to Use\nThis skill is applicable to execute the workflow or actions described in the overview.\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.\n","","imported","https:\u002F\u002Fgithub.com\u002Fsickn33\u002Fantigravity-awesome-skills","user_system_seed","SkillOPIC",true,125,2081,"2026-05-16 13:10:09",{"id":8,"name":21,"slug":22,"icon":23,"description":24,"sort":25,"createdAt":26},"编程开发","coding","mdi-code-braces","代码生成、调试、审查，提升开发效率",2,"2026-05-16 12:53:40",{"id":7,"name":28,"slug":29,"icon":30,"description":31,"moduleId":8,"sort":25,"skillCount":32,"createdAt":26},"后端开发","backend","mdi-server","API、数据库、服务端架构",296,[34],{"id":35,"skillId":4,"version":36,"fileName":37,"fileSize":38,"filePath":39,"fileHash":40,"manifest":41,"createdAt":19},"c92ba9e0-4872-42a0-924c-f2f1fc4eb97e","1.0.0","cc-skill-backend-patterns.zip",4697,"uploads\u002Fskills\u002Fa8d08023-3083-4ad0-be7d-29c6f664180c\u002Fcc-skill-backend-patterns.zip","6f711e9b145827f9b3a2564f9d7aadee917ea9c5fb766126ef5650e86b7ddc9b","[{\"path\":\"SKILL.md\",\"isDirectory\":false,\"size\":13665}]",{"code":43,"message":44,"data":45},200,"success",{"items":46,"stats":47,"page":50},[],{"averageRating":48,"totalRatings":48,"ratingCounts":49},0,[48,48,48,48,48],{"limit":51,"offset":48,"hasMore":52,"nextOffset":51,"ratedOnly":16},15,false]