Migrate from Vite to Next.js 15 with SSR

- Replace Vite + React Router with Next.js 15 App Router
- Implement i18n with next-intl (URL-based: /de, /en, /sr)
- Add SSR/SSG for all pages (48 static pages generated)
- Setup Supabase SSR client for auth
- Migrate all pages: Home, About, Portfolio, Blog, Contact, Login, Dashboard, Imprint, Privacy, Terms
- Add Docker support with standalone output
- Replace i18next with next-intl JSON translations
- Use next/image for optimized images

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-17 01:00:33 +01:00
co-authored by Claude Opus 4.5
parent a66f51b9a2
commit b1ec7b4d61
281 changed files with 8024 additions and 8901 deletions
+123
View File
@@ -0,0 +1,123 @@
import { setRequestLocale } from 'next-intl/server';
import type { Metadata } from 'next';
import { getTranslations } from 'next-intl/server';
import Link from 'next/link';
type Props = {
params: Promise<{ locale: string }>;
};
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { locale } = await params;
const t = await getTranslations({ locale, namespace: 'portfolio.seo' });
return {
title: t('title'),
description: t('description'),
};
}
const projects = [
{
slug: 'ai-data-reader',
title: 'AI Data Reader',
description: 'KI-gestuetzte PDF-Datenextraktion mit Claude AI und JTL-Integration',
category: 'Data Processing',
technologies: ['Python', 'FastAPI', 'Claude AI', 'JTL-Wawi'],
featured: true,
},
{
slug: 'smart-warehouse',
title: 'Smart Warehouse',
description: 'RFID-basierte Lagerverwaltung mit IoT-Integration',
category: 'Integration',
technologies: ['Python', 'RFID', 'Zebra Hardware', 'PostgreSQL'],
featured: true,
},
{
slug: 'website-mit-ki',
title: 'KI-Portfolio Website',
description: 'Diese Portfolio-Website mit Next.js und modernen Web-Technologien',
category: 'Web Development',
technologies: ['Next.js', 'TypeScript', 'Tailwind CSS', 'Vercel'],
featured: true,
},
{
slug: 'power-platform-governance',
title: 'Power Platform Governance',
description: 'Enterprise Governance-Loesung fuer Microsoft Power Platform',
category: 'Enterprise Software',
technologies: ['Power Automate', 'SharePoint', 'Azure', 'TypeScript'],
featured: false,
},
];
export default async function PortfolioPage({ params }: Props) {
const { locale } = await params;
setRequestLocale(locale);
const t = await getTranslations('portfolio');
return (
<main className="min-h-screen py-20 px-4">
<div className="max-w-6xl mx-auto">
{/* Breadcrumb */}
<nav className="mb-8">
<Link href={`/${locale}`} className="text-zinc-400 hover:text-white transition-colors">
Home
</Link>
<span className="text-zinc-600 mx-2">/</span>
<span className="text-white">Portfolio</span>
</nav>
{/* Header */}
<section className="mb-16">
<h1 className="text-4xl sm:text-5xl font-bold mb-4">{t('sections.title')}</h1>
<p className="text-zinc-400 text-lg max-w-2xl">
{t('sections.subtitle')}
</p>
</section>
{/* Projects Grid */}
<section>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{projects.map((project) => (
<Link
key={project.slug}
href={`/${locale}/portfolio/${project.slug}`}
className="group bg-zinc-800/50 rounded-lg overflow-hidden border border-zinc-700/50 hover:border-zinc-600 transition-colors"
>
<div className="aspect-video bg-zinc-700/50 flex items-center justify-center">
<span className="text-zinc-500 text-sm">{project.category}</span>
</div>
<div className="p-6">
<div className="flex items-start justify-between mb-2">
<h2 className="text-xl font-semibold text-white group-hover:text-blue-400 transition-colors">
{project.title}
</h2>
{project.featured && (
<span className="text-xs bg-blue-600/20 text-blue-400 px-2 py-1 rounded">
Featured
</span>
)}
</div>
<p className="text-zinc-400 mb-4">{project.description}</p>
<div className="flex flex-wrap gap-2">
{project.technologies.map((tech) => (
<span
key={tech}
className="text-xs bg-zinc-700/50 text-zinc-300 px-2 py-1 rounded"
>
{tech}
</span>
))}
</div>
</div>
</Link>
))}
</div>
</section>
</div>
</main>
);
}