# @concierge — Gäste-Einladungen mit Ablauf

**Status**: gebaut, wartet auf Zugangsdaten · Issue [#48](https://git.lab/axion1337.chat/axion1337.chat-gitops/-/issues/48)

Ein kleiner Bot, der Einladungslinks erzeugt, Gastkonten nach drei Tagen ablaufen
lässt und die dauerhafte Freischaltung an eine bewusste Admin-Handlung bindet.

## Warum es diesen Bot gibt

Registrierung läuft in diesem Stack **ausschließlich über Authentik**. Bis jetzt
hieß das: Wer jemanden einladen will, klickt in der Authentik-Oberfläche einen
Invitation-Token zusammen. Das können nur Admins, es hinterlässt keine Spur, wer
wen eingeladen hat, und ein Gastkonto bleibt für immer bestehen.

Der Bot macht daraus einen Vorgang, den ein festgelegter Kreis selbst auslösen
kann — nachvollziehbar und mit eingebautem Ablauf.

## Wie es funktioniert

```
!einladen <name>          → Authentik-Invitation (einmalig, 3 Tage) + Link im Raum
   Gast registriert sich  → Konto trägt threadnet_guest_expires_at
!verlaengern @gast        → +1 Tag, höchstens 2×
!freischalten @gast       → Ablauf entfernen, in members-Gruppe (nur Admins)
   (nichts davon)         → Bot deaktiviert das Konto nach Ablauf
```

### Berechtigung ist zweiteilig — und das ist Absicht

**Authentik-Gruppe UND Einladungsraum.** Die Gruppe entscheidet, der Raum macht
sichtbar. Eine Gruppe allein ist unsichtbar: Niemand sähe, wer eingeladen hat.
Ein Raum allein autorisiert nicht: Wer hineinkommt, dürfte alles. Zusammen ergibt
sich beides, und jede Einladung hinterlässt einen nachlesbaren Eintrag.

### Zwei Dinge, die beim Umbauen leicht kaputtgehen

⚠️ **Genau eine Instanz.** `replicas: 1` **und** `strategy: Recreate`. Der Bot
hält eine `/sync`-Schleife; zwei Instanzen führen jedes Kommando doppelt aus. Bei
`RollingUpdate` liefen während eines Deploys kurzzeitig zwei.

⚠️ **Die ConfigMap trägt bewusst einen Namens-Hash.** Anders als beim
ClamAV-Modul steht hier **kein** `disableNameSuffixHash: true`. Dadurch ändert
sich der ConfigMap-Name mit dem Skript, kustomize zieht die Referenz nach, und
der Pod startet von selbst neu. Ohne das hätten wir den Fall aus gitops#50:
geänderte Datei im Repo, alter Stand im laufenden Prozess.

### Fehlerverhalten ist absichtlich unsymmetrisch

- **Einladen und Freischalten scheitern laut.** Lieber keine Einladung als eine,
  von der niemand weiß.
- **Die Ablaufprüfung deaktiviert nur, wenn Authentik sauber geantwortet hat.**
  Ein API-Fehler darf nicht dazu führen, dass Konten reihenweise abgeschaltet
  werden; im Zweifel bleibt ein Gast einen Durchlauf länger aktiv.

## Was zur Inbetriebnahme fehlt

Der Bot ist ausgerollt, **startet aber nicht**, solange das Secret fehlt — der Pod
meldet `secret "concierge-credentials" not found`. Das ist gewollt sichtbar; ein
Bot, der still nichts tut, wäre schlechter.

### 1. Matrix-Konto anlegen

```bash
kubectl exec -it -n matrix deploy/matrix-stack-matrix-authentication-service -- \
  mas-cli manage register-user concierge --yes
kubectl exec -it -n matrix deploy/matrix-stack-matrix-authentication-service -- \
  mas-cli manage issue-compatibility-token concierge
```

### 2. Authentik-Token

*Admin → Verzeichnis → Tokens*. Braucht Schreibrechte auf Nutzer, Gruppen und
Invitations. Ein eigenes Dienstkonto ist sauberer als ein Admin-Token.

### 3. Einladungsraum

Invite-only anlegen, `@concierge` einladen. Die Raum-ID ist Teil des Secrets, weil
sie zusammen mit den Token gepflegt wird und sich beim Neuanlegen ändert.

### 4. Gruppen in Authentik

`invite-berechtigt` (wer einladen darf) und `members` (wohin Freigeschaltete
kommen). Namen sind über `INVITE_GROUP` / `MEMBER_GROUP` änderbar.

### 5. Secret

```bash
kubectl create secret generic concierge-credentials -n matrix \
  --from-literal=matrix-token='…' \
  --from-literal=authentik-token='…' \
  --from-literal=matrix-room-id='!….:axion1337.chat' \
  --dry-run=client -o yaml > /tmp/s.yaml
sops -e /tmp/s.yaml > apps/production/concierge-secret.yaml
```

⚠️ Über SOPS ins Repo, nicht mit `kubectl apply` von Hand — sonst kennt Flux das
Secret nicht und es fehlt nach einem Wiederaufbau des Clusters.

## Grenzen

- **Matrix-Localpart = Authentik-Benutzername.** Gilt hier, weil MAS aus
  Authentik provisioniert. Stimmt es einmal nicht, findet der Bot den Nutzer
  nicht und sagt das — er rät nicht.
- **Ein deaktiviertes Konto ist nicht gelöscht.** Räume und Nachrichten bleiben.
  Löschen ist bewusst nicht Sache des Bots.
- **Draupnir-Verzahnung** (Gast-Label → eingeschränkte Räume) ist Stufe 2 und
  nicht Teil dieser Fassung.
