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>
15 KiB
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:
# 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:
- Compress original to <500KB maintaining visual quality
- Generate responsive variants (300, 600, 900, 1200px widths)
- Create AVIF and WebP versions for modern browser support
- Update Next.js Image component with blur placeholder
- 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:
- Run image usage audit:
grep -r "portrait.jpg" src/ --include="*.tsx" --include="*.ts" grep -r "hero-portrait.jpg" src/ --include="*.tsx" --include="*.ts" - Replace references with optimized versions
- Remove unused originals from
/public
1.3 Production Performance Verification
Issue: PageSpeed API was blocked during testing. Production verification required.
Action Required:
-
Visit PageSpeed Insights
-
Test all main URLs:
https://www.damjan-savic.com/dehttps://www.damjan-savic.com/enhttps://www.damjan-savic.com/srhttps://www.damjan-savic.com/de/abouthttps://www.damjan-savic.com/de/portfoliohttps://www.damjan-savic.com/de/contact
-
Document scores for Desktop and Mobile
-
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:
-
For animation-dependent components, consider:
- Static initial render as RSC
- Minimal client wrapper for animations only
- Use CSS animations where possible (GPU-accelerated)
-
Conversion pattern:
// 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:
// 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.tsxsrc/app/[locale]/about/loading.tsxsrc/app/[locale]/portfolio/loading.tsxsrc/app/[locale]/contact/loading.tsx
2.3 Blur Placeholder for Hero Image
Recommendation: Add blur placeholder for improved perceived LCP:
// 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:
- Install plaiceholder:
pnpm add plaiceholder sharp - Generate blur data URLs at build time
- 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:
// 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:
-
Use Partytown for off-main-thread execution:
pnpm add @builder.io/partytown -
Defer non-critical scripts:
// 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" /> -
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:
-
Subset fonts to required characters only:
/* 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; } -
Preload critical font files:
<link rel="preload" href="/fonts/inter-var.woff2" as="font" type="font/woff2" crossorigin="anonymous" /> -
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_sessiononsession_id
Recommended Additional Indexes:
-- 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:
-
Create service worker:
// src/app/sw.ts import { precacheAndRoute } from 'workbox-precaching'; precacheAndRoute(self.__WB_MANIFEST); -
Add manifest:
// 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" } ] } -
Configure next.config.ts for PWA:
pnpm add next-pwa
4.2 Bundle Analysis and Code Splitting
Recommendation:
-
Analyze current bundle:
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 -
Identify large dependencies for lazy loading:
- framer-motion (if not needed on all pages)
- lucide-react icons (ensure tree-shaking)
- openai SDK (server-only)
-
Implement dynamic imports for heavy components:
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:
-
Configure Vercel Edge Config for dynamic content:
// Cache API responses at edge export const runtime = 'edge'; export const revalidate = 60; // 1 minute -
Implement stale-while-revalidate for blog posts:
export async function generateStaticParams() { return blogPosts.map((post) => ({ slug: post.slug })); } export const dynamicParams = true; export const revalidate = 3600; // 1 hour -
Use ISR (Incremental Static Regeneration) for portfolio projects
4.4 Content Delivery Optimization
Recommendations:
- Enable Brotli compression (Vercel default)
- Use HTTP/2 Push for critical resources
- Implement preload hints:
<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
# .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
Related Reports
PERFORMANCE_BASELINE.md- Initial performance analysisPAGESPEED_VERIFICATION_REPORT.md- PageSpeed test resultsSEO_FINAL_STATUS_COMPLETE.md- SEO implementation statusSEO_AUDIT_REPORT.md- Detailed SEO findings
Report generated by auto-claude as part of the SEO Optimization, Performance Testing & Chatbot Integration project.