AI Skill Report Card
Building Web Applications
Quick Start
Bash# Create Next.js app with TypeScript npx create-next-app@latest my-app --typescript --tailwind --eslint --app cd my-app # Add common dependencies npm install @types/node prisma @prisma/client zod react-hook-form @hookform/resolvers npm install -D @types/react @types/react-dom # Project structure src/ ├── app/ │ ├── api/ │ ├── components/ │ └── lib/ ├── prisma/ └── types/
Recommendation▾
Remove basic explanations like 'Database logic here' and focus on actual implementation patterns - Claude knows these fundamentals
Workflow
Progress:
- Project setup with proper TypeScript configuration
- Database schema design and Prisma setup
- API routes with type safety and validation
- Frontend components with proper typing
- State management and data fetching
- Error handling and loading states
- Testing and deployment
1. Environment Setup
TypeScript// next.config.js /** @type {import('next').NextConfig} */ const nextConfig = { experimental: { serverActions: true, }, } module.exports = nextConfig
2. Type-Safe API Routes
TypeScript// app/api/users/route.ts import { NextRequest, NextResponse } from 'next/server' import { z } from 'zod' const CreateUserSchema = z.object({ email: z.string().email(), name: z.string().min(1), }) export async function POST(request: NextRequest) { try { const body = await request.json() const { email, name } = CreateUserSchema.parse(body) // Database logic here return NextResponse.json({ id: 1, email, name }) } catch (error) { return NextResponse.json({ error: 'Invalid input' }, { status: 400 }) } }
3. Server Components with Database
TypeScript// app/users/page.tsx import { PrismaClient } from '@prisma/client' const prisma = new PrismaClient() export default async function UsersPage() { const users = await prisma.user.findMany() return ( <div> {users.map(user => ( <div key={user.id}>{user.name}</div> ))} </div> ) }
Recommendation▾
Add concrete input/output examples showing the actual HTTP requests/responses and database queries with real data
Examples
Example 1: Form Handling Input: User registration form with validation Output:
TypeScript'use client' import { useForm } from 'react-hook-form' import { zodResolver } from '@hookform/resolvers/zod' import { z } from 'zod' const schema = z.object({ email: z.string().email(), password: z.string().min(8), }) type FormData = z.infer<typeof schema> export default function RegisterForm() { const { register, handleSubmit, formState: { errors } } = useForm<FormData>({ resolver: zodResolver(schema) }) const onSubmit = async (data: FormData) => { const response = await fetch('/api/auth/register', { method: 'POST', body: JSON.stringify(data), }) } return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('email')} /> {errors.email && <span>{errors.email.message}</span>} </form> ) }
Example 2: API Route with Database Input: CRUD operations for blog posts Output:
TypeScript// app/api/posts/route.ts import { prisma } from '@/lib/prisma' import { NextResponse } from 'next/server' export async function GET() { const posts = await prisma.post.findMany({ include: { author: true } }) return NextResponse.json(posts) } export async function POST(request: Request) { const { title, content, authorId } = await request.json() const post = await prisma.post.create({ data: { title, content, authorId } }) return NextResponse.json(post) }
Recommendation▾
Convert the workflow checklist into a more actionable step-by-step process with specific commands and code snippets for each step
Best Practices
- Use App Router for new projects, not Pages Router
- Implement proper error boundaries and loading states
- Validate all inputs with Zod schemas
- Use Prisma for type-safe database operations
- Prefer Server Components when possible
- Use TypeScript strict mode
- Implement proper SEO with metadata API
- Use Tailwind CSS for consistent styling
- Set up ESLint and Prettier for code quality
Common Pitfalls
- Don't fetch data in Client Components when Server Components can do it
- Don't skip input validation on API routes
- Don't ignore TypeScript errors or use
anytype - Don't put sensitive data in client-side code
- Don't forget to handle loading and error states
- Don't use
useEffectfor data fetching when Server Components are available - Don't mix Server and Client Component patterns incorrectly