# Discord Bot

Der GSM Discord Bot bietet Live-Status-Updates für alle Gameserver direkt in Discord. Der Bot kann auf mehreren Discord-Servern gleichzeitig laufen.

## Features

- **Live-Status**: Automatisch aktualisiertes Embed mit Server-Status, Spielerzahlen und Metriken
- **Alerts**: Benachrichtigungen wenn Server online/offline gehen oder Spieler joinen/leaven
- **Multi-Guild**: Kann auf beliebig vielen Discord-Servern eingesetzt werden
- **Auto-Setup**: Erstellt automatisch alle nötigen Channels beim Beitreten

## Bot einladen

### Invite-Link

```
https://discord.com/oauth2/authorize?client_id=1458251194806833306&permissions=34359831568&integration_type=0&scope=bot+applications.commands
```

Der Link ist auch im GSM Dashboard unter den Server-Cards verfügbar.

### Benötigte Permissions

| Permission | Verwendung |
|------------|------------|
| View Channels | Channels sehen |
| Manage Channels | Channels erstellen |
| Send Messages | Nachrichten senden |
| Manage Messages | Eigene Nachrichten bearbeiten |
| Embed Links | Rich Embeds für Status |
| Read Message History | Alte Nachrichten lesen |
| Create Public Threads | Forum-Threads erstellen |

## Automatisch erstellte Channel-Struktur

Wenn der Bot einem Server beitritt, erstellt er automatisch folgende Struktur:

```
🎮 Gameserver (Kategorie)
├── ℹ️│info          - Informationen zum GSM System
├── 📊│status        - Live-Status aller Gameserver (Auto-Update)
├── 📢│alerts        - Server-Events und Spieler-Benachrichtigungen
├── 📰│updates       - Ankündigungen zu neuen Gameservern
├── 💬│diskussion    - Diskussions-Channel (User können schreiben)
└── 💡│requests      - Forum für Gameserver-Vorschläge
```

### Channel-Permissions

| Channel | @everyone | Bot |
|---------|-----------|-----|
| Kategorie | Lesen | ViewChannel + Schreiben |
| info | Lesen (kein Schreiben) | ViewChannel + Schreiben |
| status | Lesen (kein Schreiben) | ViewChannel + Schreiben |
| alerts | Lesen (kein Schreiben) | ViewChannel + Schreiben |
| updates | Lesen (kein Schreiben) | ViewChannel + Schreiben |
| diskussion | Lesen + Schreiben | ViewChannel + Schreiben |
| requests | Lesen + Threads erstellen | ViewChannel + Schreiben |

**Wichtig**: Der Bot braucht explizit `ViewChannel` Permission für jeden Channel, auch wenn @everyone den Channel sehen kann. Ohne `ViewChannel` kann der Bot nicht in den Channel schreiben ("Missing Access" Fehler).

## Datenbank

### guild_settings Tabelle

Speichert die Channel-IDs für jeden Discord-Server:

```sql
CREATE TABLE guild_settings (
  guild_id TEXT PRIMARY KEY,
  category_id TEXT,
  info_channel_id TEXT,
  status_channel_id TEXT,
  status_message_id TEXT,
  alerts_channel_id TEXT,
  updates_channel_id TEXT,
  discussion_channel_id TEXT,
  requests_channel_id TEXT,
  requests_info_thread_id TEXT,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
```

Die Datenbank liegt in `backend/db/users.sqlite`.

### DB-Funktionen

In `backend/db/init.js`:

```javascript
initGuildSettings()           // Tabelle erstellen
getGuildSettings(guildId)     // Settings für einen Server
getAllGuildSettings()         // Alle Server-Settings
setGuildSettings(guildId, {}) // Settings speichern
deleteGuildSettings(guildId)  // Settings löschen (bei Bot-Kick)
```

## Bot-Events

### guildCreate

Wird ausgelöst wenn der Bot einem neuen Server beitritt:

1. Erstellt Kategorie und alle Channels
2. Postet Info-Nachricht im `ℹ️│info` Channel
3. Erstellt Info-Thread im `💡│requests` Forum
4. Speichert alle Channel-IDs in der Datenbank
5. Sendet erste Status-Nachricht

### guildDelete

Wird ausgelöst wenn der Bot von einem Server entfernt wird:

1. Löscht alle Settings aus der Datenbank

## Status-Updates

Der Bot aktualisiert die Status-Nachricht in allen registrierten Guilds alle 30 Sekunden:

```javascript
async function updateAllGuildStatus() {
  const guilds = getAllGuildSettings();
  for (const guild of guilds) {
    await updateGuildStatus(guild);
  }
}
```

Jeder Server bekommt ein eigenes Embed mit:
- Server-Name und Status (Online/Offline)
- Aktuelle Spielerzahl
- CPU und RAM Auslastung
- Verbindungsadresse

## Konfiguration

### Umgebungsvariablen (.env)

```env
DISCORD_CLIENT_ID=1458251194806833306
DISCORD_CLIENT_SECRET=xxx
DISCORD_BOT_TOKEN=xxx

# Multi-Server OAuth Login
# User muss nur in EINEM der Server Mitglied sein
# Rollen werden pro Server geprüft, höchste Berechtigung zählt

# Server 1: Bacanaks
DISCORD_GUILD_ID_1=729865854329815051
DISCORD_ADMIN_ROLE_ID_1=1024693717434650736
DISCORD_MOD_ROLE_ID_1=1024693170958766141

# Server 2: Piccadilly
DISCORD_GUILD_ID_2=730907665802330224
DISCORD_ADMIN_ROLE_ID_2=1458595551514988584
DISCORD_MOD_ROLE_ID_2=1458591909210488914
```

**Hinweis**: Die Guild-IDs werden nur für den Discord OAuth Login verwendet, nicht für den Bot selbst.

### OAuth Login-Logik

```
1. User loggt sich via Discord OAuth ein
2. Für jeden konfigurierten Server:
   - Ist User Mitglied? → Rollen prüfen
   - Admin-Rolle → superadmin
   - Mod-Rolle → moderator
   - Nur Mitglied → user
3. Höchste Berechtigung aus allen Servern wird verwendet
4. Nicht in mindestens einem Server → Login verweigert
```

| User ist in... | Bacanaks Rolle | Piccadilly Rolle | GSM Rolle |
|----------------|----------------|------------------|-----------|
| Nur Bacanaks | Admin | - | superadmin |
| Nur Piccadilly | - | Mod | moderator |
| Beide | Mitglied | Admin | superadmin |
| Keinem | - | - | ❌ Kein Login |

### Developer Portal Einstellungen

1. Gehe zu https://discord.com/developers/applications
2. Wähle die Bot-Application
3. **Bot** Tab:
   - "Public Bot" aktivieren (damit andere einladen können)
   - Privileged Gateway Intents:
     - Server Members Intent: Optional
     - Message Content Intent: Nicht benötigt

## Dateien

| Datei | Beschreibung |
|-------|--------------|
| `backend/services/discord.js` | OAuth-Logik, Multi-Guild Membership-Prüfung |
| `backend/services/discordBot.js` | Bot-Logik und Event-Handler |
| `backend/routes/auth.js` | Auth-Endpoints (Login, Callback, Refresh) |
| `backend/db/init.js` | Guild-Settings DB-Funktionen |
| `frontend/src/pages/Dashboard.jsx` | Invite-Button im Dashboard |

## Implementierungsdetails

### Multi-Guild OAuth

Die OAuth-Implementierung in `discord.js` verwendet **lazy initialization** für die Guild-Konfigurationen:

```javascript
let _guildConfigs = null;

function getGuildConfigs() {
  if (_guildConfigs === null) {
    _guildConfigs = [
      { name: 'Bacanaks', guildId: process.env.DISCORD_GUILD_ID_1, ... },
      { name: 'Piccadilly', guildId: process.env.DISCORD_GUILD_ID_2, ... }
    ].filter(config => config.guildId);
  }
  return _guildConfigs;
}
```

**Wichtig**: Die Konfiguration darf NICHT beim Modul-Import initialisiert werden, da zu diesem Zeitpunkt dotenv die `.env` noch nicht geladen hat. Die lazy initialization stellt sicher, dass die Umgebungsvariablen verfügbar sind.

### Funktionen

| Funktion | Beschreibung |
|----------|--------------|
| `getGuildMemberships(userId)` | Prüft alle konfigurierten Server, gibt Array von Memberships zurück |
| `getUserRoleFromMemberships(memberships)` | Bestimmt höchste Rolle aus allen Memberships |
| `getGuildMember(userId)` | Legacy-Funktion, gibt ersten Match zurück |
| `getUserRole(memberRoles)` | Legacy-Funktion für einzelne Rollen-Liste |

### Rollen-Priorität

```javascript
const ROLE_PRIORITY = { superadmin: 3, moderator: 2, user: 1 };
```

Bei mehreren Memberships wird immer die höchste Rolle verwendet.

### Voraussetzungen

- Der Bot muss auf **allen** konfigurierten Discord-Servern sein
- Der Bot braucht Zugriff auf die Guild Members API

## Troubleshooting

### Login schlägt fehl mit "nicht Mitglied"

1. **Bot auf allen Servern?** Der Bot muss auf Bacanaks UND Piccadilly eingeladen sein
2. **Env-Variablen prüfen**:
   ```bash
   grep GUILD /opt/gameserver-monitor/backend/.env
   ```
3. **Mit --update-env neustarten**:
   ```bash
   pm2 restart gameserver-backend --update-env
   ```
4. **Logs prüfen**:
   ```bash
   pm2 logs gameserver-backend --lines 30 | grep -i discord
   ```

### Rolle wird nicht erkannt

1. **Rollen-IDs prüfen** - Discord Developer Mode aktivieren, Rechtsklick auf Rolle → ID kopieren
2. **User-Rollen abfragen**:
   ```bash
   curl -s -H "Authorization: Bot BOT_TOKEN" \
     "https://discord.com/api/v10/guilds/GUILD_ID/members/USER_ID" | jq '.roles'
   ```
3. **Konfigurierte IDs vergleichen** mit den tatsächlichen Rollen des Users

### Bot erstellt keine Channels

- Prüfen ob Bot "Manage Channels" Permission hat
- Prüfen ob Bot-Rolle hoch genug in der Rollen-Hierarchie ist

### Status-Nachricht wird nicht aktualisiert

```bash
pm2 logs gameserver-backend --lines 50
```

Suche nach `[DiscordBot]` Log-Einträgen.

### Bot aus Datenbank entfernen

```bash
cd /opt/gameserver-monitor/backend
node -e "
import Database from 'better-sqlite3';
const db = new Database('./db/users.sqlite');
db.prepare('DELETE FROM guild_settings WHERE guild_id = ?').run('GUILD_ID_HIER');
console.log('Deleted');
"
```

Alternativ mit sqlite3 (falls installiert):
```bash
sqlite3 /opt/gameserver-monitor/backend/db/users.sqlite
DELETE FROM guild_settings WHERE guild_id = 'xxx';
```

### Missing Access Fehler

Wenn der Bot "Missing Access" meldet obwohl er eingeladen wurde:

1. **ViewChannel Permission prüfen**: Der Bot braucht explizit `ViewChannel` für jeden Channel
2. Im Discord: Rechtsklick auf Channel → Bearbeiten → Berechtigungen → Bot auswählen → "Kanal ansehen" aktivieren
3. Logs prüfen: `pm2 logs gameserver-backend --lines 50 | grep -i "missing\|access"`

### Status-Nachricht wurde gelöscht

Wenn die Status-Nachricht manuell gelöscht wurde, erscheint "Unknown Message" in den Logs. Fix:

```bash
cd /opt/gameserver-monitor/backend
node -e "
import Database from 'better-sqlite3';
const db = new Database('./db/users.sqlite');
// Status Message ID auf NULL setzen, Bot erstellt neue beim nächsten Update
db.prepare('UPDATE guild_settings SET status_message_id = NULL WHERE guild_id = ?').run('GUILD_ID_HIER');
console.log('Reset status_message_id');
"
```

## Login vs. Bot

| Feature | Login (OAuth) | Bot |
|---------|--------------|-----|
| Erfordert Mitgliedschaft | Bacanaks oder Piccadilly | Nein |
| Server-Steuerung | Ja (je nach Rolle) | Nein |
| Status sehen | Ja | Ja |
| Alerts erhalten | Nein | Ja |
| Verfügbar für | Mitglieder beider Discord-Server | Alle mit Bot |

Der Login zur Webapp erfordert Mitgliedschaft in mindestens einem der konfigurierten Discord-Server (Bacanaks oder Piccadilly). Die höchste Rolle aus beiden Servern bestimmt die GSM-Berechtigung. Der Bot ist davon unabhängig und zeigt nur passive Status-Updates.
