# So funktioniert die Sync-Engine

Neu in v1.10.0

Diese Seite beschreibt die Sync-Engine, die mit **WCPOS v1.10.0** eingeführt wurde. Frühere Versionen verwenden ein anderes Replikationsmodell pro Bildschirm — siehe [Was sich in v1.10.0 geändert hat](#what-changed-in-v1100) am Ende dieser Seite.

WCPOS arbeitet nach dem Local-First-Prinzip: Jeder Bildschirm liest und schreibt in eine Datenbank auf dem Gerät, und eine **Sync-Engine** hält diese Datenbank und Ihren WooCommerce-Shop im Hintergrund konvergent. Diese Seite erklärt, wie die Engine entscheidet, was sie abruft, wann sie es abruft und wie Ihre Verkäufe zurück auf den Server gelangen — mit dem Detailgrad, der für Entwickler, Integratoren und Shop-Betreiber nützlich ist, die verstehen möchten, was das POS mit ihrem Hosting macht.

## Eine Engine pro Shop und Kassierer[​](#one-engine-per-scope "Direkter Link zu Eine Engine pro Shop und Kassierer")

Das POS betreibt auf jedem Gerät **eine Sync-Engine pro Kombination aus Website + Shop + Kassierer**. Diese Engine besitzt ihre eigene lokale Datenbank, sodass ein Wechsel von Shop oder Kassierer die gesamte Datenebene wechselt, statt einen gemeinsamen Datenbestand zu filtern. Die Trennung pro Kassierer ist beabsichtigt: Zwei Kassierer auf demselben Gerät teilen sich niemals lokale Daten.

Bei Upgrades werden lokale Datenbanken niemals an Ort und Stelle migriert — die App startet eine frische Datenbank und lädt vom Server neu herunter, der stets die maßgebliche Kopie besitzt (siehe [Upgrade von v1.9](#upgrading-from-v19)).

Bei Pro-Installationen mit mehreren Shops weist jede Sync-Anfrage ihren Shop aus, sodass ein an der Kasse geänderter Preis den Preis dieses Shops aktualisiert und nicht den des Onlineshops.

## Was im Hintergrund läuft[​](#sync-lanes "Direkter Link zu Was im Hintergrund läuft")

Alles, was die Engine planmäßig erledigt, ist eine **Spur** (lane) — eine benannte, begrenzte Einheit an Hintergrundarbeit. Die Spuren teilen sich in drei Gruppen auf:

| Gruppe      | Spuren                                                                           | Standard-Takt                                                                               |
| ----------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| **Abruf**   | Änderungsprüfung (Änderungssignal)                                               | 10 s – 5 min, je nach Ihrer [Sync-Voreinstellung](/de/support/store-health.md#sync-presets) |
|             | Aktuelle Bestellungen, Erstbefüllung Produktkatalog, Erstbefüllung Referenzdaten | \~5 min                                                                                     |
|             | Kunden-Nachladen (nur im Leerlauf)                                               | \~5 min                                                                                     |
| **Versand** | Warteschlange leeren — sendet lokale Änderungen aus der Warteschlange            | \~10 s                                                                                      |
| **Wartung** | Integritäts- und Löschprüfungen, Aktualisierung der Server-Gesamtzahlen          | alle paar Minuten bis \~17 min                                                              |

Für jede Spur gelten zwei Eigenschaften:

* **Jede Spur deklariert eine Obergrenze an Anfragen pro Durchlauf.** Keine Spur darf sich in einem Durchlauf auf eine unbegrenzte Anzahl von Anfragen auffächern; größere Aufgaben laufen in begrenzten Stapeln mit fortsetzbaren Cursorn. Das ist eine zentrale Design-Invariante und wird ausführlich unter [Sync-Leistung](/de/reference/sync-performance.md) behandelt.
* **Wartung tritt hinter den Kassierer zurück.** Prüfungen und Hintergrund-Vorbefüllungen laufen erst nach der interaktiven Arbeit, die eine Kasse verkaufsbereit macht, niemals davor — und sie werden als Erstes pausiert, wenn Ihr Server Anzeichen von Überlastung zeigt.

Die obigen Taktraten sind Standardwerte. Prüfintervall und Datensätze pro Anfrage können Händler pro Gerät unter **Shop-Zustand → Leistung** im POS anpassen — siehe [Shop-Zustand](/de/support/store-health.md).

## Wie das POS von Änderungen erfährt[​](#change-signal "Direkter Link zu Wie das POS von Änderungen erfährt")

Die Engine lädt Daten nicht erneut herunter, um herauszufinden, ob sie sich geändert haben. Der Server führt ein Änderungsprotokoll, und das POS ruft eine schlanke **Änderungsprüfung** ab, die genau eine Frage beantwortet: Hat sich seit meiner letzten Position etwas bewegt?

* **Eine Prüfung deckt acht Sammlungen ab** — Produkte, Variationen, Steuersätze, Kunden, Gutscheine, Kategorien, Marken und Schlagwörter. Bestellungen stehen bewusst nicht auf der Änderungsprüfung; ihre Aktualität stammt aus der eigenen Spur für aktuelle Bestellungen — deshalb können Produkt- und Bestellaktualisierungen in unterschiedlichen Rhythmen eintreffen.
* **Eine untätige Kasse kostet fast nichts.** Die Engine sendet bedingte Anfragen: Hat sich nichts geändert, antwortet der Server mit einem einzigen `304 Not Modified` ohne Inhalt. Ein ruhiger Shop pendelt sich auf eine winzige Antwort pro Prüfung ein.
* **Prüfungen werden um ±20 % gestreut**, damit mehrere Kassen einer Website auseinanderdriften, statt den Server in synchronisierten Schüben zu treffen.
* **Verlangsamung im Leerlauf:** Nach 10 Minuten ohne Interaktion werden die Prüfabstände gedehnt (bis zu einer Untergrenze von 60 Sekunden). Jede echte Aktivität — eine Berührung, ein Tastendruck, ein akzeptierter Barcode-Scan — kehrt sofort zum vollen Takt zurück und löst umgehend eine Nachhol-Prüfung aus. Die Verlangsamung dehnt das Intervall immer nur; sie fragt nie häufiger ab als eingestellt.
* **Eine tagelang geschlossene Kasse setzt neu auf, statt die Historie nachzuspielen.** Ist das Änderungsprotokoll zu weit über die letzte Position der Kasse hinausgelaufen, würde das Nachspielen jeder Zeile Hunderte von Anfragen kosten. Stattdessen springt die Engine mit ihrem Cursor an den Anfang und prüft den aktuellen Serverzustand dessen erneut, was das Gerät bereits besitzt — die Kosten skalieren also mit dem Umfang der lokalen Kopie und nicht damit, wie lange die Kasse abwesend war.

## Wie Bildschirme an ihre Daten kommen[​](#declared-demand "Direkter Link zu Wie Bildschirme an ihre Daten kommen")

In v1.10.0 führen Bildschirme keine eigene Synchronisierung mehr aus. **Ein Bildschirm erklärt, was er anzeigt — Suchbegriff, Filter, Sortierung, Seite — und die Engine entscheidet, ob dafür überhaupt eine Anfrage nötig ist.** Jede Erklärung wird auf eine von drei Arten aufgelöst:

* **Abgerufen** — die Engine hat dafür Arbeit auf der Leitung geleistet.
* **Lokal bedient** — das Gerät hatte die Antwort bereits, oder ein identischer kürzlicher Abruf deckt sie ab.
* **Überholt** — der Bildschirm ist weitergezogen (Sie haben gescrollt oder einen Filter geändert) und eine neuere Erklärung hat sie ersetzt. Das ist Routine, kein Fehler.

Ein Filter, der sich nur lokal beantworten lässt, gelangt nie zum Server. Und eine erfolgreiche Erklärung bedeutet nicht, dass eine Sammlung vollständig heruntergeladen ist — die Vollständigkeit wird separat verfolgt (nächster Abschnitt).

Nicht alles wird vorsorglich heruntergeladen, und was beim Start auf dem Gerät liegt, ist je nach Sammlung unterschiedlich:

1. **Vorbefüllt** — Produkte füllen sich über eine begrenzte Katalog-Erstbefüllung; Steuersätze werden beim Start geholt (ein POS kann ohne sie nicht rechnen).
2. **Bei Bedarf, plus Nachladen im Leerlauf** — Kunden haben keine vorsorgliche Erstbefüllung. Das Kunden-Nachladen holt pro Leerlaufintervall einen kleinen Stapel und setzt vollständig aus, sobald der Kassierer aktiv ist; neue und geänderte Kunden kommen über die Änderungsprüfung an.
3. **Beim ersten Öffnen abgerufen** — Kategorien, Schlagwörter, Marken und Gutscheine werden geholt, wenn ein Kassierer sie zum ersten Mal öffnet. Eine Sammlung, die niemand öffnet, erzeugt niemals eine einzige Anfrage.

Variationsauswahlen aktualisieren zusätzlich Preis und Lagerbestand einmal pro Öffnen, sodass eine bereits vorhandene Variation sofort erscheint, aber nie einen tagealten Lagerbestand anzeigt.

## „Ist alles heruntergeladen?“ — ehrliche Abdeckung[​](#coverage "Direkter Link zu „Ist alles heruntergeladen?“ — ehrliche Abdeckung")

Eine Anzeige wie *„1.240 von 5.000 Produkten“* braucht eine **serverseitige** Gesamtzahl als Nenner. Die Engine führt eine solche pro Sammlung (etwa alle 15 Minuten aktualisiert, meist kostenlos — echte Sync-Antworten enthalten die Gesamtzahl bereits, sodass eine eigene Anfrage selten nötig ist) und hält sich an einen strengen Ehrlichkeitsvertrag:

* Eine veraltete oder fehlende Server-Gesamtzahl wird als *wird geprüft …* angezeigt — niemals stillschweigend durch eine lokale Zählung ersetzt. Ein lokaler Nenner würde immer 100 % ergeben und genau die Lücke verbergen, die die Zahl sichtbar machen soll.
* Wenn die Engine für die Vollständigkeit nicht bürgen kann, lautet das Urteil *unbekannt*, und die Oberfläche kennzeichnet den Wert als lokale Zählung.
* Der Abdeckungsbalken für Bestellungen misst gegen die **gesamte** Bestellhistorie auf dem Server, während die Kasse bewusst nur offene und aktuelle Bestellungen vorhält — eine gesunde Kasse wird dort also planmäßig als teilweise abgedeckt angezeigt.

Diese Zahlen erscheinen unter **Shop-Zustand → Datenbank**, zusammen mit dem Meilenstein *Verkaufsbereit*, der umspringt, sobald das erste Produkt auf dem Gerät liegt — offline zu sein blockiert ihn nicht, denn genau darum geht es beim Offline-Verkauf. Siehe [Shop-Zustand](/de/support/store-health.md).

## Wie Änderungen zurück in Ihren Shop gelangen[​](#write-path "Direkter Link zu Wie Änderungen zurück in Ihren Shop gelangen")

Jeder lokale Schreibvorgang — ein Verkauf, eine Produktänderung, eine Kundenaktualisierung — landet zuerst in einer **dauerhaften ausgehenden Warteschlange** auf dem Gerät, und eine Versandspur schiebt die Warteschlange alle paar Sekunden zu WooCommerce. Das macht den Offline-Verkauf sicher: Ein ohne Verbindung abgerechneter Verkauf bleibt in der Warteschlange und wird gesendet, sobald die Verbindung zurückkehrt.

Wichtige Details:

* **Warenkorb-Schreibvorgänge werden pro Bestellung serialisiert.** Schnelle Scanner-Salven werden nacheinander angewendet, und ein wiederholtes Hinzufügen wird mit der Position zusammengeführt, die es dupliziert, statt eine zweite Position in die Warteschlange zu stellen.
* **Bestellbestätigungen übernehmen die Kopie des Servers.** WooCommerce vergibt beim Anlegen IDs für Bestellpositionen; die Engine übernimmt die bestätigte Bestellung, damit spätere Aktualisierungen zu diesen Positionen passen, statt Duplikate anzuhängen. Die Übernahme ist zurückhaltend — sie überschreibt nie eine lokale Änderung, die der Server noch nicht gesehen hat, und gilt nur für Bestellungen.
* **Ein Schreibvorgang, den der Server dauerhaft ablehnt, wird nie stillschweigend wiederholt.** Er wird mit der Begründung des Servers geparkt und unter **Shop-Zustand → Datenbank** als *„Änderungen haben Ihren Server nie erreicht“* angezeigt, mit zwei ausdrücklichen Aktionen: **Erneut senden** (baut die Anfrage aus dem Datensatz in seinem aktuellen Zustand neu auf, sodass spätere Korrekturen berücksichtigt werden) und **Verwerfen**. Es gibt keine automatische Wiederholschleife — die Wiederherstellung ist immer eine sichtbare, bewusste Handlung. Die Anleitung für Händler finden Sie unter [Shop-Zustand](/de/support/store-health.md#database).

### Mehrere Browser-Tabs[​](#multi-tab "Direkter Link zu Mehrere Browser-Tabs")

Das Web-POS in mehreren Tabs desselben Shops zu betreiben, wird unterstützt. Jeder Tab kann einen Verkauf abrechnen — Schreibvorgänge werden an die gemeinsame Warteschlange angehängt —, aber **ein gewählter Tab übernimmt den Versand** für jeden Bereich aus Shop + Kassierer. Wird dieser Tab geschlossen, befördert der Browser automatisch den nächsten. Zwei Tabs, die als unterschiedliche Kassierer angemeldet sind, sind getrennte Bereiche und verwalten jeweils ihre eigene Warteschlange.

## Lokaler Speicher[​](#local-storage "Direkter Link zu Lokaler Speicher")

Die Web- und Desktop-Apps speichern Daten über einen **OPFS-Worker** (Origin Private File System); die iOS- und Android-Apps nutzen dasselbe Format auf der Festplatte über eine Dateisystem-Engine. Alle vier Plattformen teilen sich ein Speicherformat und dieselben Werkzeuge zur Wiederherstellung nach Beschädigungen. (Frühere Versionen nutzten IndexedDB im Web und SQLite nativ.)

Abfragen werden innerhalb der Datenbankschicht ausgeführt — Selektor, Sortierung und Seite —, sodass nur die sichtbare Zeilenseite in die App übergeht. Bei einem synthetischen Testbestand von 10.000 Bestellungen senkte diese Verlagerung die Aktualisierungskosten pro Schreibvorgang unter einem aktiven Abonnement von \~27 ms auf \~0,06 ms.

## Upgrade von v1.9[​](#upgrading-from-v19 "Direkter Link zu Upgrade von v1.9")

v1.10.0 migriert lokale Datenbanken nicht — es führt eine **Kalt-Neusynchronisierung** durch:

1. Beim ersten Start öffnet die App eine frische lokale Datenbank und lädt aus Ihrem Shop neu herunter. Rechnen Sie auf jedem Gerät mit einem einmaligen vollständigen erneuten Download.
2. Es geht nichts verloren: Ihr WooCommerce-Server ist die maßgebliche Kopie aller synchronisierten Daten. Ausstehende, noch nicht gesendete Änderungen werden **vor** dem Aufräumen der alten Daten gesendet oder sichtbar gemacht — das Upgrade kann keinen ungesendeten Verkauf vernichten.
3. **App und Plugin erscheinen im Gleichschritt.** Clients der Version v1.10.0 sprechen die v2-Sync-API des Plugins. Wird nur eine Seite aktualisiert, schlagen Anfragen mit `rest_no_route`-Fehlern fehl — dieses Muster bedeutet „aktualisieren Sie die andere Hälfte“ und nicht „defekte Installation“.

## Was sich in v1.10.0 geändert hat[​](#what-changed-in-v1100 "Direkter Link zu Was sich in v1.10.0 geändert hat")

|                                 | v1.9.x                                                    | v1.10.0                                                                                      |
| ------------------------------- | --------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| Einheit der Synchronisierung    | Ein Replikationsstrom pro eingebundener Bildschirmabfrage | Eine Engine pro Website + Shop + Kassierer                                                   |
| Was einen Abruf auslöst         | Das Einbinden eines Bildschirms                           | Ein Bildschirm, der seinen Bedarf erklärt                                                    |
| Änderungserkennung              | Regelmäßige Abfragen + stündliche Vollprüfung             | Cursor im Änderungsprotokoll mit bedingten `304`-Antworten                                   |
| Server-Gesamtzahlen             | Nicht erfasst                                             | Gesamtzahlen pro Sammlung mit ehrlichen *wird geprüft …*-Zuständen                           |
| Fehlgeschlagene Schreibvorgänge | Undurchsichtig wiederholt                                 | Dauerhafte Warteschlange, sichtbares Wiederherstellungsfenster, keine stillen Wiederholungen |
| Mehrere Web-Tabs                | Unkoordiniert                                             | Ein gewählter Sender pro Bereich                                                             |
| Lokale Suche                    | Wortanfang-Treffer                                        | Teilstring-Treffer (mindestens 3 Zeichen)                                                    |
| Speicher                        | IndexedDB (Web), SQLite (nativ)                           | Speicher im OPFS-Format auf allen Plattformen                                                |
| Sync-Feinjustierung             | Fest                                                      | Voreinstellungen und Regler pro Gerät im Shop-Zustand                                        |

Zur Leistungsphilosophie hinter der Engine — Anfrageobergrenzen, Zurückschalten bei Serverlast und die gemessenen Zahlen — siehe [Sync-Leistung](/de/reference/sync-performance.md).
