Yurna verstehen: Bot, Dashboard und Admin-API
Yurnas drei Anwendungen teilen Daten, tragen aber unterschiedliche Verantwortung. Ein konkreter Konfigurationsablauf zeigt, wie Zuständigkeiten, Fehlerbehandlung und überprüfbare Übergänge zwischen Discord, Browser und Verwaltung zusammenpassen, ohne die Architektur unnötig aufzublähen.
1584 Wörter · 8 Min. Lesezeit
- yurna
- architektur
- discord
- dashboard
Schematische Illustration zur Artikelserie; keine privaten Betriebsdaten.
Eine Einstellung im Browser zu ändern wirkt wie eine einzelne Handlung. Tatsächlich können mehrere Entscheidungen darin stecken: Darf die Person diesen Server verwalten? Ist der ausgewählte Kanal noch vorhanden? Wurde der neue Wert gespeichert? Hat der Bot ihn bereits übernommen? Wer diese Fragen in einer einzigen Erfolgsmeldung versteckt, baut eine Oberfläche, die unter guten Bedingungen angenehm und bei Störungen kaum erklärbar ist. Yurna lässt sich besser verstehen, wenn man die Grenzen dieser Entscheidungen sichtbar macht.
Im untersuchten Quellstand gibt es drei Anwendungen: den Discord-Bot, das Dashboard und eine eigene Admin-API. Daneben stehen gemeinsame Pakete, unter anderem für Datenbankzugriffe, Hilfsfunktionen und Übersetzungen. Das ist zunächst eine Aussage über die Organisation des Codes. Daraus folgt weder, welche Funktionen auf einem bestimmten Server aktiviert sind, noch welche Prozesse gerade laufen. Für Architekturarbeit reicht diese Unterscheidung weit: Vorhandene Bausteine werden untersucht, Betriebsannahmen müssen anschließend gesondert überprüft werden.
Drei Eingänge mit verschiedenen Aufgaben
Der Bot steht dort, wo Mitglieder mit Yurna interagieren. Er verarbeitet Discord-Ereignisse und führt Aktionen aus, die Discord betreffen. Ein Rollenwechsel, eine Antwort auf einen Befehl oder die Veröffentlichung einer Ticketnachricht haben eine direkte Verbindung zum Discord-Zustand. Der Bot kann deshalb nicht allein aus einer Datenbankzeile ableiten, dass eine gewünschte Änderung bereits erfolgreich sichtbar geworden ist. Zwischen gespeichertem Wunsch und ausgeführter Aktion liegt ein weiterer, störbarer Schritt.
Das Dashboard bietet mehr Platz für Einstellungen, Listen und Erklärungen. Seine Stärke ist die Bearbeitung zusammenhängender Informationen. Ein Formular kann Eingaben prüfen und eine Änderung vor dem Speichern zusammenfassen. Es hat aber keinen besonderen Wahrheitsvorsprung, nur weil es im Browser läuft. Eine dort angezeigte Rolle kann inzwischen gelöscht worden sein. Eine Person kann während einer offenen Sitzung ihre Verwaltungsberechtigung verlieren. Deshalb muss der Server jede relevante Mutation selbst prüfen, auch wenn die Oberfläche den passenden Knopf bereits ausgeblendet hat.
Die Admin-API ist im Quellstand eine eigenständige Hono-Anwendung mit Fachrouten etwa für Server, Tickets, Lizenzen, Einstellungen und Status. In ihrer zentralen Registrierung steht eine Tokenprüfung vor den geschützten Routen; eine Gesundheitsroute wird davor eingebunden. Das zeigt eine bewusste Trennung der Zugänge. Es bedeutet nicht, dass ein Verwaltungszugang automatisch für Browsercode geeignet wäre. Besonders weitreichende Funktionen gehören hinter eine eigene Vertrauensgrenze und sollten nicht als bequeme Abkürzung für gewöhnliche Dashboard-Aktionen dienen.
Gemeinsame Daten sind noch keine gemeinsame Wahrheit
Das Prisma-Schema verwendet SQLite und bezieht den Datenbankpfad aus der Umgebung. Ein Kommentar beschreibt ausdrücklich das Problem getrennter Dateien bei relativ aufgelösten Pfaden. Der praktische Architekturpunkt dahinter ist einfach: Drei Prozesse können dasselbe Schema importieren und trotzdem in unterschiedliche Datenbestände schreiben. Eine erfolgreiche Speicherung im Dashboard sagt dann nichts darüber aus, was der Bot beim nächsten Lesen findet. Die Übereinstimmung der tatsächlichen Datenquelle ist daher Teil der Bereitstellung und kein Detail der Typdefinitionen.
Auch bei einer gemeinsamen Datei bleiben Unterschiede zwischen den Sichten bestehen. Ein Prozess kann eine Einstellung im Speicher halten, ein anderer bereits den neuen Wert lesen. Eine Discord-Nachricht kann noch die vorige Konfiguration zeigen. Diese Zustände sind nicht zwangsläufig Fehler, solange das System ihre Grenzen kennt und vermittelt. Problematisch wird es, wenn eine ältere Anzeige wie eine aktuelle Bestätigung behandelt wird oder eine Anwendung ihre zwischengespeicherte Kopie unbemerkt wieder über den neueren Datenstand schreibt.
Für jede wichtige Information lohnt sich deshalb eine kurze Eigentümerregel. Der ausgewählte Zielkanal wird als Konfiguration gespeichert. Ob der Kanal existiert und welche Rechte dort gelten, bestimmt Discord. Ob eine Veröffentlichung noch aussteht, gehört in einen nachvollziehbaren Arbeitszustand. Der Browser zeigt diese Informationen gemeinsam an, sollte sie aber nicht zu einer einzigen unklaren Eigenschaft namens „aktiv“ verschmelzen. Unterschiedliche Zustände brauchen unterschiedliche Aussagen, selbst wenn sie optisch in derselben Karte erscheinen.
Ein durchgehendes Beispiel: einen Ausgabekanal ändern
Als Entwurf dient eine Einstellung, die den Kanal für eine automatische Nachricht festlegt. Angenommen wird ein Server mit einer berechtigten Verwaltungsperson, einem laufenden Bot und einer gemeinsamen Datenbank. Die Person wählt im Dashboard einen neuen Kanal. Bevor gespeichert wird, prüft das Backend die Zugehörigkeit zum ausgewählten Server, die Berechtigung der Person und das erwartete Format. Falls eine Discord-Abfrage notwendig ist, erhält sie ein Zeitlimit. Ein langsamer externer Dienst darf keine beliebig lange Datenbanksperre erzeugen.
Danach wird die neue Konfiguration mit einer Versionsnummer gespeichert. Die Version ist kein Schmuck für die Oberfläche. Sie erlaubt festzustellen, ob eine weitere Person dieselbe Einstellung inzwischen verändert hat. Im Beispiel sendet das Formular die gelesene Version mit. Passt sie nicht mehr, zeigt das Dashboard den aktuellen Wert und bittet um eine bewusste erneute Entscheidung. Ein stilles Überschreiben wäre zwar einfacher zu implementieren, würde aber gerade bei gemeinsam betreuten Communities schlecht erklärbare Rücksprünge produzieren.
// Architekturentwurf: keine unverändert einsetzbare Yurna-Funktion.
type ChannelChange = {
guild: string;
channel: string;
expectedVersion: number;
};
type SavedChange = {
version: number;
delivery: "pending" | "applied" | "failed";
};Nach dem Speichern darf die Oberfläche „Einstellung gespeichert“ melden. Eine zusätzliche Veröffentlichung wird als eigener Schritt dargestellt. Schlägt sie fehl, bleibt die Konfiguration nicht deshalb automatisch ungeschehen. Stattdessen erscheint eine klare Aussage: Der neue Kanal ist hinterlegt, die Nachricht konnte noch nicht veröffentlicht werden. Damit entsteht eine bewusste Wahl: Veröffentlichung wiederholen oder die Einstellung zurücknehmen. Beide Handlungen haben unterschiedliche Folgen und verdienen getrennte Bedienelemente.
Dieses Modell kostet etwas mehr Zustandsverwaltung als ein einzelner Erfolgswert. Es zahlt sich aus, sobald ein Netzfehler auftritt oder Discord eine Anfrage ablehnt. Der Support kann dann feststellen, an welcher Grenze der Ablauf angehalten hat. Ohne diese Information müsste er Datenbank, Browser und Discord manuell vergleichen und aus fehlenden Nachrichten auf mögliche Ursachen schließen. Eine kleine zusätzliche Zustandsangabe reduziert hier einen großen Teil späterer Unsicherheit.
Wo gemeinsame Pakete helfen
Ein gemeinsames Datenbankpaket verhindert, dass jede Anwendung eigene Feldnamen und widersprüchliche Datentypen erfindet. Gemeinsame Hilfsfunktionen können dieselbe fachliche Prüfung mehreren Eingängen zur Verfügung stellen. Entscheidend ist allerdings, welche Abhängigkeiten sie mitbringen. Eine reine Prüfung des Eingabeformats braucht keinen verbundenen Discord-Client. Eine Funktion zum Versenden einer Nachricht braucht dagegen genau diesen Zugang. Werden beide Aufgaben vermischt, werden Tests und Wiederverwendung unnötig schwer.
Eine brauchbare Trennung beginnt mit kleinen Ergebnissen. Eine Prüffunktion liefert beispielsweise eine akzeptierte Kanaländerung oder strukturierte Gründe für eine Ablehnung. Erst die aufrufende Anwendung übersetzt diese Gründe in eine Browsermeldung, eine Discord-Antwort oder eine API-Antwort. So bleibt dieselbe Regel erhalten, ohne alle Oberflächen in dieselbe Darstellung zu zwingen. Der Bot kann knapp antworten, während das Dashboard die betroffenen Felder markiert und einen weiterführenden Hinweis anbietet.
Nicht jede Ähnlichkeit rechtfertigt sofort ein gemeinsames Paket. Zwei kurze Formatierungen dürfen zunächst ähnlich aussehen, wenn ihre Anforderungen noch unklar sind. Zu frühe Verallgemeinerung erzeugt oft Funktionen mit vielen Schaltern, die niemand vollständig versteht. Gemeinsam werden sollte vor allem, was tatsächlich dieselbe fachliche Bedeutung hat: die Identifikation eines Servers, zulässige Zustandsübergänge oder die Interpretation einer gespeicherten Konfiguration. Oberflächliche Ähnlichkeit allein ist ein schwacher Grund für zusätzliche Abhängigkeiten.
Fehler an der richtigen Grenze behandeln
Ein Eingabefehler ist anders zu behandeln als eine fehlende Berechtigung. Eine vorübergehend nicht erreichbare Discord-API ist wiederum etwas anderes als ein gelöschter Kanal. Wenn alle Fälle mit „Interner Fehler“ enden, kann die Verwaltung keine sinnvolle nächste Handlung wählen. Die Architektur sollte daher eine kleine, stabile Menge fachlicher Fehler vorsehen. Die konkreten technischen Details bleiben im internen Protokoll; nach außen gelangt eine verständliche Ursache mit passender Handlungsoption.
Wiederholungen verdienen besondere Aufmerksamkeit. Nach einem Verbindungsabbruch weiß der Browser möglicherweise nicht, ob die Speicherung erfolgreich war. Sendet er dieselbe Aktion erneut, darf daraus kein zweiter fachlicher Vorgang entstehen, falls nur einer beabsichtigt war. Bei reinen Einstellungen ist das oft durch eine eindeutige Zielversion handhabbar. Bei Aktionen wie dem Erstellen einer Nachricht braucht es einen eigenen Vorgangsschlüssel und einen gespeicherten Bearbeitungsstand. Welche Strategie passt, hängt von der Wirkung ab, nicht vom verwendeten Transportprotokoll.
Dass Datenbanktransaktionen atomare Änderungen erlauben, löst externe Nebenwirkungen nicht mit. Eine Nachricht bei Discord und eine lokale Datenbankzeile gehören nicht automatisch zu derselben Transaktion. Die SQLite-Dokumentation zu Transaktionen beschreibt die Garantien innerhalb der Datenbank. Für den entworfenen Ablauf ergibt sich daraus die separate Aufgabe, gespeicherte Absicht und externe Ausführung miteinander abzugleichen. Diese Grenze sollte im Entwurf offen benannt werden.
Die Architektur mit Störungen prüfen
Ein guter Durchlauf beginnt mit dem normalen Fall: Kanal auswählen, speichern, Version kontrollieren und die resultierende Discord-Ausgabe ansehen. Danach wird dieselbe Abfolge mit einer zweiten offenen Browsersitzung durchgeführt. Eine Sitzung speichert zuerst; die andere versucht anschließend, ihre ältere Sicht zu übernehmen. Erwartet wird ein sichtbarer Konflikt und keine zufällige Reihenfolge, deren letzter Schreibzugriff alle vorherigen Entscheidungen verdeckt. Dieser Versuch prüft das Fachverhalten genauer als ein bloßer erfolgreicher HTTP-Status.
Der nächste Versuch unterbricht die externe Ausführung nach erfolgreicher Speicherung. Nun muss der Browser zwischen hinterlegtem Wert und ausstehender Veröffentlichung unterscheiden. Anschließend wird der Arbeitsprozess neu gestartet. Die offene Aufgabe darf nicht allein deshalb verschwinden, weil ein Prozessspeicher geleert wurde. Zuletzt wird der Zielkanal zwischen Auswahl und Ausführung entfernt. Der Ablauf sollte eine konkrete, behebbar erklärte Störung zeigen und nicht endlos dieselbe aussichtslose Anfrage senden.
Für solche Tests hilft es, Discord-Zugriffe hinter einer kleinen Schnittstelle zu führen. Die offizielle Beschreibung von Interaktionen definiert den Eingang von Nutzeraktionen; der eigene Code entscheidet darüber, wie daraus fachliche Arbeit entsteht. Im Test ersetzt ein kontrollierter Adapter nur den externen Dienst. Datenänderung, Konflikterkennung und Fehlermeldung bleiben echte Bestandteile des untersuchten Ablaufs. So entsteht Vertrauen in die Zusammenarbeit der Anwendungen, ohne jede Prüfung von einem echten Server abhängig zu machen.
Eine Landkarte für die nächste Änderung
Vor einer neuen Funktion sollten drei Sätze beantwortbar sein: Wo kommt der Wunsch an, welcher Baustein entscheidet fachlich darüber und wo wird die Wirkung ausgeführt? Beim beschriebenen Kanalwechsel sind das Dashboard, die gemeinsame Prüfung mit Speicherung und der Discord-Zugang des Bots. Dazu kommt die Rückmeldung über den Bearbeitungsstand. Wenn diese Antworten unscharf bleiben, wird zusätzliche Funktionalität wahrscheinlich an mehreren Stellen unabhängig voneinander dieselben Regeln nachbauen.
Die Architektur von Yurna gewinnt deshalb nicht dadurch, dass möglichst viele Dienste entstehen. Sie gewinnt durch Grenzen, die auch im Fehlerfall verständlich bleiben. Drei vorhandene Anwendungen können eng zusammenarbeiten und trotzdem präzise Zuständigkeiten haben. Eine Verwaltungsperson muss diese interne Aufteilung nicht kennen. Sie sollte aber jederzeit erkennen können, ob ihre Eingabe abgelehnt, gespeichert, noch in Bearbeitung oder tatsächlich umgesetzt wurde. Genau daran lässt sich die Qualität der technischen Trennung im Alltag messen.