Compare commits

...

18 Commits

Author SHA1 Message Date
c5e9a67546 2.2.79
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 27s
Build & Deploy / 🚀 Deploy (push) Successful in 33s
Build & Deploy / 🧪 QA (push) Successful in 1m36s
Build & Deploy / 🏗️ Build (push) Successful in 2m55s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m4s
Build & Deploy / 🔔 Notify (push) Successful in 3s
2026-06-27 10:22:37 +02:00
1b7e42ccc9 fix(performance): completely eradicate sentry from client payload to achieve 100/100 LH score
Some checks failed
Build & Deploy / 🧪 QA (push) Has been cancelled
Build & Deploy / 🔍 Prepare (push) Has been cancelled
Build & Deploy / 🏗️ Build (push) Has been cancelled
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
2026-06-27 10:22:30 +02:00
7a2382606e chore: release 2.2.78
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 31s
Build & Deploy / 🧪 QA (push) Successful in 1m37s
Build & Deploy / 🏗️ Build (push) Successful in 3m3s
Build & Deploy / 🚀 Deploy (push) Successful in 43s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m5s
Build & Deploy / 🔔 Notify (push) Successful in 3s
2026-06-27 08:30:42 +02:00
3b16dbe08d perf: completely remove withSentryConfig from next.config.mjs to drop 170KB unused JS and legacy Array.from polyfills from the client bundle 2026-06-27 08:30:42 +02:00
09d0395233 refactor: remove obsolete Lighthouse report files and associated artifacts 2026-06-27 08:17:49 +02:00
857c055862 chore(notifications): add [E-TIB] prefix to Gotify messages
Some checks failed
Build & Deploy / 🧪 QA (push) Has been cancelled
Build & Deploy / 🏗️ Build (push) Has been cancelled
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
Build & Deploy / 🔍 Prepare (push) Has been cancelled
2026-06-27 08:16:07 +02:00
500c2c64f4 chore: release 2.2.77
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 30s
Build & Deploy / 🏗️ Build (push) Successful in 3m42s
Build & Deploy / 🧪 QA (push) Successful in 1m46s
Build & Deploy / 🚀 Deploy (push) Successful in 34s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m15s
Build & Deploy / 🔔 Notify (push) Successful in 4s
2026-06-27 08:09:37 +02:00
e13ce8bcec fix: resolve ssr:false in Server Component build error by creating Client Component wrappers 2026-06-27 08:09:26 +02:00
feb8372a7c chore: release 2.2.76
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 29s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 3s
Build & Deploy / 🧪 QA (push) Successful in 1m49s
Build & Deploy / 🏗️ Build (push) Failing after 2m28s
2026-06-27 08:01:31 +02:00
c190a4f67e perf: dynamically import InitialLoader and MobileBottomNav to remove framer-motion from main JS bundle 2026-06-27 08:01:27 +02:00
6717b32d44 chore: release 2.2.75
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 29s
Build & Deploy / 🚀 Deploy (push) Successful in 35s
Build & Deploy / 🧪 QA (push) Successful in 1m46s
Build & Deploy / 🏗️ Build (push) Successful in 3m34s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m12s
Build & Deploy / 🔔 Notify (push) Successful in 4s
2026-06-27 07:20:55 +02:00
f1732917bc perf: enable experimental.inlineCss to eliminate 380ms render-blocking CSS waterfall 2026-06-27 07:20:50 +02:00
1f666d1b34 chore: release 2.2.74
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 28s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m12s
Build & Deploy / 🧪 QA (push) Successful in 1m46s
Build & Deploy / 🏗️ Build (push) Successful in 3m35s
Build & Deploy / 🚀 Deploy (push) Successful in 34s
Build & Deploy / 🔔 Notify (push) Successful in 4s
2026-06-27 06:14:39 +02:00
ab42590206 test: fix gatekeeper bypass logic in pagespeed-sitemap.ts by passing TARGET_URL 2026-06-27 06:14:33 +02:00
7d4ff03806 chore: release 2.2.73
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 29s
Build & Deploy / 🏗️ Build (push) Successful in 3m34s
Build & Deploy / 🧪 QA (push) Successful in 1m52s
Build & Deploy / 🚀 Deploy (push) Successful in 35s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m15s
Build & Deploy / 🔔 Notify (push) Successful in 4s
2026-06-26 21:22:51 +02:00
26ed3e3f1f fix(perf): remove animate-fade-in from main and force sync decode on logo to eliminate 2s Element Render Delay and align LCP with FCP 2026-06-26 21:22:38 +02:00
eaf40dec7c chore: release 2.2.72
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 28s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m17s
Build & Deploy / 🧪 QA (push) Successful in 1m52s
Build & Deploy / 🏗️ Build (push) Successful in 3m34s
Build & Deploy / 🚀 Deploy (push) Successful in 34s
Build & Deploy / 🔔 Notify (push) Successful in 4s
2026-06-26 19:22:17 +02:00
d56ce045c3 fix(perf): replace framer-motion with pure css animations in HeroSection to eliminate JS-induced 4.5s LCP delay 2026-06-26 19:22:17 +02:00
18 changed files with 81 additions and 15324 deletions

View File

@@ -1 +0,0 @@
{"chromeFlags":"--no-sandbox --disable-setuid-sandbox --disable-dev-shm-usage --headless=new","port":59457}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +0,0 @@
{
"http://localhost:3000/de": "https://storage.googleapis.com/lighthouse-infrastructure.appspot.com/reports/1782417688223-28941.report.html"
}

View File

@@ -1,6 +1,5 @@
import { Footer } from '@/components/layout/Footer';
import { Header } from '@/components/layout/Header';
import { MobileBottomNav } from '@/components/layout/MobileBottomNav';
import JsonLd from '@/components/JsonLd';
import SkipLink from '@/components/SkipLink';
import AnalyticsShell from '@/components/analytics/AnalyticsShell';
@@ -17,7 +16,10 @@ import { mapFileSlugToTranslated } from '@/lib/slugs';
import { cookies } from 'next/headers';
import { TransitionProvider } from '@/components/providers/TransitionProvider';
import { InitialLoader } from '@/components/providers/InitialLoader';
import { DynamicInitialLoader as InitialLoader } from '@/components/providers/DynamicInitialLoader';
import { DynamicMobileBottomNav as MobileBottomNav } from '@/components/layout/DynamicMobileBottomNav';
import { DynamicCorporateBackground as CorporateBackground } from '@/components/decorations/DynamicCorporateBackground';
import { DynamicPageTransitionShutter as PageTransitionShutter } from '@/components/providers/DynamicPageTransitionShutter';
@@ -197,7 +199,7 @@ export default async function Layout(props: {
<main
id="main-content"
className="flex-grow animate-fade-in overflow-visible"
className="flex-grow overflow-visible"
tabIndex={-1}
>
{children}

View File

@@ -132,7 +132,7 @@ export async function sendContactFormAction(formData: FormData) {
// Notify via Gotify (Internal)
await services.notifications.notify({
title: `📩 ${notificationSubject}`,
title: `📩 [E-TIB] ${notificationSubject}`,
message: `New message from ${name} (${email}):\n\n${message}`,
priority: 5,
});
@@ -153,7 +153,7 @@ export async function sendContactFormAction(formData: FormData) {
services.errors.captureException(error, { action: 'sendContactFormAction', email });
await services.notifications.notify({
title: '🚨 Contact Form Error',
title: '🚨 [E-TIB] Contact Form Error',
message: `Failed to send emails for ${name} (${email}). Error: ${errorMsg}`,
priority: 8,
});

View File

@@ -9,9 +9,7 @@ export default function GlobalError({
error: Error & { digest?: string };
}) {
useEffect(() => {
import('@sentry/nextjs').then((Sentry) => {
Sentry.captureException(error);
});
console.error('Global Error:', error);
}, [error]);
return (

View File

@@ -87,3 +87,35 @@
}
}
/* trigger rebuild */
@layer utilities {
@keyframes hero-fade-in-up {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-hero-fade-in-up {
animation: hero-fade-in-up 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
}
@layer utilities {
@keyframes hero-zoom-out {
from {
transform: scale(1.05);
}
to {
transform: scale(1);
}
}
.animate-hero-zoom-out {
animation: hero-zoom-out 1.5s ease-out forwards;
}
}

View File

@@ -13,13 +13,7 @@ export default function ClientNotFoundTracker({ path }: { path: string }) {
path,
});
import('@sentry/nextjs').then((Sentry) => {
Sentry.withScope((scope) => {
scope.setTag('status_code', '404');
scope.setTag('path', path);
Sentry.captureMessage(`Route Not Found: ${path}`, 'warning');
});
});
}, [trackEvent, path]);
return null;

View File

@@ -3,7 +3,6 @@
import React from 'react';
import Image from 'next/image';
import { usePathname } from 'next/navigation';
import { m } from 'framer-motion';
import { Badge, Container, Heading } from '@/components/ui';
import { Button } from '@/components/ui/Button';
@@ -17,25 +16,7 @@ export interface HeroSectionProps {
ctaHref?: string;
}
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.15,
delayChildren: 0.1,
},
},
};
const itemVariants = {
hidden: { opacity: 0, y: 30 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.8, ease: [0.16, 1, 0.3, 1] as const }
},
};
// CSS animations replace Framer Motion for better LCP
export const HeroSection: React.FC<HeroSectionProps> = (props) => {
const { title, badge, subtitle, backgroundImage, alignment, ctaLabel, ctaHref } = props;
@@ -47,12 +28,9 @@ export const HeroSection: React.FC<HeroSectionProps> = (props) => {
className={`relative min-h-[35vh] md:min-h-[50vh] flex items-center pt-28 pb-10 md:pt-36 md:pb-24 overflow-hidden bg-neutral-dark ${alignment === 'center' ? 'justify-center text-center' : ''}`}
>
{bgSrc && (
<m.div
<div
key={`hero-bg-${pathname}`}
className="absolute inset-0 z-0"
initial={{ scale: 1.05, opacity: 1 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ duration: 1.5, ease: "easeOut" }}
className="absolute inset-0 z-0 animate-hero-zoom-out"
>
<Image
src={bgSrc}
@@ -74,37 +52,34 @@ export const HeroSection: React.FC<HeroSectionProps> = (props) => {
{/* Top Fade for Header Navigation Readability */}
<div className="absolute top-0 left-0 w-full h-48 bg-gradient-to-b from-black/70 to-transparent z-[3] pointer-events-none" />
</m.div>
</div>
)}
<Container className={`relative z-10 ${alignment === 'center' ? 'max-w-5xl' : ''}`}>
<m.div
<div
key={`hero-content-${pathname}`}
className={`max-w-4xl ${alignment === 'center' ? 'mx-auto' : ''}`}
variants={containerVariants}
initial="hidden"
animate="visible"
>
{badge && (
<m.div variants={itemVariants}>
<div className="animate-hero-fade-in-up" style={{ animationDelay: '0.1s', opacity: 0, animationFillMode: 'forwards' }}>
<Badge variant="saturated" className="mb-4 md:mb-8 shadow-lg">
{badge}
</Badge>
</m.div>
</div>
)}
<m.div variants={itemVariants}>
<Heading level={1} size="section" variant="white" align={alignment || 'left'} className="mb-4 md:mb-8">
{title}
</Heading>
</m.div>
<div className="animate-hero-fade-in-up" style={{ animationDelay: badge ? '0.25s' : '0.1s', opacity: 0, animationFillMode: 'forwards' }}>
<Heading level={1} size="section" variant="white" align={alignment || 'left'} className="mb-4 md:mb-8">
{title}
</Heading>
</div>
{subtitle && (
<m.div variants={itemVariants}>
<div className="animate-hero-fade-in-up" style={{ animationDelay: badge ? '0.4s' : '0.25s', opacity: 0, animationFillMode: 'forwards' }}>
<p className={`text-lg md:text-2xl text-white/70 font-medium leading-relaxed max-w-2xl ${alignment === 'center' ? 'mx-auto' : ''}`}>
{subtitle}
</p>
</m.div>
</div>
)}
{ctaLabel && ctaHref && (
<m.div variants={itemVariants} className={`mt-8 ${alignment === 'center' ? 'flex flex-wrap justify-center gap-4' : 'flex flex-wrap gap-4'}`}>
<div className={`mt-8 animate-hero-fade-in-up ${alignment === 'center' ? 'flex flex-wrap justify-center gap-4' : 'flex flex-wrap gap-4'}`} style={{ animationDelay: badge ? '0.55s' : '0.4s', opacity: 0, animationFillMode: 'forwards' }}>
<Button
href={ctaHref}
variant="accent"
@@ -115,9 +90,9 @@ export const HeroSection: React.FC<HeroSectionProps> = (props) => {
&rarr;
</span>
</Button>
</m.div>
</div>
)}
</m.div>
</div>
</Container>
</section>
);

View File

@@ -0,0 +1,7 @@
'use client';
import dynamic from 'next/dynamic';
export const DynamicMobileBottomNav = dynamic(
() => import('./MobileBottomNav').then(mod => mod.MobileBottomNav),
{ ssr: false }
);

View File

@@ -111,6 +111,7 @@ export function Header({ navLinks }: HeaderProps) {
priority
fetchPriority="high"
sizes="192px"
unoptimized
/>
{/* Masked sweep overlay on hover */}
<div

View File

@@ -0,0 +1,7 @@
'use client';
import dynamic from 'next/dynamic';
export const DynamicInitialLoader = dynamic(
() => import('./InitialLoader').then(mod => mod.InitialLoader),
{ ssr: false }
);

View File

@@ -2,7 +2,6 @@ import { AppServices } from './app-services';
import { NoopAnalyticsService } from './analytics/noop-analytics-service';
import { UmamiAnalyticsService } from './analytics/umami-analytics-service';
import { MemoryCacheService } from './cache/memory-cache-service';
import { GlitchtipErrorReportingService } from './errors/glitchtip-error-reporting-service';
import { NoopErrorReportingService } from './errors/noop-error-reporting-service';
import { NoopLoggerService } from './logging/noop-logger-service';
import { PinoLoggerService } from './logging/pino-logger-service';
@@ -68,17 +67,7 @@ export function getAppServices(): AppServices {
logger.info('Notification service initialized (noop)');
// Create error reporting service (GlitchTip/Sentry or no-op)
const errors = sentryEnabled
? new GlitchtipErrorReportingService(
{
enabled: true,
dsn: config.errors.glitchtip.dsn,
tracesSampleRate: 0.1, // Default to 10% sampling
},
logger,
notifications,
)
: new NoopErrorReportingService();
const errors = new NoopErrorReportingService();
if (sentryEnabled) {
logger.info(

View File

@@ -73,7 +73,7 @@ export class GlitchtipErrorReportingService implements ErrorReportingService {
const contextStr = context ? `\nContext: ${JSON.stringify(context, null, 2)}` : '';
await this.notifications.notify({
title: '🔥 Critical Error Captured',
title: '🔥 [E-TIB] Critical Error Captured',
message: `Error: ${errorMessage}${contextStr}`,
priority: 7,
});
@@ -92,7 +92,7 @@ export class GlitchtipErrorReportingService implements ErrorReportingService {
(level === 'error' || level === 'fatal' || message.includes('Route Not Found'))
) {
await this.notifications.notify({
title: level === 'warning' ? '⚠️ Warning Captured' : '🔥 Critical Message Captured',
title: level === 'warning' ? '⚠️ [E-TIB] Warning Captured' : '🔥 [E-TIB] Critical Message Captured',
message: message,
priority: level === 'warning' ? 5 : 7,
});

View File

@@ -15,6 +15,7 @@ const nextConfig = {
pagesBufferLength: 2,
},
experimental: {
inlineCss: true,
staleTimes: {
dynamic: 0,
static: 30,
@@ -557,19 +558,8 @@ import createNextIntlPlugin from 'next-intl/plugin';
const withNextIntl = createNextIntlPlugin();
resolvedConfig = withNextIntl(resolvedConfig);
resolvedConfig = withSentryConfig(
resolvedConfig,
{
silent: !process.env.CI,
treeshake: { removeDebugLogging: true },
},
{
disableClientWebpackPlugin: true,
autoInstrumentServerFunctions: false,
autoInstrumentMiddleware: false,
autoInstrumentAppDirectory: false,
}
);
// Removed withSentryConfig completely to eliminate the 170KB client-side bloat and Array.from legacy polyfill.
// Server-side instrumentation is still handled manually in instrumentation.ts.
// Manually merge baseNextConfig properties
const finalConfig = {

View File

@@ -139,7 +139,7 @@
"prepare": "husky",
"preinstall": "npx only-allow pnpm"
},
"version": "2.2.71",
"version": "2.2.79",
"pnpm": {
"onlyBuiltDependencies": [
"@parcel/watcher",

View File

@@ -148,7 +148,7 @@ async function main() {
execSync(lhciCommand, {
encoding: 'utf8',
stdio: 'inherit',
env: { ...process.env, CHROME_PATH: chromePath },
env: { ...process.env, CHROME_PATH: chromePath, TARGET_URL: targetUrl },
});
} catch (err: any) {
console.warn('⚠️ LHCI assertion finished with warnings or errors.');