Files
ai-wpa/todo/PERFORMANCE_OPTIMIZATION.md
2025-08-30 18:18:57 +05:30

328 lines
8.1 KiB
Markdown

# Performance Optimization Checklist
**Current Status**: Largest Contentful Paint (LCP) = 2.6s
**Target**: LCP < 1.2s (excellent), < 2.5s (good)
**Priority**: 🔴 Critical - Blocking user experience
**Instructions**: Each task should be completed individually. AI should ask for user validation before marking as complete and moving to next task.
---
## 🚨 Critical Issues (Must Fix)
### Task 1: Remove Blocking Startup Check from Layout
**Impact**: -1.5s LCP improvement
**Status**: Pending
**File**: `app/layout.tsx`
**Lines**: 37-40
**Action**: Remove the following blocking code from root layout:
```typescript
// REMOVE THIS:
if (typeof window === 'undefined') {
const { runStartupChecks } = await import('@/lib/startup')
await runStartupChecks()
}
```
**Validation**: Page should load immediately without waiting for database connections
- [ ] **TASK 1 COMPLETED**
---
### Task 2: Create Background Startup Instrumentation
**Impact**: Maintain startup checks without blocking
**Status**: Pending
**File**: Create `app/instrumentation.ts`
**Action**: Create new file with background startup checks:
```typescript
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
import('./lib/startup').then(({ runStartupChecks }) => {
runStartupChecks().catch(console.error)
})
}
}
```
**Validation**: Startup checks run in background, visible in terminal logs
- [ ] **TASK 2 COMPLETED**
---
### Task 3: Create Redis User Caching Utility
**Impact**: -0.45s improvement
**Status**: Pending
**File**: Create `lib/auth-cache.ts`
**Action**: Create Redis caching utility:
```typescript
import { connectRedis } from './redis'
const USER_CACHE_PREFIX = 'user:'
const CACHE_TTL = 300 // 5 minutes
export async function getCachedUser(userId: string) {
try {
const redis = await connectRedis()
const cached = await redis.get(`${USER_CACHE_PREFIX}${userId}`)
return cached ? JSON.parse(cached) : null
} catch (error) {
console.error('Redis cache get error:', error)
return null // Fallback to DB if Redis fails
}
}
export async function setCachedUser(userId: string, userData: any) {
try {
const redis = await connectRedis()
await redis.setex(`${USER_CACHE_PREFIX}${userId}`, CACHE_TTL, JSON.stringify(userData))
} catch (error) {
console.error('Redis cache set error:', error)
// Don't throw - caching is optional
}
}
export async function clearCachedUser(userId: string) {
try {
const redis = await connectRedis()
await redis.del(`${USER_CACHE_PREFIX}${userId}`)
} catch (error) {
console.error('Redis cache clear error:', error)
}
}
```
**Validation**: File created with proper Redis integration
- [ ] **TASK 3 COMPLETED**
---
### Task 4: Update /me Endpoint to Use Redis Cache
**Impact**: Reduce MongoDB calls by 80%
**Status**: Pending
**File**: `app/api/auth/me/route.ts`
**Action**: Replace the current GET function with:
```typescript
import { getCachedUser, setCachedUser } from '@/lib/auth-cache'
export const GET = withAuth(async (request: NextRequest & { user?: any }) => {
try {
// 1. Check Redis cache first
const cached = await getCachedUser(request.user.userId)
if (cached) {
return NextResponse.json({
success: true,
data: { user: cached },
})
}
// 2. Only hit MongoDB if not cached
await connectDB()
const user = await User.findById(request.user.userId).select('-password -refreshToken').lean() // Better performance
if (!user) {
return NextResponse.json(
{ success: false, error: { message: 'User not found', code: 'USER_NOT_FOUND' } },
{ status: 404 }
)
}
// 3. Cache for next time
await setCachedUser(request.user.userId, user)
return NextResponse.json({
success: true,
data: { user },
})
} catch (error) {
console.error('Get user info error:', error)
return NextResponse.json(
{ success: false, error: { message: 'Internal server error', code: 'INTERNAL_ERROR' } },
{ status: 500 }
)
}
})
```
**Validation**: /me endpoint returns cached data on subsequent calls
- [ ] **TASK 4 COMPLETED**
---
### Task 5: Add Cache Invalidation to User Updates
**Impact**: Ensure cache consistency
**Status**: Pending
**File**: `app/api/auth/refresh/route.ts`
**Action**: Add cache clearing after user update:
```typescript
// Add import at top:
import { setCachedUser } from '@/lib/auth-cache'
// After user.save(), add:
await setCachedUser(user._id.toString(), user.toJSON())
```
**Validation**: User cache updates when refresh token is used
- [ ] **TASK 5 COMPLETED**
---
### Task 6: Optimize Auth Context with localStorage
**Impact**: -0.25s improvement
**Status**: Pending
**File**: `contexts/AuthContext.tsx`
**Lines**: 157-180
**Action**: Replace the restoreSession function:
```typescript
const restoreSession = async () => {
try {
setLoading(true)
// 1. Load from localStorage immediately (sync)
const cachedUser = localStorage.getItem('nextjs_user')
if (cachedUser) {
const userData = JSON.parse(cachedUser)
setUser(userData)
setHasCheckedAuth(true)
setLoading(false)
// 2. Validate in background (async)
apiCall('/me')
.then((data) => {
setUser(data.data.user)
localStorage.setItem('nextjs_user', JSON.stringify(data.data.user))
})
.catch(() => {
// Try refresh token if /me fails
apiCall('/refresh', { method: 'POST' })
.then((refreshData) => {
setUser(refreshData.data.user)
localStorage.setItem('nextjs_user', JSON.stringify(refreshData.data.user))
})
.catch(() => {
// Both failed, clear cache and user
localStorage.removeItem('nextjs_user')
setUser(null)
})
})
return
}
// 3. Only do full auth check if no cached user
const data = await apiCall('/me')
setUser(data.data.user)
localStorage.setItem('nextjs_user', JSON.stringify(data.data.user))
setHasCheckedAuth(true)
} catch (err) {
// If /me fails, try refresh token
try {
const refreshData = await apiCall('/refresh', { method: 'POST' })
setUser(refreshData.data.user)
localStorage.setItem('nextjs_user', JSON.stringify(refreshData.data.user))
setHasCheckedAuth(true)
} catch (refreshErr) {
// Both failed, user is not authenticated
setUser(null)
setHasCheckedAuth(true)
}
} finally {
setLoading(false)
}
}
```
**Validation**: Page loads show cached user immediately, then validates in background
- [ ] **TASK 6 COMPLETED**
---
### Task 7: Clear localStorage on Logout
**Impact**: Proper cache cleanup
**Status**: Pending
**File**: `contexts/AuthContext.tsx`
**Function**: logout
**Action**: Add localStorage clearing to logout function:
```typescript
// In the logout function, add this line:
localStorage.removeItem('nextjs_user')
```
**Validation**: User data cleared from localStorage after logout
- [ ] **TASK 7 COMPLETED**
---
### Task 8: Add Database Query Optimization
**Impact**: -0.1s improvement
**Status**: Pending
**File**: `app/api/auth/login/route.ts`
**Lines**: 23
**Action**: Optimize user lookup query:
```typescript
// Replace:
const user = await User.findOne({ email: validatedData.email.toLowerCase() })
// With:
const user = await User.findOne({ email: validatedData.email.toLowerCase() })
.lean()
.select('+password')
```
**Validation**: Login queries use optimized database access
- [ ] **TASK 8 COMPLETED**
---
## 📊 Progress Tracking
**Completed**: 0/8 tasks
**Expected LCP Improvement**: 0s of 2.2s total
**Current Status**: Ready to start Task 1
---
## 🎯 Success Criteria
After completing all tasks:
- **LCP**: Should improve from 2.6s to ~0.4s
- **Redis Cache Hit Rate**: Should be >80% for /me endpoint
- **Page Load**: Should render immediately without database waits
- **Auth Restoration**: Should show cached user instantly
---
**Next Action**: Start with Task 1 - Remove Blocking Startup Check