# Offene Punkte

Was bewusst liegen geblieben ist, mit dem nächsten konkreten Schritt. Nicht
für Kleinigkeiten gedacht – die gehören in einen Commit, nicht in eine Liste.

Stand: 25.09.2026

## 1. Auslauf-Markierung aus der Wawi holen

**Wo es steht.** Der Konnektor schickt `isCloseout` bei jedem Artikel als
`true` – in den Mitschnitten unter `var/log/jtl-sync/` 90 von 90. Der Haken
bedeutet in Shopware „wenn nicht auf Lager, dann weg", und zwar auch aus der
Artikelseite: 846 Artikel antworteten deshalb mit 404. Der Haken ist deshalb
überall entfernt und für die Wawi gesperrt
(`ProductPayloadGuard::NIEMALS`).

Die Gegenstelle steht schon: In den Plugin-Einstellungen des
JTL-Schreibschutzes gibt es **„Wawi-Feld für ‚Auslauf'"**. Wird dort ein
Feldname eingetragen, entscheidet nur noch dieses Feld über den Haken – nie
der Pauschalwert des Konnektors. Gelesen wird aus den Rohdaten des Abgleichs,
bevor der Schreibschutz `customFields` verwirft; das Feld muss also nicht
durchgelassen werden.

**Was fehlt.** Das Feld selbst. In der Datenbank gibt es es nicht: der
JTL-Feldsatz `custom_jtl` (Artikel, Kategorie, Kunde, Bestellung) enthält
einzig `short_description`. Auch in Eigenschaftsgruppen, Eigenschaftswerten,
Tags, Kategorien, Produktgruppen und in keinem Spaltennamen der Datenbank
steht etwas zu Abverkauf, Auslauf oder Restposten.

**Nächster Schritt.** In der JTL-Wawi ein eigenes Feld (Attribut) für den
Abverkauf anlegen und an den Konnektor übergeben. Der Konnektor legt es dann
in Shopware von selbst an – so wie `short_description`. Danach:

```bash
php dev/daten/artikel/wawi-felder-zeigen.php   # nennt den genauen Feldnamen
```

und den Namen in die Plugin-Einstellung eintragen.

**Danach noch zu entscheiden.** Sobald der Haken wieder gezielt gesetzt wird,
verschwinden ausgelaufene Artikel ohne Bestand erneut mit 404. Die
Shop-Einstellung „Artikel mit Abverkauf ausblenden, wenn nicht auf Lager"
abzuschalten hält sie sichtbar und zeigt stattdessen „Nicht mehr verfügbar" –
besser für Suchmaschinen und für Kunden mit altem Link.

## 2. Lieferzeiten sind nirgends gepflegt

**0 von 2.166 Artikeln** haben eine Lieferzeit. Shopware sagt zur
Verfügbarkeit deshalb von sich aus nichts, und der Liefertermin im Warenkorb
kommt aus der Versandart – der kennt den Bestand nicht.

Überbrückt ist das mit einem Bestandshinweis auf Artikelseite und im
Warenkorb; der Versand-Countdown verschwindet bei Ware ohne Bestand. Das ist
die Krücke, nicht die Lösung.

**Nächster Schritt.** `deliveryTimeId` und `restockTime` aus der Wawi holen.
Beide stehen im Schreibschutz in der Gruppe „Bestellregeln", die müsste nur
eingeschaltet werden – vorausgesetzt, die Wawi hat die Daten.

## 3. JTL-Regelpreise

1.874 Artikel werden über ihrem Grundpreis berechnet, 823 davon genau auf
UVP-Höhe. Sichtbar zum Beispiel an der Basis: die beiden **verfügbaren**
100-ml-Basen kosten 52,99 €, die baugleichen Artikel mit 2,95 € und 4,49 €
sind nicht verfügbar. Der Liquidrechner legt damit 53 € Basis in den
Warenkorb – die Funktion rechnet richtig, der Preis ist es vermutlich nicht.

**Nächster Schritt.** Angebot steht: eine Vergleichsliste Wawi gegen Shop,
damit sichtbar wird, welche Preise auseinanderlaufen. Entscheidung offen.

## 4. Nikotinstärke fehlt bei der Hälfte der Shots

Bei 5 von 10 kaufbaren Einzel-Shots steht die Stärke in keinem Datenfeld –
darunter beide Cloud-Shots. Der Liquidrechner schlägt für eine
Cloud-Mischung deshalb den Balance-Shot vor: Stärke exakt richtig,
Verhältnis leicht daneben. Beim Riccardo Cloud Nikotin-Shot steht
„20 mg/ml" wörtlich in der eigenen Beschreibung – bewusst **nicht**
automatisch übernommen, eine Nikotindosis wird nicht geraten.

**Nächster Schritt.** Katalog-Team pflegt die Eigenschaft `Nikotingehalt`
bei diesen fünf Artikeln nach.

## 5. Erfundene Erscheinungsdaten auf Dev

Damit die beiden Neuheiten-Seiten überhaupt gefüllt zu sehen sind, stehen auf
Dev vier Testdaten:

| Artikel | Datum |
|---|---|
| 10006091 Vaporesso ECO Nano 2 | 19.09.2026 |
| 10005556 Voopoo Doric Galaxy | 27.09.2026 |
| 10007100 Eleaf iCita PRO | 24.10.2026 |
| 10006191 OXBAR Oxpod Elite | 23.12.2026 |

**Nächster Schritt.** Rausnehmen, sobald die Wawi echte Daten liefert – sonst
gehen sie mit auf Produktion. Bis dahin sind `/Coming-Soon/` und
`/Neu-bei-uns/` ohne diese vier leer, und leere Kacheln auf der Startseite
sind vor dem Go-live keine gute Figur.

Dazu: Der Tagesjob `product_stream.mapping.update` **muss laufen**. Shopware
rechnet die relativen Datumsfilter beim Aufbau in feste Daten um; ohne den Job
altern beide Seiten still vor sich hin.

## 6. Pflichtangaben

* 27 Artikel ohne verantwortliche Person in der EU.
* Vier Platzhalter-Profile nennen uns als Hersteller – betrifft rund 3.193
  Artikel.
* 604 unfertige Zeilen im Gefahrstoffverzeichnis des Kunden.

## 7. Geräteserie fehlt an den Geräten

Die Geräteserien „Uwell UN2" und „Voopoo PnP" hängen nur an Coils und Pods, an
keinem einzigen Gerät. Deshalb liefen 11 gepflegte Cross-Selling-Gruppen
(„Passende Geräte") ins Leere; sie sind abgeschaltet, nicht gelöscht.

**Nächster Schritt.** Serie an den passenden Geräten pflegen, dann die
Gruppen wieder anschalten. Unsere Regel für Verbrauchsmaterial greift dort
danach ebenfalls.

## 8. Lieferanten-Passwort steht im Klartext

Das Zugangspasswort zum Lieferantenportal liegt als Plugin-Einstellung in
`system_config` – bei Shopware so vorgesehen, heißt aber: jeder Benutzer mit
Zugriff auf die Plugin-Einstellungen kann es lesen, und es steht in jedem
Datenbank-Abzug.

**Nächster Schritt.** Entweder auf einen eigenen Zugang mit engen Rechten
umstellen, oder den Wert aus einer Umgebungsvariable holen statt aus der
Konfiguration.

## 9. Kleinkram

* 161 Texte mischen Sie und du.
* 56 doppelte Artikelnamen.
* Geschmacksnote „Eisreme" statt „Eiscreme" bei einem Artikel.
* Ghostscript auf den Produktions-Frontends installieren (für die
  PDF-Verkleinerung).

## Lasttest: bewusst nicht gemacht (Stand 25.09.2026)

Der Lasttest hat ergeben: zwei Frontends tragen **130 gleichzeitige
Einkäufer**, heute sind es in der Freitagsspitze **14**. Faktor 9. Deshalb
wurde Folgendes geprüft und **absichtlich liegen gelassen**:

**Drittes Frontend.** Wird fällig, wenn die Zustandsseite dauerhaft über
1,2 Last je Kern meldet – das entspricht etwa 110 gleichzeitigen Einkäufern
oder rund 21.000 Sitzungen am Tag (heute: 1.430). Anlegen geht mit
`dev/deploy/frontend-aufnehmen.sh`.

**Suchseite cachebar machen.** Der größte Hebel, aber spekulativ. Die
Suchseite schickt `cache-control: private` und geht bei jedem Aufruf durch
PHP, während die Kategorieseite mit `s-maxage=7200` auf über 5.000
Varnish-Treffer kommt. Bei 0,83 Suchen je Sitzung wäre das viel – *wenn*
oft dasselbe gesucht wird. Das zählt `riccardo_search_term` bereits mit;
nach ein paar Wochen Echtbetrieb ist es eine Rechnung statt einer Vermutung.

**Weniger Filter.** 42 % der Zeit einer Suchseite geht ins Twig-Rendering,
und 24 sichtbare Filtergruppen mit 1.158 Werten sind viel. Eingeklappte
Gruppen wären sofort messbar – aber es ist eine Frage an die Kunden, nicht
an die Technik.

**opcache.validate_timestamps = 0.** Brächte ein paar Prozent, aber dann
wirkt keine Dateiänderung ohne FPM-Neustart. Bei dem Tempo, in dem hier
gerade Dinge geändert werden, ist das die falsche Abwägung.

## Datenqualität bei den Eigenschaften (gefunden 25.09.2026)

Beim Einrichten der Suche aufgefallen, nicht behoben – es sind Änderungen an
Produktdaten, die jemand mit Warenkenntnis entscheiden sollte:

**13 verwaiste Eigenschaftsgruppen** hängen an null Artikeln:
`Farbe` (476 Werte), `Frabe` (Tippfehler, 10 Werte), `Nikotinstärke`
(22 Werte), `Variante` (38 Werte) und neun weitere. Sie kosten zur Laufzeit
nichts, machen aber die Pflege im Admin unübersichtlich.

**Doppelte Werte in der Geschmacksrichtung:** `Guava` neben `Guave`,
`Rharbarber` (Tippfehler) neben `Rhabarber`. Seit die Eigenschaften
durchsucht werden, bedeutet jede Dublette, dass ein Teil der Artikel bei
der einen Schreibweise nicht gefunden wird.

**Zwei Gruppen für dasselbe:** `Geschmack` (5 grobe Werte, 1.700 Artikel)
und `Geschmacksrichtung` (248 genaue Werte, 1.195 Artikel). Das kann so
gewollt sein – grob zum Filtern, genau zum Suchen –, sollte aber bewusst so
sein.

**Nicht filterbar, obwohl sie es sein müssten:** `Geschmacksrichtung`,
`Liquid-Typ` (1.503 Artikel), `Ohm`, `Anzahl Akkus`. Kunden können danach
also nicht eingrenzen.

## Unscharfe Suche bewusst so gelassen

Der n-gram-Filter zerlegt in 4–5 Zeichen. „Erdbeere" enthält damit `beer`
und `eere` und findet auch Himbeere, Blaubeere, Brombeere. Über die ganze
Trefferliste sieht das nach 21 % Genauigkeit aus – auf der ersten Seite sind
es aber 67 bis 92 %, weil exakte Treffer mit 2,0 und Wortgruppen mit 4,0
gewichtet sind, unscharfe nur mit 0,4. Schärfer zu stellen würde die
Tippfehler-Toleranz kosten und auf Seite 1 kaum etwas bringen.

## Worker und Warteschlange (25.09.2026)

**Behoben.** `rz-scheduler.service` und `rz-worker@.service` riefen
`/usr/bin/php` auf – auf den Frontends ist das 8.3.6 für die
Altanwendungen, der Shop verlangt ≥ 8.4.1. Beide starben 2.414 Mal
hintereinander an `vendor/composer/platform_check.php`; systemd startete
brav weiter neu, und niemand sah ins Journal. Aktiv war nur
`riccardo-worker.service` – ein Laravel-Worker für `/var/www/stores`, also
eine andere Anwendung.

Die Shopware-Warteschlange hatte damit seit dem Übertrag **keinen
Verbraucher**. Der Shop lief trotzdem, weil Varnish und die Datenbank das
nicht brauchen; aufgefallen ist es erst, als der Suchindex nicht vorankam.

Nachgewiesen nach der Korrektur: Rückstand von 168 auf 0 in 20 Sekunden,
null Fatal-Meldungen, ein Verbraucher je Strom auf beiden Knoten.

Offen dazu:

- **Nur eine Worker-Instanz je Knoten.** Die Unit ist ein Template
  (`rz-worker@.service`), es läuft aber nur `@1`. Bei 195 Nachrichten
  Rückstand war das kein Problem – wenn der JTL-Abgleich viele Artikel
  schickt, könnte eine zweite Instanz sinnvoll sein. Erst messen.
- **`riccardo-worker.service` gehört nicht zu diesem Shop.** Er bedient
  `/var/www/stores`. Nicht angefasst, weil unklar ist, wer ihn braucht –
  aber der Name lädt zur Verwechslung ein und hat genau dazu geführt.
- **Niemand merkt es, wenn ein Dienst stirbt.** 2.414 Neustarts ohne
  Alarm. Die Zustandsseite zeigt jetzt die Warteschlange samt Verbraucher-
  zahl; ein Verbraucher von 0 wäre das Warnsignal. Eine Empfehlung dafür
  ist noch nicht eingebaut.

## Bestand und Lieferzeit (geregelt 25.09.2026)

Ausverkaufte Artikel waren bestellbar – 2.446 Stück, 37 % des Sortiments.
Ursache war `is_closeout = 0` auf allen Artikeln: Shopware rechnet
`available = (is_closeout × stock) >= (is_closeout × min_purchase)`, und bei
0 lautet das `0 >= 0`, also immer verfügbar. Der Haken stand auf 0, weil wir
JTL das Setzen verboten hatten (es setzte ihn auf *alle* Artikel).

**Entschieden: sichtbar, nie bestellbar.** Umgesetzt in drei Teilen –
`is_closeout = 1` sperrt den Kauf, `AusverkauftSichtbarFilter` hebt das
Ausblenden aus Listen und Suche auf, `LieferbaresZuerstSubscriber` stellt
Lieferbares voran. Ohne den dritten Teil waren in *Aromen* alle 24 Kacheln
der ersten Seite gesperrt.

Dazu eine pauschale Lieferzeit von 1–3 Tagen auf alle Artikel. Vorher hatte
**kein einziger** eine, und Shopware sagt dann zur Lieferbarkeit gar nichts –
in Deutschland ist die Angabe Pflicht.

Offen dazu:

- **Die Pauschale stimmt nicht für alles.** 1–3 Tage gilt für Lagerware.
  Sobald die Wawi echte Lieferzeiten liefert, sollten sie die Pauschale
  überschreiben – `bestand-regeln.php` setzt sie nur, wo keine steht.
- **1.600 ausverkaufte Artikel haben keinen Wiederbeschaffungstermin.**
  Auf der Seite steht dann „Ein Termin steht noch nicht fest". Das ist
  ehrlich, aber für ein Viertel des Sortiments unbefriedigend.
- **Das eigene Abverkauf-Feld in der Wawi fehlt weiterhin.** Solange es das
  nicht gibt, ist `is_closeout` bei uns die Regel „nicht über den Bestand
  verkaufen" und *nicht* die Kennzeichnung „läuft aus". Wer später echten
  Auslauf kennzeichnen will, braucht dafür ein eigenes Feld – sonst
  verwechselt sich beides wieder.
- **Merkzettel statt Sackgasse.** Ein gesperrter Artikel bietet heute keinen
  Weg, sich benachrichtigen zu lassen. Bei 2.446 Artikeln wäre eine
  „Benachrichtige mich"-Funktion naheliegend.
