Files
Nexumi/docs/PHASE-TRACKING.md
TheOnlyMace 67ac16d36b Refactor self-role management to use a role builder interface
- Replaced the text area for role input with a structured role builder, enhancing user experience and reducing input errors.
- Updated the self-role management logic to handle roles as structured objects instead of plain text, improving data integrity.
- Introduced new functions for parsing and validating roles, ensuring compliance with the new builder format.
- Enhanced error handling for role creation and updates, providing clearer feedback for missing or invalid data.
- Updated localization files to reflect changes in role management terminology and instructions.
2026-07-25 15:53:27 +02:00

466 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 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`, Entrypoint `websecure`, `certresolver=letsencrypt`
- Host-Port `3000` entfernt; 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; `/login` leitet 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` (Netz `traefik-network` muss existieren)
- [ ] TLS-Zertifikat (Resolver-Name ggf. an Traefik anpassen)
- [ ] Login `/` → Dashboard; Session-Cookie `Secure`
## 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 Job `retention`/`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
- [ ] `/privacy` und `/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_V2` für Welcome/Tags, Leave-Typen, custom_id `cv2:{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-Queue `messages`/`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 → `/ban` antwortet „Modul deaktiviert“
- [ ] Owner: User-Blacklist → Interactions blockiert; Guild-Blacklist → Bot verlässt Server
- [ ] `/metrics` mit 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/captcha` mit Provider-Widgets; Server-side Siteverify
- Alt-Account-Erkennung: gesalzener IP-Hash (Captcha-Flow) + Invite-Cluster; optional blockieren via `failAction`
- Prisma `VerificationRecord` + Config-Felder; Migration `20260723120000_verification_captcha_alt`
- Slash `/verify setup`: `captcha_provider`, `alt_detection`
### Manuell testen
- [ ] `.env`: `RECAPTCHA_SITE_KEY`/`SECRET` setzen → 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_SALT` gesetzt (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 end` wirft bei fehlender/bereits beendeter ID Fehler statt Fake-Erfolg
- Dashboard „Jetzt beenden“ prüft `endedAt` nach Job; Timeout/Fehler → kein Erfolgs-Toast
### Manuell testen
- [ ] Neues Giveaway: Endzeit als „in X Stunden“ sichtbar, nicht als Roh-`<t:…>`
- [ ] `/giveaway end` mit 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); `addJobAndAwait` rethrowt 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: `endGiveaway` removed its own locked BullMQ job → End-Job crashte vor DB-Update (Timer/UI/Command hingen)
- `cancelGiveawayJob` nur 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: `recoverOverdueGiveaways` beendet ü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 setup` funktioniert trotz `enabled: 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 1100, Channel Pflicht bei enabled, NSFW-Hinweis
- Unit-Tests `emojiMatches` / `shouldIgnoreMessage`
### Manuell testen
- [ ] `/starboard setup` auf 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 `presenceRefresh` nach 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 `BotAboutConfig` Singleton + Migration `20260724120000_bot_about`
- Owner `/owner/about`: TEXT / Embed / Components V2 (Builder), Redis-Cache, Audit
- Components-V2-Source `a` für Button-Interaktionen aus `/about`
### Manuell testen
- [ ] Migration deploy + Bot/WebUI neu bauen
- [ ] Owner About Embed speichern → `/about` zeigt Embed
- [ ] About deaktivieren → Deaktiviert-Hinweis
- [ ] `/info` unverä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` / `deactivateLockdown` an den Bot
- Anti-Raid-Aktion `VERIFY` (Unverified-Rolle) zusätzlich zu `LOCKDOWN`
- Moderation: Warn-Tabelle + Case edit/delete im Dashboard
- `/lock` `/unlock` Option `server` für guild-weiten Lock
- Shared: `AutomodRuleDashboardSchema`, `CaseUpdateDashboardSchema`, `AntiRaidAction` inkl. 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:true` und `/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 `selfroles` mit Jobs `selfRolePanelCreate` / `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 | emoji` durch zeilenbasierten Builder ersetzt
- `DiscordRoleSelect` + Label/Beschreibung-Felder + `DiscordEmojiSelect` (Server-CDN + Unicode)
- API `GET /api/guilds/[guildId]/emojis` inkl. Redis-Cache; Shared `DiscordEmojiOption`
- Reaktions-Modus: Emoji je Rolle vor Save Pflicht
### 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
## Nächster geplanter Schritt
- Deploy auf Traefik-Server manuell verifizieren; danach ggf. `deploy``main` mergen (nur auf Freigabe).