Eine R-/Shiny-Anwendung für DMUN e.V., die aus einem zentralen Masterplan für jede Person einen individuellen Zeitplan erzeugt und ihn per Slack-Direktnachricht verschickt. Statt jeder/jedem Teilnehmenden manuell den passenden Ausschnitt zu schicken, lädt man eine Tabelle hoch (oder bindet ein Google Sheet an), prüft die Treffer und versendet alles in einem Durchgang.
- Masterplan einlesen – als hochgeladene
.xlsxoder direkt aus einem Google Sheet. - Blatt und erste Personen-Spalte wählen – damit weiß die App, welche Spalten zur Programm-Beschreibung gehören und ab welcher Spalte die einzelnen Personen beginnen.
- Pro Person einen Zeitplan bauen – aus allen Programmzeilen, in denen die
jeweilige Person mit einer
1markiert ist. - Slack-Empfänger zuordnen – über einen Namens-Abgleich, mit Anzeige der Treffergüte und manueller Korrekturmöglichkeit.
- Versenden – als Slack-DM an die echten Nutzer oder testweise an einen Test-Channel.
Die Tabelle ist breit aufgebaut: links die Kopf-/Programmspalten, rechts je eine Spalte pro Person.
| Uhrzeit | Programmpunkt | Ort | Anna Berger | Jonas Keller | … |
|---|---|---|---|---|---|
| 09:00 | Anreise | Foyer | 1 | 1 | |
| 10:30 | Eröffnungsplenum | Saal A | 1 | ||
| 14:00 | Lobbying GV | Saal B | 1 | 1 |
- Alles links der gewählten „Erste Personen-Spalte" gilt als Kopfinformation und landet im Zeitplan jeder Person.
- Jede Personen-Spalte enthält eine
1in genau den Zeilen, an denen die Person teilnimmt. Leere Zellen werden automatisch als0behandelt. - Hat eine Person keine einzige
1, entsteht ein leerer Zeitplan (siehe unten). - Hinter dem Tag: wird der name des Blattes aus Excel/Google genommen
Beispiel-Ergebnis für Anna Berger:
Zeitplan für Anna Berger
Tag: Tag 1 – Mittwoch
09:00 Anreise Foyer
10:30 Eröffnungsplenum Saal A
14:00 Lobbying GV Saal B
Die Oberfläche (Bootstrap 5 / bslib) führt in vier nummerierten Schritten
durch Verbindung → Datenquelle → Nachrichten prüfen → Versenden. Ein
Hell-/Dunkel-Umschalter ist oben rechts verfügbar.
Die Zuordnung Masterplan-Name → Slack-Nutzer läuft über einen normalisierten, token-sortierten Jaro-Winkler-Vergleich kombiniert mit einer Token-Überschneidung. Damit werden zuverlässig erkannt:
- vertauschte Reihenfolge („Keller, Jonas" ↔ „Jonas Keller"),
- fehlende Zweit- bzw. Mittelnamen und Initialen,
- Umlaute und Akzente (locale-unabhängig, läuft auch im Container ohne UTF-8-Locale),
- kleinere Tippfehler.
Für jede Person zeigt die App die Ähnlichkeit in Prozent und eine farbige Bewertung:
- 🟢 Sicher (≥ 90 %)
- 🟡 Unsicher (75–89 %) – bitte kurz prüfen
- 🔴 Kein guter Treffer (< 75 %) – sehr wahrscheinlich kein passender Slack-Nutzer
Wichtig: Der Abgleich liefert immer einen Vorschlag, aber bei niedriger Ähnlichkeit ist das nur die „am wenigsten falsche" Wahl. Deshalb lässt sich pro Person der Slack-Empfänger über ein durchsuchbares Dropdown manuell korrigieren.
Jede Nachricht wird pro Empfänger als Karte mit Klartext-Vorschau angezeigt – so, wie sie in Slack ankommt. Über das Empfänger-Dropdown und den „Senden"-Schalter lässt sich jede Karte einzeln anpassen oder ausschließen.
Personen ohne einen einzigen Programmpunkt werden mit dem Hinweis „Leerer Zeitplan" markiert, aber nicht automatisch entfernt. Über den Button „Leere Zeitpläne ausschließen" lassen sich alle leeren mit einem Klick vom Versand ausnehmen; einzeln geht es weiterhin über den „Senden"-Schalter.
Solange „An Test-Channel senden" aktiv ist, gehen alle Nachrichten an den hinterlegten Test-Channel. Wird der Schalter deaktiviert, erscheint vor dem echten Versand eine Bestätigungsabfrage mit Übersicht (Anzahl sicherer, unsicherer, schlechter Treffer und leerer Zeitpläne). Erst nach „Senden bestätigen" werden die DMs verschickt.
Es ist kein Slack-Token fest hinterlegt. Über „Workspace wechseln"
öffnet sich ein Dialog, in den ausschließlich das Bot-Token (xoxb-…)
eingegeben wird. Das Token wird ausschließlich in der aktuellen
Browser-Session gehalten und nicht auf dem Server gespeichert (weder als
Umgebungsvariable noch in einer Konfigurationsdatei). Schließt man den Tab oder
läuft die Session aus, ist das Token weg. Jede:r Nutzer:in arbeitet so mit einem
eigenen, getrennten Slack-Kontext.
Nach dem Verbinden wird im Schritt „Versenden" ein Dropdown „Test-Channel"
befüllt. Es listet nur Channels, in denen der Bot Mitglied ist – nur dorthin
kann er zuverlässig posten. Damit ein Channel hier erscheint, muss der Bot zuvor
mit /invite @AppName in den Channel eingeladen werden (öffentliche wie private
Channels). Wird kein Test-Channel ausgewählt, bleibt der Button „Nachrichten
versenden" im Testmodus deaktiviert; ein Hinweistext (Hover über den Button)
nennt den Grund.
Nutzerliste und Channel-Dropdown werden beim Verbinden geladen. Mit „Slack-Daten aktualisieren" lassen sie sich neu abrufen, ohne das Token erneut eingeben zu müssen – nützlich, wenn kurz vorher neue Personen in den Workspace eingeladen oder der Bot in einen weiteren Channel aufgenommen wurde.
Über „Google-Tools" kann statt einer hochgeladenen Datei ein Google Sheet
als Datenquelle genutzt werden („Als input nutzen"). Zusätzlich gibt es eine
Mapping-Funktion, die Gruppen-Zuordnungen automatisch in individuelle
1-Markierungen umwandelt und ins Sheet zurückschreibt – ausführlich
beschrieben im Abschnitt Google-Mapping.
Die Abschlussmeldung nach dem Versand nutzt die lokale Zeit (Europe/Berlin) – keine Abhängigkeit mehr von einer externen Zeit-API.
Viele Tätigkeiten werden auf Gruppen-Ebene geplant („GV", „Presse",
„Vorbereitungsteam" …), während der Masterplan eine 1 pro Einzelperson
braucht. Das Google-Mapping nimmt einem diese Übersetzung ab: Es liest, welche
Gruppe(n) einem Programmpunkt zugeordnet sind, schlägt die Mitglieder der Gruppe
nach und trägt für jede dieser Personen automatisch eine 1 ein – direkt im
Google Sheet.
Die Funktion arbeitet mit zwei Blättern (Tabs) innerhalb desselben Google-Spreadsheets:
- Plan-Blatt – der eigentliche Zeitplan, in den die
1-Markierungen geschrieben werden. Aufbau wie ein normaler Masterplan (Kopfspalten links, eine Spalte je Person rechts) plus einer Spalte mit der Gruppen-Zuordnung. - Mapping-Blatt – eine einfache Nachschlage-Tabelle. Es zählen nur die
ersten beiden Spalten: Spalte 1 = Gruppenname, Spalte 2 =
Mitglieder als
;-getrennte Liste (die Namen müssen exakt den Personen-Spaltenüberschriften im Plan-Blatt entsprechen).
Mapping-Blatt (z. B. Tab „Mapping"):
| Gruppe | Mitglieder |
|---|---|
| GV | Anna Berger;Jonas Keller |
| Presse | Sophie Wagner |
Plan-Blatt vorher (Spalte „Gruppe" = Mapping-Spalte):
| Uhrzeit | Programmpunkt | Gruppe | Anna Berger | Jonas Keller | Sophie Wagner |
|---|---|---|---|---|---|
| 09:00 | Anreise | Alle | |||
| 10:30 | GV-Sitzung | GV | |||
| 14:00 | Pressekonferenz | Presse;GV |
Plan-Blatt nachher (durch das Mapping eingetragen):
| Uhrzeit | Programmpunkt | Gruppe | Anna Berger | Jonas Keller | Sophie Wagner |
|---|---|---|---|---|---|
| 09:00 | Anreise | Alle | 1 | 1 | 1 |
| 10:30 | GV-Sitzung | GV | 1 | 1 | |
| 14:00 | Pressekonferenz | Presse;GV | 1 | 1 | 1 |
Regeln, die dabei greifen:
- Mehrere Gruppen pro Zeile sind möglich, getrennt durch
;(z. B.Presse;GV) – die Mitglieder aller genannten Gruppen werden gesetzt. - Der Sonderwert
Alle(Groß-/Kleinschreibung egal) setzt eine1für alle Personen-Spalten dieser Zeile. - Zeilen, deren Gruppen-Zelle leer oder
0ist, werden übersprungen. - Spalten, deren Name mit
sumbeginnt, werden ignoriert. - Bereits vorhandene
1-Markierungen bleiben erhalten; das Mapping ergänzt nur.
- Google-Tools öffnen und die Sheet-ID des Spreadsheets eingeben. Das Service-Account (siehe Konfiguration) muss Bearbeitungsrechte auf das Sheet haben – das Mapping schreibt zurück, Leserechte allein genügen nicht.
- Auf „Sheet Mapping" klicken.
- Im Dialog die vier Angaben wählen:
- Wähle das Blatt – das Plan-Blatt, in das geschrieben wird.
- Wähle das Mapping-Blatt – die Nachschlage-Tabelle.
- Was ist der erste Name? – die erste Personen-Spalte im Plan-Blatt.
- Was ist die Mapping-Spalte? – die Spalte im Plan-Blatt mit der Gruppen-Zuordnung.
- „Mapping durchführen" – die App geht alle betroffenen Zeilen durch,
trägt die
1en ein und schreibt sie direkt ins Google Sheet. Eine Statuszeile meldet, welche Zeilen/Gruppen verarbeitet wurden. - Anschließend das Plan-Blatt wie gewohnt als Eingabe nutzen („Als input nutzen") und mit dem normalen Ablauf (Blatt + erste Personen-Spalte wählen → Nachrichten erstellen → versenden) fortfahren.
Hinweis: Da direkt ins Sheet geschrieben wird, empfiehlt sich vorher eine Sicherungskopie des Spreadsheets. Stimmen Mitgliedernamen im Mapping-Blatt nicht exakt mit den Spaltenüberschriften im Plan-Blatt überein, werden die betreffenden Personen nicht markiert.
Die App benötigt pro Workspace ein Bot-Token (beginnt mit xoxb-). So
erhältst du es:
- App anlegen – auf https://api.slack.com/apps einloggen (mit einem Account des Ziel-Workspaces), „Create New App" → „From scratch" wählen, einen aussagekräftigen Namen vergeben (z. B. „DMUN Zeitplan-Bot") und den Ziel-Workspace auswählen.
- Berechtigungen (Scopes) setzen – im linken Menü „OAuth & Permissions"
öffnen, zum Abschnitt „Bot Token Scopes" scrollen und über „Add an OAuth
Scope" folgende Scopes hinzufügen:
chat:write– Nachrichten / Direktnachrichten sendenusers:read– Nutzerliste abrufen (Grundlage für den Namens-Abgleich)channels:read,groups:read,im:read,mpim:read– Channels und Konversationen auflistenim:write– Direktnachricht-Konversationen öffnen
- App installieren – oben auf „Install to Workspace" klicken und mit „Allow" bestätigen.
- Token kopieren – unter „OAuth & Permissions" das „Bot User OAuth
Token" (
xoxb-…) kopieren. Es wird beim Verbinden direkt in den Dialog „Workspace wechseln" eingegeben (gilt nur für die Session). - Bot in den Test-Channel einladen – im gewünschten Test-Channel
/invite @DeinAppNameausführen. Das ist zwingend: nur Channels, in denen der Bot Mitglied ist, erscheinen in der App im Dropdown „Test-Channel" – und nur dorthin darf der Bot posten. Schritt für jeden weiteren Channel wiederholen, der als Test-Ziel nutzbar sein soll.
Hinweise:
- Bot-Token laufen nicht ab, können von Slack aber widerrufen werden – etwa wenn das Token öffentlich auftaucht. Token deshalb nie in den Code oder ins Repository schreiben.
- Direktnachrichten erscheinen beim Empfänger als Nachricht des Bots / der App, nicht als Nachricht einer echten Person. App-Name und -Icon daher sinnvoll wählen – genau das sehen die Empfangenden.
- Nach jeder Scope-Änderung muss die App erneut installiert werden, damit die neuen Berechtigungen greifen.
In dieser Version werden keine Slack-Zugangsdaten mehr über Umgebungsvariablen gesetzt – das Slack-Token gibt jede:r Nutzer:in zur Laufzeit ein (siehe „Workspace verbinden"). Es verbleiben nur optionale Variablen:
| Variable | Zweck |
|---|---|
GOOGLEAUTH_EMAIL |
Service-Account-E-Mail (Google Sheets) – optional |
GOOGLEAUTH_SECRET |
Privater Schlüssel des Service-Accounts – optional |
TZ |
Zeitzone des Containers (Europe/Berlin) |
Sind die Google-Variablen leer, startet die App trotzdem; die „Google-Tools" (Sheet-Anbindung) sind dann inaktiv, der Excel-Upload funktioniert weiterhin. Der vom Nutzer eingegebene Slack-Bot braucht Rechte zum Auflisten von Nutzern und zum Senden von Direktnachrichten (Scopes siehe oben).
docker compose up --buildDie App ist anschließend unter http://localhost:3838 erreichbar (Port siehe
docker-compose.yaml). Zugangsdaten vorher als Umgebungsvariablen setzen.
# einmalig benötigte Pakete
install.packages(c(
"shiny", "bslib", "shinyjs", "stringdist", "purrr", "dplyr", "stringr",
"magrittr", "data.table", "readxl", "openxlsx", "httr", "jsonlite",
"listviewer", "reactR", "googlesheets4"
))
# Umgebungsvariablen setzen (s. o.), dann:
shiny::runApp("app.R")- Erst testen: Vor dem ersten echten Versand einer Konferenz einmal mit aktivem Test-Channel durchlaufen – das prüft Namens-Treffer, Empfänger-Korrekturen und die Bestätigungsabfrage im Zusammenspiel.
- Treffer immer kontrollieren: Besonders gelbe und rote Bewertungen vor dem Versand prüfen. Ein schlechter automatischer Treffer kann sonst an die falsche Person gehen.
Code von Maximilian Ilzhöfer für DMUN e.V.