feat: rebuild mintel.me as a single-page freelance site

The site now presents one freelance developer on one page: hero, introduction,
four typical cases (developer for a product, make an app reliable, automate a
process, a website) with what you get, how it runs and what it costs, a
process automation section, technology and project fit, how I work, two live
references, questions and contact.

- Hero and closing headline are drawn from running binary digits.
- Each case explains its four steps with an animated drawing; the automation
  section shows example workflows with work travelling between systems; a
  pipeline run shows what a test catches before a release.
- Contact is one email address, kept in parts and assembled in the browser so
  it never appears in the page source (src/domain/email.ts, spec first).
- Imprint and privacy pages added.
- The old site (blog, case studies, contact form, fixed-price pages, video
  rendering and related scripts) is removed. Its URLs redirect to the homepage.
- The deploy smoke test checks the legal pages and the redirects instead of
  the removed case study.
- Dev scripts use docker compose v2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 22:33:06 +02:00
co-authored by Claude Opus 5.5
parent 4eb663f42a
commit fa40fefe2f
781 changed files with 4925 additions and 55137 deletions
+18 -47
View File
@@ -1,6 +1,5 @@
import withMintelConfig from "@mintel/next-config";
import createMDX from '@next/mdx';
import path from 'path';
import { fileURLToPath } from 'url';
@@ -16,15 +15,6 @@ const nextConfig = {
'require-in-the-middle',
'import-in-the-middle'
],
transpilePackages: [
'@mintel/content-engine',
'@mintel/concept-engine',
'@mintel/estimation-engine',
'@mintel/meme-generator',
'@mintel/pdf',
'@mintel/thumbnail-generator'
],
images: {
remotePatterns: [
{
@@ -37,51 +27,32 @@ const nextConfig = {
},
],
},
// The site is a single page. Old URLs from the previous site lead to it.
async redirects() {
return [
{
source: '/case-studies/klz',
destination: '/case-studies/klz-cables',
permanent: true,
},
];
},
async rewrites() {
return {
beforeFiles: [
// Map Patttern: Global assets moved into KLZ showcase folder
{
source: '/assets/klz-cables.com/:path*',
destination: '/showcase/klz-cables.com/assets/klz-cables.com/:path*',
},
{
source: '/wp-content/:path*',
destination: '/showcase/klz-cables.com/wp-content/:path*',
},
{
source: '/wp-includes/:path*',
destination: '/showcase/klz-cables.com/wp-includes/:path*',
},
{
source: '/case-studies/assets/:directory/:path*',
destination: '/showcase/:directory/assets/:directory/:path*',
},
]
};
"/about",
"/process",
"/notes/:path*",
"/book",
"/contact",
"/websites",
"/blog/:path*",
"/case-studies/:path*",
"/technologies/:path*",
"/tags/:path*",
]
.map((source) => ({ source, destination: "/", permanent: true }))
.concat([
{ source: "/impressum", destination: "/imprint", permanent: true },
{ source: "/datenschutz", destination: "/privacy", permanent: true },
]);
},
// In Standalone mode, Next.js expects the tracing root to be the monorepo root
outputFileTracingRoot: path.join(dirname, '../../'),
outputFileTracingIncludes: {
'/(site)/blog/[slug]': ['./content/blog/**/*'],
'/blog/[slug]': ['./content/blog/**/*'],
},
};
const withMDX = createMDX({});
// Clean, standard wrapper application
// Rewrites are now handled by src/middleware.ts for maximum robustness
const config = withMintelConfig(withMDX(nextConfig));
const config = withMintelConfig(nextConfig);
// Cleanup config to prevent Next.js 16 warnings about deprecated keys
if (config.serverActions) {