**TL;DR.** Weiterleitungen im E-Commerce dienen dazu, SEO-Wert bei URL-Änderungen zu bewahren. Verwenden Sie 301 für permanente Verschiebungen (Slug-Korrekturen, Rebrands). Verwenden Sie 410 für permanente Löschungen. Verfolgen Sie die Slughistorie pro Entität, damit alte URLs automatisch weitergeleitet werden. Erkennen und glätten Sie Ketten wöchentlich. Rendern Sie nicht mehr vorhandene Seiten mit nützlichen Inhalten, nicht mit generischen 404.

## HTTP-Statuscodes für E-Commerce

| Code | Name              | Bedeutung                     | Anwendungsfall                                      |
| ---- | ----------------- | ----------------------------- | --------------------------------------------------- |
| 200  | OK                | Seite existiert               | Normale Produkt-/Kategorie-Seite                     |
| 301  | Permanently Moved | Verwenden Sie die neue URL für immer | Slug-Änderungen, Rebrands, Domainmigrationen        |
| 302  | Found             | Temporäre Weiterleitung       | A/B-Tests, Geo-Weiterleitungen, temporäre Ausfälle   |
| 307  | Temporary Redirect | Dasselbe wie 302, aber bewahrt die Methode | API-Weiterleitungen mit POST                         |
| 308  | Permanent Redirect | Dasselbe wie 301, aber bewahrt die Methode | API-Weiterleitungen mit POST                         |
| 404  | Not Found         | Seite existiert nicht, könnte zurückkommen | Tippfehler, falsch erinnerte URLs                   |
| 410  | Gone              | Permanently removed           | Eingestellte Produkte, gelöschte Inhalte             |

Für E-Commerce ist das gängige Paar **301** für Verschiebungen und **410** für permanente Löschungen.

## Wann man 301 verwenden sollte

Häufige 301-Szenarien:

| Ereignis                     | Muster                                              |
| ---------------------------- | --------------------------------------------------- |
| Produkt-Slug-Korrektur (Tippfehler) | `/products/leather-bagg` → `/products/leather-bag`   |
| Produkt-Rebrand              | `/products/leather-bag` → `/products/heritage-bag`    |
| Kategorie-Neustrukturierung  | `/products/bags-leather` → `/categories/leather-bags` |
| Domainmigration              | `oldbrand.com/...` → `newbrand.com/...`               |
| Locale-URL-Änderung         | `/products/bag` → `/en/products/bag`                  |
| Normalisierung des abschließenden Schrägstrichs | `/products/bag/` → `/products/bag`                    |
| HTTP → HTTPS                 | `http://...` → `https://...`                          |

Implementierung in Next.js:

```ts
// next.config.ts
export default {
  async redirects() {
    return [
      {
        source: '/products/leather-bagg',
        destination: '/products/leather-bag',
        permanent: true,  // 301
      },
    ];
  },
};
```

Oder über eine Laufzeit-Weiterleitungstabelle:

```ts
// src/middleware.ts oder proxy.ts
const redirect = await getRedirect(request.url);
if (redirect) {
  return NextResponse.redirect(redirect.to, redirect.statusCode);
}
```

## Wann man 410 verwenden sollte

Ein 410 Gone ist die richtige Antwort, wenn:

- Ein Produkt dauerhaft eingestellt wird.
- Ein Blogbeitrag aus Genauigkeits- oder rechtlichen Gründen entfernt wird.
- Eine Kategorie mit einer anderen zusammengelegt wurde und der alte Slug dauerhaft gelöscht werden sollte.
- Eine Seite absichtlich gelöscht wird und nicht zurückkommt.

```ts
// Pseudocode
const gone = await isGonePath(storeId, request.url.pathname);
if (gone) {
  return new Response(renderGonePage(gone.suggestions), {
    status: 410,
    headers: { 'Content-Type': 'text/html' },
  });
}
```

Die 410-Seite sollte:

- `<meta name="robots" content="noindex">` rendern.
- Ähnliche Produkte vorschlagen (verwenden Sie pgvector-Kosinus auf der Einbettung des nicht mehr vorhandenen Objekts).
- Ein Suchfeld bereitstellen.
- Eine klare Nachricht "Dieses Produkt ist nicht mehr verfügbar" haben.

## Slughistorie pro Entität

Wenn sich ein Produkt-Slug ändert, muss die alte URL zur neuen URL weitergeleitet werden. Dies manuell zu speichern, ist fragil. Verfolgen Sie die Slughistorie pro Entität:

```sql
CREATE TABLE product_slug_history (
  id SERIAL PRIMARY KEY,
  product_id UUID NOT NULL,
  old_slug TEXT NOT NULL,
  new_slug TEXT NOT NULL,
  changed_at TIMESTAMPTZ DEFAULT NOW()
);
```

Bei der Slug-Aktualisierung:

```ts
async function updateProductSlug(productId: string, newSlug: string) {
  const product = await db.products.findOne({ id: productId });
  const oldSlug = product.slug;

  if (oldSlug === newSlug) return;

  await db.products.update({ id: productId, slug: newSlug });
  await db.productSlugHistory.insert({ productId, oldSlug, newSlug });
  await db.storeRedirects.insert({
    from: `/products/${oldSlug}`,
    to: `/products/${newSlug}`,
    statusCode: 301,
  });
  await enqueueIndexNow([`/products/${oldSlug}`, `/products/${newSlug}`]);
}
```

Die Slughistorie-Tabelle ermöglicht es Ihnen, die URL-Evolution eines Produkts nachzuvollziehen (nützlich für den Support und für rechtliche/Compliance-Archive).

## Weiterleitungsketten

Eine Kette: `A → B → C`.

Warum Ketten schlecht sind:

- Jeder Sprung verliert 5–10% Linkwert (Google hat dies bestätigt).
- Jeder Sprung fügt 100–500 ms Latenz hinzu.
- Drei oder mehr Sprünge erhöhen die Wahrscheinlichkeit, dass Google das Tracking aufgibt.

Erkennung: HEAD-Trace jede Weiterleitung wöchentlich.

```ts
async function traceRedirect(url: string, hops: number = 0): Promise<{ finalUrl: string; chainLength: number }> {
  if (hops > 5) return { finalUrl: url, chainLength: hops }; // Schleifenwächter

  const res = await fetch(url, { method: 'HEAD', redirect: 'manual' });
  if (res.status >= 300 && res.status < 400) {
    const location = res.headers.get('location');
    if (!location) return { finalUrl: url, chainLength: hops };
    return traceRedirect(location, hops + 1);
  }
  return { finalUrl: url, chainLength: hops };
}
```

Ketten glätten: Schreiben Sie die Quelle um, um direkt auf die endgültige URL zu verweisen.

```ts
// Vorher: A → B → C
await db.redirects.update({ from: '/a', to: '/b' });  // bestehend
// Nach dem Glätten:
await db.redirects.update({ from: '/a', to: '/c' });  // umgeschrieben
```

## Weiterleitungsschleifen

`A → B → A` ist fatal. Erkennen Sie dies zur Schreibzeit:

```ts
async function writeRedirect(from: string, to: string) {
  const wouldLoop = await detectLoop(from, to);
  if (wouldLoop) {
    throw new Error(`Weiterleitung von ${from} nach ${to} erzeugt eine Schleife`);
  }
  await db.redirects.insert({ from, to, statusCode: 301 });
}
```

## Ping IndexNow

Nach dem Schreiben einer Weiterleitung:

```ts
await enqueueIndexNow([oldUrl, newUrl]);
```

Die Engine ruft die alte URL erneut ab, sieht die 301 und aktualisiert ihr Index.

## Best Practices

- Halten Sie die Weiterleitungstabelle kompakt. Im Laufe der Zeit erzeugen Dutzende kleiner Slug-Bearbeitungen Dutzende von Weiterleitungen. Glätten Sie Ketten regelmäßig.
- Leiten Sie keine gesamten Kategorien zur Startseite weiter. Das ist ein 'soft 404' für Google. Leiten Sie stattdessen zur nächstgelegenen äquivalenten Kategorie weiter.
- Vermeiden Sie Weiterleitungen zu noindex-Seiten. Das untergräbt den Zweck, den Wert zu bewahren.
- Dokumentieren Sie die Absicht der Weiterleitung. Eine Kommentarspalte in der Weiterleitungstabelle hilft Ihnen, in Zukunft zu verstehen, warum.

## Wie Ordiko Weiterleitungen handhabt

- `storeRedirects`-Tabelle mit den Spalten `from`, `to`, `statusCode`, `tenant`.
- Slughistorie pro Entität: `productSlugHistory`, `categorySlugHistory` usw.
- Automatisches Schreiben von 301 bei Slug-Änderung.
- `productLifecycle.archive()` schreibt eine 410-Zeile in `storeRedirects`.
- Die Gone-Paths-Schicht rendert `/products/[slug]/gone` mit Ähnlichkeitsempfehlungen.
- Trigger.dev wöchentliche Aufgabe `redirect-chain-verify.task.ts` HEAD-traced jede Weiterleitung und kennzeichnet Ketten und defekte Ziele.
- Ein-Klick "Kette glätten" schreibt A → C direkt um.
- IndexNow-Pings bei jeder Erstellung einer Weiterleitung.

## FAQ

**Was ist der praktische Unterschied zwischen 301 und 302?**
301 = permanent. Überträgt nahezu den gesamten Linkwert. Cacht die Weiterleitung stark. Verwenden Sie es für Slug-Änderungen, Domainmigrationen. 302 = temporär. Überträgt weniger Wert. Cacht nicht so aggressiv. Verwenden Sie es für A/B-Tests oder temporäre Ausfälle. Für die meisten E-Commerce-Weiterleitungen ist 301 korrekt.

**Was ist der Unterschied zwischen 404 und 410?**
404 = 'nicht gefunden, könnte zurückkommen'. Google kann die URL eine Weile in seinem Index behalten, falls sie zurückkommt. 410 = 'verschwunden, dauerhaft entfernt'. Google entfernt die URL schneller. Für dauerhaft eingestellte Produkte ist 410 eine bessere SEO-Hygiene.

**Wie viele Weiterleitungssprünge sind zu viele?**
Zwei Sprünge sind die praktische Grenze. Jeder Sprung verliert 5–10% Linkwert und fügt Latenz hinzu. Drei oder mehr Sprünge sind ein Warnsignal. Erkennen und glätten Sie sie automatisch.

**Wie geht Ordiko mit der Slughistorie um?**
Jede Entitätstabelle hat eine entsprechende Slughistorie-Tabelle (z. B. product_slug_history). Bei einer Slug-Änderung wird eine neue Zeile mit dem alten Slug eingefügt; eine 301-Weiterleitung wird automatisch in storeRedirects geschrieben. Die wöchentliche Aufgabe redirect-chain-verify von Trigger.dev HEAD-traced Weiterleitungen und kennzeichnet Ketten und defekte Ziele.