Commit Graph
61 Commits
Author SHA1 Message Date
D4rkst3randClaude Opus 5 21eab627b9 fix: die Panel-Anbindung steht jetzt dort, wo man sie sucht
Deploy / check (push) Canceled after 0s
Deploy / deploy (push) Canceled after 0s
Der Betreiber hat sie nicht gefunden, und das zu Recht: die zwei Felder
gab es nur auf der Modul-Detailseite unter Module -> Game-Server-Monitor.
Der Reiter "Game-Server" hat aber einen eigenen, handgeschriebenen Block
mit Status- und Alarm-Kanal -- und genau dort schaut nach, wer den
Monitor einrichtet.

Also stehen sie jetzt auch dort, direkt unter den Kanaelen, mit dem
Absatz, der erklaert wofuer das gut ist. Die Modulseite behaelt sie; es
sind dieselben Formularwerte, keine zweite Wahrheit -- genauso wie
status_channel_id schon an beiden Stellen steht.

Und ins Suchregister (setting-index.js), sonst findet die Suche in der
Seitenleiste das Feld nicht und man sucht es mit den Augen. Das Register
traegt selbst den Kommentar, dass ein vergessener Eintrag genau so
endet.

Geprueft, indem die Frontend-Stufe des Images gebaut und im Ergebnis
nachgesehen wurde -- "Panel-Adresse", "Panel-Zeichen" und
"Panel-Anbindung speichern" stehen im ausgelieferten Bundle.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 18:38:52 +02:00
D4rkst3r d6124fc2cd feat: der Monitor fragt das Panel, wenn eine Abfrage nicht ausreicht
Deploy / check (push) Canceled after 0s
Deploy / deploy (push) Canceled after 0s
gamedig FRAGT einen Server. Ein startendes Modpack antwortet nicht, und
nach zwei Fehlversuchen stand im Alarm-Kanal eine Ausfallmeldung, obwohl
niemand etwas kaputtgemacht hat -- am ATM10 des Betreibers gemessen jedes
Mal 306 Sekunden Fehlalarm.

Das d4rk_gameserver-Panel SIEHT den Container, statt ihn zu fragen. Neu
ist deshalb `src/panel.js`: Zustand, Fertig-Merkmal, RAM und CPU kommen
als Zusatzauskunft dazu, einmal je Durchlauf abgerufen und 20 Sekunden
zwischengespeichert.

Was das im Alarm-Kanal aendert:

  startet gerade   kein Alarm, aber nur innerhalb einer Gnadenfrist von
                   15 Minuten. Ohne diese Grenze fraesse die Anbindung
                   genau den Alarm, fuer den es sie gibt -- `bereit`
                   wird nie von allein wahr, ein haengender Start bliebe
                   sonst fuer immer stumm.
  im Panel gestoppt  kein Alarm (Code 0/143/137)
  abgestuerzt      ALARM, mit Code im Embed
  OOM-Kill         ALARM, und beim Namen genannt statt als Absturz
                   getarnt -- bei Modpacks die haeufigste Ursache
  Container weg    ALARM

Der Zaehler wird beim Unterdruecken NICHT zurueckgesetzt: ein bereits
gemeldeter Ausfall bleibt gemeldet, sonst verschluckt ein Stopp im Panel
die spaetere "wieder online"-Entwarnung und im Kanal bliebe ein Alarm
ohne Aufloesung stehen.

ES IST DURCHGEHEND OPTIONAL. Adresse und Zeichen stehen im Webinterface
unter "Server" und NICHT in der .env; ohne Eintrag -- und ebenso, wenn
das Panel nicht antwortet -- verhaelt sich der Monitor exakt wie vorher.
Das Zeichen darf nur lesen, damit auch ein verlorenes niemandem einen
Server stoppen kann.

`tools/panel-pruefen.mjs` prueft die Logik ohne Discord und ohne
Datenbank; deshalb laedt panel.js die Einstellungen erst beim Aufruf.
2026-08-13 18:05:24 +02:00
D4rkst3randClaude Opus 5 1ef06f747c Modliste: melden was sich geaendert hat, einzeln laden
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Bisher gab es fuer Mods nur einen Link auf das Sammelpaket des Hosters — vier
Gigabyte, auch wenn sich zwei Dateien geaendert haben. Jetzt liest der Bot die
Modliste aus der Statusabfrage, die er ohnehin holt, und meldet im Kanal, was
neu, aktualisiert oder entfernt wurde. Beim ersten Durchlauf bleibt es still,
sonst kaeme eine Meldung ueber 110 "neue" Mods.

Geaendert heisst: andere Version oder anderer Hash. Beides einzeln reicht
nicht — manche Modder bessern nach, ohne die Version zu erhoehen.

Dazu die Seite /mods/<server>: jeder Mod mit Version und Groesse, Suche ueber
Titel, Dateiname und Autor, und ein Download je Zeile. Der laeuft durch den
Bot, damit der Zugangs-Code des Spielservers nicht in einem Link landet — mit
dem Code liesse sich auch der ganze Spielstand lesen. Angefragt wird nur, was
wirklich in der Modliste steht; ueber den Dateinamen kommt man an nichts
anderes heran.

Groessen lernt der Bot beim Weiterleiten. Der Spielserver beantwortet kein
HEAD (501) und ignoriert Range, es gibt also keinen billigen Weg, sie vorher
zu erfahren — und 4 GB nur fuers Anzeigen zu holen waere keiner.

Nebenbei gefunden und behoben: 'server.mods' und 'commands.tag' gab es je
zweimal in den Sprachdateien. Der spaetere Eintrag gewinnt still, deshalb
stand auf dem neuen Knopf woertlich "%s Mods (110)" und auf der Befehlsseite
die Beschreibung von /tag statt der Kopfzeile.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 11:22:55 +02:00
D4rkst3randClaude Opus 5 9b681754fa Ein Embed je Hof, das sich selbst aktualisiert
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Der Fuhrpark stand bisher nur als Gesamtzahl im Karten-Embed. Jetzt bekommt
jeder Hof eine eigene Nachricht im selben Kanal, die bei jedem Durchlauf
bearbeitet statt neu gepostet wird: Land, Fahrzeuge mit Wert und
Betriebsstunden, was in die Werkstatt muss, was gewaschen gehoert und was
geladen ist.

Die Fahrzeuge kommen aus vehicles.xml, blockweise gelesen — Verschleiss und
Schmutz stehen in Kindelementen und gehoeren sonst dem falschen Fahrzeug.
Gemietete Missionsfahrzeuge bleiben draussen, sie verfaelschen Anzahl und
Wert. Faellt die Datei einmal aus, bleiben die Embeds stehen, statt dass ein
Hof verschwindet und gleich darauf doppelt gepostet wird.

Damit tauchen auch Hoefe auf, die noch kein Land gekauft haben: die Liste der
Hoefe kommt aus Parzellen und Fuhrpark zusammen.

Dazu raus, was nur den Kanal vollgeschrieben hat: die Meldung zum
Monatswechsel und die zum Landkauf. Der Monat wird still weitergestellt — er
steht ohnehin im Embed. Damit faellt der Ereignis-Kanal weg und mit ihm die
gespeicherte Besitzliste.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 14:53:02 +02:00
D4rkst3randClaude Opus 5 ea523b76b3 Servername aus dem Spiel und ein Schloss fuer Passwort oder Whitelist
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Der Name im Panel ist der, den DU vergibst — wie der Server sich im Spiel
nennt, stand nirgends. Steht jetzt darunter, aber nur wenn es etwas anderes
ist als der eingetragene Name; sonst haette dieselbe Zeile zweimal dagestanden.

Beim Schloss war die Frage, wie viel die Abfrage ueberhaupt hergibt. Nachgesehen
statt geraten: 31 der 358 gamedig-Protokolle melden ein Passwort. valve
gehoert dazu, deckt also CS2, Rust, ARK, Squad, 7DTD, Zomboid, Gmod und DayZ
ab. Minecraft nicht, Farming Simulator auch nicht — im LS-XML kommt das Wort
Passwort kein einziges Mal vor. Und eine Whitelist meldet grundsaetzlich kein
Spiel, die steht in einer Datei auf dem Server.

Also beides: automatisch, wo es geht, und eine Einstellung, die es schlaegt.
Wer "Whitelist" eintraegt, bekommt sie angezeigt, auch wenn der Server
schweigt.

Wichtig dabei ist der dritte Zustand. "Sagt nichts" ist nicht "offen" —
deshalb `null` und kein `false`. Ein Schloss, das bei jedem schweigenden
Server fehlt, waere eine Aussage, die wir nicht belegen koennen; umgekehrt
waere ein Schloss ohne Grundlage eine Luege. Bei unbekannt steht schlicht
nichts da.

Geprueft: Einstellung schlaegt Messung in allen vier Faellen, automatisch mit
true/false/null, fehlender Server, unbekannter Wert faellt auf automatisch
zurueck statt zu sperren, Schloss im Embed-Titel nur wenn belegt, Spielname
nur bei echtem Unterschied (auch mit Leerzeichen drumherum). Panel und
/server-Seite im laufenden Frontend angesehen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 14:12:33 +02:00
D4rkst3randClaude Opus 5 b69cb6c5e4 Freie Links je Server statt fester Felder
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
connect_url und mods_url waren zwei Spalten fuer zwei Zwecke — und beim
naechsten Zweck waere eine dritte dazugekommen. Jetzt gibt es eine Liste:
Beschriftung plus Adresse, so viele wie noetig. Regeln, TeamSpeak, Shop,
Bewerbung.

Als JSON-Spalte, nicht als eigene Tabelle: es haengt an genau einem Server,
wird immer komplett gelesen und immer komplett geschrieben. Gelesen wird es als
Liste, geschrieben darf es als Liste hereinkommen — better-sqlite3 kann kein
Array binden und wuerde sonst werfen. Kaputtes JSON ergibt eine leere Liste
statt eines Absturzes im Monitor.

Discord nimmt fuenf Knoepfe je Reihe; ab jetzt werden sie umgebrochen, bei
zwei Reihen ist Schluss. Die Grenze steht im Code und nicht im Fehler beim
Senden, den niemand sieht. Zu lange Beschriftungen werden auf 80 Zeichen
gekuerzt, halbe Zeilen fliegen raus statt als leerer Knopf zu erscheinen. Was
nicht http(s) ist — ts3server://, steam:// —, wird wie bisher ein Codeblock im
Embed zum Kopieren.

Dabei umbenannt: das Embed-Feld fuer einen nicht klickbaren Connect-Link hiess
"Connect", der Knopf daneben "Verbinden". Jetzt heisst beides gleich.

Geprueft: Umbruch bei zwoelf Links, Reihenfolge mit Connect und Mods vorn,
halbe Zeilen, ueberlange Beschriftung, nicht klickbare Schemata, fehlendes und
unbrauchbares links-Feld, dazu Speichern, Aendern und kaputtes JSON in der
Datenbank. Panel und /server-Seite im laufenden Frontend angesehen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-09 13:39:10 +02:00
D4rkst3randClaude Opus 5 9f929fe0e4 Eigene Kategorie Gaming fuer Game-Server und LS
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Der Game-Server-Monitor stand unter "Server & Technik" zwischen DB-Sicherung,
Repo-Sicherung und Member-Gate. Technisch nicht falsch — dort laeuft alles,
was der Bot an Infrastruktur anfasst. Nur sucht niemand seinen LS-Server neben
dem Datenbank-Backup. Mit dem LS-Modul waren es zwei Eintraege in der falschen
Schublade, und das reicht fuer eine eigene.

Getrennt wird nach dem, worum es geht: "Server & Technik" ist der Bot selbst,
"Gaming" sind die Spiele-Server drumherum. Beide Ebenen ziehen mit — die
Modul-Kacheln ueber MODULE_GROUPS, die Seitenleiste ueber TAB_SECTIONS —, und
der Tab heisst jetzt "Game-Server" statt "Server", weil "Server" im selben
Panel schon zweierlei bedeutete.

Nebenbei: das Modul hiess "Server-Monitor" und ueberwacht Game-Server; jetzt
steht das auch dran. Die Suche im Panel findet den Tab zusaetzlich ueber "ls",
"landwirtschaft", "farming", "hof", "karte" und "preise".

Geprueft: kein Modul ohne Gruppe, keine leere Gruppe, Seitenleiste und
Modul-Kacheln im laufenden Panel angesehen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-09 08:24:34 +02:00
D4rkst3randClaude Opus 5 e215cd4c7c LS-Modul: Besitzkarte auf dem Luftbild und Preiskurven
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Der Feed eines LS-Servers gibt viel mehr her als die Spielerzahl, die der
Monitor bisher davon benutzt hat: in denselben 49 KB stehen 163 Parzellen mit
Besitzer und Hektar, 130 Felder, jedes Fahrzeug samt Ladung und die Position
jedes Spielers. Und das Luftbild liefert der Server auch, in jeder Groesse bis
4096.

Also eine Karte: gekaufte Parzellen nach Hof eingefaerbt, Kreisflaeche gleich
Hektar, Fahrzeuge und Spieler live, dazu eine Hof-Uebersicht mit Flaeche und
Wert. Wechselt Land den Besitzer, kommt eine Meldung — beim allerersten
Durchlauf bewusst nicht, sonst haette der Botstart eine Meldung pro bereits
gekaufter Parzelle abgesetzt.

Dazu die Preiskurven aus der economy.xml: je Fruchtart, was sie in welcher der
zwoelf Perioden bringt, als Balkenzeile mit "jetzt verkaufen" oder "+43 Prozent
im Hochwinter".

Was NICHT geht, und zwar grundsaetzlich: welche Frucht auf welchem Feld steht
und wie weit sie ist. Das liegt in einer binaeren Density-Map, die kein
Endpunkt herausgibt. Ich habe 18 Dateinamen durchprobiert, es gibt genau drei.
Die Mods, die das anzeigen, sind reine HUD-Overlays ohne Ausgang. Und keiner
der fuenf anderen LS-Bots kann es, obwohl einer davon Geld kostet. Das steht
mit allen Belegen in docs/ls-feed.md, damit die Frage nicht dreimal kommt.

Beim Bauen aufgefallen:

- istLsServer() gab den Zugangs-Code zurueck statt true — die &&-Kette liefert
  den letzten wahren Wert. Beim ersten Log-Aufruf haette der Code im Klartext
  im Protokoll gestanden.
- Die Karte als PNG war 2,5 MB, als JPEG 268 KB. Es ist ein Luftbild.
- Nach Preisschwankung sortiert gewinnt Spargel: 26 bis 7540 Euro, und Weizen
  taucht gar nicht mehr auf. Die Liste arbeitet jetzt mit einer Auswahl.
- Die Jahreszeit steht in keinem Endpunkt. Schaetzbar waere sie, aber nur
  solange niemand die Zeitskala aendert — also eine Einstellung.

Geprueft gegen echte Serverdaten: Zerlegen der Statusabfrage inklusive
Vollstaendigkeit aller 163 Parzellen, Ladung ohne Diesel und leere Slots,
Hof-Uebersicht ohne verlorene Parzellen, Preiskurve mit vollem und leerem
Balken an der richtigen Stelle, flache Kurve ohne Division durch Null,
Besitzwechsel inklusive Erstlauf und neu hinzugekommener Parzelle,
Hof-Namen aus der Einstellung, SVG ohne NaN und mit maskierten Namen, und der
Merker in der Datenbank inklusive kaputtem JSON.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-09 01:52:25 +02:00
D4rkst3randClaude Opus 5 eec170ff41 Connect-Links im Discord anklickbar, und Mods bekommen einen eigenen Knopf
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Im Kanal stand woertlich das da:

    [https://cfx.re/join/4odv68](https://cfx.re/join/4odv68)

Der Link war sein eigener Linktext. Discord macht aus der nackten URL zwischen
den eckigen Klammern zuerst selbst einen Link und kommt mit der
Masked-Link-Schreibweise dann nicht mehr durch — heraus kommen die Klammern im
Klartext. Der Kommentar an der Stelle behauptete ausserdem, so seien steam://
und Konsorten klickbar. Waren sie nie.

Jetzt sind es Link-Knoepfe unter dem Embed. Die Frage nach der Schreibweise
stellt sich damit gar nicht mehr, und ein Knopf sieht auch nach einem aus.
Discord nimmt dort nur http(s) an; fivem:// und steam:// stehen deshalb weiter
im Embed, aber als Codeblock zum Kopieren statt als toter Link.

Dazu ein eigenes Feld fuer den Mod-Download. Vorher landete der beim
Connect-Link, weil es kein anderes gab — und dann fuehrte "Verbinden" zu einer
ZIP-Datei. Farming Simulator liefert die Modliste ohnehin mit, also steht die
Anzahl jetzt auch im Embed und als Chip auf der Seite.

Beim Testen aufgefallen: eine neue Spalte hat jeden Aufrufer umgebracht, der
sie noch nicht kannte — better-sqlite3 wirft bei einem fehlenden benannten
Parameter. createGameserver und updateGameserver fuellen die Felder jetzt
einmal auf, statt das an jeder Aufrufstelle nachzuziehen.

Geprueft: was in einen Knopf darf und was nicht (https, http, fivem://,
steam://, leer, null, Leerzeichen, Satz mit Link drin), beide Knoepfe in einer
Reihe, nur einer, gar keiner — eine leere Reihe weist Discord ab —, https
landet im Knopf und nicht doppelt auch im Embed, fivem:// umgekehrt, Mods bei
47/0/null, und der Aufruf ohne die neue Spalte. Seite im laufenden Frontend
angesehen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 22:52:08 +02:00
D4rkst3randClaude Opus 5 4e7fc99999 Server-Seite ueberarbeitet, und die Spielauswahl kommt jetzt aus gamedig
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
LS25 fehlte, aber nicht nur LS25: die Auswahl im Panel war eine von Hand
gepflegte Liste mit neunzehn Eintraegen, und fuenf davon gab es bei gamedig
gar nicht — "arkse", "ark", "sevendaystodie", "minecraftbe" und "terraria".
Wer eines davon auswaehlte, bekam einen Server, der dauerhaft offline stand,
ohne dass irgendwo ein Grund stand. Die echten IDs heissen ase, sdtd, mbe und
terrariatshock.

Also nicht LS25 nachtragen, sondern die Liste abschaffen: sie kommt jetzt aus
gamedig selbst, 360 Eintraege, sortiert, mit Suche. Jedes Update bringt neue
Spiele automatisch mit. Dazu der Standard-Query-Port als Vorschlag, sobald man
ein Spiel waehlt. Bestehende Eintraege mit den toten IDs werden beim Start
einmalig umgebogen.

Farming Simulator hat noch eine zweite Huerde: der Server antwortet nur mit
Zugangs-Code, und den hat queryServer nie durchgereicht. LS25 waere also auch
mit richtiger ID offline geblieben. Jetzt gibt es eine Spalte dafuer, das Feld
erscheint nur bei Spielen, die einen brauchen (Farming Simulator, Terraria —
bei Satisfactory optional), und Speichern ohne Code wird abgelehnt statt
stillschweigend hingenommen. Der Code steht nicht in der oeffentlichen API.

Nebenbei aufgefallen: input[type=password] war im CSS nirgends erfasst. Das
erste solche Feld kam voellig ungestylt daher.

Die /server-Seite dazu:

- Auslastungs-Balken mit eigener Farbe statt des XP-Balkens vom Level-System.
  Gruen frei, gelb ab 80 Prozent, rot voll — die Zahl steht rechtsbuendig,
  mittig laege sie bei 50 Prozent genau auf der Fuellkante.
- Map, Version und Ping als Chips. Vorher standen sie mit Punkten getrennt in
  der Statuszeile und wurden auf dem Handy zu Brei.
- Wer gerade drauf ist. Die Namen holt der Monitor ohnehin schon fuers Embed,
  auf der Seite standen sie nur nirgends.
- Welches Spiel es ueberhaupt ist. Das stand nirgends ausser im Emoji.
- Offline-Karten waren bisher leer bis auf das Wort. Jetzt steht dort, seit
  wann — soweit der Verlauf reicht, sonst gar nichts statt einer Schaetzung.
- Zeitachse und Peak-Linie am Verlauf. Eine Flaeche ohne Bezugspunkt sagt
  nicht, wie hoch hoch ist.
- Plaetze insgesamt in der Uebersicht oben.

Geprueft: Token speichern und aendern, Spielnamen inklusive unbekannter ID,
Token-Bedarf pro Protokoll, Liste ohne Doppler, alle Icon-Schluessel gegen
gamedig, "zuletzt online" ignoriert Offline-Proben, und die Migration mit einer
Datenbank im alten Stand. Beide Seiten am laufenden Frontend angesehen, auch
auf Handybreite.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 16:52:09 +02:00
D4rkst3randClaude Opus 5 22054c109e Mod-Log: eigenes Gedaechtnis, damit beim Loeschen nicht "unbekannt" dasteht
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Dein Eintrag war der Normalfall, nicht die Ausnahme:

    User: unbekannt
    Inhalt: [kein Text / nicht im Cache]

Discord schickt beim Loeschen nur eine Huelle, sobald die Nachricht nicht mehr
im Cache des Bots liegt. Der reicht ein paar hundert Nachrichten weit und faengt
erst beim Start des Bots an — bei einem Post von gestern ist sie also nie drin.
Ein Protokoll, das genau dann nichts weiss, wenn es interessant wird, ist keins.

Also merkt sich der Bot Nachrichten jetzt kurz selbst: Verfasser, Wortlaut,
Namen der Anhaenge. Beim Loeschen steht das im Eintrag, danach wird der Merker
weggeworfen. Wie lange aufbewahrt wird, steht unter Werte — sieben Tage
voreingestellt, 0 heisst gar nicht mitschreiben. Bewusst knapp und einstellbar:
das ist ein Werkzeug zum Nachvollziehen von Loeschungen, kein Archiv.

Dazu drei Sachen, die vorher fehlten:

- Wer geloescht hat. Steht in Discords Audit-Log, aber nur wenn es jemand
  anders war als der Verfasser. Gemeldet wird nur, was frisch ist und zu Kanal
  und Verfasser passt — Discord zaehlt bei wiederholtem Loeschen denselben
  Eintrag hoch statt neue anzulegen, da ist eine falsche Angabe schnell
  gemacht. Lieber keine als eine falsche.
- Sammel-Loeschungen. /purge und Discords eigenes Aufraeumen standen gar nicht
  im Log: eine geloeschte Nachricht fiel auf, hundert nicht. Jetzt mit Anzahl,
  Kanal und den ersten fuenfzehn Zeilen.
- Anhaenge. Dass ein Bild dranhing, war vorher nirgends zu sehen — und das
  Bild selbst ist nach dem Loeschen ohnehin weg.

Nebenbei: "[kein Text / nicht im Cache]" waren zwei Aussagen in einer und beide
unklar. Jetzt steht dort entweder der Wortlaut, oder dass die Nachricht keinen
hatte, oder dass sie aelter ist als die Aufbewahrung reicht.

Beim Testen gefunden: pruneMessageCache(0) hat nichts geloescht. "-0 days" ist
genau jetzt, und `created_at < jetzt` laesst die eben geschriebene Zeile stehen.
Bei 0 wird jetzt alles geleert, wie es gemeint war.

Geprueft: Merken, Wiederfinden, Anhaenge durch JSON, Bearbeiten zieht mit,
Vergessen nach dem Loggen, unbekannte ID, doppelte ID, Aufbewahrung mit einem
zu alten und einem frischen Eintrag, und der 0-Fall. Ereignisnamen und
AuditLogEvent gegen die installierte discord.js geprueft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 09:25:37 +02:00
D4rkst3randClaude Opus 5 b6b767acb7 Bis fuenf Eintraege Knoepfe statt Auswahlmenue
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Du hattest recht. Bei vier Anliegen ist ein Auswahlmenue der schlechtere Weg:
zwei Klicks statt einem, und die Moeglichkeiten sieht man erst nach dem
Aufklappen. Ein Knopf ist beides — sichtbar und sofort.

Umgekehrt gilt es nicht immer. Ab sechs wird die Knopfreihe zur Wand und
Discord bricht sie um; dann ist das Menue das ruhigere Bild. Also nicht
"Knoepfe statt Menue", sondern der Uebergang: bis fuenf Knoepfe, darueber
Menue. Fuenf, weil genau so viele in eine Reihe passen.

Betroffen waren nur zwei Stellen — Ticket-Anliegen und Wunsch-Bereiche. Alles
andere im Bot waren ohnehin schon Knoepfe.

Eine Sache verliert man dabei: die graue Beschreibungszeile, die ein Menue
unter jedem Eintrag anzeigt. Die steht jetzt im Text des Aufruf-Posts, und da
ist sie ehrlich gesagt besser aufgehoben — man liest sie, bevor man klickt,
statt danach.

Geprueft gegen discord.js selbst, weil Ueberlaengen und ungueltige Emojis sonst
erst beim Posten auffallen: null Eintraege (der eine alte Knopf), eins bis
fuenf (Knoepfe mit Emoji und der ID in der Kennung), sechs (zurueck zum Menue),
Murks-Emoji (faellt weg, Knopf bleibt), 200 Zeichen langer Name (auf 80
gekuerzt), und die Beschreibungszeile in allen drei Faellen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 09:14:59 +02:00
D4rkst3randClaude Opus 5 b3758f1f76 Screenshots zu Ideen, und der Bot legt die Forum-Tags selbst an
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Zwei Fragen, zwei Antworten — eine davon ein Nein mit Umweg.

## Bilder im Eingabefenster: geht nicht

Discord-Modals koennen nur Textfelder. Kein Datei-Anhang, keine Umgehung — das
ist eine Grenze der Plattform, nicht unseres Codes.

Der Umweg ist besser als er klingt: Wer nach dem Einreichen einen Screenshot in
den Thread haengt, sieht ihn auf der Ideen-Seite. Die Bestaetigung nach dem
Absenden sagt das jetzt auch. Damit kann man auch nachtraeglich noch Bilder
dazulegen, was im Eingabefenster gar nicht ginge.

## Warum nicht einfach der Discord-Link

Discord haengt seit einiger Zeit eine Signatur an die Anhang-Links
(?ex=&is=&hm=), die nach etwa einem Tag ablaeuft. Ein gespeicherter Link zeigt
morgen ein kaputtes Bild. Deshalb laden Devlogs und Galerie seit dem ersten Tag
herunter — im Kopf von devlog-archive.js steht der Grund. Wuensche machen es
jetzt genauso, ausgeliefert unter /wish-assets/.

Beim Loeschen eines Beitrags oder eines ganzen Wunsches gehen die Dateien mit;
sonst waechst der Ordner mit Bildern, auf die nichts mehr zeigt.

Das Herunterladen stand vorher zweimal fast wortgleich im Code. Mit den
Wuenschen waeren es drei Kopien geworden — also einmal nach bot/bilder.js, und
Devlogs und Galerie ziehen mit um. Ein Fehler steckt jetzt an einer Stelle
statt an dreien.

## Forum-Tags per Knopf

Bisher musstest du sie von Hand anlegen. Jetzt macht es das Panel: die Bereiche
von dort plus die fuenf Staende, mit ihren Emojis. Vorhandene bleiben, auch
fremde — die Liste wird ergaenzt und nicht ersetzt. Discords Grenze von 20 Tags
wird eingehalten, was nicht mehr reinpasst, wird gemeldet statt still
verschluckt.

Geprueft: forumTagsAnlegen gegen eine Kanal-Attrappe — leeres Forum, teilweise
vorhandene, Gross/Kleinschreibung, fremde Tags, nichts zu tun (dann wird auch
nicht geschrieben), volles Forum, kein Forum, kein Kanal. Im Browser die
Ideen-Seite mit Bildern in einem Beitrag, einem Beitrag nur aus Bild ohne Text,
und der Lightbox darueber.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 00:17:01 +02:00
D4rkst3randClaude Opus 5 5073e7bcf4 Jede Idee bekommt ihre eigene Seite mit der Unterhaltung aus dem Thread
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Vorbild windrose.support: Klick auf eine Idee, und man sieht sie ganz — Stand,
Begruendung, wer sie eingereicht hat, und darunter, was dazu geschrieben wurde.

Der Unterschied bleibt, wo geschrieben wird. Die Beitraege sind aus dem
Discord-Thread gespiegelt, nicht hier getippt. Deshalb fuehrt der einzige
Knopf am Ende in den Thread und nicht in ein Formular. Ein zweiter Ort fuer
dieselbe Unterhaltung waere genau das, was ich beim Konzept als das Falsche
bezeichnet habe.

Bisher wurde nur mitgezaehlt. Jetzt landen die Beitraege in einer eigenen
Tabelle — mit Bearbeiten und Loeschen, sonst stuende auf der Webseite fuer
immer, was in Discord laengst zurueckgenommen wurde. Reine Bild-Posts ohne Text
bleiben draussen, die haetten hier nichts zu sagen.

Der Kommentar-Zaehler wird jetzt aus der Tabelle gezaehlt statt in einer Spalte
mitgefuehrt. Eine Wahrheit statt zwei, die auseinanderlaufen koennen — dieselbe
Ueberlegung wie beim Zuspruch.

Nebenbei geprueft, weil es haette schiefgehen koennen: /api/wishes/suche und
/api/wishes/:id liegen auf derselben Ebene. Der Router bevorzugt die feste
Route vor der mit Platzhalter — nachgestellt mit find-my-way, nicht aus dem
Gedaechtnis behauptet.

Geprueft: im Browser die Seite mit drei Beitraegen und die ohne (kein Thread,
keine Begruendung, Hinweis statt Liste), der Weg von der Roadmap dorthin ohne
Neuladen, Migration erneut durchgespielt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 00:05:27 +02:00
D4rkst3randClaude Opus 5 cc7a51f02e Emojis zum Anklicken, und Wuensche als Forums-Beitraege mit Tags
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Ueberall, wo ein Emoji nach Discord geht — Rollen-Menues, Ticket-Anliegen,
Wunsch-Bereiche, Portal-Kacheln — stand ein leeres Textfeld, in das man mit
Win+. hineintippen musste. Jetzt sitzt daneben ein Knopf mit einer Tafel:
sieben Gruppen, deutsche Suchbegriffe ("auto", "geld", "warnung"), ein Klick
schreibt ins Feld. Das Feld bleibt daneben stehen, denn Server-Emojis
(<:name:123>) kennt nur Discord.

Bewusst eine eigene Liste statt einer Bibliothek: die vollstaendige
Unicode-Tabelle waere ein halbes Megabyte fuer eine Handvoll Symbole, und die
Suchbegriffe duerfen deutsch sein.

## Forum-Tags

Ist der Voting-Kanal ein Forum, wird jeder Wunsch jetzt ein Forums-Beitrag
statt Nachricht-plus-Thread — und bekommt Tags fuer Bereich und Stand. Damit
laesst sich auch in Discord filtern, wofuer Tags ja da sind. Beim Wechsel des
Stands zieht das Tag mit: der alte fliegt raus, der neue kommt rein, der
Bereich bleibt stehen.

Zugeordnet wird ueber den Namen. Wer im Forum ein Tag "Fahrzeuge" anlegt,
bekommt es automatisch gesetzt; wer keines anlegt, verliert nichts. Bewusst
keine ID-Zuordnung im Panel — das waere eine zweite Liste, die man pflegen
muss und die beim ersten Umbenennen auseinanderlaeuft.

Dabei aufgefallen und mitgefixt: im Forum liegt die Startnachricht im Beitrag
selbst und nicht im Kanal. Der Status-Aktualisierer hat sie vorher im Kanal
gesucht und nicht gefunden — die Begruendung waere im Forum also nie im Post
gelandet. Und der Titel wird jetzt nur um den Stand ergaenzt statt
ueberschrieben, damit "🚗 Fahrzeuge" stehen bleibt.

Geprueft: tagsFuer gegen 20 Faelle — kein Forum, Medien-Kanal, fehlende Tags,
Gross/Kleinschreibung, Deckel bei fuenf (mehr nimmt Discord nicht), und alle
fuenf Staende einzeln. Im Browser die Emoji-Tafel an allen vier Stellen:
Suche, Escape, Klick daneben, Leeren, Uebernehmen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 23:45:18 +02:00
D4rkst3randClaude Opus 5 edf8fa14c5 Ideen bekommen Bereiche und einen Thread zum Reden
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Nach dem Vorbild von windrose.support: Bereiche zum Einsortieren, Sortierung
nach Top / Bewegung / Neu, und eine Zahl daneben, wie viel darueber geredet
wird.

Der Unterschied zu so einem Dienst ist, wo geredet wird. Zu jedem Wunsch macht
der Bot jetzt einen Thread unter dem Post auf. Der Kommentar-Zaehler auf der
Roadmap zaehlt die Beitraege darin und verlinkt hinein — es gibt also einen
Zaehler wie bei einem Ideen-Board, aber ohne ein zweites Kommentarsystem neben
Discord zu stellen. Genau das hatte ich beim letzten Mal als das Falsche
bezeichnet, und dabei bleibt es.

Eingereicht wird jetzt auch ueber einen Aufruf-Post: /wunsch-setup postet ihn,
und mit Bereichen wird daraus ein Auswahlmenue — erst wohin, dann das
Formular. Ohne Bereiche bleibt es beim einen Knopf. Derselbe Aufbau wie bei den
Ticket-Anliegen, bis hin zur Emoji-Pruefung, die ich mir dort schon geschrieben
hatte.

Das Anlegen selbst ist nach bot/wishes.js gewandert. /wunsch, der Knopf und die
Webseite gehen jetzt denselben Weg — vorher hatte die Webseite ihr eigenes
Embed zusammengebaut, das dem aus dem Befehl nur aehnlich sah und keinen Thread
bekam.

"Bewegung" sind die Stimmen der letzten sieben Tage. Die Rangliste allein
zementiert alte Wuensche: was einmal oben steht, bleibt oben, egal ob noch
jemand hinschaut. Sortiert wird auf dem Server, weil die Zeitstempel der
Stimmen im Browser gar nicht ankommen.

Bewusst nicht uebernommen: Gegenstimmen. Windrose hat sie, aber bei einer
Community dieser Groesse laden sie zum Nachtreten ein und schrecken vom
Einreichen ab — und eine Zahl, die aus zwei Richtungen kommt, sagt am Ende
weniger als eine, die nur zaehlt, wer etwas will.

Geprueft: Migration erneut durchgespielt (das Schema hat drei Spalten
dazubekommen), Routen, SQL gegen das Schema, und im Browser alle drei
Filterreihen einzeln und kombiniert, der Sortierwechsel, die Thread-Links und
die Bereichs-Pflege im Panel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 23:31:55 +02:00
D4rkst3randClaude Opus 5 fb61e7279d Wuensche bekommen einen Ausgang statt nur einer Punktzahl
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Voting hatten wir. Was fehlte, war alles danach: ein Wunsch sammelte zwoelf
Stimmen und dann passierte sichtbar nie wieder etwas damit. Genau das nennt der
Artikel, der die Idee angestossen hat, "letting the board become a graveyard" —
und das war der Zustand.

Jeder Wunsch hat jetzt einen Stand: wird geprueft, geplant, in Arbeit,
umgesetzt, nicht geplant — mit Begruendung. Die steht oeffentlich unter dem
Wunsch auf der Roadmap und wird in den Discord-Post zurueckgeschrieben, wo
abgestimmt wurde. Ein abgelehnter Wunsch mit einem Satz Begruendung ist mehr
wert als einer, der ewig oben schwebt.

Springt ein Wunsch auf "umgesetzt", bekommt jeder eine Direktnachricht, der
dafuer gestimmt hat. Das ist der Punkt, an dem unser Aufbau einem fertigen
Voting-Dienst ueberlegen ist: der Draht zu jedem Einzelnen ist ohnehin offen.

## Zwei Sachen, die kaputt waren

Doppelt abstimmen ging. Der Zuspruch wurde von zwei Wegen hochgezaehlt — 👍 in
Discord und der Web-Knopf — und nur der Web-Weg merkte sich, wer geklickt hat.
Dieselbe Person zaehlte zweimal. Jetzt wird nicht mehr hochgezaehlt, sondern
gezaehlt: eine Zeile je Person, egal woher der Klick kam. Der zusammengesetzte
Schluessel schliesst den Fall aus, statt ihn nachtraeglich zu korrigieren.

Die Discord-Nachrichten-ID war der Primaerschluessel. Damit konnte ein Wunsch
nur existieren, solange seine Nachricht existiert, das Team konnte keinen von
Hand eintragen, und zwei Doppler liessen sich nicht zusammenfuehren. Wuensche
haben jetzt eine eigene ID; die Nachrichten-ID ist nur noch ein Verweis.

Die Migration erhaelt den Zuspruch: was vom alten Punktestand nicht auf
gespeicherte Web-Stimmen zurueckgeht, waren Reaktionen ohne Namen — die Zahl
bleibt als Sockel stehen, weil rueckwirkend niemand mehr feststellen kann, wer
das war. Durchgespielt gegen eine Datenbank im alten Aufbau: Punktestand
erhalten, verwaiste Stimmen fallen raus, ein zweiter Start migriert nicht
nochmal, und der Fall, in dem der alte Zaehler hinter den echten Stimmen
zurueckhing, zaehlt jetzt richtig.

## Dazu

Doppler zusammenfuehren: die Stimmen wandern zum Original, wer fuer beide
gestimmt hat, zaehlt dort weiterhin einmal. Beim Tippen im Wunsch-Feld zeigt die
Seite, was es schon gibt — ein Klick darauf stimmt mit, statt einen zweiten
gleichen Wunsch anzulegen. Und die Liste laesst sich nach Stand filtern.

Was ich bewusst nicht gebaut habe: Kommentare auf der Webseite. Jeder Wunsch
ist schon eine Discord-Nachricht — die Diskussion gehoert in den Thread
darunter und nicht in ein zweites System.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 23:18:29 +02:00
D4rkst3randClaude Opus 5 1c5c7d2470 Playtester werden jetzt beworben, nicht angeklickt
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Der Knopf unter dem Playtester-Aufruf hat jeden aufgenommen, der ihn gedrueckt
hat — ohne Frage, ohne Pruefung. Fuer ein Programm, dessen Teilnehmer Zugang
und Alpha-Keys bekommen, ist das die falsche Tuer.

Statt einen zweiten Pruef-Ablauf danebenzustellen, laeuft die Aufnahme jetzt
ueber die Bewerbungs-Formulare, die es laengst gibt: Modal ausfuellen,
Review-Embed im Staff-Kanal,  oder , Rolle und Antwort-DM bei Zusage. Das
ist dieselbe Maschinerie, nur ein anderer Aufhaenger — und damit auch nur eine
Stelle, an der spaeter etwas kaputtgehen kann.

Ein Formular laesst sich als Playtester-Formular markieren ("Annahme traegt als
Playtester ein"). Wer dort angenommen wird, landet zusaetzlich in der
Playtester-Liste, damit die Schluessel-Verteilung ihn kennt. Nur eines kann es
sein — sonst wuesste /playtester-setup nicht, welches es posten soll.

/playtester-setup postet jetzt den Knopf dieses Formulars. Fehlt das Formular,
fehlen Fragen oder fehlt der Review-Kanal, sagt der Befehl das, statt einen
Aufruf zu posten, der ins Leere fuehrt.

Der alte Knopf in bereits geposteten Nachrichten nimmt niemanden mehr auf: er
verweist auf den Aufruf. Austreten bleibt Selbstbedienung — dafuer braucht es
keine Freigabe.

Im Panel steht im Playtester-Bereich, ueber welches Formular die Aufnahme
laeuft, ob es schon gepostet ist, und ein Weg dorthin. Ohne markiertes Formular
steht dort, dass gerade niemand hereinkommt — das ist sonst der Grund, warum
sich tagelang niemand bewirbt.

Geprueft: Routen, SQL gegen das Schema, und im Browser beide Zustaende des
Hinweises sowie der neue Schalter — beim Wechsel zwischen zwei Formularen
folgt er dem richtigen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 10:04:16 +02:00
D4rkst3randClaude Opus 5 ddd7610d6c Playtester bekommen einen eigenen Bereich, Module ziehen um
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Playtester und Alpha-Keys standen als zwei Kaesten mitten im Community-Bereich
zwischen Geburtstagen und Starboard. Die Liste war reine Anzeige: Namen und
Datum, sonst nichts. Wer einem Einzelnen einen Schluessel geben wollte, konnte
nur "an alle verteilen" druecken, und wer jemanden wieder rausnehmen wollte,
musste an die Datenbank.

Jetzt ist es ein eigener Bereich mit drei Zahlen oben und einer Liste, in der
neben jedem Namen sein Schluessel steht. Daneben, je nach Zustand, "Schluessel
geben" oder "Zurueckziehen", und ein ✕ zum Entfernen — die Rolle geht dabei
mit, denn nur aus der Liste zu streichen und die Rolle stehen zu lassen waere
eine Halbwahrheit.

Der Vorrat ist jetzt sichtbar, nicht nur seine Groesse: einen vertippten
Schluessel findet man sonst nie wieder. Nachlegen und "wer bekommt einen?"
laufen ueber Dialoge, damit der Bereich nicht zumuellt — dafuer gibt es jetzt
eine kleine Dialog-Komponente, gebaut wie die Lightbox (Portal, Escape,
Hintergrund festhalten).

Zurueckziehen legt den Schluessel zurueck in den Vorrat. Die Person hat ihn per
DM natuerlich weiterhin — das ist eine Buchhaltung, keine Sperre. Loeschen geht
absichtlich nur bei freien Schluesseln.

## Module dorthin, wo man sie sucht

Ein paar Module standen im falschen Bereich, teils seit Langem:

- Willkommens-Karte: Support → Brand. Sie ist Aussehen, kein Support-Fall, und
  im Brand-Bereich steht der Rest vom Auftritt. Der Block ist woertlich
  umgezogen, nur in eine eigene Konstante — so kann sich beim Umzug nichts am
  Inhalt geaendert haben.
- Twitch & YouTube: System → Feeds. Es ist ein Feed.
- Events: System → Community.
- Auto-Rolle und Rollen merken: Ihre Felder standen laengst im Rollen-Bereich,
  nur das Register sagte "Community" — dadurch sprang "Einrichten" woanders hin
  als die Einstellung liegt.
- Playtester und Alpha-Keys: Community → eigener Bereich.

Damit ist System kein Sammelbecken mehr, sondern nur noch Technik: Waechter,
Sprachkanaele, Erinnerungen, Sicherungen, Member-Gate.

Geprueft: Routen (alle vier neuen bewacht), SQL gegen das Schema, und im
Browser beide Dialoge (Escape schliesst, Hintergrund wird wieder freigegeben,
Hinzufuegen bleibt bei leerem Feld aus), die Liste in allen drei Zustaenden,
und die Suche — "willkommen" fuehrt jetzt nach Brand, "twitch" zu Feeds,
"sticky" zu Rollen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 09:49:27 +02:00
D4rkst3randClaude Opus 5 bb2aee7818 Tickets: Anliegen zur Auswahl, und das Team kann uebernehmen
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Bisher sah jedes Ticket gleich aus: ein Knopf, ein Thread, und im Thread stand
als Erstes die Frage, worum es ueberhaupt geht. Und wer sich darum kuemmert,
stand nirgends — man sah hinterher nur, wer zufaellig auf "Schliessen" geklickt
hat.

Anliegen sind Kategorien, die man in der Config anlegt: Name, Emoji, eine
Zeile Beschreibung, ein Einstiegstext und optional eine Rolle, die beim
Oeffnen erfaehrt, dass etwas anliegt. Der Ticket-Post wird dadurch vom Knopf
zum Auswahlmenue; das gewaehlte Anliegen steht im Thread-Namen und der
Einstiegstext gleich im ersten Beitrag — gute Stelle fuer "was wir wissen
muessen".

Wer keine anlegt, merkt nichts: ohne Eintrag bleibt es beim einen Knopf. Wer
nur eine Sorte Tickets hat, soll nichts einrichten muessen.

Uebernehmen ist ein Knopf im Thread, sichtbar fuers Team (wer aufraeumen darf,
darf auch uebernehmen). Danach steht im Thread, wer sich kuemmert, und der
Knopf wird zu "Freigeben". Die Bedingung "nur wenn noch niemand dran ist"
steckt im UPDATE und nicht davor — zwei gleichzeitige Klicks wuerden sonst
beide gewinnen. Beim Schliessen landen Anliegen und Bearbeiter im Transcript
und im Mod-Log-Eintrag.

Die Erstellung ist dabei aus client.js nach tickets.js gewandert. Knopf und
Menue gehen jetzt denselben Weg, und in client.js sind drei Importzeilen
weggefallen, die nur noch dort standen.

Geprueft: alsEmoji gegen 20 Eingaben (Unicode, Hautfarbe, ZWJ-Ketten,
Server-Emoji, Murks) und das fertige Panel gegen discord.js selbst — ein
ungueltiges Emoji oder ein zu langes Label laesst Discord sonst die ganze
Nachricht fallen, und das faellt erst beim Senden auf. Im Browser: Liste,
Bearbeiten-Formular und der leere Zustand.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 09:14:49 +02:00
D4rkst3randClaude Opus 5 2292dedeaa README auf den heutigen Stand bringen und neu ordnen
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Die Funktionsliste war eine einzige Tabelle mit 46 Zeilen — in der Reihenfolge,
in der die Sachen entstanden sind, also in keiner. Jetzt ist sie nach denselben
Bereichen sortiert wie das Panel: Inhalte, Community, Moderation, Server, dazu
Plattform fuer alles, was keine Discord-Funktion ist. Wer im Panel etwas sucht,
findet den Abschnitt in der README am selben Platz.

Nachgetragen, was seither dazugekommen ist: AutoMod, Raid-Schutz, verknuepfte
Rollen, native Umfragen, Statusseite, Herzschlag, Seiten-Editor, Englisch fuer
die oeffentlichen Seiten. Und die Trennung in zwei Domains stand bisher gar
nicht drin, obwohl sie das Erste ist, was man verstehen muss — sie steht jetzt
ganz oben, mit einer Tabelle welche Seite was zeigt.

Korrigiert: 35 Module waren es mal, es sind 39. 15 Config-Bereiche waren es
mal, es sind 16. Die Seitentabelle fuehrte Hub-Seiten unter der Bot-Domain.
Die Projektstruktur kannte die Haelfte der Dateien nicht. In der
Ersteinrichtung fehlten die Rechte fuer AutoMod und Kanal-Anlegen sowie die
zusaetzlichen OAuth-Redirects.

Dazu ein Inhaltsverzeichnis, eine docs/README.md als Wegweiser, und in
konzept-zwei-seiten.md steht nicht mehr "muss noch aktiviert werden" — es
laeuft seit Ende Juli.

Geprueft mit einem kleinen Skript: 11 Markdown-Dateien, keine toten
Datei-Links, keine toten Anker, keine Tabelle mit falscher Spaltenzahl.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 07:16:32 +02:00
D4rkst3randClaude Fable 5 c026b2a603 Wichtige Funktionen direkt in der Seitenleiste
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Nach dem Umbau lagen alle Funktionen hinter dem Raster — für die vier, fünf,
die man dauernd anfasst, ist das ein Umweg zu viel.

Oben in der Seitenleiste steht jetzt „Meine Funktionen": ein Klick öffnet
die Seite direkt. Welche dort stehen, entscheidet der Stern auf der
Modul-Karte oder auf der Seite selbst.

Bewusst nicht alle 35: Deckel bei acht, sonst ist der Gewinn gegenüber dem
Raster wieder weg. Der Standard ist eine Vermutung (Devlogs, Willkommen,
Tickets, Starboard, Galerie) und ausdrücklich zum Ändern gedacht.

Die Auswahl liegt als Einstellung in der Datenbank, nicht im Browser — sie
gilt damit auf jedem Gerät und fürs ganze Team. Eine geleerte Auswahl wird
als solche gespeichert, sonst käme beim nächsten Laden der Standard zurück.

Der Stern ist ungeheftet nur angedeutet und wird erst beim Überfahren
deutlich — 35 Karten mit vollen Sternen sähen aus wie ein Sternenhimmel.

Nebenbei: bei geöffneter Modul-Seite war sowohl „Module" als auch die
Funktion in der Leiste hervorgehoben. Jetzt nur noch die Funktion.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 22:08:42 +02:00
D4rkst3randClaude Fable 5 c88926aba0 Modul-Seiten: alles zu einer Funktion an einem Ort
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Bisher war eine Funktion über vier Bereiche verteilt: Schalter unter Module,
Kanal unter Support, Texte unter Texte, Werte unter Werte. Wer die
Begrüßung ändern wollte, brauchte drei Bereiche.

Jetzt öffnet ein Klick auf die Karte die Seite dieser Funktion — mit
Schalter, ihren Kanälen und Feldern, ihren Texten, ihren Werten und dem Weg
zum passenden Werkzeug. Für „Willkommen" also Kanal, Karte, Farben,
Vorschau und beide Texte untereinander.

Bewusst keine 35 Einträge in der Seitenleiste: das Modul-Raster ist die
Navigation, wie bei MEE6. Die Seitenleiste bleibt so lang wie vorher.

Die Seite wird aus den Registern gebaut, nicht von Hand: modules.js kennt
die Felder (neu: `fields` für alles jenseits der Pflichtkanäle, `tool` für
den Verweis auf einen Editor), templates.js hatte die Zuordnung schon,
tuning.js hat sie bekommen. Eine neue Funktion bekommt ihre Seite dadurch
geschenkt — es gibt keinen Ort, an dem man sie vergessen könnte.

Was ein eigenes Werkzeug hat — Rollen-Menüs, Bewerbungen, Composer,
Server-Monitor —, bleibt in seinem Bereich; die Modul-Seite verlinkt nur
dorthin. Dort ist mehr Platz, und die Editoren lassen sich nicht sinnvoll
aus Registern erzeugen.

Texte und Werte bleiben zusätzlich als flache Übersicht: wer alle Texte am
Stück durchgehen will, soll dafür nicht 27 Seiten öffnen müssen.

Beim Umbau ist mir ein Skript in die Quelldatei gelaufen — der Schreibvorgang
scheiterte an einem Emoji und hinterließ modules.js leer. Wiederhergestellt
aus dem letzten Commit; die Skripte schreiben jetzt erst in eine
Zwischendatei und benennen danach um.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 21:54:31 +02:00
D4rkst3randClaude Fable 5 01fadadcd8 Grundgerüst-Assistent: alle fehlenden Kanäle auf einmal
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Der Einzelknopf war der Anfang; wer frisch startet, klickt sich damit
sechzehnmal durch. Der Assistent macht das in einem Durchlauf.

Erst eine Vorschau, bevor irgendetwas passiert: was neu entsteht, was schon
existiert und nur verknüpft wird, welche Kanäle privat werden und in welche
Kategorie alles kommt. Die Kategorie heißt wie die Marke und wird
wiederverwendet, wenn es sie schon gibt.

Der Plan ist nach Einstellung entdoppelt — Devlogs und Wochen-Rückblick
brauchen denselben Kanal, der soll nicht zweimal auftauchen. Rollen kommen
ohne Kategorie, die gibt es dort nicht.

Zwischen zwei Anlagen liegen 350 ms. Discord verträgt ein Dutzend
Kanal-Erstellungen am Stück schlecht, und ein Rate-Limit mitten im Lauf
wäre die unangenehmste Art zu scheitern.

Scheitert ein Schritt, laufen die übrigen weiter und das Ergebnis zeigt pro
Zeile, was passiert ist. Vorher hätte ein einzelner Fehler den Rest
verschluckt.

Im Test: 19 offene Punkte, Vorschau zeigt 16, danach bleiben 2 — die beiden
ohne Vorlage (Gitea-Token und Watchdog-Adressen), die sich nicht anlegen
lassen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 21:17:36 +02:00
D4rkst3randClaude Fable 5 684573b88c Fehlende Kanäle und Rollen aus dem Panel anlegen
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Die Status-Seite listet Module, denen ein Kanal oder eine Rolle fehlt.
Bisher hieß das: rüber zu Discord, Kanal anlegen, Rechte setzen, zurück ins
Panel, auswählen, speichern. Jetzt steht daneben ein Knopf, der genau das
in einem Schritt macht — inklusive Eintragen der Einstellung.

Die Vorlagen hängen bei den Modulen (modules.js): Name, Thema und ob der
Kanal privat sein soll. Private Kanäle bekommen @everyone entzogen und
Bot plus alle Rollen mit Moderationsrecht eingetragen — sonst legt man
einen Modmail-Kanal an, den das Team nicht sieht.

Gibt es Kanal oder Rolle schon (bei Rollen unabhängig von Groß- und
Kleinschreibung), werden sie verknüpft statt doppelt angelegt. Beim
Temp-Voice-Hub entsteht ein Sprachkanal statt eines Textkanals.

Fehlen dem Bot die Rechte, steht das im Panel im Klartext („Dem Bot fehlt
das Recht Kanäle verwalten") statt einer Discord-Fehlernummer.

Bewusst nur Anlegen: kein Löschen, kein Umbenennen. Ein Fehlklick beim
Anlegen kostet einen überflüssigen Kanal, einer beim Löschen dessen
Verlauf. Umbenennen wäre zusätzlich eine Falle, weil Discord es auf zwei
Änderungen pro zehn Minuten und Kanal begrenzt.

moduleMissing liefert dafür Objekte statt Beschriftungen, damit das Panel
weiß, was sich anlegen lässt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 18:29:54 +02:00
D4rkst3randClaude Fable 5 0240225165 Config-Suche findet einzelne Einstellungen
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Die Seitenleisten-Suche kannte nur Bereiche: „starboard" führte zu
Community, aber nicht zum Schwellwert-Feld. Bei rund 60 Einstellungen
heißt das raten, in welchem Bereich etwas liegt.

setting-index.js hält jetzt fest, wo jede Einstellung wohnt, mit
Suchwörtern und Synonymen. Die Suche zeigt Treffer als eigene Gruppe unter
den Bereichen; ein Klick wechselt den Bereich, scrollt zum Feld und hebt es
kurz hervor. Enter nimmt den ersten Treffer, wobei Einstellungen Vorrang
vor Bereichen haben — wer „schwellwert" tippt, will das Feld.

Die Felder tragen dafür data-setting="<schlüssel>"; das Attribut wurde
skriptgesteuert ergänzt, ohne die Struktur anzufassen. Fünf Einstellungen
teilen sich ein Feld mit einer anderen (etwa die beiden Markenfarben) —
die zeigen über `target` auf den Nachbarn.

Textfelder werden beim Sprung fokussiert, Kanal-Auswahlen bewusst nicht:
deren Fokus klappt die Liste auf und verdeckt alles darunter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 18:22:35 +02:00
D4rkst3randClaude Fable 5 3549b06cef /bug und /wunsch als Eingabefenster
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Beide Befehle nahmen ihre Eingaben als Slash-Optionen entgegen. Das heißt:
eine Fehlerbeschreibung einzeilig in die Befehlszeile tippen, ohne
Umbrüche, ohne Absätze. Entsprechend dürftig fielen die Meldungen aus.

/bug öffnet jetzt ein Fenster mit vier Feldern: Titel, was ist passiert,
was war erwartet, wie kann man es nachstellen. Die letzten beiden sind
freiwillig und erzeugen im Issue nur dann eine Überschrift, wenn sie
ausgefüllt sind. /wunsch fragt die Idee und ein optionales „warum wäre das
gut?" ab — die Rückfrage macht aus einem Einzeiler einen Vorschlag, über
den man abstimmen kann.

Der Screenshot bleibt eine Option am Befehl, weil Discord in Fenstern
keine Dateien erlaubt. Er hängt damit an der Befehls-Interaktion, das
Formular kommt aber als eigene zurück — der Anhang wird deshalb kurz
zwischengeparkt und nach dem Absenden verwendet. Abgelaufene Einträge
räumt der nächste Aufruf mit weg, damit da nichts liegen bleibt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 16:53:04 +02:00
D4rkst3randClaude Fable 5 2ce274707a Config statt Setup: Bereiche gruppiert, Suche, Status als Einstieg
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Die Seite hieß Setup und listete 15 Bereiche flach untereinander. Wer
nicht wusste, dass Geburtstage unter „Community" stecken und Willkommens-
Texte unter „Support", hat geklickt bis er es fand.

Die Seitenleiste gruppiert jetzt nach Überblick, Auftritt, Inhalte,
Community, Technik und Zugang. Darüber steht ein Suchfeld, das nicht nur
Beschriftungen durchsucht, sondern auch Stichwörter je Bereich — „geburtstag"
führt zu Community, „ticket" zu Support. Enter springt zum ersten Treffer.

Der aktive Bereich steht in der Adresse (/settings#texte). Damit überlebt er
das Neuladen, und man kann jemandem einen Link auf genau die Stelle schicken.

Der Status-Bereich war die leerste Seite im ganzen Panel: sechs Zahlen. Er ist
jetzt der Einstieg und beantwortet die Frage, die man beim Öffnen wirklich hat
— was läuft noch nicht? Eingeschaltete Module, denen ein Kanal oder eine Rolle
fehlt, stehen dort mit einem Knopf, der direkt an die richtige Stelle springt.
Ist alles eingerichtet, sagt die Seite genau das.

Umbenannt in „Config", weil „Setup" nach einmaliger Einrichtung klingt — die
Seite ist aber der Ort, an dem man dauerhaft alles einstellt.

Schmale Bildschirme: die Leiste wird zur umbrechenden Zeile ohne
Gruppen-Überschriften, das Suchfeld nimmt die volle Breite.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 16:13:33 +02:00
D4rkst3randClaude Fable 5 dadd75d452 Texte: 27 Bot-Nachrichten im Panel bearbeitbar
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Bisher standen Begrüßung, Level-Ansage, Ticket-Texte und alle
Bestätigungs-Nachrichten fest im Code. Wer den Ton ändern wollte, musste
die Quelldateien anfassen und neu deployen — für alle außer mir also gar
nicht.

src/templates.js hält jetzt alle nach außen gehenden Texte an einer
Stelle: Standardtext, Platzhalter mit Erklärung und die Zuordnung zum
Modul. Der neue Setup-Tab „Texte" zeigt sie als Karten mit Textfeld;
die Bausteine darunter fügen sich per Klick an der Cursor-Position ein.

Der Standard bleibt im Code, die Datenbank speichert nur echte
Abweichungen. Ein leeres Feld heißt deshalb „wieder Standard" — und
angepasste Vorlagen sind an einer Marke erkennbar. Vorlagen zu
ausgeschalteten Modulen sind als solche gekennzeichnet, damit niemand
einen Text feilt, den gerade nichts sendet.

Unbekannte Platzhalter bleiben stehen statt still zu verschwinden, damit
ein Tippfehler in der Nachricht sichtbar wird.

Die Route heißt /api/texts, nicht /api/templates — letzteres sind seit je
die gespeicherten Composer-Nachrichten.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 16:06:27 +02:00
D4rkst3randClaude Fable 5 59aad27534 Modul-System: alle 35 Funktionen im Panel ein- und ausschaltbar
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Bisher waren die Schalter über die Oberfläche verstreut: fünf Funktionen
hatten einen Haken, 22 weitere gingen nur über den Umweg „Kanal leeren".
Für jeden außer dem Owner war das nicht auffindbar.

Jetzt steht in src/modules.js ein zentrales Register aller Funktionen mit
Beschreibung, Standard-Zustand und den Einstellungen, die sie brauchen.
Daraus entsteht ein neuer Setup-Tab mit Karten: Schiebeschalter, kurze
Erklärung, Hinweis was noch fehlt ("Fehlt noch: Release-Kanal") und ein
Sprung zu den Einstellungen.

Damit die Schalter keine Attrappen sind, prüfen die Bot-Module jetzt an
18 Stellen zentral, ob sie laufen dürfen — Starboard, Galerie, Modmail,
Willkommen, Protokoll, Auto-Antworten, Sprachkanäle, Erinnerungen,
Events, Twitch/YouTube, Monitor, Wächter, Releases, Rückblick,
Geburtstage, Verlosungen und geplante Beiträge.

Funktionen mit vorhandenem Schalter (Level-System, Backups, Member-Gate …)
nutzen weiterhin dieselbe Einstellung, damit keine zweite Wahrheit
entsteht und bestehende Konfigurationen unverändert weiterlaufen.

Nebenbei gefunden und behoben: Beim Anlegen eines Modmail-Threads wurde
`member.client` benutzt, obwohl es an der Stelle kein `member` gibt — der
erste Modmail-Thread wäre mit einem Fehler abgebrochen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 15:53:44 +02:00
D4rkst3randClaude Fable 5 e8158ce90b Seiten-Editor: Inhalte pflegen ohne Code-Änderung
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Antwort auf den CMS-Wunsch aus der Community — statt eines Forums, das
neben aktivem Discord erfahrungsgemäß verwaist, ein schlanker Editor für
eigene Seiten: Regeln, Über uns, Mitmachen, FAQ.

- neuer Setup-Tab "Seiten" (Scope content): Titel, Adress-Kürzel wird aus
  dem Titel abgeleitet, Markdown-Editor mit Live-Vorschau daneben
- pro Seite wählbar: veröffentlicht oder Entwurf, im Community-Menü oder
  nur per Direktlink, Reihenfolge
- Anzeige unter /<kürzel>, gerendert mit dem vorhandenen Markdown-Parser
- Entwürfe sind öffentlich nicht abrufbar — sie brauchen den content-Scope
- reservierte Kürzel (devlogs, settings, api, impressum …) werden
  abgelehnt, damit nichts die festen Routen überschreibt

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 15:08:21 +02:00
D4rkst3randClaude Fable 5 b5617a9d18 Repo-Backups, Gitea-Theme und Auto-Deploy
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
- Repo-Backups: nachts um 04:00 werden alle Gitea-Repos als git-Bundle
  gesichert — eine Datei pro Repo mit kompletter Historie, aus der sich
  direkt wieder klonen lässt. 14 Tage Rotation wie beim DB-Backup,
  Schalter und "Repos jetzt sichern" im System-Tab. Nutzt den bereits
  vorhandenen Gitea-Token; Dockerfile installiert dafür git mit.
- Gitea-Theme im D4RKST3R-Look (docs/gitea-theme/): Neon-Gelb/Orange auf
  Schwarz, gebaut gegen die Variablen von Gitea 1.26, Diff-Farben bleiben
  lesbar. Einbau-Anleitung liegt daneben.
- Auto-Deploy statt manuellem "Pull and redeploy": Workflow für Gitea
  Actions (prüft Server-Syntax und Frontend-Build, bevor deployed wird)
  plus dokumentierter Runner-loser Weg über den Portainer-Webhook.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 14:01:31 +02:00
D4rkst3randClaude Fable 5 c73b4e1074 Portal-Dienste und geteiltes Design-System für die anderen Apps
- Dienste (Gitea, Kanban, Cloud …) werden im System-Tab gepflegt und
  erscheinen als Kacheln auf der Startseite; GET /api/services ist
  öffentlich, Pflege braucht den settings-Scope
- /brand.css liefert die Design-Tokens (Farben live aus dem Brand-Tab,
  ändern sich damit überall mit) plus Basis-Klassen d4rk-card,
  d4rk-btn, d4rk-title, d4rk-tag
- /brand-nav.js baut die D4RKST3R-Leiste in jede fremde App ein, mit
  Links zum Hub und zu allen gepflegten Diensten; die Links stecken
  fertig im Skript, dadurch kein zweiter Request und kein CORS nötig
- Beide Dateien mit offenem CORS-Header und 5 Minuten Cache
- Doku für Anbindung + Schriften in docs/sso.md ergänzt

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 13:28:50 +02:00
D4rkst3randClaude Fable 5 70cae85064 Single Sign-On: der Bot als Identity-Provider für die anderen Dienste
Andere Apps (Kanban, Platform …) nutzen ab sofort den Discord-Login des
Bots mit, statt jeweils eigenes OAuth zu bauen — und bekommen die
Discord-Rollen des Users gleich mitgeliefert.

Ablauf: App leitet auf /sso/authorize weiter, der Bot prüft die Session
(ggf. erst Discord-Login) und schickt einen signierten Token zurück, den
die App serverseitig per POST /sso/verify gegen die Nutzerdaten tauscht.

Sicherheit:
- Rücksprung-Ziele müssen einem registrierten Präfix entsprechen
  (kein Open Redirect, kein Token-Abgriff über fremde Hosts)
- Token HMAC-signiert, 60 Sekunden gültig, nur einmal einlösbar
- Verify braucht das App-Secret (timing-safe verglichen)
- SSO bleibt Mitgliedern des Discord-Servers vorbehalten
- App-Verwaltung ist Owner-only, Secret wird nur einmal angezeigt

Dazu: sso_apps-Tabelle, Verwaltung im API-Tab, Rücksprung nach dem
Login (return-Cookie, nur interne Pfade), Anleitung in docs/sso.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 13:24:03 +02:00
D4rkst3randClaude Fable 5 8853bce2ec Impressum, Datenschutzerklärung und DSGVO-Löschfunktion
- /impressum (§ 5 DDG) und /datenschutz als öffentliche Seiten im
  Brand-Look; Betreiber-Angaben (Name, Anschrift, E-Mail, Zusatz)
  liegen als Settings und sind bewusst Owner-only — Team-Mitglieder
  mit settings-Scope kommen an die private Anschrift nicht heran
- Die Datenschutzerklärung beschreibt die tatsächliche Verarbeitung
  dieser Instanz: Server-Logs, Session-Cookies (einwilligungsfrei nach
  § 25 Abs. 2 TDDDG, kein Tracking), Discord-Login, Level, Wünsche,
  Geburtstage, Playtester/Alpha-Keys, Bewerbungen, Tickets/Modmail,
  Erinnerungen, Moderation und Audit-Log
- DSGVO Art. 17: DELETE /api/profile löscht XP, Geburtstag,
  Playtester-Eintrag, Abstimmungen, Erinnerungen, Rollen-Sicherung,
  Giveaway-Teilnahmen und gibt den Alpha-Key wieder frei; Button im
  Profil unter „Meine Daten", Löschung landet im Audit-Log
- Footer verlinkt beide Rechtstexte, neues GET /api/legal (öffentlich)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 13:19:33 +02:00
D4rkst3randClaude Fable 5 676fc45bb1 Willkommens-Karten, Geburtstage, Devlog-Permalinks mit OG-Vorschau, Auto-Publish
- Willkommens-Karten: gerendertes PNG (SVG → sharp) mit Avatar im
  Neon-Ring, Willkommens-Schriftzug und Member-Nummer; Fallback aufs
  bisherige Embed wenn das Rendering scheitert; Dockerfile installiert
  fonts-dejavu-core für die Text-Darstellung
- Geburtstags-System: /geburtstag setzen|entfernen (birthdays-Tabelle),
  tägliche Runde ab 09:00 Europe/Berlin (Doppel-Post-Schutz über
  last_birthday_run), Gratulations-Embed + Tages-Rolle (wird am
  nächsten Morgen wieder abgeräumt); Kanal + Rolle im Community-Tab
- Devlog-Permalinks: /devlogs/:id als eigene Seite (GET /api/devlogs/:id),
  Link-Symbol an jeder Karte, Link-kopieren-Button; der Server injiziert
  Open-Graph-Tags ins SPA-HTML — Devlog-Links zeigen Titel, Anriss und
  Bild, alle anderen Seiten bekommen Default-Tags (auch die Startseite)
- Auto-Publish: maybeCrosspost() veröffentlicht Devlog-, Release-,
  Composer- und geplante Posts automatisch in Ankündigungs-Kanälen
- brandEmbed: leere Avatar-URL crasht nicht mehr die Footer-Validierung

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 22:43:15 +02:00
D4rkst3randClaude Fable 5 ef0fb066f7 Startseite, Server-Seite v2 mit Logos, Lightbox-Fix, Navbar-Ausrichtung
- Startseite (/): Hero mit CTAs (Discord-Invite + Devlogs), Live-Zahlen
  (Member, Server online, Spieler), Bereichs-Kacheln, neuestes Devlog
  als Teaser — kein Redirect mehr auf /devlogs
- Server-Seite v2: Übersichtsleiste (X/Y online, Spieler gesamt),
  2-Spalten-Grid, Server-Logo (neues Feld image_url, https-only, auch
  als Embed-Thumbnail im Discord-Status), große Spielerzahl, Uptime %
  + Peak aus den 24h-Samples, Adresse als Copy-Button
- Lightbox: rendert jetzt per Portal in <body> (Header/Scanlines
  schienen durchs Overlay), Pfeile stehen neben dem Bild statt drauf,
  Info-Zeile unterm Bild
- Navbar: Community-Dropdown-Button auf Link-Höhe ausgerichtet
  (line-height + align-items)
- Setup Server-Tab: Logo-URL-Feld

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 22:25:30 +02:00
D4rkst3randClaude Fable 5 be11398f7c UX-Paket: Navbar aufgeräumt, /server-Seite, Lightbox, Skeletons, Audit-Log, Reroll
- Navbar entschlackt: nur noch Devlog · Roadmap · Server · Community ·
  Setup; Galerie/Level/Events/Changelog im Community-Dropdown,
  Profil/Commits/Logout im Avatar-Menü; Mobile-Burger mit Drawer
- Öffentliche /server-Seite: Live-Status-Karten mit Spieler-Balken,
  Map, Connect-Button und 24h-Spielerzahl-Chart (SVG); Monitor sampelt
  jede Abfrage in player_history (7 Tage Retention), GET /api/servers
  liefert nur öffentliche Felder (keine Query-URLs/Hosts)
- Lightbox: Galerie- und Devlog-Bilder öffnen im Overlay mit
  Pfeiltasten, Buttons, Wisch-Gesten und Zähler statt neuem Tab
- Skeleton-Loader: schimmernde Platzhalter auf Devlogs, Roadmap,
  Galerie, Level, Changelog und Server statt "Lade …"
- Team-Audit-Log: audit_log-Tabelle (max 500 Einträge), Logging bei
  Settings/Composer/Vorlagen/Rollen-Menüs/Gameservern/Team/API-Keys/
  Branding, GET /api/auditlog (Owner) + Liste im Team-Tab
- Giveaway: 🔁 Reroll-Button (Admin-only) + 👥 Teilnehmerliste am
  Gewinner-Post

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 22:15:58 +02:00
D4rkst3randClaude Fable 5 aa12dff7ab Member-Bereich: Profilseite, Rollen-Selfservice, Web-Voting, Member-Gate
Der Discord-Login ist jetzt für alle Member nützlich:
- /profil: Rang + XP-Fortschritt, Discord-Rollen als Chips, Playtester-
  Badge, eigener Alpha-Key mit Kopier-Button
- Rollen-Selfservice: veröffentlichte Rollen-Menüs direkt im Browser
  togglen (gleiche Exklusiv-Logik wie die Discord-Buttons; nur Rollen
  aus aktiven Menüs erlaubt)
- Wunsch-Voting im Web: auf /roadmap Wünsche einreichen (postet wie
  /wunsch in den Voting-Kanal) und upvoten (wish_votes-Tabelle,
  ein Vote pro Member, unabhängig von Discord-👍)
- Member-Gate: Login nur für Mitglieder der konfigurierten Guild;
  Abgewiesene sehen einen Banner mit Discord-Invite-Link (neue
  Settings member_gate_enabled + discord_invite_url im System-Tab)
- Membership-Check mit 5-Minuten-Cache, Owner immer erlaubt

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 21:52:59 +02:00
D4rkst3randClaude Fable 5 00249f9d8b Server-Monitor v3, Composer v2, Temp-Voice-Panel und Embed-Polish
- Server-Monitor v3: gamedig-Integration (300+ Spiele), GSM-Stil-Embeds
  (Spieler-Balken mit %, Map, Spieler-Liste, klickbarer Connect-Link,
  Ping im Footer), Down/Up-Alerts (2 Fails → 🚨, Recovery →  mit
  Downtime) in konfigurierbaren Alert-Kanal; Server-Tab mit 19
  Spiel-Presets, Host/Port bzw. Query-URL und Connect-URL
- Composer v2: visueller Embed-Builder mit Live-Discord-Preview
  (Autor, Felder, Bilder, Farbe, Footer, Timestamp), speicherbare
  Vorlagen (/api/templates), /api/compose versteht volle Embeds
- Temp-Voice: Control-Panel im erstellten Kanal (Umbenennen, Sperren,
  Limit, Löschen) — nur der Kanal-Besitzer darf bedienen
- Embed-Polish: brandEmbed-Factory (src/embeds.js), Footer überall
  mit Bot-Avatar-Icon

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 02:17:30 +02:00
D4rkst3randClaude Fable 5 332e89dcbd Server-Tab (DiscordGSM-Stil), Team-Rechte und Bot-Profil-Beschreibung
- Game-Server: eigene Tabelle statt CSV-Setting (automatische Migration), eigener
  Setup-Tab mit Server-Builder (Name, Typ fivem/http, Query-URL, Anzeige-Adresse);
  pro Server ein Live-Embed (gruen/rot, Spieler-Balken, Map, Adresse als Code-Block),
  edit in place; Embed wird beim Server-Loeschen mit entfernt
- Team-System: web_admins mit Bereichs-Scopes (content/community/rollen/bewerbungen/
  server/settings/devlogs); Owner behaelt Brand/System/API-Keys/Team exklusiv;
  32 Routen-Guards auf Scopes umgestellt, sensible PUT-Felder fuer Team gestrippt;
  Team-Tab (Owner) + Tab-Filterung im Frontend, /api/me liefert Scopes
- Bot-Karte: Profil-Beschreibung (Ueber mich) via application.edit
- Fix: settings-Tabelle wird vor der Gameserver-Migration angelegt (frische DBs
  crashten sonst beim Start)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 01:23:11 +02:00
D4rkst3randClaude Fable 5 19ec2802ac Tickets: Transcript beim Schließen + Thread-Löschung
- Schließen-Button erstellt jetzt ein Text-Transcript (chronologisch, inkl.
  Attachment-URLs, max 500 Nachrichten) und schickt es dem Ersteller per DM
- Kopie ins Mod-Log (Aufbewahrung fürs Team, mit Hinweis falls DM blockiert)
- Thread wird danach gelöscht statt nur archiviert (Fallback: sperren+archivieren,
  falls dem Bot Lösch-Rechte fehlen)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 01:11:16 +02:00
D4rkst3randClaude Fable 5 e72e6c8991 Community-Endgame: Alpha-Keys, Bewerbungen, Events, Stats, Triggers, /remind, Social, Temp-Voice + MEE6-Bot-Karte
- Alpha-Keys: Pool im Community-Tab, Ein-Klick-Verteilung per DM an alle Playtester
  (Key bleibt frei, wenn die DM geblockt wird)
- Bewerbungs-Formulare: Builder im neuen Bewerbungen-Tab (bis 5 Fragen),
  Button → Discord-Modal → Review-Embed mit /, Rolle + DM bei Entscheidung
- Events: GuildScheduledEventCreate → Announce-Embed; öffentliche /events-Seite
  aus den Discord-Events (5-min-Cache)
- Server-Stats: activity_daily (Nachrichten/Joins/Leaves) → Balken-Chart auf /level
- Triggers (Auto-Antworten, 30s-Cooldown), /remind (DM-Scheduler),
  Twitch-Live (Helix, App-Creds write-only) + YouTube-RSS-Announcements,
  Temp-Voice (Join to Create, Cleanup bei Leerstand + Start)
- Brand-Tab: MEE6-Style Bot-Identity-Karte (Avatar-Vorschau mit Status-Dot,
  Bot-Name via setUsername, Presence online/idle/dnd, Aktivität)
- Neue Intents: GuildVoiceStates, GuildScheduledEvents; alles smoke-getestet

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 01:02:47 +02:00
D4rkst3randClaude Fable 5 f7b261c648 Branding-Tab: Name/Farben/Bot-Status/Avatar/Banner + Button-Farben für Rollen-Menüs
- Alle Embeds nutzen jetzt brandName/brandColor/brandColor2/brandFooter aus den
  Settings (Codemod über 20 Module) — Farbe & Name serverweit per Klick änderbar
- Bot-Status (Presence): Typ (Spielt/Schaut/Hört/Status) + Text, sofort angewendet;
  Server-Monitor nutzt die Presence nur noch, wenn kein eigener Status gesetzt ist
- Avatar-/Banner-Upload direkt aufs Bot-Profil (Base64, 8-MB-Limit,
  Discord-Rate-Limit sauber gemeldet)
- Env-Verlagerung: GITEA_API_TOKEN (write-only Setting) und DISCORD_GUILD_ID
  jetzt auch über den Brand-Tab pflegbar — weniger Redeploys
- Rollen-Menüs: Button-Farbe pro Eintrag wählbar (Grau/Blau/Grün/Rot)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 00:40:08 +02:00
D4rkst3randClaude Fable 5 db9c7d07c9 Carl-Bot-Paket: Moderation, Auto-/Sticky-Roles, Level-System, Tags, geplante Posts
- Moderation: /warn (DM + Mod-Log), /warns (Historie + löschen), /timeout (max 28d),
  /purge (bulk, 14-Tage-Limit sauber gemeldet); Mod-Log erweitert um Join/Leave
  und Nick-/Rollen-Änderungen
- Auto-Rolle bei Join + Sticky-Roles (Rollen bei Leave gesichert, bei Rejoin
  wiederhergestellt; managed/@everyone ausgenommen) — Rollen-Tab
- Level-System (opt-in): 15-25 XP/Nachricht mit 60s-Cooldown, MEE6-Formel,
  Level-Up-Announce, Rollen-Belohnungen (Level=RolleID), /rank mit Fortschritt,
  öffentliche Bestenliste /level; Community-Tab
- Tags: /tag mit Autocomplete, Verwaltung im Composer-Tab (/api/tags)
- Geplante Posts: einmalig/täglich/wöchentlich, Minuten-Scheduler, DST-sicher
  über Neuberechnung aus Zeitfeldern; Composer-Tab (/api/scheduled)
- Autocomplete-Dispatch im InteractionCreate; alles smoke-getestet

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 00:30:23 +02:00
D4rkst3randClaude Fable 5 a27a594a07 Rollen-Menüs (Carl-Bot-Ersatz) + Setup-Redesign mit Tab-Sidebar
- Rollen-Menüs: Builder im Webinterface (Titel, Beschreibung, Kanal, Emoji/Label/Rolle,
  Exklusiv-Modus = max. 1 Rolle pro Menü), Bot postet Button-Embeds; Klick = Rolle
  nehmen/abgeben (ephemeres Feedback), Update editiert den Discord-Post in place,
  Löschen räumt ihn mit auf
- Bewusst Buttons statt klassischer Emoji-Reaktionen: kein Reaction-Spam am Post,
  kein Custom-Emoji-Parsing, exklusive Menüs möglich; halbfertige Reaction-Variante
  aus abgebrochener Session entfernt und konsolidiert
- Setup-Seite: komplett neu strukturiert in 8 Tabs mit sticky Sidebar
  (Status/Feeds/Community/Rollen/Support/Composer/System/API), Feedback als Toast
- Modern-Polish: weiche Radien auf Karten/Inputs/Buttons, ruhigere Input-Flächen
  mit Fokus-Glow, Sektions-Hover; JSON-Parser akzeptiert leere Bodies
- API: /api/rolemenus CRUD + publish (Admin), README aktualisiert

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 00:15:29 +02:00
D4rkst3randClaude Opus 4.8 4d1b0a956d Ticket-System, Web-Composer und Nachrichten-Bearbeitung
- Tickets: /ticket-setup postet 🎫-Button; Klick erstellt privaten Thread
  (ein offenes Ticket pro User), Schließen-Button sperrt + archiviert
- Composer auf der Setup-Seite: Nachricht/Embed als Bot in beliebigen Kanal
  senden oder per Message-ID bearbeiten (nur eigene Bot-Posts)
- API v1: PATCH /api/v1/message — Skripte können ihre Bot-Posts aktualisieren
- Setting ticket_channel_id; README ergänzt

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 13:43:27 +02:00
D4rkst3randClaude Opus 4.8 f631c0e2ab README aktualisiert (Setup-Sektionen, Endpoints, Struktur) + Community-Ankündigungspost
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 13:27:56 +02:00
D4rkst3randClaude Opus 4.8 bc000aaa9f Feature-Voting, Giveaways und Contribution-Heatmap
- /wunsch: Voting-Embed mit 👍, Reaction-Tracking (add/remove) in SQLite,
  Top-20-Rangliste öffentlich auf der Roadmap-Seite
- /giveaway (Admin): Preis/Dauer/Gewinnerzahl, 🎉-Teilnahme-Button (toggle),
  Minuten-Scheduler zieht Gewinner, schließt das Embed ab und pingt sie
- Contribution-Heatmap: 52-Wochen-Grid in Brand-Gelb aus dem Commit-Archiv
  (/api/heatmap) auf der Roadmap-Seite
- Setting voting_channel_id auf der Setup-Seite

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 13:20:44 +02:00
D4rkst3randClaude Opus 4.8 075ea36bd2 Moderation & Kontakt + Game-Server-Monitor
- Modmail: DMs an den Bot landen als Threads im privaten Staff-Kanal,
  Thread-Antworten gehen als DM zurück (Zustell-Feedback per Reaktion)
- Willkommens-Embed für neue Member (GuildMemberAdd; Server-Members-Intent nötig)
- Mod-Log: gelöschte/bearbeitete User-Nachrichten in privaten Log-Kanal
- Server-Monitor: FiveM-kompatible Endpoints (/dynamic.json) alle 2 min,
  persistentes Status-Embed (edit in place) + Spielerzahl als Bot-Presence
- Neue Intents: DirectMessages, GuildMembers; Partials.Channel
- Setup-Seite: Sektionen // Moderation & Kontakt und // Game-Server

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 13:14:18 +02:00