---
title: "Document Engine"
description: "PDF-Dokumente mit HTML, CSS und Liquid gestalten: Datenobjekte, Shipment-Details auf einer Tour, Barcodes und scanbare Links, Schriften und eigene Typografie, mehrseitige Etiketten, Tests und wie erzeugte Dokumente versioniert werden."
url: "https://support.pr-4.orbit.do/de/advanced-features/document-engine"
locale: "de"
lastReviewed: "2026-08-04"
---

# Document Engine

PDF-Dokumente mit HTML, CSS und Liquid gestalten: Datenobjekte, Shipment-Details auf einer Tour, Barcodes und scanbare Links, Schriften und eigene Typografie, mehrseitige Etiketten, Tests und wie erzeugte Dokumente versioniert werden.

## Überblick

Mit der Orbit Document Engine erzeugen Sie PDF-Dokumente dynamisch aus Ihren operativen Daten. Sie verbindet die üblichen Web-Technologien (HTML und CSS) mit der Template-Sprache Liquid. Statt starrer, fertiger Vorlagen haben Sie volle Kontrolle über Layout, Gestaltung und Inhalt Ihrer Dokumente. Ob Versandetiketten, CMR-Frachtbriefe, Rechnungen oder eigene Berichte: Sie gestalten sie genau nach Ihren Vorgaben.

## Erste Schritte

### Die Document Engine öffnen

So legen Sie Templates an oder bearbeiten sie:

1. Öffnen Sie **Orbit MissionControl**.
2. Gehen Sie zu **Einstellungen > Dokumenten-Templates**.
3. Klicken Sie auf **Dokumenten-Template anlegen** oder wählen Sie ein bestehendes Template.

### Datenobjekte festlegen

Datenobjekte legen fest, auf welche Art von Objekt das Template zugreifen kann. Jedes Datenobjekt, das Sie einem Template hinzufügen, muss beim Erzeugen mitgegeben werden. Legen Sie zum Beispiel ein Template mit dem Datenobjekt „Tour“ an, müssen Sie beim Erzeugen eine Tour-ID angeben.

Wählen Sie in der Werkzeugleiste des Editors über das Dropdown „Daten hinzufügen“ Ihre Quelldaten (z. B. Tour, Order). Damit stehen die passenden Liquid-Variablen bereit, und die Vorschau lädt die zugehörigen Beispieldaten.

### Inhalt des Templates

Im Inhaltseditor des Templates nutzen Sie normales HTML und CSS in Style-Tags, um das Layout des Dokuments festzulegen. Das umfasst alle HTML-Eigenschaften, die moderne Webbrowser unterstützen.

Zusätzlich zu HTML nutzt der Inhalt die Template-Sprache Liquid. Damit greifen Sie auf spezielle Funktionen, Datenobjekte und Kontrollstrukturen zu. Die Beispiele unten zeigen, wie Sie Liquid einsetzen. Eine ausführliche Referenz zu Liquid finden Sie [unter diesem Link](https://liquidjs.com/).

Um Dokumentgröße und Seiteneinrichtung für den Druck zu steuern, empfehlen wir das CSS-Modul „Paged Media“. Es bietet eigene CSS-Anweisungen für Seitengröße, Ränder und Seitenumbrüche. Die Beispiele unten decken diese Eigenschaften ab. Eine ausführliche Referenz finden Sie [unter diesem Link](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_paged_media).

### Live-Vorschau

Mit der Live-Vorschau testen Sie Ihr Layout sofort mit Beispieldaten. Während Sie tippen, aktualisiert sich die Vorschau in Echtzeit.

## Anleitung Teil 1: Einseitiges Etikett

In diesem ersten Schritt legen wir ein einfaches Versandetikett mit einer physischen Größe von 100 mm x 150 mm an.

**Kopieren Sie das in den Editor:**

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Shipping Label</title>
    <style>
      /* 1. Define Page Size */
      @page {
        size: 100mm 150mm;
        margin: 0;
      }

      body {
        font-family: Arial, sans-serif;
        margin: 0;
        padding: 0;
      }

      /* 2. Define the container for our content */
      .label-page {
        width: 100mm;
        height: 150mm;
        padding: 5mm;
        box-sizing: border-box;
        display: flex;
        flex-direction: column;
        border: 1px dashed #ccc;
      }

      .section {
        border-bottom: 2px solid black;
        padding-bottom: 5px;
        margin-bottom: 5px;
      }

      .barcode-container {
        text-align: center;
        margin-top: auto;
      }

      .barcode-container svg {
        width: 80mm;
        height: 15mm;
      }
    </style>
  </head>
  <body>
    <!-- 3. Label Content -->
    <div class="label-page">
      <!-- Inject Addresses -->
      {% assign sender = tour.stops | first %} {% assign recipient = tour.stops
      | last %}

      <div class="section">
        <strong>FROM:</strong><br />
        {{ sender.address.companyName }}<br />
        {{ sender.address.street }} {{ sender.address.houseNumber }}<br />
        {{ sender.address.zipCode }} {{ sender.address.city }}
      </div>

      <div class="section">
        <strong>TO:</strong><br />
        <h2 style="margin: 0;">{{ recipient.address.companyName }}</h2>
        {{ recipient.address.street }} {{ recipient.address.houseNumber }}<br />
        {{ recipient.address.zipCode }} {{ recipient.address.city }}
      </div>

      <!-- Barcode (Tour ID) -->
      <div class="barcode-container">{{ tour.id | code128 }}</div>
    </div>
  </body>
</html>
```

### Barcodes hinzufügen

Im Beispiel oben haben wir mit `{{ tour.id | code128 }}` einen Barcode erzeugt. Barcodes entstehen über Liquid-Filter, die einen beliebigen String in ein SVG-Bild umwandeln.

**Verfügbare Barcode-Typen:**

| Filter       | Typ         | Am besten für                              | Beispiel                                  |
| ------------ | ----------- | ------------------------------------------ | ----------------------------------------- |
| `code128`    | Code 128    | IDs, Trackingnummern, Etiketten            | `{{ tour.id \| code128 }}`                |
| `qrcode`     | QR-Code     | URLs, längere Texte, Scannen mit dem Handy | `{{ "<https://example.com>" \| qrcode }}` |
| `datamatrix` | Data Matrix | Kompakte Daten, Einsatz in der Industrie   | `{{ load.id \| datamatrix }}`             |

**Anwendungsbeispiel:**

```html
<!-- Code 128 Barcode -->
<div class="barcode-container">{{ tour.id | code128 }}</div>

<!-- QR Code -->
<div class="qr-container">
  {{ "<https://track.example.com/>" | append: tour.id | qrcode }}
</div>

<!-- Data Matrix -->
<div class="matrix-container">{{ load.id | datamatrix }}</div>
```

> Tipp: Alle Barcode-Filter geben Inline-SVG aus. Sie können sie also mit CSS gestalten (Breite, Höhe usw.).

***

## Anleitung Teil 2: Mehrseitige Etiketten

Nun soll es ein Etikett pro Ladung (`Load`) geben (z. B. 5 Paletten = 5 Seiten).

**Wichtig:** Eine Ladung kann eine Anzahl größer als eins haben. Dann müssen mehrere Einheiten derselben Ladung (mit gleichen Maßen und gleichem Gewicht, wie in der Ladung festgelegt) behandelt werden. Das Beispiel unten berücksichtigt die Anzahl nicht. Ein Etikett pro Einheit ist zwar möglich, wir empfehlen diesen Weg für Etiketten aber nicht. Sorgen Sie stattdessen dafür, dass `count` immer eins ist, und legen Sie ein Etikett pro Ladung an.

### 1. Mehrere Seiten aktivieren

Um mehrere Seiten im PDF und in der Vorschau zu erzeugen, nutzen Sie die CSS-Regel `page-break-after` zusammen mit einer Liquid-Schleife.

**Passen Sie Ihr CSS an:**

Fügen Sie `page-break-after: always;` zu Ihrer Klasse `.label-page` hinzu:

```css
.label-page {
  /* ... existing styles ... */

  /* IMPORTANT: This triggers the page break */
  page-break-after: always;
}

/* Optional: Prevent empty page at the end */
.label-page:last-child {
  page-break-after: auto;
}
```

> @page und page-break-after im Vergleich:
>
> | CSS-Regel                      | Zweck                                                               |
> | ------------------------------ | ------------------------------------------------------------------- |
> | `@page { size: 100mm 150mm; }` | Legt die **Seitenmaße** für das PDF fest.                           |
> | `page-break-after: always`     | Erzwingt nach jedem Element einen **ausdrücklichen Seitenumbruch**. |
>
> Beide Regeln wirken zusammen:
>
> * `@page` sagt der PDF-Engine, wie groß jede Seite ist
> * `page-break-after` sagt ihr, **wo** eine neue Seite beginnt
>
> Ohne `page-break-after` bricht der Inhalt nur um, wenn er über die Seitengröße hinausläuft. Bei Schleifen (wie `{% for load in tour.loads %}`) brauchen Sie `page-break-after: always`, damit jeder Durchlauf auf einer neuen Seite beginnt.

> So funktioniert die Vorschau:
>
> Browser wenden `@page`-Regeln nur im Druckmodus an, nicht in der normalen Bildschirmdarstellung. Der Editor bildet mehrseitige Layouts deshalb nach: Er durchsucht Ihre `<style>`-Blöcke nach `page-break-after: always`. Findet er die Regel, dann:
>
> 1. wird der Body zu einem Flex-Container mit Abständen
> 2. erscheint jedes passende Element als eigenes Blatt Papier mit Schatten
> 3. liegt zwischen den Seiten ein sichtbarer Abstand (24px)
>
> Diese Erkennung läuft automatisch. Außer der CSS-Regel brauchen Sie keine besonderen Klassen oder Auszeichnungen.

### 2. Durch die Ladungen laufen

Packen Sie Ihren Inhalt nun in eine Liquid-Schleife. So entsteht für jede Ladung eine Seite und damit ein Etikett.

**Vollständiges mehrseitiges Beispiel:**

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Shipping Labels - {{ tour.id }}</title>
    <style>
      @page {
        size: 100mm 150mm;
        margin: 0;
      }

      body {
        font-family: Arial, sans-serif;
        margin: 0;
        padding: 0;
      }

      .label-page {
        width: 100mm;
        height: 150mm;
        padding: 5mm;
        box-sizing: border-box;
        display: flex;
        flex-direction: column;
        border: 1px dashed #ccc;
        page-break-after: always;
      }

      .label-page:last-child {
        page-break-after: auto;
      }

      .header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        border-bottom: 2px solid black;
        padding-bottom: 3mm;
        margin-bottom: 3mm;
      }

      .load-badge {
        background: #333;
        color: white;
        padding: 2mm 4mm;
        font-weight: bold;
        font-size: 14px;
      }

      .section {
        border-bottom: 1px solid #ccc;
        padding-bottom: 3mm;
        margin-bottom: 3mm;
      }

      .recipient {
        flex: 1;
      }

      .recipient h2 {
        margin: 0 0 2mm 0;
        font-size: 18px;
      }

      .load-info {
        background: #f5f5f5;
        padding: 3mm;
        margin-bottom: 3mm;
      }

      .barcode-container {
        text-align: center;
        margin-top: auto;
        padding-top: 3mm;
        border-top: 2px solid black;
      }

      .barcode-container svg {
        width: 80mm;
        height: 12mm;
      }

      .barcode-text {
        font-family: monospace;
        font-size: 10px;
        margin-top: 1mm;
      }
    </style>
  </head>
  <body>
    {% assign sender = tour.stops | first %} {% assign recipient = tour.stops |
    last %}

    <!-- Loop: One label per load -->
    {% for load in tour.loads %}
    <div class="label-page">
      <div class="header">
        <div class="load-badge">
          {{ forloop.index }} / {{ tour.loads.size }}
        </div>
        <div>{{ tour.latestStart | formatDate: "en" }}</div>
      </div>

      <div class="section">
        <strong>FROM:</strong><br />
        {{ sender.address.companyName }}<br />
        {{ sender.address.city }}
      </div>

      <div class="recipient">
        <strong>TO:</strong>
        <h2>{{ recipient.address.companyName }}</h2>
        {{ recipient.address.street }} {{ recipient.address.houseNumber }}<br />
        {{ recipient.address.zipCode }} {{ recipient.address.city }}
      </div>

      <div class="load-info">
        <strong>Load:</strong> {{ load.type }}<br />
        <strong>Quantity:</strong> {{ load.count }}<br />
        <strong>Weight:</strong> {{ load.totalWeight }} kg
      </div>

      <div class="barcode-container">{{ load.id | code128 }}</div>
    </div>
    {% endfor %}
  </body>
</html>
```

In der Vorschau sehen Sie jetzt mehrere Etiketten, getrennt durch einen Abstand.

## Testen und prüfen

Sobald Sie mit dem Layout zufrieden sind, können Sie Ihr Template mit echten Daten aus Ihrem Orbit-Konto testen.

### Testlauf

1. Öffnen Sie in den Einstellungen die Liste **Dokumenten-Templates**.
2. Klicken Sie neben Ihrem Template auf die Schaltfläche **Testen** (Play-Symbol).
3. Ein Dialog öffnet sich, in dem Sie **echte Daten** aus Ihrem System wählen (z. B. eine echte Tour, eine Order oder ein Shipment).
4. Klicken Sie auf **Generieren**, um das Template mit den gewählten Daten zu erzeugen.
5. Das erzeugte PDF wird **automatisch heruntergeladen**.

So prüfen Sie, ob Ihr Template mit Produktivdaten korrekt funktioniert, bevor Sie es in Ihren Abläufen einsetzen.

## Dokumente erzeugen

Der wichtigste Weg, das Erzeugen von Dokumenten in Ihre Abläufe einzubinden, sind Automatisierungen. Unser kommendes Feature **Orbit Automations** wird das Erzeugen von Dokumenten bald direkt und vollwertig in der Plattform unterstützen. Diese Funktion ist aber noch in Entwicklung.

Bis Orbit Automations erscheint, lassen sich Dokumente nur programmatisch über die [Orbit API](https://orbit-api.readme.io/reference/general-info) erzeugen.

Um diese Lücke heute zu schließen, empfehlen wir einen externen Automatisierungsanbieter (etwa [n8n](https://n8n.io/)), der Orbit Webhooks mit der **Document Templates API** verbindet. So reagieren Sie auf Ereignisse und lösen das Erzeugen automatisch aus. Wenn Sie Hilfe beim Einrichten brauchen oder diese Automatisierungen lieber von uns betreuen lassen, wenden Sie sich an den Orbit-Support.

## Templates, Dokumente und Versionen

Es hilft, zwei Dinge zu trennen. Ein **Template** ist das wiederverwendbare Rezept, das Sie hier gestalten; ein Dokument (`Document`) ist die Datei, die daraus entsteht.

* **Aus einem Template entsteht ein versioniertes Dokument.** Jede Datei, die Orbit ablegt, behält ihre Historie.
* **Erneutes Erzeugen legt kein Duplikat an.** Erzeugen Sie dasselbe Dokument noch einmal, zum Beispiel nachdem sich ein Stopp (`Stop`) oder eine Adresse geändert hat, kommt eine neue Version zum bestehenden Dokument hinzu. Es liegen also keine zwei konkurrierenden Dateien nebeneinander. Sie sehen die neueste Version; ältere bleiben erhalten.
* **Eine Vorschau speichert nichts.** Mit der Live-Vorschau und dem Testlauf prüfen Sie das Layout mit Beispiel- oder echten Daten, sie legen aber nichts an einer Tour, einer Order oder einem Shipment ab. Um eine Datei zu behalten, erzeugen Sie sie als Teil Ihres Ablaufs.
* **Ein leeres Feld ist normal.** Hat ein Platzhalter für den Datensatz, gegen den Sie erzeugt haben, keinen Wert, bleibt er einfach leer. Das ist so gewollt und kein Fehler im Template.

Wie erzeugte Dateien gespeichert und an Orders, Shipments und Touren geheftet werden und wie der Abliefernachweis erfasst wird, lesen Sie im Artikel **Dokumente und Abliefernachweis**.

## Schriften und Typografie

PDFs werden mit einem ausgewählten Satz an Schriften erzeugt, der mit der Plattform ausgeliefert wird. Nichts wird vom Gerät des Lesers geladen. Ein Dokument sieht also überall gleich aus, wo es geöffnet oder gedruckt wird.

**Websichere Schriftnamen werden auf metrisch kompatible Entsprechungen abgebildet.** Die klassischen Namen funktionieren weiter: Text in `Arial` oder `Helvetica` erscheint als Liberation Sans, `Times New Roman` als Liberation Serif und `Courier New` als Liberation Mono. Diese Schriften haben dieselben Zeichenbreiten wie ihre Vorbilder. Layouts, die für die Originale gestaltet wurden, verschieben sich also nicht.

| Wert für `font-family`               | Erscheint als                  | Am besten für                             |
| ------------------------------------ | ------------------------------ | ----------------------------------------- |
| `Arial`, `Helvetica`                 | Liberation Sans                | Allgemeinen Text                          |
| `Times New Roman`                    | Liberation Serif               | Serifen- und Briefdokumente               |
| `Courier New`                        | Liberation Mono                | Referenznummern, Tabellenziffern          |
| `Noto Sans`                          | Noto Sans                      | Moderne Sans mit breiter Zeichenabdeckung |
| `Roboto Condensed`                   | Roboto Condensed               | Dichte Tabellen und schmale Spalten       |
| `Open Sans`                          | Open Sans                      | Die klassische Standard-Sans              |
| `DejaVu Sans`                        | DejaVu Sans                    | Breite Abdeckung von Symbolen             |
| `sans-serif` / `serif` / `monospace` | Liberation Sans / Serif / Mono | Allgemeine Ausweichschriften              |

Normal, **fett**, *kursiv* und fett-kursiv sind bei den Familien Liberation und Noto Sans echte Schriftschnitte (Roboto Condensed: normal und fett). Nichts wird künstlich verdickt oder schräg gestellt.

**Symbole erscheinen zuverlässig.** Zeichen wie ▲ ▼ → ❄ ✓ ● ★ greifen automatisch auf Symbolschriften zurück, statt zu verschwinden. Bewusst nicht enthalten sind CJK-Schriften und farbige Emoji. Braucht ein Dokument sie, laden Sie eine eigene Schrift (siehe unten).

> **Setzen Sie immer eine** `font-family` **auf** `body`**.** Ein Template ohne Angabe erscheint in einer Serifenschrift, wie es Webbrowser standardmäßig tun. Die Beispiele der Anleitung auf dieser Seite beginnen alle mit `font-family: Arial, sans-serif`.

### Eigene Schriften mit @font-face

Firmenschriften müssen nicht vorinstalliert sein. Geben Sie sie mit einer öffentlich erreichbaren URL an; sie werden dann beim Erzeugen des Dokuments heruntergeladen und ins PDF eingebettet:

```css
@font-face {
  font-family: "BrandFont";
  src: url("https://example.com/fonts/BrandFont-Regular.ttf");
}

body {
  font-family: "BrandFont", "Liberation Sans", sans-serif;
}
```

* Die URL muss zum Zeitpunkt des Erzeugens öffentlich und ohne Anmeldung erreichbar sein.
* Empfohlen sind TrueType- und OpenType-Dateien.
* Behalten Sie eine der mitgelieferten Familien als Ausweichschrift in der Liste. Ist die URL nicht erreichbar, fällt der Text auf sie zurück, statt dass das Erzeugen scheitert.
* Geben Sie pro Schnitt (normal, fett, kursiv) ein eigenes `@font-face` mit passendem `font-weight` / `font-style` an. Sonst wird die Auszeichnung nur nachgeahmt.

## Referenz

### Eigene Filter

| Filter                     | Beschreibung                                                                                                 | Max. Länge        | Beispiel                                                              |
| -------------------------- | ------------------------------------------------------------------------------------------------------------ | ----------------- | --------------------------------------------------------------------- |
| `code128`                  | Erzeugt einen Code-128-Barcode (SVG).                                                                        | ca. 2.000 Zeichen | `{{ tour.id \| code128 }}`                                            |
| `qrcode`                   | Erzeugt einen QR-Code (SVG).                                                                                 | ca. 4.000 Zeichen | `{{ "<https://orbit.com>" \| qrcode }}`                               |
| `datamatrix`               | Erzeugt einen Data-Matrix-Code (SVG).                                                                        | ca. 2.000 Zeichen | `{{ load.id \| datamatrix }}`                                         |
| `formatDate`               | Formatiert einen Unix-Zeitstempel. Locales: `'de'` (DD.MM.YYYY), `'en'` (YYYY-MM-DD).                        | entfällt          | `{{ tour.latestStart \| formatDate: 'de' }}`                          |
| `generateLoadDeepLink`     | Baut einen scanbaren Link zu einer physischen Ladung. Nimmt die Shipment-ID und die Tenant-ID als Argumente. | entfällt          | `{{ load.id \| generateLoadDeepLink: load.shipmentId, tour.tenant }}` |
| `generateShipmentDeepLink` | Baut einen scanbaren Link zu einem Shipment. Nimmt die Tenant-ID als Argument.                               | entfällt          | `{{ load.shipmentId \| generateShipmentDeepLink: tour.tenant }}`      |
| `generateTourDeepLink`     | Baut einen scanbaren Link zu einer Tour. Nimmt die Tenant-ID als Argument.                                   | entfällt          | `{{ tour.id \| generateTourDeepLink: tour.tenant }}`                  |

> Hinweis: Ist der Inhalt eines Barcodes länger als erlaubt, erscheint ein Fehler-Platzhalter, statt dass das Erzeugen abbricht.

### Verfügbare Datenobjekte

| Datenobjekt  | Template-Variable | Beschreibung                                                                                                                                                    |
| ------------ | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Tour         | `tour`            | Tour mit Stopps, Ladungen, Zeiten usw. Jede Ladung trägt zudem eine Zusammenfassung des Shipments, zu dem sie gehört (siehe *Shipment-Details auf einer Tour*). |
| Order        | `order`           | Details zur Order                                                                                                                                               |
| Shipment     | `shipment`        | Angaben zum Shipment                                                                                                                                            |
| Carrier      | `carrier`         | Daten der Carrier-Firma                                                                                                                                         |
| Carrier-User | `carrierUser`     | Einzelner Carrier-User                                                                                                                                          |
| Carrier-Team | `carrierTeam`     | Angaben zum Carrier-Team                                                                                                                                        |

### CSS-Eigenschaften für mehrere Seiten

| Eigenschaft                | Beschreibung                                                          |
| -------------------------- | --------------------------------------------------------------------- |
| `page-break-after: always` | Erzwingt nach dem Element einen Seitenumbruch                         |
| `page-break-after: auto`   | Auf `:last-child` verwenden, um eine leere Seite am Ende zu vermeiden |

## Shipment-Details auf einer Tour

Eine Tour trägt viele Shipments. Sie können `Shipment` also nicht als zweites Datenobjekt hinzufügen und erwarten, dass es zu jeder Ladung passt. Stattdessen trägt jeder Eintrag in `tour.loads` schon eine Zusammenfassung des Shipments, zu dem die Ladung gehört:

| Feld                               | Beschreibung                                                                       |
| ---------------------------------- | ---------------------------------------------------------------------------------- |
| `load.shipment.shipperName`        | Name des Shippers, der das Shipment gebucht hat.                                   |
| `load.shipment.extras`             | Anforderungen an die Handhabung des Shipments, zum Beispiel eine Temperaturklasse. |
| `load.shipment.pickupCompanyName`  | Firma an der Beladeadresse des Shipments.                                          |
| `load.shipment.dropoffCompanyName` | Firma an der Entladeadresse des Shipments.                                         |
| `load.shipment.displayName`        | Die eigene Bezeichnung des Shipments, wenn eine gesetzt ist.                       |
| `load.shipment.id`                 | Die Shipment-ID, zum Drucken oder Codieren.                                        |

So wird aus einer Ladeliste, die nur Paletten aufzählt, ein Dokument, mit dem ein Fahrer (Driver) und ein Lagerteam arbeiten können: wem die Ware gehört, woher sie kommt, wohin sie geht und wie sie zu behandeln ist.

```html
{% for load in tour.loads %}
<tr>
  <td>{{ load.shipment.shipperName | default: "—" }}</td>
  <td>{{ load.shipment.dropoffCompanyName | default: "—" }}</td>
  <td>{{ load.count }}&times; {{ load.type }}</td>
  <td>{{ load.shipment.id | generateShipmentDeepLink: tour.tenant | qrcode }}</td>
</tr>
{% endfor %}
```

> Diese Felder werden beim Erzeugen des Dokuments gefüllt. Lässt sich ein Shipment nicht auflösen, bleiben die Felder einfach leer. Sichern Sie alles Wichtige deshalb mit einem `default`-Wert ab, wie oben gezeigt.

## Scanbare Links

Die drei Filter `generate…DeepLink` machen aus einer ID einen Link, den die Orbit-Fahrer-App beim Scannen öffnet. Leiten Sie das Ergebnis an `qrcode` weiter, um ihn aufs Blatt zu bringen. Wählen Sie die Ebene, die zur Zeile passt: eine Zeile pro Palette nutzt den Ladungs-Link, eine Zeile pro Shipment den Shipment-Link und die Fußzeile des Dokuments den Tour-Link.

> **Codieren Sie den Link, keine bloße ID.** Eine reine ID enthält keinen Verweis auf ein Objekt. Wer sie scannt, öffnet also nichts. Das ist der häufigste Grund, warum die Codes eines Dokuments ins Leere führen.
>
> **Geben Sie dem Code Platz.** Ein Link ergibt ein deutlich dichteres QR-Raster als eine kurze ID. Unter etwa 12 mm wird das Muster für Handykameras und Bürodrucker zu fein. Bemessen Sie die Fläche entsprechend und prüfen Sie einen Probedruck, statt der Vorschau am Bildschirm zu trauen.

## Fehlerbehebung

### Seiten werden in der Vorschau nicht getrennt?

1. Stellen Sie sicher, dass `page-break-after: always` in einem `<style>`-Block steht (nicht inline)
2. Prüfen Sie, ob der CSS-Selektor zu Ihren Seitenelementen passt
3. Die Regel muss genau `page-break-after: always` lauten

### Barcode zeigt einen Fehler?

Der Inhalt ist zu lang. Code128 unterstützt ca. 2.000 Zeichen, QR-Codes ca. 4.000.

### Text erscheint in einer Serifenschrift?

Das Template setzt keine `font-family`, deshalb wird die Standard-Serifenschrift verwendet. Setzen Sie ausdrücklich eine auf `body`, zum Beispiel `font-family: Arial, sans-serif;`. Siehe **Schriften und Typografie** oben.

### Variablen erscheinen nicht?

1. Prüfen Sie, ob Sie in der Werkzeugleiste das richtige Datenobjekt gewählt haben
2. Prüfen Sie, ob der Variablenpfad existiert (z. B. `tour.stops`, nicht `tour.stop`)
3. Nutzen Sie `{% if variable %}` für optionale Felder

## Externe Dokumentation

* **LiquidJS:** Für Syntax, Schleifen und Standardfilter.

  [LiquidJS-Dokumentation](https://liquidjs.com/)

* **CSS Paged Media:** Für Seitengröße und Seitenumbrüche.

  [Paged-Media-Dokumentation (MDN)](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_paged_media)
