Current production website for Stackwerkhaus. The project is the public business site for a German-first web and automation studio, combining service positioning, case-study content, Drupal-backed publishing, conversion-oriented landing sections, and a lightweight contact pipeline.
Stackwerkhaus needed more than a personal portfolio: the site has to explain the offer, show credible project work, publish content, and convert qualified inquiries without feeling like a generic agency template.
I built a content-driven Next.js 16 site with a sharp German positioning layer, routed service and project pages, Drupal blog publishing, local MDX case studies, technical SEO primitives, and reduced-motion-safe GSAP islands.
- Use App Router metadata routes for sitemap, robots, and canonical structure
- Keep motion isolated in client components so content and SEO stay server-first
- Support local preview mode when live email credentials are not available
- Separate Drupal blog content from local project case studies
- Keep verification scripts close to the publishing and smoke-test paths
The repository now represents the live Stackwerkhaus website and should be read as a current production case, not an old portfolio rebuild experiment.
- Production-oriented Next.js 16 / React 19 implementation
- German-first content architecture for services, case studies, and landing pages
- Drupal-backed blog publishing plus local MDX project content
- SEO primitives, sitemap generation, robots handling, and metadata structure
- Motion-enhanced UI with reduced-motion-safe GSAP client islands
- Contact flow that can run locally without live email delivery
This repository is not a generic starter. It is a content-driven production site with:
- a custom homepage and section-based marketing layout
- routed blog and project detail pages
- Drupal-backed blog publishing plus local MDX project entries
- technical SEO primitives such as metadata,
robots.ts, andsitemap.ts - motion-enhanced UI with reduced-motion-safe GSAP client islands
- a contact endpoint that can run in preview mode without live email delivery
Next.js 16with the App RouterReact 19TypeScriptTailwind CSS v4GSAPand@gsap/reactnext-mdx-remotefor local project MDX renderingResendfor contact email delivery
app/ App Router pages, metadata routes, and API handlers
components/ Layout, section, UI, and MDX rendering components
content/ Local MDX content for project entries
lib/ Site config, content loaders, animation helpers, utilities
public/ Static images, icons, logos, and project assets
scripts/ Content and smoke test scripts
tests/ Additional verification assets
- Node.js 22.19+
pnpm
pnpm installpnpm devThe app runs locally with Next.js development tooling and uses .env.local for local configuration.
pnpm dev # start local development
pnpm build # production build
pnpm start # run the built app
pnpm lint # eslint across the repo
pnpm typecheck # TypeScript without emit
pnpm test:content # content-level checks
pnpm test:drupal-richtext # Drupal rich text parser tests
pnpm test:mobile # rich text tests + mobile smoke pass
pnpm test:smoke # rich text tests + general smoke pass
pnpm start:local-prod # start local production server on 127.0.0.1:3000
pnpm lighthouse # run local Lighthouse budgets for home, blog, and project detailCopy .env.example to .env.local and provide only what you need for the current environment:
| Variable | Purpose |
|---|---|
NEXT_PUBLIC_SITE_URL |
Canonical site URL used for metadata and sitemap generation |
NEXT_PUBLIC_PLAUSIBLE_DOMAIN |
Enables analytics integration when set |
RESEND_API_KEY |
Enables live contact email delivery |
CONTACT_TO_EMAIL |
Override recipient for inbound contact submissions |
SMOKE_BASE_URL |
Base URL for local smoke and Lighthouse validation |
SMOKE_BLOG_SLUG |
Deterministic Drupal blog detail slug for verification |
- If
RESEND_API_KEYis missing, the contact API stays in validation-only preview mode and returns a successful non-sending response. - If
NEXT_PUBLIC_PLAUSIBLE_DOMAINis missing, analytics remains disabled in local and preview environments.
Use .env.local.test for all local signoff work. It pins canonicals to http://127.0.0.1:3000 and gives the smoke/Lighthouse scripts deterministic route inputs.
set -a
source .env.local.test
pnpm build
pnpm start:local-prodRun verification in a second shell with the same env loaded:
set -a
source .env.local.test
pnpm lint
pnpm typecheck
pnpm test:content
pnpm test:smoke
pnpm test:mobile
pnpm lighthouseThe Lighthouse runner enforces full budgets for the blog and project detail routes. The homepage still audits accessibility, best practices, and SEO, but it treats a performance: null result as a warning because the hero shell intentionally stays hidden until the intro animation is ready.
- Blog posts are published through Drupal JSON:API
- Project entries live in
content/projects - Routed detail pages are generated from content loaders in
lib/ - The default site language and marketing copy are German
- Motion is intentionally isolated to client components and includes reduced-motion-safe fallbacks.
- The site-level metadata is centrally defined through
lib/site-config.tsandapp/layout.tsx. - The contact flow is implemented in
app/api/contact/route.ts. - SEO support is part of the app surface, including
app/sitemap.tsandapp/robots.ts.
