Loading...
// AI-generated component with full type safety
import { useState } from 'react'
import { api } from '@/lib/trpc/client'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { toast } from 'sonner'
interface UserProfileFormProps {
userId: string
initialData?: {
name: string
email: string
bio: string
}
}
export function UserProfileForm({ userId, initialData }: UserProfileFormProps) {
const [formData, setFormData] = useState({
name: initialData?.name ?? '',
email: initialData?.email ?? '',
bio: initialData?.bio ?? ''
})
const utils = api.useUtils()
const updateProfile = api.user.updateProfile.useMutation({
onSuccess: () => {
toast.success('Profile updated successfully')
utils.user.getProfile.invalidate({ userId })
},
onError: (error) => {
toast.error(`Failed to update: ${error.message}`)
}
})
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
await updateProfile.mutateAsync({ userId, ...formData })
}
return (
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="name" className="block text-sm font-medium">
Name
</label>
<Input
id="name"
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
required
/>
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium">
Email
</label>
<Input
id="email"
type="email"
value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
required
/>
</div>
<div>
<label htmlFor="bio" className="block text-sm font-medium">
Bio
</label>
<textarea
id="bio"
value={formData.bio}
onChange={(e) => setFormData({ ...formData, bio: e.target.value })}
className="w-full rounded-md border p-2"
rows={4}
/>
</div>
<Button type="submit" disabled={updateProfile.isPending}>
{updateProfile.isPending ? 'Saving...' : 'Save Changes'}
</Button>
</form>
)
}// server/api/routers/user.ts
import { z } from 'zod'
import { createTRPCRouter, protectedProcedure, publicProcedure } from '../trpc'
import { TRPCError } from '@trpc/server'
// AI-generated validation schemas
const userProfileSchema = z.object({
name: z.string().min(2).max(100),
email: z.string().email(),
bio: z.string().max(500).optional()
})
const getUserSchema = z.object({
userId: z.string().uuid()
})
export const userRouter = createTRPCRouter({
// Public query - get user profile
getProfile: publicProcedure
.input(getUserSchema)
.query(async ({ ctx, input }) => {
const user = await ctx.db.user.findUnique({
where: { id: input.userId },
select: {
id: true,
name: true,
email: true,
bio: true,
createdAt: true,
_count: {
select: {
posts: true,
followers: true
}
}
}
})
if (!user) {
throw new TRPCError({
code: 'NOT_FOUND',
message: 'User not found'
})
}
return user
}),
// Protected mutation - update profile
updateProfile: protectedProcedure
.input(
z.object({
userId: z.string().uuid()
}).merge(userProfileSchema)
)
.mutation(async ({ ctx, input }) => {
// Verify user can only update their own profile
if (ctx.session.user.id !== input.userId) {
throw new TRPCError({
code: 'FORBIDDEN',
message: 'Cannot update another user\'s profile'
})
}
const updatedUser = await ctx.db.user.update({
where: { id: input.userId },
data: {
name: input.name,
email: input.email,
bio: input.bio
}
})
return updatedUser
}),
// AI-powered search with fuzzy matching
searchUsers: publicProcedure
.input(
z.object({
query: z.string().min(1),
limit: z.number().min(1).max(50).default(10)
})
)
.query(async ({ ctx, input }) => {
const users = await ctx.db.$queryRaw`
SELECT id, name, email, bio,
similarity(name, ${input.query}) as name_similarity
FROM users
WHERE similarity(name, ${input.query}) > 0.3
ORDER BY name_similarity DESC
LIMIT ${input.limit}
`
return users
})
})// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
previewFeatures = ["fullTextSearch", "postgresqlExtensions"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
extensions = [pg_trgm]
}
model User {
id String @id @default(uuid())
email String @unique
name String
bio String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
posts Post[]
comments Comment[]
followers Follow[] @relation("following")
following Follow[] @relation("follower")
sessions Session[]
// AI-suggested indexes for common queries
@@index([email])
@@index([name(ops: GinTrgmOps)]) // Fuzzy search
@@map("users")
}
model Post {
id String @id @default(uuid())
title String
content String
published Boolean @default(false)
views Int @default(0)
authorId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
comments Comment[]
tags TagOnPost[]
// AI-optimized composite indexes
@@index([authorId, published, createdAt(sort: Desc)])
@@index([published, views(sort: Desc)])
@@index([title(ops: GinTrgmOps), content(ops: GinTrgmOps)])
@@map("posts")
}
model Comment {
id String @id @default(uuid())
content String
postId String
authorId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
@@index([postId, createdAt])
@@index([authorId])
@@map("comments")
}
model Tag {
id String @id @default(uuid())
name String @unique
posts TagOnPost[]
@@map("tags")
}
model TagOnPost {
postId String
tagId String
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
@@id([postId, tagId])
@@map("tags_on_posts")
}
model Follow {
followerId String
followingId String
createdAt DateTime @default(now())
follower User @relation("follower", fields: [followerId], references: [id], onDelete: Cascade)
following User @relation("following", fields: [followingId], references: [id], onDelete: Cascade)
@@id([followerId, followingId])
@@map("follows")
}
model Session {
id String @id @default(uuid())
userId String
expiresAt DateTime
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@index([expiresAt])
@@map("sessions")
}// app/actions/posts.ts
'use server'
import { z } from 'zod'
import { revalidatePath } from 'next/cache'
import { redirect } from 'next/navigation'
import { db } from '@/lib/db'
import { getCurrentUser } from '@/lib/auth'
import { ratelimit } from '@/lib/rate-limit'
const createPostSchema = z.object({
title: z.string().min(5).max(200),
content: z.string().min(10).max(10000),
tags: z.array(z.string()).max(5)
})
export async function createPost(formData: FormData) {
// Authentication check
const user = await getCurrentUser()
if (!user) {
return { error: 'Unauthorized' }
}
// Rate limiting
const { success } = await ratelimit.limit(user.id)
if (!success) {
return { error: 'Too many requests. Please try again later.' }
}
// Validate input
const rawData = {
title: formData.get('title'),
content: formData.get('content'),
tags: JSON.parse(formData.get('tags') as string)
}
const validation = createPostSchema.safeParse(rawData)
if (!validation.success) {
return {
error: 'Invalid input',
fieldErrors: validation.error.flatten().fieldErrors
}
}
const { title, content, tags } = validation.data
try {
// AI-suggested: Use transaction for atomicity
const post = await db.$transaction(async (tx) => {
// Create post
const newPost = await tx.post.create({
data: {
title,
content,
authorId: user.id,
published: false
}
})
// Create or connect tags
for (const tagName of tags) {
const tag = await tx.tag.upsert({
where: { name: tagName },
create: { name: tagName },
update: {}
})
await tx.tagOnPost.create({
data: {
postId: newPost.id,
tagId: tag.id
}
})
}
return newPost
})
// Revalidate relevant paths
revalidatePath('/dashboard/posts')
revalidatePath(`/posts/${post.id}`)
return { success: true, postId: post.id }
} catch (error) {
console.error('Failed to create post:', error)
return { error: 'Failed to create post. Please try again.' }
}
}
export async function publishPost(postId: string) {
const user = await getCurrentUser()
if (!user) {
return { error: 'Unauthorized' }
}
try {
// Verify ownership
const post = await db.post.findUnique({
where: { id: postId },
select: { authorId: true }
})
if (!post || post.authorId !== user.id) {
return { error: 'Post not found or unauthorized' }
}
// Publish
await db.post.update({
where: { id: postId },
data: { published: true }
})
revalidatePath(`/posts/${postId}`)
redirect(`/posts/${postId}`)
} catch (error) {
console.error('Failed to publish post:', error)
return { error: 'Failed to publish post' }
}
}// lib/websocket/server.ts
import { WebSocketServer, WebSocket } from 'ws'
import { z } from 'zod'
import { verifyToken } from '@/lib/auth'
interface Client {
ws: WebSocket
userId: string
roomId: string
}
const clients = new Map<string, Client>()
const messageSchema = z.discriminatedUnion('type', [
z.object({
type: z.literal('join'),
roomId: z.string(),
token: z.string()
}),
z.object({
type: z.literal('leave'),
roomId: z.string()
}),
z.object({
type: z.literal('typing'),
roomId: z.string(),
isTyping: z.boolean()
}),
z.object({
type: z.literal('message'),
roomId: z.string(),
content: z.string()
})
])
export function setupWebSocketServer(server: any) {
const wss = new WebSocketServer({ server })
wss.on('connection', (ws: WebSocket) => {
let clientId: string | null = null
ws.on('message', async (data: Buffer) => {
try {
const raw = JSON.parse(data.toString())
const message = messageSchema.parse(raw)
switch (message.type) {
case 'join': {
const user = await verifyToken(message.token)
if (!user) {
ws.send(JSON.stringify({ error: 'Invalid token' }))
ws.close()
return
}
clientId = `${user.id}-${Date.now()}`
clients.set(clientId, {
ws,
userId: user.id,
roomId: message.roomId
})
// Broadcast user joined
broadcastToRoom(message.roomId, {
type: 'user-joined',
userId: user.id
}, clientId)
break
}
case 'typing': {
if (!clientId) return
const client = clients.get(clientId)
if (!client) return
broadcastToRoom(
message.roomId,
{
type: 'user-typing',
userId: client.userId,
isTyping: message.isTyping
},
clientId
)
break
}
case 'message': {
if (!clientId) return
const client = clients.get(clientId)
if (!client) return
// AI-powered message moderation could go here
const moderatedContent = await moderateContent(message.content)
broadcastToRoom(message.roomId, {
type: 'new-message',
userId: client.userId,
content: moderatedContent,
timestamp: new Date().toISOString()
})
break
}
case 'leave': {
if (!clientId) return
handleDisconnect(clientId)
break
}
}
} catch (error) {
console.error('WebSocket error:', error)
ws.send(JSON.stringify({ error: 'Invalid message format' }))
}
})
ws.on('close', () => {
if (clientId) {
handleDisconnect(clientId)
}
})
})
function broadcastToRoom(roomId: string, message: any, excludeClientId?: string) {
for (const [id, client] of clients.entries()) {
if (client.roomId === roomId && id !== excludeClientId) {
client.ws.send(JSON.stringify(message))
}
}
}
function handleDisconnect(clientId: string) {
const client = clients.get(clientId)
if (client) {
broadcastToRoom(client.roomId, {
type: 'user-left',
userId: client.userId
}, clientId)
clients.delete(clientId)
}
}
}
async function moderateContent(content: string): Promise<string> {
// AI-powered content moderation
// This could integrate with OpenAI Moderation API or similar
return content
}// lib/stores/editor-store.ts
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
import { immer } from 'zustand/middleware/immer'
interface EditorState {
content: string
title: string
tags: string[]
savedAt: string | null
isDirty: boolean
// Actions
setContent: (content: string) => void
setTitle: (title: string) => void
addTag: (tag: string) => void
removeTag: (tag: string) => void
markSaved: () => void
reset: () => void
}
const initialState = {
content: '',
title: '',
tags: [],
savedAt: null,
isDirty: false
}
export const useEditorStore = create<EditorState>()((
persist(
immer((set) => ({
...initialState,
setContent: (content) =>
set((state) => {
state.content = content
state.isDirty = true
}),
setTitle: (title) =>
set((state) => {
state.title = title
state.isDirty = true
}),
addTag: (tag) =>
set((state) => {
if (!state.tags.includes(tag)) {
state.tags.push(tag)
state.isDirty = true
}
}),
removeTag: (tag) =>
set((state) => {
state.tags = state.tags.filter((t) => t !== tag)
state.isDirty = true
}),
markSaved: () =>
set((state) => {
state.savedAt = new Date().toISOString()
state.isDirty = false
}),
reset: () => set(initialState)
})),
{
name: 'editor-storage',
partialize: (state) => ({
content: state.content,
title: state.title,
tags: state.tags
})
}
)
))// __tests__/api/user.test.ts
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { createCaller } from '@/server/api/root'
import { db } from '@/lib/db'
import { createMockContext } from '@/server/api/test-utils'
describe('User API', () => {
beforeEach(async () => {
await db.user.deleteMany()
})
afterEach(async () => {
await db.user.deleteMany()
})
describe('getProfile', () => {
it('should return user profile when user exists', async () => {
const ctx = createMockContext()
const caller = createCaller(ctx)
const user = await db.user.create({
data: {
email: 'test@example.com',
name: 'Test User',
bio: 'Test bio'
}
})
const result = await caller.user.getProfile({ userId: user.id })
expect(result).toMatchObject({
id: user.id,
name: 'Test User',
email: 'test@example.com',
bio: 'Test bio'
})
})
it('should throw NOT_FOUND when user does not exist', async () => {
const ctx = createMockContext()
const caller = createCaller(ctx)
await expect(
caller.user.getProfile({ userId: 'non-existent-id' })
).rejects.toThrow('User not found')
})
})
describe('updateProfile', () => {
it('should update user profile when authenticated', async () => {
const user = await db.user.create({
data: {
email: 'test@example.com',
name: 'Old Name'
}
})
const ctx = createMockContext({ userId: user.id })
const caller = createCaller(ctx)
const result = await caller.user.updateProfile({
userId: user.id,
name: 'New Name',
email: 'new@example.com',
bio: 'Updated bio'
})
expect(result.name).toBe('New Name')
expect(result.email).toBe('new@example.com')
expect(result.bio).toBe('Updated bio')
})
it('should prevent updating another user\'s profile', async () => {
const user1 = await db.user.create({
data: { email: 'user1@example.com', name: 'User 1' }
})
const user2 = await db.user.create({
data: { email: 'user2@example.com', name: 'User 2' }
})
const ctx = createMockContext({ userId: user1.id })
const caller = createCaller(ctx)
await expect(
caller.user.updateProfile({
userId: user2.id,
name: 'Hacked',
email: 'hacked@example.com'
})
).rejects.toThrow('Cannot update another user\'s profile')
})
})
}){
"maxTokens": 4000,
"temperature": 0.4,
"systemPrompt": "You are a full-stack AI development agent focused on modern web applications with AI-assisted workflows"
}Type safety broken between frontend TypeScript and backend API responses
Generate types with openapi-typescript. Use tRPC for end-to-end type safety. Validate runtime with zod. Run: npm run codegen to sync. Set strict:true in tsconfig.json.
AI code generation producing syntactically correct but logically flawed code
Add unit tests for validation. Use Claude with function calling for structured output. Implement code review. Test with: npm test before commit. Set temperature=0.2.
Full-stack hot reload breaking after AI-generated code changes
Restart dev server after schema changes. Clear build cache with: rm -rf .next/cache. Check for circular imports. Verify webpack config allows new file types. Use: next dev --turbo for faster rebuilds.
Database migrations failing after AI-generated schema modifications
Review migration first. Use reversible up/down migrations. Test on staging. Run: npx prisma migrate diff to preview. Backup DB before migrate. Handle data transformations.
AI assistant context window exceeded causing incomplete responses
Chunk large files into segments. Use RAG for codebase. Implement sliding window for history. Set max_tokens=4000 for responses. Summarize old context to save tokens.
Loading reviews...
Expert frontend developer specializing in modern JavaScript frameworks, UI/UX implementation, and performance optimization
Deploy AI-powered DevOps automation with predictive analytics, self-healing systems, and intelligent CI/CD optimization for modern infrastructure.
AI-powered code review specialist focusing on security vulnerabilities, OWASP Top 10, static analysis, secrets detection, and automated security best practices enforcement
Growing community of AI engineers actively building with Claude
Live in 5 minutes • Growing community