---
title: "Building a Zero-Backend Privacy-First Micro-SaaS Decision Suite with Next.js 15, App Router & Web Workers"
description: "How to build a zero-server privacy-first micro-SaaS suite using Next.js 15 SSG, Web Workers, and automated Open Graph dynamic metadata."
tags: ["nextjs", "react", "typescript", "webdev"]
canonical_url: "https://entscheidomat.com/ratgeber/zufallsgenerator-richtig-nutzen"
target_keywords: ["entscheidungshilfe online", "entscheidungsfinder", "zufallsgenerator online", "nextjs 15 app router", "web workers react"]
---

# Building a Zero-Backend Privacy-First Micro-SaaS Decision Suite with Next.js 15, App Router & Web Workers

Building and scaling modern web applications often involves managing complex server infrastructure: database connections, user authentication, server-side API rate limiting, and monthly hosting bills.

However, for utilities like decision tools, random generators, or productivity suites (such as [Entscheidomat](https://entscheidomat.com)), a **Zero-Backend Client-First Architecture** offers immense benefits:
1. **$0 Hosting Infrastructure Costs:** The application compiles to static HTML/JS/CSS assets deployed to global CDNs (Vercel, Cloudflare Pages, Netlify).
2. **100% GDPR & Privacy Compliance:** User data (lists, names, decision options) never leaves the browser. Zero data server transmission.
3. **Instant Performance:** Near 100/100 Google Lighthouse scores with sub-second page loads.

In this article, we will examine how to architect a privacy-first Micro-SaaS decision suite using **Next.js 15 App Router**, **Static Site Generation (SSG)**, **Web Workers** for heavy computation, and **Dynamic Open Graph image generation**.

---

## 1. Architecture Overview: Zero-Backend Client Suite

In a zero-backend architecture, the browser handles 100% of data persistence (via `localStorage` and `IndexedDB`) and computation.

```text
 ┌────────────────────────────────────────────────────────────────────────┐
 │                      Next.js 15 App Router (SSG)                       │
 ├─────────────────────────┬───────────────────┬──────────────────────────┤
 │ Static Page Engine      │ Web Workers Engine│ Dynamic Open Graph (@og) │
 │ (Next.js HTML/CSS)      │ (Heavy PRNG Tasks)│ (Social Share Previews)  │
 └────────────┬────────────┴─────────┬─────────┴─────────────┬────────────┘
              │                      │                       │
              ▼                      ▼                       ▼
    ┌──────────────────┐   ┌──────────────────┐    ┌────────────────────┐
    │ Browser Storage  │   │ Web Crypto API   │    │ Social Networks    │
    │ (localStorage)   │   │ (PRNG Engine)    │    │ (Twitter/LinkedIn) │
    └──────────────────┘   └──────────────────┘    └────────────────────┘
```

---

## 2. Offloading Heavy Computation to Web Workers in React

If a user imports a list of 50,000 items to shuffle or run Monte Carlo simulations on, executing the calculation on React's main thread will lock the UI, dropping frames and causing unresponsive UI lag.

We solve this by offloading computation to a **Web Worker**:

### `worker/shuffle.worker.ts`
```typescript
// Web Worker for background array shuffling and simulations
ctx.addEventListener("message", (event: MessageEvent<{ items: string[] }>) => {
  const { items } = event.data;
  const result = [...items];

  // Fisher-Yates Shuffle inside Web Worker
  const buffer = new Uint32Array(1);
  for (let i = result.length - 1; i > 0; i--) {
    crypto.getRandomValues(buffer);
    const j = Math.floor((buffer[0] / (0xFFFFFFFF + 1)) * (i + 1));
    const temp = result[i];
    result[i] = result[j];
    result[j] = temp;
  }

  // Send shuffled result back to main thread
  ctx.postMessage({ shuffled: result });
});

export {};
```

### React Custom Hook: `useShuffleWorker.ts`
```typescript
import { useState, useEffect, useCallback } from "react";

export function useShuffleWorker() {
  const [worker, setWorker] = useState<Worker | null>(null);
  const [isProcessing, setIsProcessing] = useState<boolean>(false);

  useEffect(() => {
    // Instantiate Web Worker on component mount
    const w = new Worker(new URL("../worker/shuffle.worker.ts", import.meta.url));
    setWorker(w);

    return () => {
      w.terminate();
    };
  }, []);

  const processShuffle = useCallback((items: string[]): Promise<string[]> => {
    return new Promise((resolve) => {
      if (!worker) return resolve(items);

      setIsProcessing(true);

      const handleMessage = (e: MessageEvent<{ shuffled: string[] }>) => {
        setIsProcessing(false);
        worker.removeEventListener("message", handleMessage);
        resolve(e.data.shuffled);
      };

      worker.addEventListener("message", handleMessage);
      worker.postMessage({ items });
    });
  }, [worker]);

  return { processShuffle, isProcessing };
}
```

---

## 3. Automated Open Graph Image Generation in Next.js 15

To drive organic viral traffic from social media shares (Twitter, LinkedIn, WhatsApp), every page must output custom dynamic Open Graph banner images containing the page title and tool parameters.

Using Next.js 15 `@vercel/og` (`ImageResponse` API), we generate dynamic social cards on the fly:

### `app/ratgeber/[slug]/opengraph-image.tsx`
```typescript
import { ImageResponse } from "next/og";
import { getGuide } from "@/lib/guides";

export const runtime = "edge";
export const alt = "Entscheidomat Ratgeber";
export const size = { width: 1200, height: 630 };
export const contentType = "image/png";

export default async function Image({ params }: { params: { slug: string } }) {
  const guide = getGuide(params.slug);
  const title = guide ? guide.title : "Entscheidomat Ratgeber";

  return new ImageResponse(
    (
      <div
        style={{
          background: "linear-gradient(135deg, #101114 0%, #1c2237 100%)",
          width: "100%",
          height: "100%",
          display: "flex",
          flexDirection: "column",
          alignItems: "flex-start",
          justifyContent: "center",
          padding: "60px 80px",
          color: "#ffffff",
          fontFamily: "sans-serif",
        }}
      >
        {/* Brand Tag */}
        <div
          style={{
            fontSize: 20,
            fontWeight: 700,
            letterSpacing: "0.15em",
            color: "#7d97ff",
            textTransform: "uppercase",
            marginBottom: 24,
          }}
        >
          ENTSCHEIDOMAT · RATGEBER
        </div>

        {/* Dynamic Title */}
        <div
          style={{
            fontSize: 48,
            fontWeight: 800,
            lineHeight: 1.25,
            maxWidth: "900px",
            color: "#eceef2",
          }}
        >
          {title}
        </div>

        {/* Footer Domain Badge */}
        <div
          style={{
            marginTop: 40,
            display: "flex",
            alignItems: "center",
            gap: "12px",
            fontSize: 22,
            color: "#7b818c",
          }}
        >
          <span>entscheidomat.com</span>
        </div>
      </div>
    ),
    { ...size }
  );
}
```

---

## 4. Next.js 15 Metadata & Canonical URL Configuration

To ensure maximum organic search engine rankings, every route must export proper SEO metadata tags with cross-domain canonical URLs:

```typescript
import type { Metadata } from "next";

export async function generateMetadata({ params }: { params: { slug: string } }): Promise<Metadata> {
  const guide = getGuide(params.slug);

  if (!guide) {
    return { title: "Not Found" };
  }

  const canonicalUrl = `https://entscheidomat.com/ratgeber/${guide.slug}`;

  return {
    title: `${guide.title} | Entscheidomat`,
    description: guide.description,
    alternates: {
      canonical: canonicalUrl,
    },
    openGraph: {
      title: guide.title,
      description: guide.description,
      url: canonicalUrl,
      siteName: "Entscheidomat",
      locale: "de_DE",
      type: "article",
    },
    twitter: {
      card: "summary_large_image",
      title: guide.title,
      description: guide.description,
    },
  };
}
```

---

## Summary & Key Takeaways

1. **Zero-Backend Architecture:** Compiling to static HTML (SSG) delivers $0$ infrastructure cost, 100% GDPR compliance, and sub-second page loading speeds.
2. **Web Workers:** Keep React main threads smooth at 60 FPS by executing computational tasks (array shuffles, Monte Carlo simulations) in Web Workers.
3. **Dynamic Open Graph Images:** Use `@vercel/og` in Next.js 15 to automatically synthesize 1200x630 social preview banners.

Explore a zero-backend decision suite live on [Entscheidomat](https://entscheidomat.com).

---

## FAQ (Schema Structured Data)

```json
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "What is a Zero-Backend Micro-SaaS architecture?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "A zero-backend web architecture compiles the app into static client assets (SSG) where 100% of state and logic executes inside the user's browser, eliminating server hosting costs and GDPR risks."
      }
    },
    {
      "@type": "Question",
      "name": "Why use Web Workers in Next.js applications?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Web Workers offload heavy computations to background browser threads, preventing UI freeze and maintaining smooth 60 FPS user interaction."
      }
    }
  ]
}
```
