Skip to content
Back to skills

Backend

ASecurity

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

  • 57 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 17, 2026
developmenttypescriptbashapidatabasefrontendbackendsecurity

Works with

  • cli
  • api

Security analysis

A100/100

Scanned October 17, 2026

npx -y skills add diegosouzapw/awesome-omni-skill --skill backend --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Backend?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Backend
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/diegosouzapw-backend/badge)](https://www.skillsdirectory.com/skills/diegosouzapw-backend)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
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
---

# 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
```typescript
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
```typescript
'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
```typescript
// 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
```typescript
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
```typescript
// 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 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 |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.