Next.js und Sage. Vielleicht gibt es nichts aufzurufen.
Mehrere Sage-Produkte laufen auf einer Maschine im Büro des Kunden, ohne öffentliche Adresse. Das ist kein Hindernis für die Integration - es ist die Integration, und bestimmt, was eine Seite zeigt.
Es kommt eine Anforderung, das Kundenportal solle pro Konto die offenen Rechnungen zeigen, und die Rechnungen liegen in Sage. Das liest sich wie eine Aufgabe zum Datenabruf. Bevor es eine ist, gibt es eine Frage zu beantworten, die die gesamte Architektur entscheidet, und die Antwort lautet häufig, dass es keine Adresse zum Abrufen gibt.
Sage ist eine Produktfamilie und kein Produkt. Manche davon sind gehostete Dienste mit öffentlicher Schnittstelle und verhalten sich wie jede andere SaaS-Anbindung. Andere sind Anwendungen, die auf einem Server im Büro des Kunden installiert sind, und ihre Daten liegen in einer Datei auf diesem Server. Eine deployte Next.js-Anwendung erreicht diese Datei nicht, weder aus einer Server-Komponente noch von sonst wo, und keine passende Bibliothek ändert das.
Klären Sie zuerst, wo es läuft
Die erste Stunde des Projekts ist ein Telefonat, kein Schema.
Fragen Sie, welches Sage-Produkt, welche Edition und wo es installiert ist. Fragen Sie, wer diese Maschine administriert. Rechnen Sie damit, dass die Antwort unsicher ist, und rechnen Sie damit, dass "das ist in der Cloud" bedeutet, dass die Buchhaltung über den Browser auf einen Windows-Desktop zugreift - was sich für alle Beteiligten nach Cloud anfühlt und keine öffentliche API ist.
Es gibt nur zwei Ausgänge, und sie sind keine Varianten voneinander. Entweder es gibt eine Schnittstelle im Internet, dann haben Sie eine gewöhnliche Integration und die eigentliche Arbeit ist, wo welches Stück davon laufen sollte. Oder es gibt sie nicht, dann ist der nächste Abschnitt das ganze Projekt.
Die einzige Form, die genehmigt wird
Liegt das System im Netzwerk eines anderen, wird die Verbindung von innen nach außen aufgebaut. Etwas, das neben den Sage-Daten läuft - ein Dienst auf deren Server, ein geplanter Export, ein kleiner Konnektor -, schickt Daten über HTTPS nach außen an einen Endpunkt, den Sie kontrollieren. Nichts Eingehendes wird geöffnet, und deshalb ist das die Variante, die eine IT-Abteilung abzeichnet.
Ihre Next.js-Anwendung steht am anderen Ende davon, und sie ist nie das, was Sage aufruft. Sie empfängt, oder üblicher: Sie liest schlicht eine Datenbank, in die der empfangende Prozess schreibt.
Sage auf deren Server
-> Konnektor in deren Netzwerk (nur ausgehend)
-> Ingest-Endpunkt (prüft, schreibt)
-> Ihre Datenbank (das Lesemodell)
-> Server-Komponenten (rendern)
Dieses Bild in der ersten Woche zu zeichnen, ist wichtiger, als es aussieht, denn es ist zugleich der Vertrag. Alles links von Ihrer Datenbank ist eine Maschine, die Sie nicht kontrollieren, mit einem Zeitplan, den Sie nicht setzen, auf einem Server, den jemand über Weihnachten ausschaltet. Alles rechts davon gehört Ihnen und kann so schnell und so verlässlich werden, wie Sie mögen.
Sobald das Bild auf dem Papier ist, hört der Rest des Entwurfs auf, von Sage zu handeln. Es ist ein Lesemodell, und damit die gewöhnliche Aufgabe, eine Datenbank zu wählen und sie für die Abfragen Ihrer Seiten zu indizieren.
Das Alter der Daten ist ein Feld, keine Cache-Einstellung
Der Fehler, der nun folgt, ist, Aktualität als Caching-Frage zu behandeln. Das ist sie nicht, und die Unterscheidung lohnt Präzision, weil sich das Vokabular überschneidet.
use cache mit cacheLife steuert, wie lange Next.js ein berechnetes Ergebnis
behält, bevor es neu berechnet wird. Das ist eine Aussage über Ihr eigenes
Rendern. Es sagt überhaupt nichts darüber, wie alt die zugrunde liegenden Zahlen
sind, denn das Neuberechnen liest dieselbe Datenbankzeile, die der Konnektor
heute früh um halb sieben zuletzt geschrieben hat. Stellen Sie die kürzeste
Cache-Lebensdauer ein, die Sie mögen, und der Rechnungsbetrag wird davon nicht
neuer.
Das Alter der Daten muss also als Daten modelliert werden. Jede synchronisierte Entität trägt den Zeitstempel des Laufs, der sie erzeugt hat, und diese Spalte ist keine Diagnose - sie ist ein Feld, das die Oberfläche rendert:
export async function AccountBalance({ accountId }: { accountId: string }) {
const account = await db.account.findUnique({ where: { id: accountId } })
const age = Date.now() - account.syncedAt.getTime()
return (
<section>
<Amount value={account.balance} />
{age > 2 * 60 * 60 * 1000 ? (
<Warning>
Zuletzt aktualisiert {formatRelative(account.syncedAt)}. Das
Buchhaltungssystem hat sich seither nicht gemeldet.
</Warning>
) : (
<Note>Stand {formatTime(account.syncedAt)}</Note>
)}
</section>
)
}Zwei Stunden sind keine magische Zahl, und Sie sollten Ihre eigene daraus ableiten, wie oft der Konnektor laufen soll. Der Punkt ist, dass die Komponente drei Zustände hat statt zwei, und der dritte - vorhanden, aber alt - ist der Zustand, in dem das System seine schlechten Tage tatsächlich verbringt. Eine Seite, die einen vierzehn Stunden alten Saldo genauso rendert wie einen frischen, ist kein Caching-Fehler. Sie ist ein Entwurf, der diesen Fall nie bedacht hat.
Manche Zahlen dürfen gar nicht veraltet gezeigt werden
Wenn entschieden ist, dass die meisten Werte mit ihrem Alter gezeigt werden dürfen, entscheiden Sie getrennt, welche nicht.
Ein offener Saldo von heute früh ist nützlich und klar beschriftet. Ein Kreditlimit, das darüber entscheidet, ob eine Bestellung angenommen werden darf, ist eine andere Art Zahl, und ein veralteter Wert bedeutet, eine Bestellung anzunehmen, die die Buchhaltung abgelehnt hätte. Vertragspreise sind dasselbe. Verfügbarer Bestand ebenfalls, wenn jemand ihn gerade einem Kunden zusagen will.
Dafür sagt die ehrliche Oberfläche, dass die Prüfung gerade nicht möglich ist, und bietet den nächsten Schritt an - die Bestellung zur Prüfung zurückhalten, oder dem Kunden sagen, dass sich jemand meldet. Das ist eine schlechtere Erfahrung als eine Zahl und eine bessere als eine falsche, und die Buchhaltung sagt Ihnen in etwa zehn Minuten, welche Felder hierher gehören, wenn Sie direkt fragen.
Zurückschreiben ist ein anderes Versprechen
Lesen ist die leichte Richtung. Ein Formular in Ihrer Anwendung, das auf der anderen Seite etwas anlegt, ist die Stelle, an der die Architektur geprüft wird, weil Sie es nicht bestätigen können.
Die Server Action schreibt die Anfrage in Ihre eigene Datenbank und kehrt zurück. Mehr kann sie wahrheitsgemäß nicht tun. Ob der Datensatz Sage erreicht, hängt an einem Konnektorlauf, der Minuten entfernt sein kann, und die Action hat keine Möglichkeit, darauf zu warten, ohne eine Anfrage länger offen zu halten, als irgendeine Plattform erlaubt.
Was bedeutet: Ausstehend ist ein echter Zustand mit eigener Zeile, eigenem Bildschirm und eigenem Fehlerpfad, kein Spinner. Der Benutzer sendet ab, sieht, dass es eingereiht wurde, und sieht es auf bestätigt wechseln, wenn eine spätere Synchronisation zurückmeldet. Scheitert es an der Validierung auf der Sage-Seite
- ein Debitorenkonto, das es nicht gibt, ein umbenanntes Sachkonto -, muss dieser Fehler irgendwo landen, wo ein Mensch hinsieht, denn es gibt keine Anfrage mehr, an die man einen Fehler zurückgeben könnte.
Das als optimistische Oberfläche zu bauen und zu hoffen, ist die mit Abstand häufigste Art, wie diese Projekte im ersten Monat nach dem Start eine Woche verlieren. Der Schreibvorgang hat stattgefunden oder nicht, und die Anwendung ist das Einzige, was den Unterschied halten kann.
Was dabei herauskommt
Nichts davon ist ein Behelf für eine Einschränkung. Ein so gebautes Lesemodell ist schneller als jeder Live-Aufruf es gewesen wäre, steht, wenn der Buchhaltungsserver nicht steht, verbindet sich mit Ihren übrigen Daten und lässt sich für die Abfragen indizieren, die Ihre Seiten tatsächlich stellen - statt für die, für die eine Buchhaltungs-API entworfen wurde.
Was es kostet, ist die Ehrlichkeit: Die Zahlen haben ein Alter, die Oberfläche sagt es, und Schreibvorgänge sind Anfragen und keine Tatsachen. Teams, die das von Anfang an einbauen, liefern ein Portal, dem Leute glauben. Teams, die es nach dem ersten Support-Ticket nachrüsten, schreiben genau die Komponenten neu, auf die es am meisten ankommt.
Unsere Enterprise-Projekte haben weitgehend diese Form, und die Grenze zwischen Anwendung und führendem System ist der Teil, den wir zuerst zuschneiden.
