Awesome-omni-skill backend

API, database, server logic, webhooks. Auto-use for any API/DB work.

install
source · Clone the upstream repo
git clone https://github.com/diegosouzapw/awesome-omni-skill
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/backend/backend" ~/.claude/skills/diegosouzapw-awesome-omni-skill-backend && rm -rf "$T"
manifest: skills/backend/backend/SKILL.md
source content

Backend

Auto-use when: API, route, endpoint, database, Supabase, schema, migration, webhook, server action

Works with:

frontend
for UI,
security
for auth patterns


Auto-Apply Rules

1. Every Endpoint Must Have

export async function POST(request: Request) {
  // 1. AUTH (required)
  const { userId } = await auth()
  if (!userId) return Response.json({ error: 'Unauthorized' }, { status: 401 })

  // 2. VALIDATION (required)
  const body = await request.json()
  const result = Schema.safeParse(body)
  if (!result.success) {
    return Response.json({ error: 'Invalid', details: result.error.flatten() }, { status: 400 })
  }

  // 3. OWNERSHIP (if accessing resource)
  const resource = await db.findUnique({ where: { id: result.data.id } })
  if (resource?.userId !== userId) {
    return Response.json({ error: 'Not found' }, { status: 404 })
  }

  // 4. EXECUTE with try/catch
  try {
    const data = await db.create({ data: result.data })
    return Response.json(data, { status: 201 })
  } catch (error) {
    console.error('Error:', error)
    return Response.json({ error: 'Failed' }, { status: 500 })
  }
}

2. Server Actions

'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' }
  }
}

3. Database Patterns

// 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)

4. Webhooks

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')
}

Quick Reference

API Route

app/api/users/route.ts         -> GET /api/users, POST /api/users
app/api/users/[id]/route.ts    -> GET/PATCH/DELETE /api/users/:id

Server Action vs API Route

Form submission, mutations -> Server Action (preferred)
External API access needed -> API Route
Webhooks -> API Route

Supabase with RLS

// RLS handles authorization automatically
const { data } = await supabase
  .from('posts')
  .select('*')  // Only returns user's posts due to RLS

Security Checklist

[] 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

Red Flags (STOP)

If You SeeFix
No
await auth()
Add auth check
Schema.parse(body)
without try
Use safeParse
No ownership checkAdd authorization
return { error: error.message }
Generic error
db.query(\
...${input}`)`
Use parameterized
No paginationAdd pagination