Files
gh-djankies-claude-configs-…/skills/reviewing-prisma-patterns/references/example-reviews.md
2025-11-29 18:22:25 +08:00

9.7 KiB
Raw Blame History

Example Reviews

Complete code review examples showing typical findings and recommendations.


Example 1: E-commerce API (Next.js)

Context: Next.js 14 App Router with Prisma, deployed to Vercel

Project Structure:

app/
├── api/
│   ├── products/route.ts
│   ├── users/route.ts
│   └── search/route.ts
├── lib/
│   └── db.ts
└── .env

Findings:

Prisma Code Review - E-commerce API
Generated: 2025-11-21
Files Reviewed: 15

CRITICAL Issues (P0): 2
HIGH Issues (P1): 1
MEDIUM Issues (P2): 3
LOW Issues (P3): 2

Overall Assessment: CRITICAL ISSUES - Do not deploy

---

[P0] Multiple PrismaClient Instances
Files:
  - app/api/products/route.ts:8
  - app/api/users/route.ts:12
  - lib/db.ts:5
Count: 3 instances found

Code (app/api/products/route.ts:8):
```typescript
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()

export async function GET() {
  const products = await prisma.product.findMany()
  return Response.json(products)
}

Impact: CRITICAL - Connection pool exhaustion under load

  • Each API route creates separate connection pool
  • Vercel scales to 100+ concurrent functions
  • 3 routes × 100 instances × 10 connections = 3000 connections!
  • Database will reject connections (P1017)

Fix: Create global singleton in lib/db.ts, import everywhere

Remediation Steps:

  1. Create lib/prisma.ts with global singleton pattern
  2. Replace all new PrismaClient() with imports
  3. Verify with grep (should find only 1 instance)

Reference: @prisma-6/CLIENT-singleton-pattern


[P0] SQL Injection Vulnerability File: app/api/search/route.ts:23

Code:

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url)
  const query = searchParams.get('q')

  const products = await prisma.$queryRawUnsafe(
    `SELECT * FROM products WHERE name LIKE '%${query}%'`
  )

  return Response.json(products)
}

Impact: CRITICAL - Enables SQL injection attacks

  • User controls query parameter
  • Direct string interpolation allows injection
  • Attacker can execute arbitrary SQL

Example attack:

/api/search?q=%27;%20DROP%20TABLE%20products;--

Fix: Use $queryRaw tagged template with automatic parameterization

Remediation:

const products = await prisma.$queryRaw`
  SELECT * FROM products WHERE name LIKE ${'%' + query + '%'}
`

Reference: @prisma-6/SECURITY-sql-injection


[P1] Missing Serverless Configuration File: .env

Current:

DATABASE_URL="postgresql://user:pass@host:5432/db"

Impact: HIGH - Connection exhaustion in Vercel deployment

  • Default pool_size = 10 connections per instance
  • Vercel can scale to 100+ instances
  • 100 instances × 10 connections = 1000 connections
  • Most databases have 100-200 connection limit

Fix: Add ?connection_limit=1 to DATABASE_URL

Remediation:

DATABASE_URL="postgresql://user:pass@host:5432/db?connection_limit=1&pool_timeout=10"

Why this works:

  • Each Vercel function instance gets 1 connection
  • 100 instances × 1 connection = 100 connections (sustainable)
  • pool_timeout=10 prevents hanging on exhaustion

Reference: @prisma-6/CLIENT-serverless-config


[P2] Missing Input Validation Files: app/api/users/route.ts, app/api/products/route.ts

Code (app/api/users/route.ts):

export async function POST(request: Request) {
  const data = await request.json()
  const user = await prisma.user.create({ data })
  return Response.json(user)
}

Impact: MEDIUM - Invalid data can reach database

  • No validation of email format
  • No validation of required fields
  • Type mismatches cause runtime errors

Fix: Add Zod validation schemas before Prisma operations

Remediation:

import { z } from 'zod'

const userSchema = z.object({
  email: z.string().email(),
  name: z.string().min(1),
})

export async function POST(request: Request) {
  const data = await request.json()
  const validated = userSchema.parse(data)
  const user = await prisma.user.create({ data: validated })
  return Response.json(user)
}

Reference: @prisma-6/SECURITY-input-validation


[P3] Inefficient Pagination File: app/api/products/route.ts:15

Code:

const page = parseInt(searchParams.get('page') ?? '0')
const products = await prisma.product.findMany({
  skip: page * 100,
  take: 100
})

Impact: LOW - Slow queries on large datasets

  • Product table has 50k+ records
  • Offset pagination degrades with page number
  • Page 500 skips 50k records (slow!)

Fix: Use cursor-based pagination with id cursor

Remediation:

const cursor = searchParams.get('cursor')
const products = await prisma.product.findMany({
  take: 100,
  cursor: cursor ? { id: cursor } : undefined,
  orderBy: { id: 'asc' }
})

const nextCursor = products.length === 100
  ? products[99].id
  : null

Reference: @prisma-6/QUERIES-pagination


RECOMMENDATION: Fix P0 issues immediately before any deployment. P1 issues will cause production failures under load.

Priority Actions:

  1. Implement global singleton pattern (blocking)
  2. Fix SQL injection in search endpoint (blocking)
  3. Add connection_limit to DATABASE_URL (high priority)
  4. Add Zod validation to API routes (recommended)
  5. Optimize pagination for products (nice to have)

---

## Example 2: Internal Dashboard (Express)

**Context:** Express API with PostgreSQL, traditional server deployment

**Project Structure:**

src/ ├── controllers/ │ ├── users.ts │ └── reports.ts ├── db.ts └── index.ts


**Findings:**

Prisma Code Review - Internal Dashboard Generated: 2025-11-21 Files Reviewed: 8

CRITICAL Issues (P0): 0 HIGH Issues (P1): 0 MEDIUM Issues (P2): 1 LOW Issues (P3): 3

Overall Assessment: GOOD - Minor improvements recommended


[P2] Generic Error Handling File: src/controllers/users.ts:45-52

Code:

async function createUser(req: Request, res: Response) {
  try {
    const user = await prisma.user.create({
      data: req.body
    })
    res.json(user)
  } catch (error) {
    res.status(500).json({ error: 'Database error' })
  }
}

Impact: MEDIUM - P2002/P2025 not handled specifically

  • User gets generic "Database error" for all failures
  • Duplicate email returns 500 instead of 409
  • Poor developer experience debugging issues

Fix: Check error.code for P2002 (unique), P2025 (not found)

Remediation:

import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library'

async function createUser(req: Request, res: Response) {
  try {
    const user = await prisma.user.create({
      data: req.body
    })
    res.json(user)
  } catch (error) {
    if (error instanceof PrismaClientKnownRequestError) {
      if (error.code === 'P2002') {
        return res.status(409).json({
          error: 'User with this email already exists'
        })
      }
    }
    res.status(500).json({ error: 'Unexpected error' })
  }
}

Reference: @prisma-6/TRANSACTIONS-error-handling


[P3] Inefficient Pagination File: src/controllers/reports.ts:78

Code:

const reports = await prisma.report.findMany({
  skip: page * 100,
  take: 100,
  orderBy: { createdAt: 'desc' }
})

Context:

  • Reports table has 50k+ records
  • Used in admin dashboard for audit logs
  • Page 500 requires scanning 50k records

Impact: LOW - Slow queries on large datasets

  • Query time increases with page number
  • Database performs full table scan
  • Admin dashboard feels sluggish

Fix: Use cursor-based pagination with id cursor

Remediation:

const reports = await prisma.report.findMany({
  take: 100,
  cursor: lastId ? { id: lastId } : undefined,
  orderBy: { createdAt: 'desc' }
})

Reference: @prisma-6/QUERIES-pagination


[P3] Missing Select Optimization Files: 8 files with findMany() lacking select

Examples:

  • src/controllers/users.ts:23
  • src/controllers/reports.ts:45
  • src/controllers/analytics.ts:67

Code pattern:

const users = await prisma.user.findMany()

Impact: LOW - Fetching unnecessary fields

  • Returns all columns including large text fields
  • Increases response payload size
  • Wastes database bandwidth

Fix: Add select: { id, name, email } to queries

Remediation:

const users = await prisma.user.findMany({
  select: {
    id: true,
    email: true,
    name: true,
    role: true
  }
})

Reference: @prisma-6/QUERIES-select-optimization


[P3] Missing Select in List Endpoints File: src/controllers/users.ts:88

Code:

const users = await prisma.user.findMany({
  include: { posts: true }
})

Impact: LOW - Over-fetching related data

  • Returns ALL posts for each user
  • User with 1000 posts = huge payload
  • Should paginate posts separately

Fix: Limit included records or use separate query

Remediation:

const users = await prisma.user.findMany({
  select: {
    id: true,
    email: true,
    name: true,
    _count: {
      select: { posts: true }
    }
  }
})

Reference: @prisma-6/QUERIES-select-optimization


ASSESSMENT: Code quality is good. No critical issues found.

Recommended Improvements:

  1. Improve error handling with P-code checks (user experience)
  2. Optimize pagination for reports table (performance)
  3. Add select clauses to list endpoints (efficiency)

These improvements are optional but will enhance code quality and performance.


---

## Summary

**E-commerce API:**
- High-risk serverless deployment with critical security/stability issues
- Must fix P0 issues before deployment
- Typical of AI-generated code without production hardening

**Internal Dashboard:**
- Low-risk traditional server deployment with minor optimizations
- No blocking issues
- Good baseline quality with room for improvement

Both examples demonstrate the importance of systematic code review before production deployment.