- JavaScript 99.6%
- Dockerfile 0.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .agents/skills | ||
| .forgejo/workflows | ||
| .idea | ||
| .junie/memory | ||
| src | ||
| tests | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
briefbyte
Discord-Bot auf Node.js, der Nachrichten mehrerer Server in PostgreSQL speichert und per /tldr Tageszusammenfassungen über OpenRouter erstellt.
Funktionen
- Speichert Textnachrichten eingerichteter Server.
- Erkennt Gesprächsverläufe anhand von Inhalt, Kanal, genauer Postingzeit und gespeicherten Discord-Antwortreferenzen. Zusammenfassungen sollen Fragen, Antworten, Standpunkte und Ergebnisse zuordnen; zeitliche Nähe allein gilt nicht als Beleg für ein Gespräch. Noch gespeicherte Antwortziele desselben Servers werden auch aus früheren Tagen als kurzer Kontextauszug mitgegeben. Die Referenzen werden ab dieser Version erfasst, ältere Nachrichten werden nicht nachträglich ergänzt.
- Begrüßt neue Server mit einem dekorierten Embed zu Befehlen, Speicherung und Löschung.
- Nach Entfernen des Bots bleiben Serverdaten 30 Tage erhalten und werden danach automatisch gelöscht. Ein Beitritt vor Fristende hebt die Löschung auf.
- Nachrichten der konfigurierten Non-Digest-Rolle werden ohne Autorennamen und Nutzer-ID, aber mit einer tagesgebundenen Kennung gespeichert. Die Grenzen dieser Pseudonymisierung beschreibt der Abschnitt Datenschutz.
- Nicht anonyme Autoren werden mit ihren gespeicherten Discord-Anzeigenamen an die KI übermittelt und bei relevanten Gesprächen genannt. Anonyme Beiträge heißen immer „ein anonymer User“, ohne individuelle Wiedererkennung. Ihr Austausch mit anderen oder untereinander darf allgemein beschrieben werden; einzelne anonyme Personen und genaue Teilnehmerzahlen werden daraus nicht abgeleitet. Weitere persönliche Angaben sollen nicht ausgegeben werden, auch nicht aus Nachrichtentexten oder Zitaten.
/datenlöschungöffnet für jeden Nutzer ein Bestätigungsmodal mit Auswahlfeld. Erst nach ausdrücklicher Bestätigung werden alle zuordenbaren Nachrichten dieses Nutzers im aktuellen Server aus der Datenbank gelöscht. Anonyme Beiträge, vorhandene TL;DRs und die Nachrichten in Discord bleiben erhalten. Neue Nachrichten werden weiterhin gespeichert.- Slash-Command
/tldrfasst Nachrichten von heute zusammen. - TL;DRs erhalten alle relevanten Hauptthemen ohne Begrenzung ihrer Anzahl oder der Gesamtwortzahl. Pro Hauptthema genügt ein kurzer Satz mit Gesprächsteilnehmern, Kernaussage und Ergebnis oder offener Frage; bei mehreren Themen als kurze Stichpunkte ohne Zwischenüberschriften. Bei vielen Hauptthemen werden die einzelnen Formulierungen gekürzt, statt Themen wegzulassen. Beiläufige Statusmeldungen, Anekdoten, Smalltalk, Wiederholungen und Detailauflistungen entfallen; es gibt keinen Sammelpunkt „Weitere Punkte“.
- TL;DRs erscheinen als Embed mit maximal 4096 Zeichen im KI-Text, ohne Abschneiden oder Dateianhang. Zu lange oder vom Anbieter abgebrochene Antworten werden erneut erzeugt (maximal drei Versuche); bleibt die Ausgabe ungültig, schlägt die Erstellung fehl.
/tldrerzeugt höchstens einmal pro Stunde und Server eine neue Zusammenfassung. Frühere Aufrufe verweisen per Antwort auf den letzten TL;DR./tldr-date datum:01.02.2025zeigt einen archivierten Tages-TL;DR. Das Datum wird alsTT.MM.JJJJeingegeben. Ältere Archivtexte mit mehr als 4096 Zeichen werden für die Anzeige erneut durch die KI verdichtet; das gespeicherte Original bleibt erhalten.- Jeden Tag um 00:00 Uhr (Europe/Berlin) wird der Vortag in PostgreSQL archiviert. Danach werden die anonymen Roh-Nachrichten dieses Tages gelöscht; die archivierte Zusammenfassung bleibt erhalten. Der Nachtlauf postet nichts in Discord, da kein Zielkanal konfiguriert ist.
/setuprichtet den Bot einmalig ein;/settingsändert die Einstellungen danach. Owner und Administratoren behalten Zugriff. Zusätzlich lassen sich bis zu 25 berechtigte Rollen auswählen; ohne Auswahl bleiben nur Owner und Administratoren berechtigt./tldrfasst nur Nachrichten des heutigen Berliner Kalendertags zusammen. Passt der gesamte Nutzerprompt inklusive Anweisungen ins Eingabelimit, genügt eine KI-Anfrage. Das Limit beträgt standardmäßig 60000 Zeichen und ist überSUMMARY_PROMPT_MAX_CHARSkonfigurierbar. Erst längere Eingaben werden ohne Abschneiden in Chunks zerlegt, auch bei einzelnen überlangen Nachrichten. Teilsummaries mit maximal 2048 Zeichen werden bei Bedarf über mehrere Stufen zu einem TL;DR mit maximal 4096 Zeichen verdichtet; das gilt auch für lange Archivtexte. Ungültige oder abgebrochene KI-Antworten können weiterhin erneute Versuche auslösen.- Strukturierte Konsolenlogs für Commands, Modals, Datenbankaktionen und Fehler; reguläre Ereignislogs enthalten Metadaten statt Nachrichteninhalte.
Commands
Alle Commands beziehen sich auf den Server, in dem sie aufgerufen werden. Einstellungen, Nachrichten, Archive und der Stundenabstand sind nach Server-ID getrennt.
Normale Mitglieder sehen standardmäßig nur /datenlöschung, /tldr und /tldr-date. /setup, /settings und /tldr-reset werden mit Discord-Administratorrechten registriert. Für konfigurierte Einstellungsrollen ohne Administratorrechte muss ein Server-Admin die benötigten Befehle zusätzlich unter Servereinstellungen → Integrationen → Briefbyte freigeben. Die Rollenprüfung im Bot bleibt bestehen; eine Discord-Freigabe allein gewährt keine Einstellungsrechte im Bot. Bestehende Discord-Freigaben können die Standardsichtbarkeit überschreiben.
| Command | Funktion | Zugriff im Bot |
|---|---|---|
/setup |
Erstmalige Einrichtung mit denselben Feldern wie /settings: Non-Digest-Rolle und optionale Rollen für Einstellungen. |
Server-Owner oder Rolle mit Discord-Administratorrecht |
/settings |
Non-Digest-Rolle und Rollen für Einstellungen im Auswahlmodal ändern. | Server-Owner, Discord-Administratoren oder Mitglieder einer konfigurierten Einstellungsrolle |
/tldr-reset |
Stunden-Sperre für Tests im aktuellen Server zurücksetzen. | Dieselben Berechtigungen wie /settings |
/tldr |
Alle bisher erfassten Nachrichten des heutigen Tages zusammenfassen. | Servermitglieder nach Setup |
/tldr-date datum:TT.MM.JJJJ |
Gespeichertes Archiv eines vergangenen Tages anzeigen, z. B. 01.02.2025. |
Servermitglieder nach Setup |
/datenlöschung |
Bestätigung per Auswahlmodal; eigene zuordenbare Nachrichten dieses Servers löschen. | Servermitglieder, nur für eigene Daten |
Zusätzliche Einschränkungen durch Discord-Command-Berechtigungen können den Zugriff begrenzen. Tagesgrenzen richten sich nach Europe/Berlin, einschließlich Sommerzeit. Jeder neue Tages-TL;DR berücksichtigt den bisherigen Tag, nicht nur Nachrichten seit dem letzten Aufruf. Der Stundenabstand gilt serverweit für /tldr; Archivabrufe benötigen nur bei älteren Texten über der Zeichengrenze eine neue KI-Anfrage. Der automatische Nachtlauf archiviert den Vortag unabhängig davon.
Einrichtung und Betrieb
- Node.js 22 oder neuer installieren und Abhängigkeiten laden:
npm install
.env.examplenach.envkopieren und ausfüllen.SENTRY_DSNist optional und aktiviert die Fehlerüberwachung. Dabei können IDs als Fehlerkontext übertragen werden; siehe Datenschutz.ANONYMIZATION_SECRETist optional; ein eigener stabiler Wert hält anonyme Tageskennungen auch bei einem Discord-Tokenwechsel konsistent.- PostgreSQL starten:
docker compose up -d
- Bot manuell starten:
npm start
Der Bot registriert /setup, /settings, /tldr, /tldr-reset, /tldr-date und /datenlöschung global, beschränkt ihre Verfügbarkeit aber auf Server. In Direktnachrichten werden keine Slash-Commands angeboten. Änderungen werden beim Bot-Start synchronisiert. Nach der Installation auf einem Server richtet dessen Owner oder ein Discord-Administrator die Non-Digest-Rolle mit /setup ein. Vorher werden dort keine Nachrichten gespeichert. Beim Start holt der Bot versäumte Archive für Tage mit gespeicherten Nachrichten nach.
Der Discord-Bot benötigt Zugriff auf die gewünschten Kanäle und Nachrichteninhalte; die Anwendung verwendet den MessageContent-Intent. Zum Ausgeben von TL;DRs benötigt er Senderechte und für lange Zusammenfassungen die Berechtigung zum Anhängen von Dateien. Docker Compose startet nur PostgreSQL; der Bot läuft mit npm start im Terminal und lässt sich mit Strg+C beenden.
Für zusätzliche Meldungen beim manuellen Test LOG_LEVEL=debug in .env setzen. Reguläre Ereignislogs enthalten IDs, Zähler und Textlängen. Fehlertexte und Stacktraces werden ebenfalls protokolliert.
Konfiguration
| Variable | Bedeutung |
|---|---|
DISCORD_TOKEN |
Erforderlicher Bot-Zugang; gehört nicht ins Repository. |
DATABASE_URL |
Erforderliche PostgreSQL-Verbindung. |
POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD |
Datenbankzugang für Docker Compose; Standard jeweils briefbyte. Bei vorhandenen Volumes die bisherigen Werte verwenden. |
OPENROUTER_API_KEY |
Erforderlicher Zugang zur Zusammenfassung über OpenRouter. |
OPENROUTER_MODEL |
Modell für Zusammenfassungen; Standard laut .env.example. |
SUMMARY_PROMPT_MAX_CHARS |
Maximale Zeichen pro Nutzerprompt inklusive Anweisungen; Standard 60000, mindestens 6000. Passend zum Kontextfenster des Modells wählen: Anbieterlimits zählen Tokens; Systemprompt und Antwort benötigen zusätzlich Platz. |
SENTRY_DSN |
Optional; ohne Wert wird Sentry nicht initialisiert. |
LOG_LEVEL |
info als Standard, optional debug, warn oder error. |
ANONYMIZATION_SECRET |
Optionaler stabiler geheimer Schlüssel für Tageskennungen; ohne Wert wird der Discord-Token verwendet. |
HEALTH_ENABLED |
HTTP-Health-Service aktivieren (true, Standard) oder deaktivieren (false). |
HEALTH_PORT |
Port des Health-Service; Standard 8080. |
Die Non-Digest-Rolle und die Rollen für Einstellungen werden je Server in PostgreSQL gespeichert, nicht in .env. Das Compose-Volume bewahrt Daten über Container-Neustarts hinweg auf. Die mitgelieferten Datenbankzugangsdaten und die Portfreigabe sind für die lokale Entwicklung gedacht.
Anwendungsstatus
GET /health liefert JSON mit status, checks.discord, checks.database und uptimeSeconds. HTTP 200 bedeutet: Der Start ist abgeschlossen, Discord ist bereit und PostgreSQL erreichbar. Während des Starts oder bei einem Ausfall liefert der Service HTTP 503. Datenbankabfragen haben ein Timeout; Verbindungsdaten und Fehlerdetails erscheinen nicht in der Antwort. Der Service führt keine kostenpflichtigen OpenRouter-Anfragen aus.
Invoke-RestMethod http://localhost:8080/health
HEALTH_ENABLED=false schaltet den HTTP-Service ab. Der Docker-Healthcheck prüft denselben Endpunkt; bei abgeschaltetem Service wird die Prüfung übersprungen. Beim Beenden wird der Health-Service zusammen mit Bot, Nachtlauf und Datenbankpool geschlossen.
Container und Forgejo
Das optionale Compose-Profil bot startet die Anwendung zusätzlich zu PostgreSQL:
docker compose --profile bot up -d --build
Das Profil nutzt die Zugangsdaten aus .env, verbindet den Bot mit dem lokalen Compose-PostgreSQL und veröffentlicht den Health-Port auf 127.0.0.1. Ohne Profil startet Compose weiterhin nur PostgreSQL.
Bestehende Datenbank-Volumes behalten ihre Datenbank und Zugangsdaten. Für diese Installationen POSTGRES_DB, POSTGRES_USER und POSTGRES_PASSWORD in .env auf die bisherigen Werte setzen; DATABASE_URL für den manuellen Start ebenfalls beibehalten. Die Umbenennung des Projekts migriert keine vorhandene Datenbank.
Für bereits veröffentlichte Images statt eines lokalen Builds:
docker compose --profile bot pull bot
docker compose --profile bot up -d --no-build
Der Dockerfile verwendet Node.js 22 und einen Benutzer ohne Root-Rechte. .env und andere lokale Dateien werden durch .dockerignore vom Build ausgeschlossen.
.forgejo/workflows/publish-container.yml veröffentlicht git.vortige.com/vortige/briefbyte nach erfolgreichen Tests und Syntaxprüfung:
- Pushes lösen keine Package-Veröffentlichung aus.
- Täglich um 02:00 UTC:
nightly,nightly-<Commit>,latestundsha-<Commit>, wenn dieser Commit noch nicht veröffentlicht wurde. Vorhandene Commit-Tags (sha-<Commit>oder bisherigenightly-<Commit>) werden übersprungen; das gilt auch nach einem manuellen Build desselben Commits. - Manueller Start: validierter Wunsch-Tag,
latestundsha-<Commit>, auch bei bereits veröffentlichtem Commit.
Alle Läufe checken main aus. Die Registry-Anmeldung nutzt den Benutzer SvenK und das vorhandene Repository-Secret FORGEJO_TOKEN. Der Forgejo-Runner benötigt Docker und das Label ubuntu-latest.
Datenschutz
Dieser Abschnitt beschreibt den aktuellen technischen Stand des Bots. Betreiberkontakt, verwendetes Modell und Anbieter sowie die tatsächliche Aufbewahrung von Betriebslogs und Backups hängen von der jeweiligen Installation ab und sind hier nicht festgelegt.
Erfassung und gespeicherte Daten
Nach /setup verarbeitet der Bot neu eingehende Textnachrichten, die Discord ihm aus dem jeweiligen Server zustellt. Bot-Nachrichten, Direktnachrichten und Nachrichten ohne Text werden übersprungen. Alte Discord-Nachrichten werden nicht nachträglich importiert; Anhänge werden nicht heruntergeladen oder ausgewertet.
| Daten | Speicherung und Zweck |
|---|---|
| Normale Nachrichten | Inhalt, Zeitpunkt, Server-, Kanal- und Nachrichten-ID sowie Nutzer-ID und Anzeigename; Grundlage der Tageszusammenfassung. |
| Non-Digest-Nachrichten | Inhalt, Zeitpunkt, Server-, Kanal- und Nachrichten-ID, Kennzeichnung als anonym sowie Tageskennung; Nutzer-ID und Autorenname sind leer. |
| Servereinstellungen | Server-ID, ID der Non-Digest-Rolle und IDs der Rollen für Einstellungen. |
| Tagesarchive | Server-ID, Datum, Zusammenfassung und Erstellungszeitpunkt. |
| Letzter manueller TL;DR | Server-ID, Erstellungszeitpunkt sowie Kanal- und Nachrichten-ID für Stundenabstand und Antwortreferenz. |
Die Rollenzugehörigkeit wird beim Eingang einer Nachricht ausgewertet. Spätere Rollenänderungen ändern bereits gespeicherte Datensätze nicht. Bearbeiten oder Löschen einer Nachricht in Discord wird derzeit nicht mit der Datenbank synchronisiert.
Non-Digest-Rolle und Grenzen der Anonymität
Non-Digest bedeutet keine Ausnahme von Speicherung oder KI-Verarbeitung. Die Rolle unterdrückt die direkte Autorenkennzeichnung in der Datenbank. Zusammengehörige Beiträge erhalten pro Server und Tag eine mit HMAC erzeugte Kennung; diese wird für Autorenbezeichnungen in Zusammenfassungen nicht verwendet. Anonyme Beiträge erscheinen immer als „ein anonymer User“, unabhängig davon, ob ihre Kennungen gleich, unterschiedlich oder nicht vorhanden sind. Antwortreferenzen verbinden Beiträge, ohne anonyme Personen individuell wiedererkennbar zu machen. Die Zusammenfassung darf ihren Austausch mit anderen oder untereinander allgemein beschreiben, aber keine einzelnen anonymen Personen zuordnen oder genaue Teilnehmerzahlen ableiten. Nicht anonyme Autoren erhalten ihre gespeicherten Discord-Anzeigenamen; ohne verlässliche Kennung oder Namen erscheint „ein unbekannter User“. Gleiche Anzeigenamen verschiedener Nutzer werden mit einem nummerierten Zusatz unterschieden, ohne Nutzer-IDs zu übermitteln.
Technisch ist dies eine Pseudonymisierung, keine garantierte vollständige Anonymität: Nachrichten-IDs, Zeitpunkte und Inhalte können eine Zuordnung ermöglichen. Mit dem geheimen Schlüssel und einer bekannten Nutzer-ID lässt sich außerdem die Tageskennung erneut berechnen. Namen, Erwähnungen oder andere persönliche Angaben im Nachrichtentext werden vor der Übermittlung nicht automatisch entfernt. System- und Zusammenfassungsanweisungen erlauben die mitgegebenen Anzeigenamen nicht anonymer Autoren, verbieten aber die Identifizierung anonymer Beiträge sowie weitere persönliche Angaben in der Ausgabe; dies ist eine KI-Anweisung, kein garantierter technischer Filter.
Weitergabe und Sichtbarkeit
- OpenRouter und Modellanbieter: Für Zusammenfassungen werden Nachrichtentexte, genaue Zeitpunkte, Kanal- und Nachrichten-IDs, Antwortreferenzen sowie gespeicherte Discord-Anzeigenamen nicht anonymer Autoren an OpenRouter zur Modellverarbeitung gesendet. Anonyme Autoren erhalten die allgemeine Bezeichnung „ein anonymer User“. Nutzer-IDs und HMAC-Kennungen werden nicht als Autorenkennzeichnung versendet, können aber im Nachrichtentext enthalten sein. Bei Antworten kommt ein begrenzter Auszug des noch gespeicherten Antwortziels hinzu, gegebenenfalls aus einem früheren Tag. Gelöschte oder nicht erfasste Ziele werden nicht aus Discord nachgeladen; gespeichert bleibt nur die Referenz-ID, keine zusätzliche Kopie des Zieltexts. Bei langen Tageslogs werden zusätzlich Teilsummaries zur Verdichtung übertragen. Der Bot steuert keine Aufbewahrungs- oder Trainingsrichtlinien der externen Anbieter und löscht dort keine Daten nachträglich.
- Discord: Manuell angeforderte Zusammenfassungen werden im Aufrufkanal sichtbar ausgegeben, bei Überlänge als Textdatei. Sie berücksichtigen die gespeicherten Nachrichten des gesamten Servers. Es gibt derzeit keine Filterung nach den Kanalberechtigungen des aufrufenden Nutzers; dadurch können Inhalte aus eingeschränkten Kanälen in anderen Kanälen zusammengefasst werden. Der automatische Nachtlauf speichert ausschließlich das Archiv in PostgreSQL.
- Konsole und Sentry: Reguläre Logs enthalten unter anderem Server-, Kanal-, Nachrichten- und bei Commands auch Nutzer-IDs sowie Zähler und Textlängen. Bei Fehlern werden Fehlermeldungen und Stacktraces erfasst. Optional übermittelt Sentry Fehler samt Kontext wie Server-ID, Nutzer-ID oder Command.
sendDefaultPii: falseund deaktiviertes Tracing entfernen diese ausdrücklich gesetzten Kontextdaten nicht. Fehlertexte werden nicht durch einen allgemeinen Filter für personenbezogene Daten bereinigt.
Aufbewahrung und Löschung
| Daten | Aktuelles Löschverhalten |
|---|---|
| Zuordenbare Nachrichten | Solange der Bot auf dem Server ist, keine automatische zeitliche Löschung. Mit /datenlöschung im jeweiligen Server löschbar. Nach Entfernen des Bots gilt die unten beschriebene 30-Tage-Frist. |
| Non-Digest-Nachrichten samt Tageskennung | Löschung nach erfolgreicher Archivierung des betreffenden Tages, regulär ab 00:00 Uhr Europe/Berlin. Bei Archivfehlern bleiben sie gespeichert; der Nachtlauf versucht es nach fünf Minuten erneut. Nach Ausfällen wird beim Start nachgeholt. Es besteht daher keine garantierte maximale Speicherdauer von 24 Stunden. |
| TL;DR-Archive und Servereinstellungen | Solange der Bot auf dem Server ist, keine automatische Löschfrist. Nach Entfernen gilt die 30-Tage-Frist. |
| Referenz auf letzten manuellen TL;DR | Wird beim nächsten erfolgreichen manuellen TL;DR des Servers ersetzt. |
| Logs, Sentry-Daten und Backups | Keine Löschung durch /datenlöschung; Aufbewahrung hängt vom Betrieb und den Diensten ab. |
Nach Entfernen des Bots startet eine dauerhaft in PostgreSQL gespeicherte Frist von 30 × 24 Stunden. Bis dahin bleiben alle vorhandenen Nachrichten erhalten; der Nachtlauf verarbeitet diesen Server nicht weiter. Danach werden Nachrichten (auch anonyme), TL;DR-Archive, Einstellungen und TL;DR-Referenzen gemeinsam in einer Transaktion gelöscht. Die Bereinigung läuft jede Minute und beim Start sowie vor einem erneuten Beitritt. Bei Ausfällen erfolgt sie erst nach Wiederherstellung. Entfernungen während einer Offline-Zeit werden beim Start erkannt; die Frist beginnt dann mit der Erkennung. Discord-Ausfälle allein starten keine Frist. Ein Beitritt vor Ablauf hebt die Frist auf; nach Ablauf werden alte Daten auch beim Wiedereintritt gelöscht. Backups und externe KI-Dienste sind von dieser Datenbanklöschung nicht betroffen.
Das Willkommens-Embed erscheint beim Beitritt bevorzugt im Systemkanal, sonst im ersten geeigneten Textkanal. Dafür braucht der Bot die Rechte zum Ansehen des Kanals, Senden von Nachrichten und Einbetten von Links. Fehlen geeignete Kanäle, wird dies protokolliert.
/datenlöschung öffnet ein Modal mit einer nicht vorausgewählten Entscheidung zwischen Abbruch und Löschen. Erst die ausdrückliche Bestätigung entfernt alle nicht anonymen Datenbanknachrichten mit der eigenen Nutzer-ID im aktuellen Server. Die Bestätigung ist an Nutzer und Server gebunden; das Ergebnis wird nur dem aufrufenden Nutzer angezeigt. Für andere Server muss der Command dort gesondert ausgeführt werden.
Anonyme Datensätze werden dabei nicht über die Tageskennung zugeordnet oder gelöscht. Vorhandene TL;DRs und Discord-Nachrichten bleiben unverändert; bereits an externe Dienste übertragene Inhalte und laufende KI-Anfragen werden nicht zurückgerufen. Der Command ist kein dauerhafter Widerspruch gegen die Erfassung: Neue Nachrichten werden anschließend weiterhin gemäß den Servereinstellungen verarbeitet.
Entwicklung und Tests
npm test
npm run check
Der PostgreSQL-Integrationstest wird zusätzlich ausgeführt, wenn TEST_DATABASE_URL gesetzt ist. Er verwendet eine temporäre Tabelle und verändert keine gespeicherten Nachrichten.
Der Einstiegspunkt ist src/main.js. Die Fachbereiche liegen in configuration/, discord/, messages/, monitoring/, settings/ und summaries/; Tests liegen in tests/. npm run check prüft die Syntax des Einstiegspunkts; ein separater Build-, Linter- oder Formatter-Befehl ist derzeit nicht eingerichtet.