Files
Portfolio/OPTIMIZATION_RECOMMENDATIONS.md
damjan_savicandClaude Opus 4.5 ac4b85bbc1 auto-claude: subtask-8-4 - Create optimization recommendations document
Create comprehensive OPTIMIZATION_RECOMMENDATIONS.md based on audit results:
- Priority 1: Critical optimizations (image compression, production verification)
- Priority 2: High-impact (client component audit, loading states, blur placeholders)
- Priority 3: Medium-impact (reduced motion, third-party scripts, font loading, DB indexes)
- Priority 4: Strategic (PWA, bundle analysis, edge caching, CDN optimization)
- Implementation roadmap with weekly/monthly milestones
- Success metrics and targets

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 02:34:17 +01:00

563 lines
15 KiB
Markdown

# Optimization Recommendations Report
**Project:** damjan-savic.com Portfolio Website
**Date:** 2026-01-25
**Prepared by:** auto-claude
**Status:** Final Recommendations (Post-Audit)
---
## Executive Summary
This document provides comprehensive optimization recommendations based on the completed SEO audit, performance testing, and implementation work. The recommendations are organized by priority and impact, covering areas from quick wins to strategic long-term improvements.
### Current State
| Category | Status | Score |
|----------|--------|-------|
| SEO | ✅ Complete | 100% |
| Accessibility | ✅ Passing | 92-100% |
| Best Practices | ✅ Passing | 100% |
| Performance (Dev) | ⚠️ Expected Low | 47-69%* |
| Performance (Prod) | 📋 To Verify | Expected 85-95% |
*Development mode scores are lower due to unminified code, HMR overhead, and source maps.
---
## Priority 1: Critical Optimizations (Immediate Action)
### 1.1 Image Optimization - Hero Portrait
**Issue:** The hero portrait image is 2.9 MB, significantly impacting LCP and overall page weight.
**File:** `/public/hero-portrait.jpg`
**Current Size:** 2,957,516 bytes (~2.9 MB)
**Target Size:** < 500 KB (80-85% reduction)
**Recommendations:**
```bash
# Option 1: Manual compression with ImageMagick
magick hero-portrait.jpg -quality 82 -strip hero-portrait-optimized.jpg
# Option 2: Convert to WebP format
magick hero-portrait.jpg -quality 80 hero-portrait.webp
# Option 3: Use AVIF for maximum compression
magick hero-portrait.jpg -quality 60 hero-portrait.avif
```
**Implementation Steps:**
1. Compress original to <500KB maintaining visual quality
2. Generate responsive variants (300, 600, 900, 1200px widths)
3. Create AVIF and WebP versions for modern browser support
4. Update Next.js Image component with blur placeholder
5. Add `fetchpriority="high"` for LCP optimization
**Expected Improvement:**
- LCP: -1.5 to 2.0 seconds
- Page weight: -2.0 to 2.5 MB
- Mobile performance: +15-25 points
---
### 1.2 Unused Large Images Cleanup
**Issue:** Multiple large image files may not be referenced in production.
**Files to Audit:**
| File | Size | Status |
|------|------|--------|
| `/public/portrait.jpg` | 1.2 MB | Verify usage |
| `/public/hero-portrait.jpg` | 2.9 MB | Needs optimization |
**Recommendation:**
1. Run image usage audit:
```bash
grep -r "portrait.jpg" src/ --include="*.tsx" --include="*.ts"
grep -r "hero-portrait.jpg" src/ --include="*.tsx" --include="*.ts"
```
2. Replace references with optimized versions
3. Remove unused originals from `/public`
---
### 1.3 Production Performance Verification
**Issue:** PageSpeed API was blocked during testing. Production verification required.
**Action Required:**
1. Visit [PageSpeed Insights](https://pagespeed.web.dev/)
2. Test all main URLs:
- `https://www.damjan-savic.com/de`
- `https://www.damjan-savic.com/en`
- `https://www.damjan-savic.com/sr`
- `https://www.damjan-savic.com/de/about`
- `https://www.damjan-savic.com/de/portfolio`
- `https://www.damjan-savic.com/de/contact`
3. Document scores for Desktop and Mobile
4. If any score < 90%, implement specific recommendations from report
---
## Priority 2: High-Impact Optimizations (This Sprint)
### 2.1 Client Component Audit
**Issue:** 13 client-side components identified. Some may be convertible to React Server Components (RSC).
**Current Client Components:**
| Component | Client Necessary? | Recommendation |
|-----------|-------------------|----------------|
| Header.tsx | ✅ Yes | Scroll/menu state |
| ContactForm.tsx | ✅ Yes | Form state |
| LoginForm.tsx | ✅ Yes | Form state |
| PortfolioCard.tsx | 🔍 Review | Consider RSC |
| PortfolioGrid.tsx | 🔍 Review | Consider RSC |
| NavLink.tsx | 🔍 Review | Consider RSC |
| ContactInfo.tsx | 🔍 Review | Consider RSC |
| Skills.tsx | 🔍 Review | Animation-dependent |
| Experience.tsx | 🔍 Review | Animation-dependent |
| Hero.tsx (about) | 🔍 Review | Animation-dependent |
| LanguageSwitcher.tsx | ✅ Yes | Dropdown state |
| DashboardContent.tsx | ✅ Yes | Auth state |
| Chatbot.tsx | ✅ Yes | Interactive |
**Recommendation:**
1. For animation-dependent components, consider:
- Static initial render as RSC
- Minimal client wrapper for animations only
- Use CSS animations where possible (GPU-accelerated)
2. Conversion pattern:
```tsx
// Before: Full client component
'use client';
export function PortfolioCard({ project }) {
return <div>{/* all content */}</div>;
}
// After: Server component with client wrapper
export function PortfolioCard({ project }) {
return (
<PortfolioCardWrapper>
<div>{/* static content */}</div>
</PortfolioCardWrapper>
);
}
```
**Expected Improvement:**
- JavaScript bundle: -50-150 KB
- TTI (Time to Interactive): -200-500ms
---
### 2.2 Loading States and Suspense Boundaries
**Issue:** No loading.tsx files detected for route segments.
**Recommendation:**
Create loading states for improved perceived performance:
```tsx
// src/app/[locale]/loading.tsx
export default function Loading() {
return (
<div className="animate-pulse">
<div className="h-8 bg-gray-200 rounded w-1/3 mb-4" />
<div className="h-4 bg-gray-200 rounded w-full mb-2" />
<div className="h-4 bg-gray-200 rounded w-2/3" />
</div>
);
}
// src/app/[locale]/portfolio/loading.tsx
export default function PortfolioLoading() {
return (
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{[...Array(6)].map((_, i) => (
<div key={i} className="animate-pulse rounded-lg bg-gray-200 h-64" />
))}
</div>
);
}
```
**Files to Create:**
- `src/app/[locale]/loading.tsx`
- `src/app/[locale]/about/loading.tsx`
- `src/app/[locale]/portfolio/loading.tsx`
- `src/app/[locale]/contact/loading.tsx`
---
### 2.3 Blur Placeholder for Hero Image
**Recommendation:**
Add blur placeholder for improved perceived LCP:
```tsx
// In Hero component
import Image from 'next/image';
// Generate blur data URL (base64 encoded tiny version)
const heroBlurDataURL = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..."; // Generate with plaiceholder
<Image
src="/hero-portrait.jpg"
alt="Damjan Savić"
fill
priority
placeholder="blur"
blurDataURL={heroBlurDataURL}
sizes="(max-width: 768px) 100vw, 50vw"
/>
```
**Implementation:**
1. Install plaiceholder: `pnpm add plaiceholder sharp`
2. Generate blur data URLs at build time
3. Update Image components with placeholder prop
---
## Priority 3: Medium-Impact Optimizations (Next Sprint)
### 3.1 Reduced Motion Support
**Issue:** Background SVG animations may cause issues for users with vestibular disorders.
**File:** `/src/components/layout/GlobalBackground.tsx`
**Recommendation:**
```tsx
// Add media query support
const GlobalBackground = () => {
const prefersReducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)');
if (prefersReducedMotion) {
return <StaticBackground />;
}
return <AnimatedBackground />;
};
// Or use CSS-only approach
<style>
@media (prefers-reduced-motion: reduce) {
.animated-bg * {
animation: none !important;
transition: none !important;
}
}
</style>
```
---
### 3.2 Third-Party Script Optimization
**Issue:** Google Analytics may block rendering if not loaded properly.
**Current Implementation:** Review needed
**Recommendations:**
1. Use Partytown for off-main-thread execution:
```bash
pnpm add @builder.io/partytown
```
2. Defer non-critical scripts:
```tsx
// In layout.tsx or Script component
import Script from 'next/script';
<Script
src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`}
strategy="afterInteractive"
/>
```
3. Consider self-hosting analytics for better control:
- Plausible Analytics (privacy-focused, <1KB)
- Umami Analytics (self-hosted option)
**Expected Improvement:**
- TBT (Total Blocking Time): -50-100ms
- FCP: -100-200ms
---
### 3.3 Font Loading Optimization
**Current State:** ✅ Font swap implemented (good baseline)
**Further Optimizations:**
1. Subset fonts to required characters only:
```css
/* Only load Latin subset */
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153;
}
```
2. Preload critical font files:
```html
<link
rel="preload"
href="/fonts/inter-var.woff2"
as="font"
type="font/woff2"
crossorigin="anonymous"
/>
```
3. Consider variable fonts to reduce total file count
---
### 3.4 Database Indexing for Chat
**Issue:** Chat queries may become slow with scale.
**Current Indexes:**
- `idx_chat_messages_session` on `session_id`
**Recommended Additional Indexes:**
```sql
-- For visitor lookup (session continuity)
CREATE INDEX idx_chat_sessions_visitor
ON chat_sessions(visitor_id);
-- For recent sessions (cleanup queries)
CREATE INDEX idx_chat_sessions_created
ON chat_sessions(created_at DESC);
-- For message ordering
CREATE INDEX idx_chat_messages_created
ON chat_messages(session_id, created_at);
-- Composite index for efficient session + message retrieval
CREATE INDEX idx_chat_messages_session_created
ON chat_messages(session_id, created_at DESC);
```
---
## Priority 4: Strategic Improvements (Backlog)
### 4.1 Progressive Web App (PWA) Implementation
**Benefit:** Offline support, app-like experience, improved mobile engagement
**Implementation:**
1. Create service worker:
```typescript
// src/app/sw.ts
import { precacheAndRoute } from 'workbox-precaching';
precacheAndRoute(self.__WB_MANIFEST);
```
2. Add manifest:
```json
// public/manifest.json
{
"name": "Damjan Savić - Portfolio",
"short_name": "DS Portfolio",
"start_url": "/",
"display": "standalone",
"background_color": "#0a0a0a",
"theme_color": "#3b82f6",
"icons": [
{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" }
]
}
```
3. Configure next.config.ts for PWA:
```bash
pnpm add next-pwa
```
---
### 4.2 Bundle Analysis and Code Splitting
**Recommendation:**
1. Analyze current bundle:
```bash
pnpm add @next/bundle-analyzer
# In next.config.ts
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
module.exports = withBundleAnalyzer(nextConfig);
# Run analysis
ANALYZE=true npm run build
```
2. Identify large dependencies for lazy loading:
- framer-motion (if not needed on all pages)
- lucide-react icons (ensure tree-shaking)
- openai SDK (server-only)
3. Implement dynamic imports for heavy components:
```tsx
const Chatbot = dynamic(() => import('@/components/chat/Chatbot'), {
loading: () => <ChatbotSkeleton />,
ssr: false,
});
```
---
### 4.3 Edge Caching Strategy
**Current State:** Static assets cached for 1 year (good)
**Additional Recommendations:**
1. Configure Vercel Edge Config for dynamic content:
```typescript
// Cache API responses at edge
export const runtime = 'edge';
export const revalidate = 60; // 1 minute
```
2. Implement stale-while-revalidate for blog posts:
```typescript
export async function generateStaticParams() {
return blogPosts.map((post) => ({ slug: post.slug }));
}
export const dynamicParams = true;
export const revalidate = 3600; // 1 hour
```
3. Use ISR (Incremental Static Regeneration) for portfolio projects
---
### 4.4 Content Delivery Optimization
**Recommendations:**
1. Enable Brotli compression (Vercel default)
2. Use HTTP/2 Push for critical resources
3. Implement preload hints:
```html
<link rel="preload" href="/fonts/inter.woff2" as="font" crossorigin />
<link rel="preload" href="/hero-portrait.avif" as="image" />
<link rel="preconnect" href="https://api.deepseek.com" />
```
---
## Monitoring and Continuous Improvement
### Recommended Monitoring Stack
| Tool | Purpose | Priority |
|------|---------|----------|
| Google Search Console | SEO monitoring, indexing issues | ✅ Required |
| Google Analytics 4 | Traffic, user behavior | ✅ Already Implemented |
| Web Vitals Dashboard | CWV tracking over time | ⭐ Recommended |
| Vercel Analytics | Performance insights | ⭐ Recommended |
| Lighthouse CI | Automated performance testing | 🔄 Consider |
### Automated Testing Pipeline
```yaml
# .github/workflows/lighthouse.yml
name: Lighthouse CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm run build
- run: npm start &
- run: npx lighthouse-ci autorun
```
---
## Implementation Roadmap
### Week 1 (Immediate)
- [ ] Optimize hero-portrait.jpg to <500KB
- [ ] Verify production PageSpeed scores via web interface
- [ ] Remove unused large images
### Week 2-3 (High Priority)
- [ ] Audit and convert client components to RSC where possible
- [ ] Add loading.tsx files for all route segments
- [ ] Implement blur placeholders for hero images
### Month 1 (Medium Priority)
- [ ] Add prefers-reduced-motion support
- [ ] Optimize third-party script loading
- [ ] Add database indexes for chat tables
### Quarter 1 (Strategic)
- [ ] Implement PWA with service worker
- [ ] Run bundle analysis and optimize
- [ ] Set up Lighthouse CI in GitHub Actions
- [ ] Configure edge caching for dynamic content
---
## Success Metrics
| Metric | Current | Target | Measurement |
|--------|---------|--------|-------------|
| PageSpeed Performance (Desktop) | 47-69%* | ≥90% | PageSpeed Insights |
| PageSpeed Performance (Mobile) | 40-60%* | ≥90% | PageSpeed Insights |
| LCP | ~3-5s* | <2.5s | Web Vitals |
| INP | Unknown | <200ms | Web Vitals |
| CLS | <0.25 | <0.1 | Web Vitals |
| Total Page Weight | ~4-5MB | <1.5MB | Network Panel |
| JavaScript Bundle | ~1.3MB* | <500KB | Bundle Analyzer |
*Development mode estimates; production expected to be significantly better.
---
## References
### Documentation
- [Next.js Performance Guide](https://nextjs.org/docs/pages/building-your-application/optimizing)
- [Core Web Vitals](https://web.dev/vitals/)
- [PageSpeed Insights](https://pagespeed.web.dev/)
- [Lighthouse CI](https://github.com/GoogleChrome/lighthouse-ci)
### Related Reports
- `PERFORMANCE_BASELINE.md` - Initial performance analysis
- `PAGESPEED_VERIFICATION_REPORT.md` - PageSpeed test results
- `SEO_FINAL_STATUS_COMPLETE.md` - SEO implementation status
- `SEO_AUDIT_REPORT.md` - Detailed SEO findings
---
*Report generated by auto-claude as part of the SEO Optimization, Performance Testing & Chatbot Integration project.*