- Updated ticket command and interaction responses to utilize the new `ephemeral()` function for consistent ephemeral message handling. - Enhanced error handling for member fetching in ticket interactions, ensuring proper responses when members are not found. - Improved localization for new error messages related to member presence in ticket commands. - Documented changes in phase tracking to reflect updates in ticket interaction responses.
27 KiB
27 KiB
Phase 6 – WebUI-Fundament (Status: abgeschlossen, manuell bestätigt)
- OAuth/Sessions, Settings-Framework, Layout, Modul-Toggles, Access-Rules
- Login manuell bestätigt
Phase 7 – WebUI Modul-Seiten + Owner-Panel (Status: abgeschlossen, manuell bestätigt)
Abgeschlossen
- Alle Modul-Dashboard-Seiten, Commands-Seite, Overview-Aktivität
- Owner-Panel (
/owner: Übersicht, Guilds, Users, Flags, Presence, Team, Jobs, Changelog, Audit) - Prisma
20260722190000_phase7_owner, Shared Zod (dashboard.ts,owner.ts) - BullMQ WebUI↔Bot, Presence-/Wartungsmodus-Anbindung
- Manuell bestätigt (User-Freigabe)
Phase 8 – Landing, Status, Rechtsseiten (Status: abgeschlossen, manuell bestätigt)
Abgeschlossen
- Landing
/, Status/status, Rechtsseiten, Public APIs, Core-Commands,docs/verification.md - Manuell bestätigt (User-Freigabe)
Deploy-Branch (deploy) – Traefik + Dashboard-Domain
Abgeschlossen (Code auf Branch deploy; main unverändert)
- Traefik-Vollstack: Compose-Netz
traefik-network(external) +internal - WebUI hinter Traefik: Host
dashboard.nexumi.de, Entrypointwebsecure,certresolver=letsencrypt - Host-Port
3000entfernt; nur Traefik exponiert die WebUI WEBUI_URL=https://dashboard.nexumi.de(OAuth-Callback:/api/auth/callback)- Marketing-Landing archiviert unter
apps/webui/src/archived/landing-page.tsx /zeigt Login;/loginleitet auf/weiter (Query erhalten)- SPEC-Abweichung (bewusst): öffentliche Landing später extern auf
nexumi.de; Dashboard unter Subdomain - Rechtsseiten vollständig (Impressum/Datenschutz/ToS) DE+EN; Locale per Accept-Language (Cookie hat Vorrang)
- Plesk-Landing unter
landingpage/mit lokalen Rechtsseiten (impressum.php,datenschutz.php,nutzungsbedingungen.php)
Manuell testen (Deploy)
- DNS
dashboard.nexumi.de→ Traefik-Host - Discord OAuth Redirect:
https://dashboard.nexumi.de/api/auth/callback docker compose up -d --build(Netztraefik-networkmuss existieren)- TLS-Zertifikat (Resolver-Name ggf. an Traefik anpassen)
- Login
/→ Dashboard; Session-CookieSecure
Post-Phase – Premium + DSGVO (Status: implementiert, manuelle Tests offen)
Abgeschlossen (Code)
- Premium:
PremiumTierConfig, Guild-/User-Zuweisung, Owner-UI/owner/premium - Limits enforced (Tags/Feeds/Backups) in Bot + WebUI
- DSGVO:
/privacy,/gdpr delete confirm:true(Löschung/Anonymisierung +GdprDeletionLog) - Log-Retention:
LoggingConfig.retentionDays+ täglicher Jobretention/purgeExpiredLogs - Snipe standardmäßig aus (
GuildSettings.snipeEnabled, Toggle in Allgemeine Einstellungen) - Migration
20260722200000_premium_gdpr
Manuell testen
- Owner
/owner/premium: Limits speichern, Guild PREMIUM zuweisen - Free-Limit: mehr Tags/Feeds/Backups als Free-Cap → Fehler
/privacyund/gdpr delete confirm:true- Logging-Retention im Dashboard setzen
- Snipe: default aus; nach Aktivierung in Einstellungen nutzbar
Bewusst offen
- Musik- und KI-Modul (nur auf Zuruf)
- Premium-Zahlungsanbindung
- Externe Marketing-Landing auf
nexumi.de
Post-Phase – Dashboard-UI + Command-Palette + Landing-Polish (Status: implementiert)
Abgeschlossen (Code)
- Guild-/Owner-Shell: Branding, Sticky-Header, mobile Sidebar-Sheet, Overview-Polish
- Globale Cmd/Ctrl+K-Suche: Seiten, Slash-Commands, Einstellungsfelder (Deep-Links)
- Settings-Feld-Registry + Form-Anchors; Commands-Seite liest
?q= - Plesk-Landing: Inter, Hero-Hierarchie, dezente Motion, Designsprache an WebUI
Manuell testen
- Dashboard: Cmd/Ctrl+K → Seite, Command und Option navigieren (Hash-Scroll)
- Mobile: Sidebar-Sheet + Such-Trigger
- Overview und Owner-Panel Layout
- Landing Light/Dark (
prefers-color-scheme) + CTAs
Bewusst offen
- Musik- und KI-Modul (nur auf Zuruf)
- Premium-Zahlungsanbindung
Post-Phase – Channel-Picker überall (Status: implementiert)
Abgeschlossen (Code)
DiscordChannelSelect/DiscordChannelMultiSelect+useGuildChannels- Alle Modul-Forms: Kanal-ID-Texteingaben durch durchsuchbare Channel-Auswahl ersetzt
- Voice-/Category-Filter für TempVoice/Stats/Tickets
Post-Phase – Role-Picker überall (Status: implementiert)
Abgeschlossen (Code)
DiscordRoleSelect/DiscordRoleMultiSelect+useGuildRoles- Modul-Forms/Manager: Rollen-ID-Texteingaben durch durchsuchbare Role-Auswahl ersetzt (Welcome, Verification, Leveling, Logging, Birthdays, Giveaways, Tags, Tickets, Access Rules, Feeds, Scheduler, Commands)
- Selfroles: Role-Builder statt Textarea (
roleId | label | emoji)
Manuell testen
- Rollen in den Modul-Settings per Dropdown setzen und speichern
- Multi-Select (Autoroles, No-XP-Roles, Support-Roles, …) speichert string[] korrekt
- Access-Rules: Rolle wählen und Module zuweisen
Post-Phase – Command-Global-Rules + Channel-Picker (Status: implementiert)
Abgeschlossen (Code)
- Globale Command Channel-Whitelist/-Blacklist in
GuildSettings+ Commands-UI - Searchable Multi-Select für Kanäle/Rollen (statt Raw-IDs) auf der Commands-Seite
- APIs:
/commands/globals,/channels,/roles - Bot erzwingt globale + per-Command Channel/Role/Cooldown-Regeln in
routeCommand - Migration
20260722210000_command_global_channels
Manuell testen
- Commands: globale Whitelist/Blacklist speichern, in Discord prüfen
- Per-Command Channel/Rollen per Dropdown setzen
- Deaktivierter Command / Cooldown antwortet ephemeral
Post-Phase – Discord Embed-Builder (Status: implementiert)
Abgeschlossen (Code)
- Wiederverwendbare
DiscordEmbedBuilder-Komponente inkl. Live-Vorschau - Basis: Titel, Beschreibung, Farbe
- Erweitert: Author (Name/Icon/URL), Thumbnail, großes Bild, Footer (Text/Icon), Titel-URL, Timestamp
- Welcome/Leave, Tags (EMBED) und Scheduler nutzen denselben Builder +
buildEmbedFromPayload - Platzhalter in Text-/URL-Feldern inkl.
{user.avatar}/{server.icon}(Welcome/Tags)
Manuell testen
- Welcome/Leave-Embed mit Author, Thumbnail, Banner und Footer speichern und in Discord prüfen
- Tag mit Antworttyp Embed (auch nur Bild/Author ohne Titel) erstellen/bearbeiten
- Geplante Nachricht mit erweitertem Embed anlegen
- Einfaches Embed (nur Titel/Beschreibung/Farbe) funktioniert weiter wie zuvor
Post-Phase – Logging Multi-Event pro Kanal (Status: implementiert)
Abgeschlossen (Code)
- Logging-UI: pro Log-Kanal mehrere Event-Typen per Multi-Select
- Bestehende 1:1-Mappings werden beim Laden nach Kanal gruppiert; Speichern expandiert wieder auf
LogChannel-Zeilen - Event-Typen sind exklusiv (DB
@@unique([guildId, eventType])) – Auswahl in einer Zeile entfernt sie aus anderen
Manuell testen
- Mehrere Events einem Kanal zuweisen und speichern
- Event von Kanal A nach Kanal B umhängen (verschwindet bei A)
- Bot schreibt Logs der gewählten Events in den richtigen Kanal
Post-Phase – Platzhalter-Hilfe (Status: implementiert)
Abgeschlossen (Code)
- Aufklappbare
PlaceholderHelp-Komponente mit Kopieren pro Token - Kontextspezifische Presets (Welcome, Tags, Birthdays, Leveling, TempVoice, Stats, Feeds, Scheduler)
- Welcome-DM nutzt jetzt dieselben Platzhalter wie Welcome-Text (nicht nur
{user})
Manuell testen
- Welcome: Liste aufklappen, Platzhalter kopieren, in Embed/Text einfügen
- Tags/Birthdays/Leveling/Stats/Feeds/Scheduler: nur die jeweiligen Tokens sichtbar
Post-Phase – Components V2 (Status: implementiert, manuelle Tests offen)
Abgeschlossen (Code)
- Shared Zod:
MessageComponentsV2+ Actions,COMPONENTS_V2für Welcome/Tags, Leave-Typen, custom_idcv2:{source}:{ref}:{actionId} - Prisma-Migration
20260722220000_components_v2:welcomeComponents/leaveType/leaveComponents,Tag.components,ScheduledMessage.components,ComponentMessageBinding - Bot:
buildComponentsV2Payload, Anbindung Welcome/Leave/Tags/Scheduler, Interaction-Handler, Dashboard-Send-Queuemessages/dashboardMessageSend - Slash:
/embed builder+/embed components(Quick-V2) - WebUI:
DiscordComponentsV2Builder, Mode-Switches Welcome/Tags/Scheduler, Dashboard-Seite/messages
Manuell testen
- Welcome V2 mit Container + Thumbnail-Section + Link-Button + Toggle-Role-Button
- Tag V2 mit String-Select → ephemeral reply
- Scheduler V2 Ankündigung
- Dashboard Messages: Embed + Components V2 senden
- Slash
/embed components - Bestehende Embeds unverändert
- Migration anwenden (
prisma migrate deploy) und Bot/WebUI neu bauen
Bewusst offen
- Modal-only Components, File-Component, Premium-Buttons (nicht im MVP)
- Pixelgenaue Discord-Vorschau im Dashboard
Post-Phase – Harden (Sharding / Gates / Observability) (Status: implementiert)
Abgeschlossen (Code)
- Confirmations (Moderation + Guildbackup) in Redis mit TTL statt Prozess-
Map - Command-Registrierung einmal im Manager (Redis-Lock); Recurring Jobs einmal (Primary-Shard + Lock)
- Modul-Toggles + FeatureFlags + User-/Guild-Blacklists im Bot erzwungen (
routeCommand, Events, GuildCreate leave) - Moderation: Hierarchy-Checks, Duration vor Ban-Confirm, Timeout-Cap 28d, warn remove guild-scoped, atomare Case-Nummern, Temp-Ban Job-Dedup + UNBAN-Case,
setDefaultMemberPermissions - Sentry (
@sentry/node) in Bot + WebUI (instrumentation.ts); echte Prometheus-Metrics (/metrics) - Interaction-Registry statt if-Kette; Unit-Tests für Duration, Confirm-Store, Module-Gates, Metrics
Manuell testen
- Ban mit Dauer: Confirm auf anderem Shard / nach Restart innerhalb TTL
- Dashboard: Modul Moderation aus →
/banantwortet „Modul deaktiviert“ - Owner: User-Blacklist → Interactions blockiert; Guild-Blacklist → Bot verlässt Server
/metricsmit Bearer-Token: Counters + Shard-Ping- Temp-Ban ablaufen → Unban + Case
UNBAN
Bewusst offen
- Musik- und KI-Modul (nur auf Zuruf)
- Premium-Zahlungsanbindung
- P4-UX (Server-Lock, Ban deleteMessageSeconds) bewusst nachgelagert
Post-Phase – Verification Captcha-Anbieter + Alt-Erkennung (Status: implementiert)
Abgeschlossen (Code)
- Captcha-Anbieter wählbar pro Guild:
MATH,RECAPTCHA_V2,RECAPTCHA_V3,HCAPTCHA,TURNSTILE - Google/hCaptcha/Turnstile Keys in
.env(WebUI); Dashboard zeigt nur konfigurierte Anbieter - Captcha-Seite
/verify/captchamit Provider-Widgets; Server-side Siteverify - Alt-Account-Erkennung: gesalzener IP-Hash (Captcha-Flow) + Invite-Cluster; optional blockieren via
failAction - Prisma
VerificationRecord+ Config-Felder; Migration20260723120000_verification_captcha_alt - Slash
/verify setup:captcha_provider,alt_detection
Manuell testen
.env:RECAPTCHA_SITE_KEY/SECRETsetzen → Dashboard zeigt reCAPTCHA v2/v3- Guild Captcha-Modus + Anbieter wählen → Verify-Button → WebUI Captcha → Rolle
- Alt-Erkennung an: zweiter Account gleiche IP → Kick/Ban je nach failAction
- Migration:
prisma migrate deploy+ Bot/WebUI neu bauen CAPTCHA_IP_HASH_SALTgesetzt (min. 16 Zeichen), sonst keine IP-Alt-Signale
Bewusst offen
- Kein Browser-Fingerprinting (DSGVO); IP nur gehasht mit Salt
- Keine manuelle „Alt freigeben“-UI (nur Flag in
VerificationRecord)
Post-Phase – Leveling Rollen-Belohnungen UI (Status: implementiert)
Abgeschlossen (Code)
- Dashboard Leveling: Level→Rolle-Belohnungen bearbeiten (Liste, speichern ersetzt
LevelReward) - Shared Schema
rewards+hasUniqueRewardLevels; i18n DE/EN - Stapel-Toggle mit Hinweis neben dem Belohnungs-Editor
Manuell testen
- Belohnung hinzufügen (z. B. Level 5 → Rolle), speichern, Mitglied levelt → Rolle vergeben
- Stack an/aus: stapeln vs. nur aktuelle Belohnungsrolle
- Doppeltes Level → Fehlermeldung, speichern blockiert
Post-Phase – Giveaway Bugs (Timestamp + End-Status) (Status: implementiert)
Abgeschlossen (Code)
- Embed: Endzeit als Discord-Timestamp in der Description (Footer rendert
<t:…>nicht) /giveaway endwirft bei fehlender/bereits beendeter ID Fehler statt Fake-Erfolg- Dashboard „Jetzt beenden“ prüft
endedAtnach Job; Timeout/Fehler → kein Erfolgs-Toast
Manuell testen
- Neues Giveaway: Endzeit als „in X Stunden“ sichtbar, nicht als Roh-
<t:…> /giveaway endmit falscher ID → Fehlermeldung; mit korrekter ID → Reroll möglich- Dashboard „Jetzt beenden“ → Status beendet, Discord-Nachricht aktualisiert
Post-Phase – Audit Remediation (Reliability + Security) (Status: implementiert)
Abgeschlossen (Code)
- Scheduler: Self-Remove des aktiven Jobs entfernt; safeRemove für externe Cancels
- Channel-Picker: Fehler/leere Responses nicht cachen; Error+Reload wie Rollen
requirePermission: Member- vs. Bot-Permissions getrennt; Defer auf Ban/Purge/Lock/Backup/Giveaway/Media/Translate- Giveaway: atomares End (
updateMany), Pause cancel/reschedule, Dashboard Pause/Delete via BullMQ - Component-/Context-Gates: Maintenance + Modul-Toggle
- Owner-Guild-Bypass ab SUPPORT; OAuth
refresh_token+ Session-Refresh - Queue safeRemove (Temp-Ban, Reminders, Selfroles);
addJobAndAwaitrethrowt Enqueue-Fehler - DefaultMemberPermissions für Admin-Commands; Cooldown erst nach erfolgreichem Execute
- API: BadRequest/Upstream-Errors; Discord Roles/Channels 401/403/429/502
Manuell testen
- One-shot Schedule sendet einmal (kein Doppel-Post nach Worker-Retry)
- Channel-Dropdown bei API-Fehler: Retry statt permanent „Keine Treffer“
- Giveaway Pause im Dashboard → Button disabled; Unpause → Timer weiter; End trotz Pause
- Modul aus → Join-Button / Ticket-Panel antwortet „Modul deaktiviert“
- VIEWER-Owner ohne Manage Guild: kein Dashboard-Guild-Zugriff; SUPPORT+: Bypass
- Session nach Token-Ablauf refresht ohne erzwungenen Re-Login (mit gültigem refresh_token)
Post-Phase – Giveaway End Fix + Role Picker (Status: implementiert)
Abgeschlossen (Code)
- Root cause:
endGiveawayremoved its own locked BullMQ job → End-Job crashte vor DB-Update (Timer/UI/Command hingen) cancelGiveawayJobnur noch außerhalb des Workers (Command/Dashboard); locked remove wird ignoriert- Dashboard-End nutzt eindeutige Job-IDs (
giveaway-end-now-…); klarere 502-Fehler statt generischem 500 - Bot-Start:
recoverOverdueGiveawaysbeendet überfällige aktive Giveaways - Role-Picker: kein Cache von leeren/fehlerhaften Responses; Redis-Cache best-effort; manuelle Filter statt cmdk-Default
Manuell testen
- Giveaway starten (kurz), warten bis Timer abläuft → Embed „Beendet“, Button weg, Gewinner gezogen
- Giveaway vorzeitig per Dashboard „Jetzt beenden“ → kein Internal Server Error
/giveaway list→ ID kopieren →/giveaway end id:…→ Erfolg- Verifizierung: Rollen-Dropdown zeigt Serverrollen (nicht nur „Keine Treffer“)
- Nach Deploy: bereits hängende Giveaways werden beim Bot-Start recovered
Post-Phase – Starboard Verbesserungen (Status: implementiert)
Abgeschlossen (Code)
/starboard setupfunktioniert trotzenabled: false(Gate-Ausnahme)- Kanal-Permission-Check vor Setup;
/starboard status - Sync: Source-Delete/Bulk-Delete, Message-Edit, RemoveAll/RemoveEmoji
- Race-sicheres Create + Recreate wenn Starboard-Msg fehlt
- Zod/UI: Emoji bis 80 Zeichen, Threshold 1–100, Channel Pflicht bei enabled, NSFW-Hinweis
- Unit-Tests
emojiMatches/shouldIgnoreMessage
Manuell testen
/starboard setupauf frischem Server ohne Dashboard-Toggle- Stern ≥ Schwelle → Post; unter Schwelle → Post entfernt
- Original löschen/editieren → Starboard aktualisiert/entfernt
- Dashboard: aktivieren ohne Kanal → Fehler
Post-Phase – Welcome Embed Mentions + Autorole + Preview (Status: implementiert)
Abgeschlossen (Code)
- Embed
{user}in Titel/Author/Footer als Displayname (Discord resolved Mentions dort nicht) - Beschreibung/Content behalten
<@id>-Mentions - Autorole: Rollen nachladen, managed/@everyone filtern,
editable-Check, Warn-Logs bei Hierarchy/Permission - WebUI Embed-/Components-Vorschau: echte Session-User- + Guild-Daten statt Dummy
@Alex
Manuell testen
- Welcome-Embed Titel
Welcome {user}→ Anzeigename, nicht<@id> - Beschreibung
{user}→ klickbare Mention - User-Autorollen gesetzt, Bot-Rolle über Autorolle, Manage Roles → Rolle bei Join
- Dashboard Welcome-Embed-Vorschau zeigt eigenen Namen/Avatar und Servername/-icon
Post-Phase – Owner Guild-Liste Meta + Invite (Status: implementiert)
Abgeschlossen (Code)
- Owner
/owner/guilds: Discord-Name, Icon, Member-Count, ID (Live-Meta via Bot-Token, Redis-Cache) - Suche nach Name und ID
- Aktion „Invite erstellen“ (Systemkanal zuerst, max. 24h / 5 Uses, Clipboard + Owner-Audit)
Manuell testen
- Serverliste zeigt Name/Logo/Mitglieder statt nur ID
- Suche nach Servername filtert
- Invite erstellen → Link im Toast/Clipboard; Bot braucht Create Instant Invite
Post-Phase – Owner Guild-Dashboard Bypass (Status: implementiert)
Abgeschlossen (Code)
- Owner-Team (jede Owner-Rolle) kann jedes Guild-Dashboard öffnen, in dem der Bot installiert ist — ohne Discord „Server verwalten“
requireGuildAccess/ Layout nutzen Owner-Bypass; Guild-Meta via Bot-API wenn nicht in OAuth-Liste- Owner
/owner/guilds: Button „Dashboard öffnen“; Hinweisbanner im Guild-Dashboard bei Bypass
Manuell testen
- Owner-UI → Server → Dashboard öffnen (Server, auf dem man kein Member/Manager ist)
- Welcome/Settings speichern funktioniert; Banner „Owner-Zugriff“ sichtbar
- Nicht-Owner ohne Manage Guild → weiterhin kein Zugriff
Post-Phase – Owner Presence WebUI Polish (Status: implementiert)
Abgeschlossen (Code)
- PresenceForm: Live-Vorschau, i18n-Enums, Zeichenzähler, Switch+Confirm für Wartung, Hinweise
- Sofort-Apply: WebUI enqueued
presenceRefreshnach Save - Wartungsmodus: Discord DND + Wartungstext (keine Rotation)
- VIEWER read-only auf
/owner/presence(Save nur ADMIN+)
Manuell testen
- Status/Text speichern → Discord-Präsenz innerhalb weniger Sekunden
- Rotierende Zeilen → Vorschau erste Zeile; Job rotiert weiter
- Wartung an → Confirm, Discord zeigt Wartungstext, kein Rotating
- VIEWER sieht Formular, kann nicht speichern
Post-Phase – Owner About /about (Status: implementiert)
Abgeschlossen (Code)
- Core-Command
/about(neben SPEC-/info); Help-Katalog + Locales DE/EN - Prisma
BotAboutConfigSingleton + Migration20260724120000_bot_about - Owner
/owner/about: TEXT / Embed / Components V2 (Builder), Redis-Cache, Audit - Components-V2-Source
afür Button-Interaktionen aus/about
Manuell testen
- Migration deploy + Bot/WebUI neu bauen
- Owner About Embed speichern →
/aboutzeigt Embed - About deaktivieren → Deaktiviert-Hinweis
/infounverändert technisch
Post-Phase – Automod/Moderation Dashboard Ausbau (Status: implementiert)
Abgeschlossen (Code)
- Automod: alle 10 Filterregeln im Dashboard (Aktion, Schwellen, Link-WL/BL, Wörter/Regex, Ausnahmen)
- Lockdown an/aus enqueued
activateLockdown/deactivateLockdownan den Bot - Anti-Raid-Aktion
VERIFY(Unverified-Rolle) zusätzlich zuLOCKDOWN - Moderation: Warn-Tabelle + Case edit/delete im Dashboard
/lock/unlockOptionserverfür guild-weiten Lock- Shared:
AutomodRuleDashboardSchema,CaseUpdateDashboardSchema,AntiRaidActioninkl. VERIFY
Manuell testen
- Automod: WORD_FILTER Wörter setzen, EXTERNAL_LINK Whitelist, Regel speichern → Filter greift
- Lockdown-Toggle aus → Kanäle wieder beschreibbar
- Anti-Raid VERIFY: Unverified-Rolle in Verification konfiguriert, Join-Welle → Rolle
- Cases: Grund editieren / löschen; Warnings entfernen
/lock server:trueund/unlock server:true
Post-Phase – Selfroles WebUI → Discord Sync (Status: implementiert)
Abgeschlossen (Code)
- Root cause: Dashboard speicherte Selfrole-Panels nur in Postgres, ohne BullMQ-Job an den Bot
- Neue Queue
selfrolesmit JobsselfRolePanelCreate/Update/Delete - WebUI wartet (bounded) auf Bot-Bestätigung; Panel hat danach
messageId - Update zieht fehlende Discord-Nachricht nach (auch für Alt-Panels ohne
messageId) - Roles-JSON
{ entries }wird im Dashboard korrekt gelesen
Manuell testen
- WebUI: Panel erstellen → Embed/Buttons erscheinen im gewählten Channel
- Panel editieren (Titel/Rollen) → Discord-Nachricht aktualisiert sich
- Channel wechseln → alte Nachricht weg, neue im Zielkanal
- Panel löschen → Discord-Nachricht entfernt
- Alt-Panel ohne Message speichern → Nachricht wird nachgezogen
Post-Phase – Selfroles Role-Builder (Status: implementiert)
Abgeschlossen (Code)
- Textarea
roleId | label | emojidurch zeilenbasierten Builder ersetzt DiscordRoleSelect+ Label/Beschreibung-Felder +DiscordEmojiSelect(Server-CDN + Unicode)- API
GET /api/guilds/[guildId]/emojisinkl. Redis-Cache; SharedDiscordEmojiOption - Reaktions-Modus: Emoji je Rolle vor Save Pflicht
- Emoji-Picker Discord-ähnlich: 9er-Grid, Kategorie-Sidebar, Vollsatz via
@emoji-mart/data, Hautfarben, Suche
Manuell testen
- Panel mit Role-Picker, Label, Server-Emoji und Unicode speichern → Discord-Nachricht korrekt
- Dropdown: optionale Beschreibung erscheint in den Select-Optionen
- REACTIONS ohne Emoji → Toast, kein Save
- Bestehende Panels mit Custom-Emoji-Strings laden und editieren
- Emoji-Picker: Kategorien scrollen, Suche, Hautfarbe, Server-Grid
Nächster geplanter Schritt
- Deploy auf Traefik-Server manuell verifizieren; danach ggf.
deploy→mainmergen (nur auf Freigabe).
Post-Phase – Verification Panel aus WebUI (Status: implementiert)
Abgeschlossen (Code)
- Root cause: Dashboard speicherte nur
VerificationConfig, ohne Panel in Discord zu posten - Neuer BullMQ-Job
verificationPanelSync(Queueverification); WebUI wartet bounded auf Bot-Bestätigung syncVerificationPanelshared für/verify panelund Dashboard (Edit bei gleichem Kanal, sonst neu posten)- i18n DE/EN: Hinweis in Modul-Beschreibung + Fehlertexte bei Panel-Sync-Fail
Manuell testen
- WebUI: Verifizierung aktivieren, Kanal + Rolle setzen, Speichern → Panel erscheint im Kanal
- Speichern mit geändertem Modus → bestehendes Panel wird aktualisiert
- Kanal wechseln und speichern → altes Panel weg, neues im Zielkanal
- Bot ohne Send-Permission → Fehlermeldung; Config bleibt gespeichert, erneutes Speichern nach Fix
Post-Phase – Ticket Panel aus WebUI + Kategorie-Emoji-Picker (Status: implementiert)
Abgeschlossen (Code)
- Root cause: Dashboard speicherte Ticket-Config/Kategorien ohne Panel in Discord
- Prisma
TicketConfig.panelChannelId/panelMessageId; Migration20260725160000_ticket_panel - BullMQ-Job
ticketPanelSync(Queuetickets); Sync auch bei Kategorie create/update/delete syncTicketPanelshared für/ticket panel_createund Dashboard; Custom-Emoji-Parsing für Buttons/Select- WebUI: Panel-Kanal-Picker;
DiscordEmojiSelectin Kategorie-Erstellung und -Bearbeitung - Emoji-Zod max 80 (Custom-Emoji-Format)
Manuell testen
- WebUI: Kategorie(n) anlegen, Panel-Kanal setzen, Speichern → Panel mit Buttons im Kanal
- Kategorie mit Emoji-Picker (Unicode + Server-Emoji) speichern → Button zeigt Emoji
- Kategorie ändern/löschen → Panel-Buttons aktualisieren sich
- Panel-Kanal wechseln → altes Panel weg, neues im Zielkanal
Post-Phase – Ticket Support-Ping + Control-Panel (Status: implementiert)
Abgeschlossen (Code)
- Support-Rollen: Member-Cache nachladen (
guild.members.fetch), bis 50 Staff in Private Threads adden - Ticket-Eröffnung pingt Support-Rollen (
allowedMentions.roles) - Control-Panel im Ticket: Claim, Close, User-Select Add/Remove (wie TempVoice-Pattern)
- Opener darf schließen; Claim/Add/Remove nur Support-Staff
- Prioritäts-Dropdown im Discord-Control-Panel (
ticket:ctrl:priority) - Robustheit: Unknown Channel (10003) beim Close nur noch debug; Unknown Member (10007) bei Add/Remove/Interactions abgefangen; Ticket-Commands nutzen
ephemeral()flags
Manuell testen
- Ticket öffnen (Thread) → Support-Rolle wird gepingt, Staff erscheinen im Thread
- Ticket öffnen (Channel) → Support-Rolle gepingt, Rolle hat Kanal-Zugriff
- Control-Panel: Claim / Close / User hinzufügen / entfernen
- Opener kann schließen; Nicht-Staff kann nicht claimen
Post-Phase – Offene Tickets im WebUI (Status: implementiert)
Abgeschlossen (Code)
- Liste offener Tickets (
OPEN/CLAIMED) auf der Tickets-Seite - Aktionen: In Discord öffnen, Übernehmen, Schließen (optionaler Grund), Priorität setzen
- BullMQ-Job
ticketDashboardAction; Shared ZodTicketDashboard/TicketDashboardAction - API
GET …/tickets/open,POST …/tickets/open/[ticketId]/action
Manuell testen
- Ticket öffnen → erscheint in der WebUI-Liste
- Claim / Priority aus Dashboard → Nachricht im Ticket-Kanal
- Close aus Dashboard → Ticket verschwindet aus der Liste, Kanal/Thread wird geschlossen
- Refresh-Button aktualisiert die Liste
Post-Phase – Ticket Support-Rollen Speichern (Bugfix)
Abgeschlossen (Code)
- Root cause: Kategorie-Save warf Fehler wenn Panel-Sync scheiterte → UI „Speichern fehlgeschlagen“, obwohl
supportRoleIdsschon in Postgres lagen maybeSyncTicketPanelfängt Sync-Fehler ab; Kategorie-CRUD bleibt erfolgreich- Nach Speichern: Response inkl.
supportRoleIdsin die UI übernommen - Zod:
supportRoleIdsjetztSnowflakeSchema[]
Manuell testen
- Kategorie: Support-Rolle wählen → Speichern → Erfolgstoast
- Seite neu laden → Rolle ist noch ausgewählt
- Neues Ticket → Support-Rolle wird gepingt / in Thread aufgenommen
Post-Phase – Ban/Kick-Reason Logging + Verification Fail Event (Status: implementiert)
Abgeschlossen (Code)
- Root cause Ban/Kick-Reason im Log: Discord sendet Reasons nicht über Gateway (
ban.reasonwar immer leer) MEMBER_BAN/ Kick-MEMBER_LEAVElesen Reason + Moderator jetzt aus dem Audit-Log- Ephemere Success-Antworten für Ban/Kick/Timeout zeigen den Grund mit
- Neuer Log-Event-Typ
VERIFICATION_FAIL(Shared + WebUI-Picker DE/EN) - Alt-Check / Account-zu-jung schreiben ins Logging (
logVerificationFail); auch Flag-only ohne Block
Manuell testen
/kickmit Reason → Log-Kanal (MEMBER_LEAVE) zeigt Reason + Moderator/banmit Reason → Log-Kanal (MEMBER_BAN) zeigt Reason + Moderator; Bot braucht „Audit-Log anzeigen“- Logging:
VERIFICATION_FAILeinem Kanal zuordnen - Alt-Check mit Block → User sieht Fehler-Ephemeral; Log-Kanal bekommt Embed
- Alt-Check nur Flag (ohne Block) → User wird verifiziert, Log trotzdem