Rallly User-Template Integration

This commit is contained in:
XPS\Micro 2026-02-08 14:47:57 +01:00
parent 27a43ae3bb
commit a39488139c

693
backlog/plan-rallly.md Normal file
View File

@ -0,0 +1,693 @@
# Rallly User-Template Integration (Single-Container mit SQLite)
## Übersicht
**Ziel:** Rallly als neues User-Template hinzufügen, kompatibel mit dem aktuellen Single-Container-System.
**Ansatz:** Rallly-Container mit SQLite-Datenbank (statt PostgreSQL aus dem Original-Compose-File).
**Use-Case:**
1. **Angemeldeter Spawner-User** erstellt Rallly-Container
2. **Spawner-User richtet Rallly ein** (wird Rallly-Admin beim ersten Setup)
3. **Öffentlicher Zugriff** - jeder mit URL kann Rallly nutzen (OHNE Spawner-Login)
4. **Rallly-eigene Authentifizierung** - Rallly hat eigenes User-Management
**Vorteile:**
- ✅ Keine Architektur-Änderungen am Spawner-System
- ✅ Passt ins bestehende Template-System
- ✅ Automatisches Build via `install.sh`
- ✅ Traefik-Routing funktioniert sofort (öffentlich zugänglich)
- ✅ Keine Service-Dependencies
- ✅ Rallly verwaltet eigene Benutzer
---
## Zugriffs-Model & Authentifizierung
### Wie funktioniert der öffentliche Zugriff?
**Container-URL-Format:**
```
https://coder.domain.com/{user-slug}-template-rallly
```
**Zugriffskontrolle:**
1. **Spawner-Ebene (Container erstellen):**
- ✅ Nur angemeldete Spawner-User können Container erstellen
- ✅ User muss JWT-Token haben
2. **Traefik-Routing (Container aufrufen):**
- ✅ **KEINE Authentifizierung** - öffentlich zugänglich
- ✅ Jeder mit URL kann zugreifen
- ✅ Traefik routet direkt zum Container
3. **Rallly-Ebene (App-Nutzung):**
- ✅ **Rallly-eigene Authentifizierung** (optional)
- ✅ Spawner-User wird beim ersten Setup zu Rallly-Admin
- ✅ Rallly kann öffentlich oder mit Passwort genutzt werden
### Rallly Setup-Flow
**Beim ersten Container-Start:**
1. User öffnet: `https://coder.domain.com/{slug}-template-rallly`
2. Rallly zeigt **Setup-Wizard**:
- Admin-Account erstellen (Spawner-User Email)
- Passwort setzen
- Optionale Einstellungen
3. **Nach Setup:**
- Rallly-Admin kann Events erstellen
- Events können öffentlich geteilt werden (URL)
- Teilnehmer brauchen KEINEN Rallly-Account (je nach Settings)
### Environment-Variablen für öffentlichen Zugriff
**Im Dockerfile setzen:**
```bash
# Öffentlicher Zugriff erlauben (keine Registrierung erforderlich für Teilnehmer)
ENV NEXT_PUBLIC_ENABLE_SELF_REGISTRATION=false
# Base URL für Rallly (für Link-Generierung)
ENV NEXT_PUBLIC_BASE_URL="https://coder.domain.com/{slug}-template-rallly"
# Session-Secret (wird pro Container generiert)
ENV SECRET_PASSWORD=$(openssl rand -base64 32)
```
**Wichtig:** Der Spawner-User richtet Rallly nur EINMAL ein. Danach ist Rallly unabhängig nutzbar.
---
## Phase 1: Rallly Dockerfile erstellen
### Dateien erstellen
**Verzeichnis:** `user-template-rallly/`
#### 1.1 Dockerfile
**Datei:** `C:\Users\Micro\OneDrive\Dokumente\spawner\user-template-rallly\Dockerfile`
```dockerfile
FROM lukevella/rallly:latest
# Setze Environment für SQLite (statt PostgreSQL)
ENV DATABASE_URL="file:/data/rallly.db"
# Session-Secret generieren (wird pro Build neu generiert)
# In Production sollte das pro Container-Instance individuell sein
ENV SECRET_PASSWORD="change-this-in-production"
# Öffentlicher Zugriff: Teilnehmer brauchen keinen Account
ENV NEXT_PUBLIC_ENABLE_SELF_REGISTRATION=false
# Support Email (optional, für Rallly-Footer)
ENV SUPPORT_EMAIL=""
# Erstelle Datenverzeichnis
RUN mkdir -p /data && chown -R node:node /data
# Volume für SQLite-Datenbank
VOLUME ["/data"]
# Port 3000 (Standard Rallly)
EXPOSE 3000
# Start Command (nutzt Original-Entrypoint)
CMD ["npm", "start"]
```
**Wichtige Environment-Variablen:**
| Variable | Wert | Beschreibung |
|----------|------|--------------|
| `DATABASE_URL` | `file:/data/rallly.db` | SQLite-Datenbank statt PostgreSQL |
| `SECRET_PASSWORD` | Auto-generiert | Session-Verschlüsselung (sollte pro Container unique sein) |
| `NEXT_PUBLIC_ENABLE_SELF_REGISTRATION` | `false` | Nur Admin kann Accounts erstellen (Event-Teilnehmer brauchen keinen Account) |
| `SUPPORT_EMAIL` | leer | Optional: Support-Email im Footer |
**Hinweis SECRET_PASSWORD:**
Idealerweise sollte `SECRET_PASSWORD` pro Container unique sein. Das kann später in `container_manager.py` beim Spawn injiziert werden:
```python
# In container_manager.py (optional)
import secrets
environment = {
'SECRET_PASSWORD': secrets.token_urlsafe(32)
}
```
**Hinweise:**
- Rallly unterstützt SQLite nativ (Prisma ORM)
- `DATABASE_URL="file:/data/rallly.db"` aktiviert SQLite
- Volume `/data` persistiert Daten
- Port 3000 wird von Traefik geroutet
#### 1.2 .dockerignore (optional)
**Datei:** `C:\Users\Micro\OneDrive\Dokumente\spawner\user-template-rallly\.dockerignore`
```
node_modules
.git
.env
*.log
```
---
## Phase 2: Template-Konfiguration
### 2.1 templates.json erweitern
**Datei:** `C:\Users\Micro\OneDrive\Dokumente\spawner\templates.json`
**Änderung:** Füge neuen Eintrag hinzu:
```json
{
"templates": [
{
"type": "template-01",
"image": "user-template-01:latest",
"display_name": "Nginx Basic",
"description": "Einfacher Nginx-Server mit statischen Dateien"
},
{
"type": "template-02",
"image": "user-template-02:latest",
"display_name": "Nginx Advanced",
"description": "Erweiterter Nginx-Server mit Custom-Config"
},
{
"type": "template-next",
"image": "user-template-next:latest",
"display_name": "Next.js App",
"description": "Next.js Production Build mit Shadcn UI"
},
{
"type": "template-rallly",
"image": "user-template-rallly:latest",
"display_name": "Rallly Scheduler",
"description": "Termin-Abstimmung und Planung mit Rallly"
}
]
}
```
### 2.2 .env aktualisieren
**Datei:** `C:\Users\Micro\OneDrive\Dokumente\spawner\.env`
**Änderung:** Erweitere `USER_TEMPLATE_IMAGES`:
```bash
# ALT:
USER_TEMPLATE_IMAGES="user-template-01:latest;user-template-02:latest;user-template-next:latest"
# NEU:
USER_TEMPLATE_IMAGES="user-template-01:latest;user-template-02:latest;user-template-next:latest;user-template-rallly:latest"
```
**Wichtig:** Semikolon-getrennte Liste ohne Leerzeichen!
### 2.3 .env.example aktualisieren (Dokumentation)
**Datei:** `C:\Users\Micro\OneDrive\Dokumente\spawner\.env.example`
**Änderung:** Gleiche Anpassung wie in `.env`:
```bash
USER_TEMPLATE_IMAGES="user-template-01:latest;user-template-02:latest;user-template-next:latest;user-template-rallly:latest"
```
---
## Phase 3: Image bauen
### 3.1 Automatischer Build mit install.sh
Das `install.sh` Script erkennt automatisch neue Templates aus `USER_TEMPLATE_IMAGES`.
**Kommando (lokal testen):**
```bash
cd C:\Users\Micro\OneDrive\Dokumente\spawner
# Build nur Rallly-Template
docker build -t user-template-rallly:latest ./user-template-rallly
# ODER: Alle Templates neu bauen
bash install.sh
```
**Was install.sh macht:**
1. Liest `USER_TEMPLATE_IMAGES` aus `.env`
2. Extrahiert Template-Namen (z.B. `user-template-rallly`)
3. Baut Docker Image: `docker build -t user-template-rallly:latest ./user-template-rallly`
4. Zeigt Warnings wenn Verzeichnis fehlt
### 3.2 Verification nach Build
```bash
# Image prüfen
docker images | grep rallly
# Sollte zeigen: user-template-rallly:latest
# Container-Test (optional)
docker run -d --name test-rallly -p 3000:3000 user-template-rallly:latest
docker logs -f test-rallly
# Öffne Browser: http://localhost:3000
# Sollte: Rallly-Setup-Page zeigen
# Cleanup
docker stop test-rallly && docker rm test-rallly
```
---
## Phase 4: Spawner-System Deployment
### 4.1 Code committen
**Neue Dateien:**
- `user-template-rallly/Dockerfile`
- `user-template-rallly/.dockerignore` (optional)
**Geänderte Dateien:**
- `templates.json`
- `.env` (Server)
- `.env.example` (Dokumentation)
**Commit:**
```bash
cd C:\Users\Micro\OneDrive\Dokumente\spawner
git add user-template-rallly/ templates.json .env.example
git commit -m "feat: Add Rallly user-template with SQLite
- Rallly Scheduler als neues User-Template
- Single-Container mit SQLite-Datenbank (statt PostgreSQL)
- Volume /data für Datenpersistenz
- Port 3000 exponiert für Traefik-Routing
- Templates.json und .env.example aktualisiert"
git push origin main
```
### 4.2 Server Deployment
**Auf dem Synology NAS / Server:**
```bash
cd /volume1/docker/spawner
# Code pullen
git pull origin main
# .env aktualisieren (USER_TEMPLATE_IMAGES erweitern)
nano .env
# Füge hinzu: ;user-template-rallly:latest
# install.sh ausführen (baut neue Templates)
bash install.sh
# Spawner neu starten (lädt neue templates.json)
docker-compose up -d --build spawner
```
**Wichtig:** `install.sh` baut automatisch alle Templates aus `USER_TEMPLATE_IMAGES`.
---
## Phase 5: Testing & Verification
### 5.1 Frontend-Check
1. **Admin-Dashboard öffnen:** `https://coder.domain.com/admin`
2. **Prüfe:** Wird "Rallly Scheduler" als Template angezeigt?
- Falls nicht: Server-Logs prüfen (`docker logs spawner`)
### 5.2 User-Dashboard Test
1. **User-Dashboard öffnen:** `https://coder.domain.com/dashboard`
2. **Container-Grid prüfen:**
- Sollte "Rallly Scheduler" als Option zeigen
- Description: "Termin-Abstimmung und Planung mit Rallly"
### 5.3 Container Launch
1. **Klicke:** "Erstellen & Öffnen" bei Rallly
2. **Erwartetes Verhalten:**
- Container wird erstellt (`user-{slug}-template-rallly-{id}`)
- Traefik-Route wird konfiguriert
- Browser öffnet: `https://coder.domain.com/{slug}-template-rallly`
### 5.4 Rallly Setup (Spawner-User als Admin)
**Erster Besuch (als Spawner-User):**
1. Öffne: `https://coder.domain.com/{slug}-template-rallly`
2. Rallly zeigt **Setup-Wizard**
3. Erstelle Admin-Account:
- Email: Spawner-User Email
- Name: Spawner-User Name
- Passwort: Wählen
4. Setup abschließen
5. SQLite-Datenbank wird erstellt: `/data/rallly.db`
**Rallly ist jetzt eingerichtet!**
### 5.5 Öffentlichen Zugriff testen
**Test 1: Event erstellen (als Admin)**
1. Login als Rallly-Admin
2. Erstelle neues Event: "Team Meeting"
3. Event-URL wird generiert: `https://coder.domain.com/{slug}-template-rallly/p/{event-id}`
4. Kopiere URL
**Test 2: Event öffnen (öffentlich, OHNE Login)**
1. **Öffne Incognito/Private Browser** (kein Spawner-Login!)
2. Navigiere zu Event-URL: `https://coder.domain.com/{slug}-template-rallly/p/{event-id}`
3. **Erwartetes Verhalten:**
- ✅ Event wird angezeigt
- ✅ KEIN Spawner-Login erforderlich
- ✅ KEIN Rallly-Login erforderlich
- ✅ Teilnehmer kann Name eingeben und abstimmen
**Test 3: Öffentliche Nutzung ohne Spawner-Account**
1. Teile Event-URL mit jemandem der KEINEN Spawner-Account hat
2. Person öffnet URL
3. **Erwartetes Verhalten:**
- ✅ Event ist zugänglich
- ✅ Teilnahme möglich
- ✅ Kein Spawner-Redirect
**Daten-Persistenz prüfen:**
```bash
# Container stoppen
docker stop user-{slug}-template-rallly-{id}
# Container neu starten
docker start user-{slug}-template-rallly-{id}
# Sollte: Daten sind noch da (SQLite Volume)
# - Admin-Account vorhanden
# - Events vorhanden
# - Teilnehmer-Antworten erhalten
```
### 5.5 Logs prüfen
```bash
# Rallly-Container-Logs
docker logs user-{slug}-template-rallly-{id}
# Sollte zeigen:
# - Prisma Migration erfolgreich
# - Server listening on port 3000
# - Keine Fehler
# Spawner-Logs
docker logs spawner | grep rallly
# Sollte zeigen:
# - Container erfolgreich erstellt
# - Traefik-Labels gesetzt
```
---
## Kritische Dateien
| Datei | Status | Beschreibung |
|-------|--------|--------------|
| `user-template-rallly/Dockerfile` | ✅ NEU | Rallly mit SQLite-Config |
| `user-template-rallly/.dockerignore` | ⚠️ OPTIONAL | Build-Optimierung |
| `templates.json` | ✏️ ÄNDERN | Rallly-Template-Metadaten |
| `.env` | ✏️ ÄNDERN (Server) | USER_TEMPLATE_IMAGES erweitern |
| `.env.example` | ✏️ ÄNDERN | Dokumentation |
---
## Häufige Probleme & Lösungen
### Problem 1: Template erscheint nicht im Dashboard
**Symptom:** Rallly wird nicht in Container-Grid angezeigt.
**Lösung:**
```bash
# 1. Prüfe templates.json
cat templates.json | grep rallly
# Sollte Eintrag zeigen
# 2. Prüfe Config-Laden
docker logs spawner | grep "CONTAINER_TEMPLATES"
# 3. Spawner neu starten
docker-compose restart spawner
```
### Problem 2: Container startet nicht
**Symptom:** "Container konnte nicht erstellt werden" Error.
**Lösung:**
```bash
# 1. Image prüfen
docker images | grep rallly
# Sollte: user-template-rallly:latest
# 2. Manueller Container-Test
docker run -d --name test-rallly \
-e DATABASE_URL="file:/data/rallly.db" \
-p 3000:3000 \
user-template-rallly:latest
docker logs test-rallly
# Sollte: Keine Fehler
# 3. Traefik-Netzwerk prüfen
docker network ls | grep web
# Sollte existieren
```
### Problem 3: SQLite-Daten gehen verloren
**Symptom:** Nach Container-Restart sind Daten weg.
**Ursache:** Volume nicht korrekt gemountet.
**Lösung:**
```bash
# Prüfe Volume
docker inspect user-{slug}-template-rallly-{id} | grep -A10 "Mounts"
# Sollte zeigen:
# - Source: /var/lib/docker/volumes/...
# - Destination: /data
# Falls nicht: container_manager.py anpassen
# Füge Volume-Mount hinzu in spawn_multi_container()
```
**Fix in container_manager.py (falls nötig):**
```python
# Zeile ~200 in spawn_multi_container()
volumes = {
f'rallly-data-{user_id}': {'bind': '/data', 'mode': 'rw'}
}
container = self._get_client().containers.run(
image=image,
volumes=volumes, # NEU
# ... rest of config
)
```
### Problem 4: Port-Konflikt mit anderem Service
**Symptom:** Container startet aber ist nicht erreichbar.
**Lösung:**
```bash
# Prüfe Traefik-Labels
docker inspect user-{slug}-template-rallly-{id} | grep -A20 "Labels"
# Sollte zeigen:
# - traefik.http.routers.user{id}.rule = Host(...) && PathPrefix(...)
# - traefik.http.services.user{id}.loadbalancer.server.port = 3000
# Falls Port falsch: container_manager.py nutzt Port 8080 als Default
# Rallly braucht Port 3000
```
**Fix (falls Port nicht 3000):**
Rallly-Dockerfile anpassen:
```dockerfile
# Am Ende des Dockerfile:
EXPOSE 3000
# ODER: Traefik-Port explizit setzen
ENV TRAEFIK_PORT=3000
```
---
## Alternativen (falls SQLite nicht ausreicht)
### Option A: Shared PostgreSQL (später)
Falls SQLite Performance-Probleme hat:
1. Erstelle einen zentralen PostgreSQL-Container
2. Jeder User bekommt eigene Database + Credentials
3. Rallly-Container bekommt `DATABASE_URL` per Environment
**Aufwand:** ~2-3 Stunden
**Vorteil:** Bessere Performance, Multi-User-Ready
### Option B: Externe PostgreSQL-Anbindung
Falls bereits PostgreSQL-Server existiert:
1. Rallly-Dockerfile: Entferne SQLite-Config
2. `DATABASE_URL` per Environment injizieren
3. Credentials per User generieren
**Aufwand:** ~1 Stunde
**Vorteil:** Professionelle DB-Infrastruktur
---
## Zusammenfassung
**Was implementiert wird:**
1. ✅ Neues User-Template: `user-template-rallly`
2. ✅ Rallly mit SQLite-Datenbank (Single-Container)
3. ✅ Automatisches Build via `install.sh`
4. ✅ Integration ins Dashboard (templates.json)
5. ✅ Traefik-Routing (Port 3000)
**Keine Breaking Changes:**
- ✅ Bestehende Templates unverändert
- ✅ Keine Architektur-Änderungen
- ✅ Keine DB-Migration erforderlich
**Geschätzter Aufwand:**
- Dockerfile erstellen: 10 Minuten
- Templates.json + .env: 5 Minuten
- Build + Test: 15 Minuten
- Deployment: 10 Minuten
- **Total: ~40 Minuten**
**Nächste Schritte nach Approval:**
1. Erstelle `user-template-rallly/Dockerfile`
2. Aktualisiere `templates.json` und `.env.example`
3. Build Image mit `install.sh`
4. Test Container lokal
5. Commit + Push
6. Server-Deployment
---
## Traefik-Routing & Öffentlicher Zugriff
### Wie Traefik das Routing handhabt
**Aktuelles System (container_manager.py):**
```python
# Traefik-Labels beim Container-Spawn
labels = {
'traefik.enable': 'true',
f'traefik.http.routers.user{user_id}.rule': f'Host(`{spawner_domain}`) && PathPrefix(`/{slug_with_suffix}`)',
f'traefik.http.routers.user{user_id}.entrypoints': Config.TRAEFIK_ENTRYPOINT,
f'traefik.http.services.user{user_id}.loadbalancer.server.port': '3000', # Rallly-Port
# WICHTIG: Kein Traefik-Auth-Middleware!
}
```
**Routing-Flow:**
1. Request: `https://coder.domain.com/{slug}-template-rallly/p/{event-id}`
2. Traefik prüft: Host + PathPrefix Match?
3. ✅ Route zu Container (Port 3000)
4. ✅ **KEINE Authentifizierung** auf Traefik-Ebene
5. Container beantwortet Request
**Wichtig:** Das Spawner-System hat **keine JWT-Auth für Container-Zugriffe**. Nur für API-Endpoints!
### Unterschied: API vs. Container
| Endpoint | Auth erforderlich? | Beschreibung |
|----------|-------------------|--------------|
| `/api/user/containers` | ✅ JWT Token | Spawner API - Container-Liste abrufen |
| `/api/container/launch` | ✅ JWT Token | Spawner API - Container erstellen |
| `/{slug}-template-rallly/*` | ❌ KEINE Auth | User-Container - öffentlich via Traefik |
### Sicherheits-Überlegungen
**Gut für Rallly:**
- ✅ Events sollen öffentlich teilbar sein
- ✅ Teilnehmer brauchen keinen Spawner-Account
- ✅ Rallly hat eigene Admin-Authentifizierung
**Potentielle Bedenken:**
- ⚠️ Jeder mit URL kann Container nutzen (aber das ist gewollt!)
- ⚠️ Rate-Limiting nur via Traefik (nicht per User)
- ⚠️ Rallly-Admin sollte starkes Passwort setzen
**Empfohlene Rallly-Settings (für Admin):**
- Admin-Passwort: Stark & unique
- Self-Registration: Disabled (nur Admin erstellt Events)
- Event-Visibility: Optional private Events
---
## Verification Checklist
### Setup & Deployment
- [ ] `user-template-rallly/Dockerfile` erstellt
- [ ] `templates.json` erweitert (type: template-rallly)
- [ ] `.env.example` aktualisiert
- [ ] Image gebaut (`docker images | grep rallly`)
- [ ] Lokaler Container-Test erfolgreich
- [ ] Code committed & pushed
- [ ] Server `.env` aktualisiert
- [ ] `install.sh` auf Server ausgeführt
- [ ] Spawner neu gestartet
### Funktionalität
- [ ] Dashboard zeigt "Rallly Scheduler"
- [ ] Container launch erfolgreich
- [ ] Rallly erreichbar unter User-URL
- [ ] Setup-Wizard erscheint beim ersten Start
- [ ] Admin-Account erstellt (Spawner-User)
- [ ] SQLite-Daten persistiert nach Restart
### Öffentlicher Zugriff (WICHTIG!)
- [ ] Event erstellt als Rallly-Admin
- [ ] Event-URL generiert
- [ ] **Incognito-Browser:** Event ohne Spawner-Login erreichbar
- [ ] **Incognito-Browser:** Teilnahme ohne Rallly-Account möglich
- [ ] Person OHNE Spawner-Account kann Event öffnen
- [ ] Traefik routet korrekt (keine 401/403 Errors)
- [ ] Teilnehmer-Antworten werden gespeichert