Magento 2
Läuft in einem Shop, den wir selbst betreiben, und die ganze Kette ist von aussen nachgemessen — vom Warenkorb bis zum signierten Anfrageobjekt an die Wallet. Wenn etwas klemmt, klemmt es an Ihrem Aufbau, nicht am Paket.
Schon eingebaut? So legen Sie fest, welche Ware geprüft wird
Als Datei: README.md · PRUEFPLAN.md
Einbau
EdelVerify für Magento 2 — Altersprüfung über den Ausweis
Sperrt den Bestellabschluss für altersbeschränkte Artikel, bis über den Ausweis bestätigt ist, dass die Kundin oder der Kunde die verlangte Altersgrenze erfüllt. Der Shop erfährt genau diese eine Angabe — keinen Namen, kein Geburtsdatum, keine Ausweiskopie.
Die Grenze ist einstellbar: 16 oder 18, je Store-View als Vorgabe und je Kategorie als Ausnahme — die Kategorien werden aus dem Kategoriebaum ausgewählt, nicht als IDs abgetippt, und Unterkategorien zählen mit. Bei gemischtem Warenkorb gilt die strengste. Ein Store-View, der nur die Vorgabe setzt, verhält sich exakt wie vor der zweiten Schwelle.
Gegen den Quelltext von Magento Open Source 2.4.7-p3 abgeglichen — jede Klasse, jede Signatur und jeder Ereignisname ist dort nachgeschlagen. Es läuft in einem Magento 2.4.8-p5, das wir selbst betreiben (https://magento.edelbyte.ch): Warenkorb, Kasse und die Ausweisprüfung bis zum Prüffenster sind von aussen nachgemessen. Was das für Ihre Installation offenlässt, steht vollständig in PRUEFPLAN.md; arbeiten Sie diesen Plan ab, bevor Sie das Modul produktiv einsetzen.
Wie es funktioniert
Browser Magento-Server verify.edelbyte.ch
─────── ────────────── ──────────────────
Knopf «Alter bestätigen»
→ gate.js öffnet das Fenster ──────────────────────────→ POST /verifications
← QR-Code, Deeplink ←──────────────────────────────── (mit pk_…)
EdelVerify-App: Ausweis lesen
→ verification_id ──→ POST /edelverify/confirm/index
holt den Nachweis ───────────→ GET /verifications/:id
(mit sk_…)
legt `av_…` in die Sitzung
Bestellung abschicken ──→ CartManagementInterface::placeOrder()
löst den Nachweis ein ───────→ POST /proofs/verify
mit min_age = was die WARE verlangt
valid ? weiter : CouldNotSaveExceptionDrei Punkte, auf die es ankommt:
- Der Browser sieht den geheimen Schlüssel nie. Er meldet nur die Kennung der Prüfung. Den Nachweis holt der Shop-Server selbst.
- Der Riegel sitzt serverseitig. Wer den Knopf mit den Entwicklerwerkzeugen entfernt, kommt trotzdem nicht durch.
- Fail-closed überall. Kein Nachweis, kein Netz, kein Schlüssel, unklare Antwort → Bestellung abgewiesen. Nie freigegeben. Bei einer Altersprüfung ist die sichere Richtung die unbequeme.
Was Sie vorher brauchen
Das Paket: https://verify.edelbyte.ch/v1/magento/edelverify-magento.zip — darin liegt der Baum EdelByte/EdelVerify samt dieser Anleitung und dem Prüfplan. Genau so gehört er nach app/code/.
Ein Schlüsselpaar. Das Konto entsteht automatisch: Sie buchen unter https://verify.edelbyte.ch/preise einen Tarif — mit Karte oder TWINT —, und der öffentliche (pk_test_…) wie der geheime Schlüssel (sk_test_…) stehen unmittelbar danach bereit. Die erlaubten Herkunftsadressen und die Altersgrenze tragen Sie im Konto unter «Einstellungen» selbst ein.
Ausprobieren kostet nichts: Der Testbetrieb ist dauerhaft gratis. Ein Testschlüssel verlangt keinen echten Ausweis und lässt den ganzen Ablauf trotzdem durchlaufen.
Wenn Sie lieber vorher reden:
- E-Mail: info@edelbyte.ch
- Telefon: 044 500 25 04
Was es kostet: ab 19 Franken im Monat, keine Gebühr je Prüfung, monatlich kündbar und ohne Vorauszahlung. Über dem Kontingent kostet eine bestandene Prüfung 10 Rappen, nie mehr als der nächsthöhere Tarif — abgeschaltet wird die Prüfung nie. Die Stufen stehen unter https://verify.edelbyte.ch/preise. Der Testbetrieb kostet nichts, und zwar dauerhaft.
Was Sie dafür heute nicht bekommen: Nachweise über die staatliche E-ID. Der Weg ist gebaut und abgeschaltet, weil der Bund die Einführung am
- Juni 2026 verschoben hat und kein neues Datum nennt. Was heute läuft, ist
der Ausweis selbst — und was er belegt, steht im nächsten Abschnitt.
Die vollständige technische Anleitung — Schnittstelle, Fehlerschlüssel, Webhook, Testausgänge — steht unter https://verify.edelbyte.ch/entwickler
Wer kommt durch, und womit
Geprüft wird über den Ausweis Ihrer Kundschaft. Es gibt vier Wege, und sie belegen nicht dasselbe — das ist die Entscheidung, die Sie treffen, und keine Fussnote:
| Weg | Belegt | Belegt nicht |
|---|---|---|
| Staatliche E-ID | Einen vom Bund signierten Nachweis, geprüft gegen das eidgenössische Vertrauensregister. Der stärkste Nachweis, den es gibt. | Nichts, was fehlte — aber heute abgeschaltet: Der Bund hat die Einführung am 30. Juni 2026 verschoben und nennt kein neues Datum. |
| Ausweischip (App) | Dass das Dokument körperlich vorlag: Der Chip gibt nur etwas heraus, wenn ihm die abgelesenen Zeilen der Datenseite gezeigt werden. | Dass das Dokument echt ist — dafür fehlt die Prüfung gegen die Länderzertifikate. Und nicht, dass die meldende App unverändert ist. |
| Ausweiszeilen (App) | Formal gültige Zeilen eines amtlichen Ausweises: Prüfziffern gehen auf, Bauform stimmt, Dokument nicht abgelaufen. | Dass das Dokument vorlag — ein Foto der Rückseite genügt. Die Kamera unterscheidet ein Dokument nicht von seinem Abbild. |
| Ausweiszeilen (Browser) | Dasselbe, ohne App; die Prüfziffern rechnet unser Server, nicht der Browser. | Zusätzlich die Zusage, dass überhaupt gelesen wurde. Das Fenster läuft im Browser der Kundschaft. Die schwächste Stufe, die es gibt. |
Die beiden Zeilen-Stufen sind ab Werk aus. Ihr Shop verlangt den Chip, solange Sie nichts anderes sagen; freischalten lassen sie sich über info@edelbyte.ch — nachdem Sie die rechte Spalte gelesen haben. Einen Wahlschirm bekommt Ihre Kundschaft nicht zu sehen: Solange der E-ID-Weg abgeschaltet ist, startet die Ausweisprüfung sofort.
Welche Dokumente durchkommen: Schweizer Pass und Ausländerausweis über den Chip, ab Werk. Die Schweizer Identitätskarte trägt keinen Chip und kommt über die Ausweiszeilen durch — sie funktioniert also nur, wenn Sie diese Stufe freigeschaltet haben; die biometrische Identitätskarte mit Chip ist ab
- November 2026 beantragbar. Ausländische Pässe und Ausweise mit
maschinenlesbaren Zeilen ebenso.
Die App, die Chip und Zeilen liest, steht seit dem 20. August 2026 für Android im Play Store: https://play.google.com/store/apps/details?id=ch.edelbyte.edelverify Die Fassung fürs iPhone ist in Arbeit; ein Datum nennen wir dafür nicht, weil die Prüfzeit bei Apple nicht in unserer Hand liegt. Wer kein Android-Gerät hat, kommt heute nur über die Ausweiszeilen im Browser durch — und auch das nur, wenn Sie diese Stufe freigeschaltet haben.
Installation
Variante A — Dateien kopieren
cp -r EdelByte <magento-root>/app/code/
cd <magento-root>
bin/magento module:enable EdelByte_EdelVerify
bin/magento setup:upgrade
bin/magento setup:di:compile # nur im Produktionsmodus nötig
bin/magento setup:static-content:deploy de_CH fr_CH it_CH en_US
bin/magento cache:flushVariante B — über Composer
composer config repositories.edelverify path ./EdelByte/EdelVerify
composer require edelbyte/module-edelverify:^1.0
bin/magento setup:upgradesetup:upgrade legt fünf Spalten an sales_order an (siehe *Beleg an der Bestellung*). Ohne diesen Schritt läuft der Riegel, aber der Beleg wird still verworfen.
Konfiguration
Stores → Konfiguration → Verkäufe → EdelVerify — Altersprüfung
| Feld | Bedeutung |
|---|---|
| Altersprüfung aktiv | Der Hauptschalter. Vorgabe: Nein. |
| Adresse des Dienstes | https://verify.edelbyte.ch. Nur ändern, wenn Sie EdelVerify selbst betreiben (siehe *Content-Security-Policy*). |
| Öffentlicher Schlüssel | pk_live_… / pk_test_…. Steht im Quelltext der Seite — das ist so vorgesehen. |
| Geheimer Schlüssel | sk_live_… / sk_test_…. Wird verschlüsselt abgelegt (type="obscure" + Magento\Config\Model\Config\Backend\Encrypted). Leer lassen behält den bestehenden Wert. |
| Altersgrenze (Vorgabe) | ab 16 oder ab 18. Vorgabe: ab 18. Gilt bei Umfang «Ganzer Shop» für alles, sonst dort, wo keine Liste etwas anderes sagt. |
| Umfang | «Ganzer Shop» (Vorgabe) oder «Nur ausgewählte Kategorien». |
| Kategorien ab 16 | Mehrfachauswahl aus dem Kategoriebaum. Bier, Wein, Cider. |
| Kategorien ab 18 | Mehrfachauswahl aus dem Kategoriebaum. Spirituosen, Tabak, Vapes. |
| Nachweis am Kundenkonto | Vorgabe: Ja. Wer angemeldet ist, wird nach einer bestandenen Prüfung nicht erneut gefragt, solange der Nachweis gilt — ab Werk dreissig Tage, auch am zweiten Gerät. Gastbestellungen bleiben bei der Sitzung. |
Alle Felder gelten je Store-View. Ein zweisprachiger Shop mit zwei Sortimenten kann die Prüfung also in einem Store-View führen und im anderen nicht.
Beide Schlüssel bekommen Sie von uns (siehe *Was Sie vorher brauchen*); fangen Sie mit den Testschlüsseln an. Für die erlaubte Herkunft gibt es hier kein Feld: Die Liste liegt bei uns. Schicken Sie uns die Basis-URLs Ihrer Store-Views an info@edelbyte.ch — solange für Ihren Shop keine darin steht, darf jede beliebige Seite Prüfungen auf Ihren öffentlichen Schlüssel starten.
Zu den Kategorien
Die beiden Listen zeigen Ihren Kategoriebaum eingerückt; mit Strg bzw. Cmd wählen Sie mehrere aus. Gespeichert werden IDs, keine URL-Schlüssel — die ID überlebt eine Umbenennung und einen Sprachwechsel, der URL-Schlüssel nicht, und eine Altersprüfung, die nach dem Umbenennen einer Kategorie stillschweigend aufhört zu greifen, ist schlimmer als keine. Sie müssen die IDs nur nicht mehr selbst kennen.
Unterkategorien zählen mit. Wer «Tabak» wählt und die Ware in «Tabak › Zigarren» führt, prüft sie. Das galt bis Fassung 1.1 nicht — dort musste jede Unterkategorie einzeln eingetragen werden, und wer das übersah, verkaufte altersbeschränkte Ware ohne Prüfung. Die Vererbung lässt sich nicht abschalten:
- Ihre ausgeschaltete Stellung ist die, die Ware durchlässt. Ein Schalter, dessen falsche Position eine Anzeige nach sich zieht und den niemand wissentlich falsch stellt, ist keine Wahl, sondern eine Falle.
- WooCommerce und Shopware vererben ebenfalls. Ein Schalter nur in Magento hiesse, dass dieselbe Einstellung je nach Shop-System etwas anderes bedeutet.
- Was er einbrächte, gibt es ohne ihn: Wollen Sie «Spirituosen» prüfen, aber «Spirituosen › alkoholfrei» nicht, wählen Sie statt der Elternkategorie ihre Unterkategorien einzeln aus. Derselbe Aufwand, aber ohne den Ausgang, in dem nichts geprüft wird.
Eine Unterkategorie kann ihre Elternkategorie aus demselben Grund auch nicht unterbieten: «Spirituosen ab 18» plus «Spirituosen › alkoholfrei ab 16» ergibt 18. Es gilt immer die strengste zutreffende Grenze.
Wird eine ausgewählte Kategorie gelöscht, gilt der ganze Warenkorb vorsorglich als prüfpflichtig, und es steht im Log. Vorher schaltete sich das Modul durch diesen Handgriff still selbst ab.
Übernahme aus Fassung 1.1
Bis Fassung 1.1 standen die Kategorien als Text in einem Feld (edelverify/general/category_ids, z. B. 17:16,12:18). Der Datenpatch EdelByte\EdelVerify\Setup\Patch\Data\KategorienUebernehmen überträgt sie bei setup:upgrade in die beiden Auswahllisten — für jeden Geltungsbereich einzeln, in dem etwas eingestellt war, nicht nur global.
Das alte Feld bleibt in core_config_data stehen und wird danach nicht mehr gelesen. Es ist der einzige Ort, an dem noch steht, was vorher galt.
Sehen Sie die Auswahl danach durch. Nicht weil die Übernahme etwas verlöre — sondern weil ab jetzt Unterkategorien mitzählen. Ein Shop, der bis gestern «Tabak» und «Tabak › Zigarren» einzeln eintragen musste, hat jetzt einen davon zu viel in der Liste, und das ist harmlos; ein Shop, der nur «Tabak» eingetragen hatte, prüft ab jetzt mehr als vorher, und das ist der Zweck.
Zur Altersgrenze
Bei Umfang «Ganzer Shop» gilt die Vorgabe für jeden gefüllten Warenkorb. Bei «Nur ausgewählte Kategorien» gilt sie dort, wo keine der beiden Listen etwas anderes sagt — in der Praxis also nirgends, weil dann nur geprüft wird, was in einer Liste steht.
Steht eine Kategorie in beiden Listen, gilt 18. Ein unbekannter Wert der Vorgabe wird ebenfalls auf 18 angehoben, nicht auf 16 gesenkt: Im Zweifel prüft das Modul strenger, nicht milder.
Eine Grenze je Artikel gibt es in Magento nicht. Wer einen einzelnen Artikel anders behandeln muss, legt ihn in eine Kategorie, die in der passenden Liste steht. WooCommerce hat dafür ein Feld in der Produktmaske, Shopware eine Produkteigenschaft — Magento bekommt es, wenn ein Kunde es braucht.
Bei gemischtem Warenkorb gilt die strengste Grenze. Ein Sixpack neben einer Flasche Gin macht den ganzen Warenkorb zu einem 18er-Warenkorb. Liegt ein Artikel in zwei ausgewählten Kategorien mit verschiedenen Grenzen, gilt ebenfalls die strengere — eine Lockerung durch Doppelzuordnung fiele niemandem auf.
Ein Nachweis ab 18 löst auch Ware ab 16 ein; umgekehrt nicht. Wer sich für Bier ausgewiesen hat und dann Spirituosen dazulegt, wird erneut gefragt.
Zum Nachweis am Kundenkonto
Der Nachweis liegt dann in edelverify_kunden_nachweis — eine Zeile je Konto, mit einem Fremdschlüssel auf customer_entity und ON DELETE CASCADE. Wird das Konto gelöscht, geht die Zeile mit, ohne dass jemand daran denken muss.
Eigene Tabelle und kein Kundenattribut: Ein EAV-Attribut wäre in jedem Kundenformular, in jedem Export und in jedem Grid auffindbar — für einen Nachweis, den man einlösen kann, ist das die falsche Sichtbarkeit.
In der Zeile steht, dass die Altersgrenze erfüllt war, bis wann, in welcher Betriebsart und zu welcher Prüfung das gehört. Kein Geburtsdatum, kein Name, keine Ausweisnummer — der Shop bekommt sie ohnehin nie zu sehen.
Die Frist bestimmt EdelVerify, nicht das Modul. Steht sie im EdelVerify-Admin auf 0 Tagen, wirkt dieser Schalter nicht — dann ist jeder Nachweis im Augenblick seiner Ausstellung abgelaufen. Geprüft wird bei jeder Bestellung neu: Ein zurückgezogener Nachweis, eine heruntergesetzte Gültigkeitsdauer oder eine verschärfte Mindeststufe wirken sofort, und die Zeile verschwindet dabei.
Content-Security-Policy
etc/csp_whitelist.xml gibt verify.edelbyte.ch für script-src, connect-src und img-src frei. Wer eine andere Adresse einträgt, muss sie dort ergänzen — eine CSP lässt sich nicht aus einer Einstellung ableiten, die erst zur Laufzeit gelesen wird. Ohne die Freigabe erscheint in einem Shop mit scharf gestellter CSP kein Prüffenster, und die Ursache steht nur in der Browser-Konsole.
Beleg an der Bestellung
Ein Händler kauft eine Altersprüfung wegen der Nachweispflicht. Steht an der Bestellung nichts, kann er bei einem Testkauf oder einer Beanstandung nicht belegen, dass diese Bestellung geprüft war.
Geschrieben wird beides:
- Ein Eintrag im Bestellverlauf — sichtbar unter *Verkäufe → Bestellungen → <Bestellung> → Kommentare*. Das ist der Teil, den ein Sachbearbeiter tatsächlich sieht.
- Fünf Spalten in `sales_order` für Auswertungen und Exporte:
edelverify_verified(ja/nicht-noetig),edelverify_checked_at,edelverify_min_age,edelverify_mode,edelverify_ref.
edelverify_min_age trägt die tatsächlich durchgesetzte Grenze — 16 bei einem Bier-Warenkorb, 18 bei Spirituosen. Nicht pauschal 18: Genau diese Zahl ist im Streitfall der Beleg. Lautete der vorgelegte Nachweis auf eine höhere Grenze, steht das zusätzlich im Verlaufseintrag.
Nie geschrieben werden: der Nachweis selbst, ein Geburtsdatum, ein Name. edelverify_ref trägt acht Zeichen der Prüfkennung — genug, um die Prüfung im EdelVerify-Admin wiederzufinden, zu wenig, um damit einen Nachweis abzuholen oder eine Person zu bestimmen.
Was das Modul bewusst nicht mitbringt: keine Spalte in der Bestellliste und keinen eigenen Kasten im Bestellformular. Beides hiesse, in sales_order_grid zu schreiben und sales_order_view.xml umzubauen — viel Fläche für einen Beleg, der im Verlauf ohnehin steht. Wer die Spalte in der Liste braucht, findet in PRUEFPLAN.md den Punkt dazu.
Themes
Luma
Läuft ohne Zutun. Das Modul hängt sich in checkout_cart_index und checkout_index_index in den content-Container.
Das eigene JavaScript des Moduls ist absichtlich winzig und benutzt kein RequireJS und kein Knockout: zwei Ereignis-Zuhörer in reinem Browser-JavaScript. gate.js selbst baut sein Fenster in einen Shadow DOM und ist von der Theme-Welt getrennt.
Die Farben liegen als CSS-Variablen auf .edelverify-banner. Ein Theme braucht zum Umfärben eine Zeile:
.edelverify-banner { --ev-knopf: #1E3B32; --ev-grund: #FFFDF9; }Hyvä
Das ViewModel EdelByte\EdelVerify\ViewModel\Gate ist theme-unabhängig und lässt sich unverändert weiterverwenden. Nötig sind:
- Ein Layout-XML im Hyvä-Theme, das denselben Block mit einem eigenen Template einhängt (Hyvä benutzt andere Container-Namen als Luma).
- Ein Template, das den Knopf mit
data-edelverifyausgibt und das Script-Tag setzt. Das mitgeliefertegate.phtmllässt sich fast unverändert übernehmen — es braucht nur andere Klassennamen (Tailwind statt der mitgelieferten CSS-Datei). - Kein Alpine-Code. Die zwei Zuhörer im Template reichen;
x-dataist hier nicht nötig.
Die CSS-Datei view/frontend/web/css/edelverify.css sollte ein Hyvä-Theme nicht laden — sie würde nur mit dem Tailwind-Build kollidieren.
PWA Studio / entkoppelte Frontends
Der Riegel greift, der Weg zum Nachweis nicht. Das ist Absicht in der sicheren Richtung, aber ein Frontend-Team muss zwei Dinge nachliefern:
- Das Fenster.
gate.jsin die React-Anwendung laden und den Erfolg abgreifen (Ereignisedelverify:verifiedamdocument). - Einen Weg, den Nachweis abzulegen.
/edelverify/confirm/indexsetzt eine PHP-Sitzung voraus — die gibt es in einem token-basierten Frontend nicht. Nötig ist eine eigene Schnittstelle, die statt der Sitzung den Warenkorb als Ablage benutzt: - eine Spalte
edelverify_proofan der Tabellequote(etc/db_schema.xml, genau wie es Magento_Persistent mitis_persistentmacht), - ein
Magento\Framework\Webapi-Endpunkt, dercart_idundverification_identgegennimmt, ProofStoreliest dann den Warenkorb statt der Sitzung.
Das ist überschaubar, aber es ist Arbeit, und dieses Modul erledigt sie nicht. Solange sie nicht erledigt ist, findet der Riegel in einem token-basierten Checkout nie einen Nachweis und weist jede betroffene Bestellung ab.
Was ehrlicherweise ungeprüft ist
Dieses Modul ist gegen den Quellbaum von Magento 2.4.7-p3 geschrieben: Jede Klasse, jede Methode, jeder Ereignisname und jeder Schemaverweis wurde dort nachgeschlagen. Alle XML-Dateien sind gegen die echten XSD-Dateien aus dem Quellbaum validiert, alle PHP-Dateien mit php -l geprüft.
Es läuft in unserem eigenen Magento 2.4.8-p5 — der Satz «lief noch nie in einer laufenden Magento-Instanz» stand hier bis zum 5. September 2026 und war falsch. Was daraus nicht folgt, ist, dass es in Ihrer Installation trägt. Nicht geprüft sind deshalb unter anderem:
- ob
setup:di:compilein Ihrer Fassung sauber durchläuft, - ob der Plugin-Punkt in jeder Zahlungsart wirklich greift,
- ob die Layout-Einhängung in jedem Theme an der gedachten Stelle landet,
- ob die Sitzung in einem REST-Kassenaufruf tatsächlich verfügbar ist,
- ob die neuen Spalten in
sales_orderohne Konflikt angelegt werden.
PRUEFPLAN.md listet jeden dieser Punkte einzeln auf, mit dem Befehl, mit dem er sich in fünf Minuten klären lässt. Wer dieses Modul produktiv einsetzt, sollte diesen Plan zuerst abarbeiten.
Deinstallation
bin/magento module:disable EdelByte_EdelVerify
composer remove edelbyte/module-edelverify # oder rm -rf app/code/EdelByte
bin/magento setup:upgradesetup:upgrade entfernt die fünf Spalten aus sales_order wieder — dafür ist etc/db_schema_whitelist.json da. Der Beleg an bestehenden Bestellungen geht damit verloren. Wer ihn aufbewahren muss, exportiert vorher:
SELECT increment_id, edelverify_verified, edelverify_checked_at,
edelverify_min_age, edelverify_mode, edelverify_ref
FROM sales_order
WHERE edelverify_verified IS NOT NULL;Die Einträge im Bestellverlauf bleiben in jedem Fall erhalten — sie liegen in sales_order_status_history und gehören nicht diesem Modul.
Übersetzungen
i18n/de_CH.csv, fr_CH.csv, it_CH.csv, en_US.csv.
Abweichend von der Magento-Gewohnheit sind die Quelltexte deutsch, nicht englisch: Das Modul richtet sich an Schweizer Händler, und ein deutscher Quelltext ist hier der, den am ehesten jemand liest. en_US.csv ist damit eine Übersetzung wie jede andere.
Lizenz und Kontakt
Copyright © EdelByte — https://edelbyte.ch Dienst und Schlüssel: https://verify.edelbyte.ch
Prüfplan
Damit nehmen Sie den Einbau selbst ab, ohne uns zu fragen. Geht ein Punkt nicht durch, schicken Sie ihn uns mit der Nummer — dann wissen wir sofort, wo wir suchen.
Prüfplan
Was sich ohne laufende Magento-Instanz nicht klären lässt — je mit dem Befehl, mit dem es sich klären lässt.
Das Modul ist vollständig gegen den Quellbaum von Magento 2.4.7-p3 geschrieben. Alle XML-Dateien sind gegen die echten XSD-Dateien validiert, alle PHP-Dateien mit php -l geprüft. Beides sagt nichts darüber, ob es läuft.
Reihenfolge ist Absicht: 1–4 sind Abbruchkriterien, 5–12 sind Verhalten, 13–16 sind Feinheiten.
Vorbereitung
cd <magento-root>
bin/magento deploy:mode:set developer
cp -r <dieses-verzeichnis>/../../EdelByte app/code/
bin/magento module:enable EdelByte_EdelVerify1 — Lässt sich das Modul überhaupt kompilieren?
Unklar: Ob der Objektmanager alle Abhängigkeiten auflösen kann. Konstruktoren mit readonly in *promoted properties* sind PHP-8.1-Syntax; Magentos Code-Generator (Interceptor, Proxy, Factory) kommt damit erfahrungsgemäss zurecht, aber «erfahrungsgemäss» ist kein Beleg.
bin/magento setup:di:compileErwartet: Fehlerfrei. Insbesondere muss generated/code/EdelByte/EdelVerify/… entstehen und generated/code/Magento/Quote/Model/QuoteManagement/Interceptor.php unser Plugin enthalten:
grep -c "edelbyte_edelverify" generated/metadata/*.phpWenn es scheitert: Zuerst readonly aus den Konstruktoren nehmen und erneut kompilieren — das grenzt Syntax gegen Verdrahtung ab.
2 — Greift das Plugin am erwarteten Punkt?
Unklar: Ob Magento ein Plugin, das auf Magento\Quote\Api\CartManagementInterface angemeldet ist, tatsächlich auf Magento\Quote\Model\QuoteManagement überträgt. Der Kern macht das in app/code/Magento/Checkout/etc/webapi_rest/di.xml (GuestCartManagementInterface), also müsste es tragen — nachgewiesen ist es damit aber nur für den webapi_rest-Bereich, nicht global.
bin/magento dev:di:info 'Magento\Quote\Api\CartManagementInterface'Erwartet: Unter *Plugins* steht EdelByte\EdelVerify\Plugin\BlockOrderWithoutProof mit beforePlaceOrder.
Wenn es fehlt: Die Anmeldung von etc/di.xml nach etc/frontend/di.xml und etc/webapi_rest/di.xml und etc/graphql/di.xml duplizieren. Der Riegel muss in allen dreien stehen — in nur einem wäre er keiner.
3 — Werden die Spalten in `sales_order` angelegt?
Unklar: Ob sales_order in der jeweiligen Installation überhaupt schreibbar ist. Bei aufgeteilten Datenbanken (split database, Adobe Commerce) liegt sales auf einer eigenen Verbindung; resource="sales" in etc/db_schema.xml trägt dem Rechnung, ist hier aber nicht erprobt.
bin/magento setup:upgrade
bin/magento setup:db:status
mysql -e "SHOW COLUMNS FROM sales_order LIKE 'edelverify%'" <db>Erwartet: Fünf Zeilen.
4 — Ist der geheime Schlüssel wirklich verschlüsselt?
Unklar: Ob type="obscure" + Magento\Config\Model\Config\Backend\Encrypted in dieser Kombination greift. Der Kern nutzt sie (Magento_NewRelicReporting, Magento_Usps, Magento_Paypal), aber nur der Blick in die Datenbank beweist es.
Schlüssel im Backend eintragen, dann:
mysql -e "SELECT value FROM core_config_data WHERE path='edelverify/general/secret_key'" <db>Erwartet: Etwas wie 0:3:abc… — nicht sk_live_….
Und die Gegenprobe, dass das Entschlüsseln beim Lesen klappt:
bin/magento config:show edelverify/general/secret_keyErwartet: Magentos ValueProcessor (der Encrypted kennt) gibt hier ****** oder den Klartext aus — in keinem Fall den Geheimtext.
Wenn im Klartext gespeichert: Sofort stoppen. Ein Klartext-Schlüssel in core_config_data landet in jedem Datenbank-Backup.
5 — Blockiert der Riegel wirklich?
Unklar: Ob CouldNotSaveException in jeder Kasse als lesbare Meldung ankommt oder irgendwo zu einem 500er wird.
Vorbereitung: Prüfung aktiv, beide Schlüssel gesetzt, Kategorie eingetragen, altersbeschränkter Artikel im Warenkorb, keine Prüfung durchgeführt.
Dann in der Luma-Kasse auf «Bestellung aufgeben».
Erwartet: Die Meldung «Bitte bestätigen Sie zuerst Ihr Alter …» erscheint, es entsteht keine Bestellung.
mysql -e "SELECT COUNT(*) FROM sales_order WHERE created_at > NOW() - INTERVAL 5 MINUTE" <db>Erwartet: 0.
6 — Blockiert er auch an der REST-Schnittstelle?
Das ist der Punkt, an dem sich entscheidet, ob der gewählte Plugin-Ort etwas taugt. Ein Frontend-Riegel liesse sich hier umgehen.
TOKEN=$(curl -s -X POST '<base-url>/rest/V1/integration/customer/token' \
-H 'Content-Type: application/json' \
-d '{"username":"kunde@example.ch","password":"…"}' | tr -d '"')
curl -i -X PUT '<base-url>/rest/V1/carts/mine/order' \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"paymentMethod":{"method":"checkmo"}}'Erwartet: HTTP 400 mit unserer Meldung im Rumpf. Nicht 200 mit einer Bestellnummer.
7 — Und in der Gastkasse?
Die Gastkasse geht über GuestCartManagementInterface, das laut Quelltext an CartManagementInterface weiterreicht. Das ist belegt, aber Weiterreichen und Plugin-Auslösung sind zwei verschiedene Dinge — ein Plugin auf dem inneren Interface feuert nur, wenn der Aufruf wirklich durch den Objektmanager geht und nicht an einer Instanz vorbei.
CART=$(curl -s -X POST '<base-url>/rest/V1/guest-carts' | tr -d '"')
# … Artikel und Adressen setzen …
curl -i -X PUT "<base-url>/rest/V1/guest-carts/$CART/order" \
-H 'Content-Type: application/json' \
-d '{"paymentMethod":{"method":"checkmo"}}'Erwartet: HTTP 400 mit unserer Meldung.
Wenn 200: Ein zweites Plugin auf Magento\Quote\Api\GuestCartManagementInterface nachrüsten, das die maskierte Kennung über QuoteIdMaskFactory auflöst — genau wie Magento\Checkout\Plugin\Api\VerifyIsGuestCheckoutEnabledBeforePlaceOrder.
8 — Kommt der Nachweis in der Sitzung an?
Unklar (der grösste Punkt in dieser Liste): Ob Magento\Checkout\Model\Session in einem REST-Kassenaufruf dieselbe Sitzung sieht wie der Frontend-Controller, der den Nachweis abgelegt hat. Die Luma-Kasse schickt ihren Bestellabschluss als AJAX-Aufruf an rest/V1/carts/mine/payment-information — also in den Bereich webapi_rest. Dass dort PHP-Sitzungen grundsätzlich funktionieren, ist belegt (Magento\Customer\Model\Authorization\CustomerSessionUserContext liest die Kundensitzung). Dass die Checkout-Sitzung dort dieselben Daten trägt, ist es nicht.
Nach einer erfolgreichen Prüfung, vor dem Bestellabschluss:
tail -f var/log/debug.log &
# in ProofStore::getVerifiedState() voruebergehend ergaenzen:
# $this->logger->debug('EV proof', ['len' => strlen($proof), 'area' => …]);Erwartet: Beim Aufruf von payment-information steht dieselbe Länge im Log wie beim Aufruf von /edelverify/confirm/index.
Wenn der Nachweis dort fehlt: Das ist kein Sicherheitsproblem — die Bestellung wird abgewiesen, also fail-closed —, aber es macht das Modul unbrauchbar. Dann muss ProofStore auf den Warenkorb umgestellt werden: Spalte edelverify_proof an quote (etc/db_schema.xml, Vorbild Magento_Persistent mit is_persistent), Schreiben über CartRepositoryInterface::save(), Lesen über $quote->getData(). Der Skizze in der README (Abschnitt *PWA Studio*) folgen.
9 — Wird der Form Key angenommen?
Unklar: Ob Magento\Framework\Data\Form\FormKey\Validator::validate() den Schlüssel aus dem Abfrageteil der Adresse liest. Der Quelltext sagt $request->getParam('form_key'), und getParam() bedient laut Laminas sowohl Abfrageteil als auch Formularfelder — nachweisbar ist das aber nur am laufenden System (das vendor/-Verzeichnis im geprüften Quellbaum ist leer, Laminas liess sich also nicht direkt nachschlagen).
curl -i -X POST '<base-url>/edelverify/confirm/index?form_key=<aus-dem-Cookie>' \
-H 'Content-Type: application/json' \
-b 'PHPSESSID=…; form_key=…' \
-d '{"verification_id":"erfunden"}'Erwartet: HTTP 502 mit {"ok":false,"reason":"upstream_unavailable"} — also *durch* die Form-Key-Prüfung hindurch bis zum Aufruf des Dienstes.
Und die Gegenprobe ohne ?form_key=:
Erwartet: HTTP 403 mit {"ok":false,"reason":"invalid_form_key"}. Nicht eine 302-Umleitung.
Wenn 302 kommt: createCsrfValidationException() wird nicht aufgerufen — dann prüfen, ob CsrfAwareActionInterface an einer Klasse greift, die Magento\Framework\App\Action\Action nicht erweitert.
10 — Erscheint der Hinweis, und an der richtigen Stelle?
Unklar: Ob before="-" im content-Container den Block wirklich über die Kasse setzt. Bei checkout_index_index steht dort ein Knockout-Baum, den das Theme unter Umständen absolut positioniert.
bin/magento cache:flushDann Warenkorb und Kasse im Browser ansehen.
Erwartet: Der Streifen steht oben, der Knopf öffnet das Prüffenster.
bin/magento dev:template-hints:enablezeigt, in welchem Container er tatsächlich gelandet ist.
11 — Kommt gate.js an der CSP vorbei?
Unklar: Ob etc/csp_whitelist.xml in dieser Fassung von Magento_Csp gelesen wird, und ob der inline gerenderte Script-Block einen Nonce bekommt.
Kasse öffnen, Browser-Konsole ansehen.
Erwartet: Keine Content Security Policy-Meldungen.
curl -sI '<base-url>/checkout/cart/' | grep -i content-security-policyErwartet: verify.edelbyte.ch steht in script-src, connect-src und img-src.
12 — Landet der Beleg an der Bestellung?
Eine vollständige Bestellung mit bestandener Prüfung durchführen.
mysql -e "SELECT increment_id, edelverify_verified, edelverify_checked_at,
edelverify_min_age, edelverify_mode, edelverify_ref
FROM sales_order ORDER BY entity_id DESC LIMIT 1" <db>
mysql -e "SELECT comment FROM sales_order_status_history
ORDER BY entity_id DESC LIMIT 3" <db>Erwartet: ja, ein Zeitstempel, die durchgesetzte Grenze, den Modus, acht Zeichen Kennung — und einen Verlaufseintrag «Alter über EdelVerify bestätigt (ab 18) …».
Bei einem Warenkorb, der nur Ware ab 16 enthält, muss dort 16 stehen, nicht 18. Steht überall pauschal 18, hält der Beleg die falsche Grenze fest — dann läuft eine ältere Fassung des Moduls.
Unklar dabei: Ob sales_order_place_after bei jeder Zahlungsart feuert. Bei Weiterleitungs-Zahlungsarten (PayPal Express, Saferpay, Datatrans) entsteht die Bestellung an anderer Stelle. Diesen Punkt für jede eingesetzte Zahlungsart einzeln wiederholen.
13 — Bleibt der Nachweis nach der Bestellung liegen?
ClearProofAfterOrder hängt an checkout_submit_all_after. Dieses Ereignis feuert laut Quelltext in Magento\Quote\Model\QuoteManagement (Zeile 473) — aber nicht in jedem Weg zur Bestellung.
Nach einer Bestellung sofort eine zweite mit demselben Browser versuchen.
Erwartet: Der Hinweis erscheint erneut, die Prüfung wird verlangt.
Wenn nicht: Zusätzlich an sales_model_service_quote_submit_success anmelden. Das feuert in derselben Methode, aber früher, und ist der breitere Aufhänger.
13b — Der Nachweis am Kundenkonto
Nur mit eingeschaltetem Schalter Nachweis am Kundenkonto (Stores → Konfiguration → Verkäufe → EdelVerify, ab Werk *Ja*) und mit einem Testschlüssel.
| Fall | Wie herbeiführen | Erwartet |
|---|---|---|
| Angemeldet geprüft | anmelden, prüfen, abmelden, wieder anmelden | Kasse offen, kein Prüffenster |
| Zweites Gerät | in Browser A prüfen, in Browser B als dieselbe Person anmelden | Kasse offen, kein Prüffenster |
| Gast prüft, meldet sich an | als Gast prüfen, dann anmelden | Zeile in edelverify_kunden_nachweis |
| Zwei Konten, ein Gerät | mit A prüfen, abmelden, als B anmelden | B sieht das Prüffenster — A's Nachweis wandert nicht mit |
| Abmelden | nach bestandener Prüfung abmelden | Sitzung leer, Zeile bleibt |
| Zweite Bestellung | angemeldet zweimal hintereinander bestellen | die zweite Bestellung fragt nicht erneut |
| Gastkasse | ohne Konto bestellen | keine Zeile — es gibt kein Konto |
| Gültigkeit gesenkt | im EdelVerify-Admin von 30 auf 0 Tage stellen, neu prüfen | Kasse zu, Zeile verschwindet |
| Mindeststufe verschärft | nach einer Zeilen-Prüfung im Admin «nur Chip» einstellen | Kasse zu, Zeile verschwindet |
| Schlüssel gewechselt | sk_ austauschen | Zeile gilt nicht mehr (Abdruck passt nicht), Prüffenster erscheint |
| Konto gelöscht | Kunden in der Administration löschen | Zeile weg — der Fremdschlüssel räumt sie mit |
| Schalter aus | Kontobindung auf *Nein* | verhält sich wie vor der Umstellung: alles hängt an der Sitzung |
Nachsehen:
mysql -e "SELECT customer_id, min_age, expires_at, mode, ref \
FROM edelverify_kunden_nachweis" magentoDie Spalte proof steht bewusst nicht in der Abfrage: Sie ist ein Inhaberpapier und gehört in kein Terminalprotokoll. Was in der Tabelle stehen darf, sind genau diese sieben Spalten. Was dort nicht stehen darf und auch nicht entstehen kann: Geburtsdatum, Name, Ausweisnummer.
Dass der Fremdschlüssel wirklich angelegt wurde — sonst überlebt der Nachweis das gelöschte Konto:
mysql -e "SHOW CREATE TABLE edelverify_kunden_nachweis\G" magento | grep -i "foreign key"
# erwartet: FOREIGN KEY (`customer_id`) REFERENCES `customer_entity` (`entity_id`) ON DELETE CASCADEZwei Zeilen sind die wichtigen. «Zwei Konten, ein Gerät» ist der Fall, in dem ein falsch gebautes Modul eine Altersbestätigung weitergibt, ohne dass es jemand merkt — am Familienrechner nicht die Ausnahme, sondern der Regelfall. Und «Gültigkeit gesenkt» misst, ob der Shop gegen die heutige Einstellung rechnet oder gegen die von damals.
13c — Die Frist und die Stufe — zwei Handgriffe von Hand
Auf dem Rechner, auf dem diese Fassung entstand, ist kein PHP installiert; das Modul ist also nicht ausgeführt worden — auch bin/magento setup:di:compile nicht. ProofStore hat in dieser Fassung ein Argument mehr im Konstruktor (Psr\Log\LoggerInterface); ohne frische Kompilierung findet die Klasse ihre Abhängigkeit nicht. Der erste Schritt ist deshalb Punkt 1 dieses Plans.
Belegt ist nur die Seite des Dienstes (bun test, siehe src/lib/shop/fristen.test.ts und src/lib/shop/stufe.test.ts).
Eine gesenkte Gültigkeitsdauer wirkt sofort
Der Fall, der bis zu dieser Fassung nicht funktionierte: Ein Nachweis, der unter dreissig Tagen ausgestellt wurde, lief weiter dreissig Tage, auch wenn der Händler den Regler danach herunterzog.
| Schritt | Erwartet |
|---|---|
| 1. Im EdelVerify-Konto Nachweis gilt (Tage) auf 30, prüfen | Kasse offen |
2. completedAt der Prüfung in der EdelVerify-Datenbank zehn Tage zurückdatieren | Kasse weiter offen (10 < 30) |
| 3. Regler auf 5, Kasse neu laden | Kasse zu, Zeile in edelverify_kunden_nachweis verschwindet |
| 4. Regler wieder auf 30, neu laden | Kasse bleibt zu — eine erhöhte Frist belebt nichts wieder |
Schritt 4 ist der wichtigere. Eine Frist, die sich durch einen Handgriff im Portal rückwirkend verlängern liesse, wäre keine.
Gegenprobe ohne Shop — expires_at muss die kürzere der beiden Fristen tragen:
curl -s https://verify.edelbyte.ch/api/v1/proofs/verify \
-H 'content-type: application/json' -H 'x-api-key: sk_…' \
-d '{"proof":"av_…","min_age":18}' | grep expires_atEin Nachweis auf zu schwacher Stufe wird weggeräumt
| Schritt | Erwartet |
|---|---|
| 1. Ausweiszeilen freischalten, über die Zeilen prüfen | Kasse offen |
| 2. Mindeststufe zurück auf nur Chip | Kasse zu |
3. SELECT customer_id FROM edelverify_kunden_nachweis | leer — der Nachweis ist weg und nicht liegen geblieben |
4. var/log/system.log ansehen | Zeile «Nachweis auf einer Stufe, die dieser Shop nicht gelten lässt.» mit entstandenUeber und verlangtMindestens |
| 5. Dasselbe mit Gin im Korb (18) und einem 16er-Nachweis auf Zeilen-Stufe | ebenfalls weg — nicht «zu jung, liegen lassen» |
Schritt 5 ist der eigentliche Gegenstand. Vorher meldete der Dienst hier «zu jung», das Modul liess den Nachweis liegen, und er wurde bis zum Verfall wieder und wieder vorgelegt, obwohl er an dieser Kasse nie etwas eingelöst hätte. Die Schranke blieb dabei zu — aufgeräumt wurde nur nie.
Zum Vergleich der Fall, der weiterhin liegen bleiben muss: ein 16er-Nachweis auf zulässiger Stufe, Gin im Korb. Fliegt die Flasche hinaus, muss die Kasse ohne neue Prüfung aufgehen.
14 — Verhält sich der Riegel bei einer Störung richtig?
Der wichtigste Punkt der ganzen Liste, und der, den man am ehesten vergisst.
# Den Dienst unerreichbar machen — nicht abschalten, sondern ins Leere zeigen:
bin/magento config:set edelverify/general/base_url https://127.0.0.1:1
bin/magento cache:flushDann bestellen.
Erwartet: Bestellung abgewiesen. Nicht durchgelassen, nicht mit einer Warnung durchgelassen.
Dasselbe mit einem falschen geheimen Schlüssel und mit einem geleerten Schlüssel wiederholen.
bin/magento config:set edelverify/general/base_url https://verify.edelbyte.ch15 — Trifft die Kategorie-Erkennung?
Unklar: Ob $item->getProduct()->getCategoryIds() auf einem Warenkorbposten die Kategorien liefert. Der Produkt-Datensatz am Warenkorbposten ist unter Umständen mit eingeschränktem Attributsatz geladen; getCategoryIds() geht zwar an das Resource-Modell, aber bei konfigurierbaren Produkten hängen die Kategorien am Elternteil, nicht an der Variante.
Vier Fälle prüfen:
| Fall | Erwartung |
|---|---|
| Einfaches Produkt in betroffener Kategorie | Prüfung verlangt |
| Einfaches Produkt in einer anderen Kategorie | keine Prüfung |
| Einfaches Produkt nur in einer Unterkategorie der ausgewählten | Prüfung verlangt |
| Konfigurierbares Produkt, Kategorie am Elternteil | Prüfung verlangt |
| Bündel / Gruppe mit betroffenem Bestandteil | offen — hier ist am |
ehesten mit einer Lücke zu rechnen |
Die dritte Zeile ist neu und der Grund für Fassung 1.2. Bis dahin verglich das Modul nur die *direkt* zugewiesenen Kategorien: Wer «Spirituosen» eintrug und die Ware in «Spirituosen › Whisky» führte, prüfte nichts — ohne Hinweis, ohne Logeintrag, mit offener Kasse. Jetzt läuft das Modul den path der zugewiesenen Kategorie hinauf; die Einstellung «Spirituosen» trifft damit alles darunter. Legen Sie für diese Zeile eine Unterkategorie an, hängen Sie einen Artikel ausschliesslich dort hinein und wählen Sie nur die Elternkategorie aus.
Der Code läuft über getAllItems() (Elternteil und Varianten), was den dritten Fall abdecken sollte. Der vierte ist ungeklärt.
15b — Die zweite Schwelle: Bier ab 16, Gin ab 18
Nur nötig, wenn Sie zwei Grenzen führen. Wer alles gegen 18 prüft, überspringt diesen Abschnitt — für ihn ist alles Bisherige bereits die vollständige Prüfung.
Vorbereitung im Backend: Umfang auf «Nur ausgewählte Kategorien», unter «Kategorien ab 16» *Bier* wählen, unter «Kategorien ab 18» *Spirituosen*, Vorgabe auf 18 lassen. Von der Kommandozeile geht dasselbe:
bin/magento config:set edelverify/general/scope selected
bin/magento config:set edelverify/general/categories_16 17
bin/magento config:set edelverify/general/categories_18 12
bin/magento config:set edelverify/general/stand 2
bin/magento cache:flushDas stand 2 ist nicht kosmetisch: Solange es fehlt, liest das Modul noch das abgelöste Feld category_ids — genau der Zustand, in dem eine Installation zwischen setup:upgrade und dem Datenpatch steht.
| Fall | Erwartet |
|---|---|
| nur Bier im Warenkorb | Hinweis nennt 16, Prüffenster sagt «Über 16 bestätigt» |
| nur Gin | Hinweis nennt 18 |
| Bier und Gin | Hinweis nennt 18 — die strengste Grenze gewinnt |
| Bier geprüft, dann Gin dazulegen | Bestellung wird wieder abgewiesen |
| danach Gin entfernen | Bestellung geht durch, keine neue Prüfung |
| Kategorie in beiden Listen | gilt als 18, nicht als 16 |
| Unterkategorie von *Spirituosen* zusätzlich in «ab 16» | gilt trotzdem als 18 — eine Unterkategorie kann nicht unterbieten |
Die vierte Zeile ist die wichtige. Sie misst, ob ein «ja» für 16 in einen Warenkorb ab 18 hinüberträgt. Legen Sie den Gin innerhalb von 180 Sekunden dazu (ProofStore::CACHE_TTL) — genau in diesem Fenster glaubt das Modul seiner letzten Antwort. Bliebe die Bestellung möglich, wäre der Speicher nicht an die Grenze gebunden, und das Loch wäre drei Minuten breit.
Gegen die Schnittstelle, ohne Magento:
curl -s -X POST https://verify.edelbyte.ch/api/v1/verifications \
-H "x-api-key: $SK" -H 'content-type: application/json' \
-d '{"reference":"pruefplan","min_age":16,"test_outcome":"success"}'
sleep 5
# ACHTUNG: over_18 ist hier FALSE, age_ok ist TRUE
curl -s "https://verify.edelbyte.ch/api/v1/verifications/<id>" -H "x-api-key: $SK"
curl -s -X POST https://verify.edelbyte.ch/api/v1/proofs/verify \
-H "x-api-key: $SK" -H 'content-type: application/json' \
-d '{"proof":"av_…","min_age":18}' # → valid: false`over_18` ist nicht `age_ok`. Bei einer Prüfung gegen 16 steht in
over_18auch dannfalse, wenn die Person alt genug ist. Ein Modul, das nur dieses Feld liest, weist jede bestandene 16er-Prüfung ab und merkt es nie, weil im 18er-Betrieb beide Felder dasselbe sagen. Dass dieses Modulage_okliest, ist belegt:python3 scripts/pakete-pruefen.py, Abschnitt J.
16 — Kleinigkeiten
- Mehrfachversand (
Magento_Multishipping) geht überMagento\Multishipping\Model\Checkout\Type\Multishipping, nicht überCartManagementInterface::placeOrder(). **Der Riegel greift dort vermutlich nicht.** Prüfen, und falls bestätigt, entweder ein zweites Plugin nachrüsten oder den Mehrfachversand für betroffene Warenkörbe abschalten. - Admin-Bestellungen (*Verkäufe → Bestellungen → Neu*) gehen über
Magento\Sales\Model\AdminOrder\Create. Der Riegel greift dort nicht — das ist vertretbar (ein Mitarbeiter prüft am Telefon selbst), sollte aber bewusst entschieden und dem Händler gesagt werden. - Spalte in der Bestellliste. Nicht mitgeliefert. Wer sie will, braucht eine
sales_order_grid-Spalte plus einen Eintrag inview/adminhtml/ui_component/sales_order_grid.xml. Vorbild:Magento\Sales\etc\di.xml, Abschnittsales_order_grid_data_source. - Zwischenspeicher-Laufzeit.
ProofStore::CACHE_TTLsteht auf 180 Sekunden. Ob das der richtige Kompromiss zwischen «zurückgezogener Nachweis fällt schnell auf» und «nicht bei jeder Seite über das Netz» ist, zeigt erst der Betrieb. - Verbindungstest im Backend. Die WooCommerce-Fassung hat einen Knopf, der in einem Durchgang Erreichbarkeit, geheimen Schlüssel und Herkunftsprüfung testet. Dieses Modul hat ihn nicht —
EdelVerifyClient::createVerification()ist dafür bereits vorhanden, es fehlt der Admin-Controller und der Block. Das ist die erste Ergänzung, die sich lohnt: «Es geht nicht» hat bei einer Altersprüfung fast immer eine dieser drei Ursachen.