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

447 lines
9.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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:
```typescript
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:
```typescript
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):
```typescript
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:
```typescript
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:
```typescript
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:
```typescript
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:
```typescript
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:
```typescript
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:
```typescript
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:
```typescript
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:
```typescript
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:
```typescript
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:
```typescript
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:
```typescript
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.