用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/diegosouzapw/awesome-omni-skill --skill backend命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | backend |
| description | API, database, server logic, webhooks. Auto-use for any API/DB work. |
| version | 3.0.0 |
| allowed-tools | ["Read","Edit","Write","Bash","Grep","Glob"] |
Auto-use when: API, route, endpoint, database, Supabase, schema, migration, webhook, server action
Works with: frontend for UI, security for auth patterns
export async function POST(request: Request) {
// 1. AUTH (required)
const { userId } = await auth()
if (!userId) return Response.json({ error: 'Unauthorized' }, { status: })
body = request.()
result = .(body)
(!result.) {
.({ : , : result..() }, { : })
}
resource = db.({ : { : result.. } })
(resource?. !== userId) {
.({ : }, { : })
}
{
data = db.({ : result. })
.(data, { : })
} (error) {
.(, error)
.({ : }, { : })
}
}
'use server'
import { auth } from '@/lib/auth'
import { db } from '@/lib/db'
import { revalidatePath } from 'next/cache'
import { z } from 'zod'
const Schema = z.object({
title: z.string().min(1).max(200),
})
export async function createPost(input: unknown) {
const { userId } = await auth()
if (!userId) return { error: 'Unauthorized' }
const result = Schema.safeParse(input)
if (!result.success) return { error: 'Invalid', details: result.error.flatten() }
try {
const post = await db.post.create({
data: { ...result.data, authorId: userId }
})
revalidatePath('/posts')
return { data: post }
} catch (error) {
console.error('Error:', error)
return { error: 'Failed' }
}
}
// N+1 Prevention - ALWAYS use includes
const posts = await db.post.findMany({
include: { author: true } // NOT separate query
})
// Pagination - ALWAYS paginate lists
const posts = await db.post.findMany({
skip: (page - 1) * limit,
take: limit,
orderBy: { createdAt: 'desc' }
})
// Correct types
// IDs: BIGINT (not INT)
// Timestamps: TIMESTAMPTZ (not TIMESTAMP)
// Money: DECIMAL (not FLOAT)
export async function POST(request: Request) {
const body = await request.text()
const signature = headers().get('stripe-signature')!
// 1. Verify signature
let event
try {
event = stripe.webhooks.constructEvent(body, signature, secret)
} catch {
return new Response('Invalid signature', { status: 400 })
}
// 2. Idempotency check
const exists = await db.webhookEvent.findUnique({ where: { eventId: event.id } })
if (exists) return new Response('Already processed')
// 3. Process
switch (event.type) {
case 'checkout.session.completed':
await handleCheckout(event.data.object)
break
}
// 4. Mark processed
await db.webhookEvent.create({ data: { eventId: event.id } })
return new Response('OK')
}
app/api/users/route.ts -> GET /api/users, POST /api/users
app/api/users/[id]/route.ts -> GET/PATCH/DELETE /api/users/:id
Form submission, mutations -> Server Action (preferred)
External API access needed -> API Route
Webhooks -> API Route
// RLS handles authorization automatically
const { data } = await supabase
.from('posts')
.select('*') // Only returns user's posts due to RLS
[] Auth check at start
[] Zod validation on all input
[] Ownership check on resource access
[] Generic errors to client
[] Detailed errors to logs
[] No secrets in code
[] Webhook signature verification
| If You See | Fix |
|---|---|
No await auth() | Add auth check |
Schema.parse(body) without try | Use safeParse |
| No ownership check | Add authorization |
return { error: error.message } | Generic error |
db.query(\...${input}`)` | Use parameterized |
| No pagination | Add pagination |