Zum Inhalt springen

Module (NXM)

So ist das Kundenportal gebaut

Die Teile hinter einem Kundenportal, was jeder von ihnen weiß und was er nie sieht, und der Weg einer Anfrage vom Browser des Besuchers bis zum Moduldienst und zurück.

Für
Entwickler
Dauer
12 Min.

Eine Ferienhausagentur betreibt ihre Buchungsseite mit nexxus. Gäste suchen auf einer Karte, öffnen ein Haus, sehen die freien Tage und den Preis für ihren Aufenthalt und schicken eine Anfrage, die im Posteingang der Agentur landet. Weder nexxus noch die Portal-App enthalten dafür Code über Ferienhäuser. Was eine Unterkunft ist, welche ihrer Felder ein Gast sehen darf und wie ein Preis entsteht, gehört alles zum Paket der Agentur. Ein anderes Paket veröffentlicht seine Datensätze auf dieselbe Weise, ohne dass sich an nexxus etwas ändert.

Eine Buchungsseite mit Ferienhäusern als Karten links und ihren Standorten auf einer Landkarte rechts
Die Buchungsseite der Demo-Agentur. Seiten, Felder, Filter und Karte kommen aus dem Manifest des Pakets.

Diese Seite erklärt die Teile und wie sie zusammenarbeiten. Wie Sie den Abschnitt portal eines Manifests schreiben, steht unter Kundenportal.

TeilWas er tutWas er nie tut
nexxusFindet den Mandanten anhand der Webadresse, hält die Datensätze, entscheidet, was öffentlich ist, liefert Bilder und Karte aus und reicht Aufrufe von Endpunkten an den Dienst weiterCode eines Pakets ausführen. Jemanden unter einer Portal-Adresse anmelden lassen
Das PaketErklärt in seinem Manifest die Entitäten, die öffentlichen Felder und Einstellungen, die Seiten und die EndpunkteEinen Webserver mitbringen oder Code, der in nexxus läuft
Der ModuldienstRechnet aus, wofür es Logik braucht: freie Tage, einen Preis, eine Buchungsanfrage, eine Nachricht an den GastgeberEigene Daten oder Zugangsdaten halten. Er liest und schreibt über die Datensatz-Schnittstelle von nexxus, mit einem Token, das nach Minuten abläuft
Die Portal-AppZeichnet die Seiten, die das Paket erklärt, zuerst auf dem Server, dann im BrowserEtwas über eine Branche wissen. Etwas auf dem Gerät des Besuchers speichern

Dieselben Datensätze bedienen zwei Gruppen. Die Mitarbeitenden der Agentur arbeiten in nexxus mit ihnen, in den Listen, Kalendern und Kartenansichten des Pakets, mit ihren Rechten und dem KI-Assistenten. Gäste sehen im Portal den öffentlichen Teil davon. Dazwischen gibt es keine Kopie und keinen Export: Ein Haus, das die Agentur auf inaktiv setzt, verschwindet innerhalb einer Minute von der Seite, weil Antworten der Portal-Schnittstelle 60 Sekunden lang gehalten werden dürfen.

Ein Gast öffnet die Seite einer Unterkunft und wählt Reisedaten:

Browser
Portal-App
nexxus
Moduldienst
  1. 1GET /de/stays/villa-silvertreeBrowser → Portal-App
  2. 2Site, Seitendefinition und Unterkunft, mit dem Host des BesuchersPortal-App → nexxus
  3. 3Host zu Mandant, öffentlicher Datensatz, nur öffentliche Feldernexxus
  4. 4Die fertige SeitePortal-App → Browser
  5. 5GET /public/portal/<modul>/endpoints/quote?record=12&check_in=...Browser → nexxus
  6. 6Rate-Limit, erklärte Parameter, Datensatz ist öffentlichnexxus
  7. 7POST /portal/quote mit einem Aufruf-Token (60 s)nexxus → Moduldienst
  8. 8Token tauschen, die Datensätze lesen, die der Preis brauchtModuldienst → nexxus
  9. 9Das Angebot als JSONModuldienst → nexxus
  10. 10Das Angebot, Ablehnungen bereinigtnexxus → Browser
Der Browser spricht mit der Portal-App und mit nexxus, nie mit dem Moduldienst. Der Dienst braucht keine öffentliche Adresse.
  • Die erste Antwort ist eine fertige Seite. Die Portal-App fragt nexxus nach Site, Seitendefinition und Datensatz und schickt den Host des Besuchers mit (X-Forwarded-Host), weil nexxus den Mandanten am Host erkennt. Suchmaschinen lesen die Seite so, wie sie ist. Im Browser übernimmt die App, ohne dieselben Daten noch einmal abzufragen.
  • Alles danach geht vom Browser an /public/portal/... unter derselben Adresse: weitere Seiten, die nächste Seite der Treffer, der Kartenausschnitt, Preise und Formulare.
  • Endpunkte laufen über nexxus. nexxus prüft den Aufruf, bevor der Dienst ihn sieht, und die Antwort des Dienstes, bevor der Besucher sie sieht. Ein Dienst, der nicht erreichbar ist oder länger als 10 Sekunden braucht, wird für den Besucher zu 503, ohne einen Text des Dienstes darin.

Die Domains eines Mandanten haben eine Rolle. Seine eigenen Domains tragen die App und die Anmeldung, seine Portal-Domains das Portal und sonst nichts. Beide setzt ein Superadmin unter AdministrationUnternehmenMandanten.

  • Der Mandant kommt allein aus dem Host, nie aus einem Parameter, einem Cookie oder einem Header, den der Reverse Proxy nicht gesetzt hat. X-Forwarded-Host übernimmt nexxus nur von Proxys mit privaten Adressen.
  • Ein Portal-Host beantwortet zwei Pfade: die Portal-Schnittstelle unter /public/portal/ und die Karte unter /public/map/. Anmeldung, die Schnittstelle der App, der Live-Kanal und alles andere antworten dort mit 404, als gäbe es sie nicht. Auf jedem anderen Host antwortet die Portal-Schnittstelle mit 404.
  • Die Portal-App zeichnet Seiten nur für die Hosts, für die sie eingerichtet ist, damit ein gefälschter Host-Header sie keine Daten von einer anderen Adresse holen lässt.
  • Seiten auf anderen Websites können die Portal-Schnittstelle im Browser nicht lesen: Sie erlaubt Aufrufe von fremden Ursprüngen nur von den Portal-Hosts des eigenen Mandanten, und nie mit Cookies.

Das Portal bekommt immer nur, was das Paket als öffentlich erklärt hat, und nexxus prüft das an vier Stellen.

  1. Beim Hochladen. Die Paketprüfung lehnt ein Portal ab, das einen Kontakt, eine Person, ein JSON-Feld oder ein Feld veröffentlicht, das es nicht gibt, das auf einem nicht indexierten Feld filtert oder eine Seite, einen Endpunkt oder einen Dienst nennt, der fehlt. Siehe Was die Paketprüfung verlangt.
  2. Bei der Installation. Die Administration stimmt portal:public zu, angezeigt als ein Satz, den nexxus aus dem Manifest baut: welche Datensätze, welche Felder, dass Bilder und ein gerundeter Standort mitgehen, welchen Dienst Besucher aufrufen können. Ein Update, das mehr veröffentlicht, fragt erneut.
  3. Bei jeder Antwort. nexxus gibt nur die Datensätze heraus, die der öffentliche Filter der Entität auswählt, und nur die Felder aus public.<entität>.fields. Nicht veröffentlichbare Typen lässt es noch einmal weg, auch bei einem Manifest, das vor einer Regel gespeichert wurde. Einen Standort rundet es auf zwei Nachkommastellen (etwa 1 km), wenn das Manifest nicht exact sagt. Bilder bekommen eine Adresse, die für Mandant, Installation, Datensatz und Dokument signiert ist; jeder Abruf prüft erneut, ob der Datensatz öffentlich ist und das Bild noch nennt, und nur JPEG, PNG, WebP, GIF und AVIF gehen hinaus.
  4. Bei jedem Aufruf eines Endpunkts. nexxus zählt den Aufruf zuerst gegen das Rate-Limit, reicht dann nur die erklärten Parameter weiter (je höchstens 200 Zeichen), prüft, ob record ein öffentlicher Datensatz ist, lehnt einen Body über 32 KB ab und prüft das Formular Feld für Feld. Ein ausgefülltes Honeypot-Feld bekommt eine freundliche Antwort und geht nirgendwohin. Von der Antwort des Dienstes bekommt der Besucher höchstens 64 KB JSON oder eine Ablehnung, deren Texte auf schlichten Text gekürzt sind.

Der Moduldienst prüft alles noch einmal, denn der Aufruf kommt aus dem Internet.

Der Dienst ist ein eigener Prozess. nexxus ruft ihn mit einem Aufruf-Token auf, dessen Auslöser portal:<endpunkt> ist; ein Token für den Preis kann deshalb keine Buchungsanfrage schicken. Hinter einem Portal-Aufruf steht keine Person: Ruft der Dienst zurück, handelt er als Dienstkonto der Installation, mit den Berechtigungen, denen die Administration zugestimmt hat. Wie die Tokens funktionieren, steht unter Moduldienste.

Was der Dienst schreibt, erscheint in nexxus wie jeder andere Datensatz. Im Ferienhaus-Paket wird aus einer Buchungsanfrage ein Gast (über die E-Mail-Adresse gefunden, sonst neu), eine Buchung mit dem Status Anfrage und die Nachricht des Gastes im Posteingang der Agentur. Standardmäßig entwirft der Dienst eine Antwort aus den Feldern der Unterkunft und hält WLAN und Anreisedetails zurück, bis der Aufenthalt gebucht ist. Mitarbeitende lesen den Entwurf, ändern ihn bei Bedarf und geben ihn frei.

Die Karte im Portal und die Kartenansichten in nexxus nutzen dieselbe Komponente und dieselbe Quelle: ein PMTiles-Archiv mit OpenStreetMap-Daten, dazu seine Schriften und Symbole, ausgeliefert von nexxus unter /public/map/. Der Browser liest das Archiv in Byte-Bereichen, deshalb braucht nexxus keinen Kachelserver. Vom Browser des Besuchers geht keine Anfrage an einen Kartenanbieter.

Die Karte gehört der Installation, nicht einem Mandanten. Ein Archiv kann die Welt in niedrigen Zoomstufen und die Regionen, die eine Installation bedient, in voller Tiefe enthalten; außerhalb dieser Regionen hört die Karte auf zu zoomen, statt leere Kacheln zu zeigen.

Adresssuche und geocodeFrom von Paketfeldern laufen nur auf dem Server. Standardmäßig fragen sie den öffentlichen Nominatim-Server der OpenStreetMap Foundation, höchstens einmal pro Sekunde, wie dessen Nutzungsregeln es verlangen, und behalten jede Antwort 180 Tage (eine Adresse ohne Treffer 7 Tage).

Die Portal-App setzt keine Cookies und nutzt weder Local Storage noch Session Storage oder IndexedDB. Seiten, Daten, Bilder, Kartenkacheln und Schriften kommen alle von der eigenen Adresse des Portals. Beim Verschieben der Karte suchen bleibt für den Besuch im Speicher. Deshalb braucht eine Seite auf dieser Grundlage keinen Cookie-Banner. Halten Sie das so, wenn Sie auf dem Portal aufbauen, und sagen Sie es in der Datenschutzerklärung der Seite, wie es das Ferienhaus-Paket tut.