Ship It — Deployment auf Cloudflare Workers (Teil 6/6)
Wir haben es geschafft. Fünf Teile Bauen, Verschlüsseln, Testen und Polieren. Jetzt bringen wir das Ding ins Internet.
Eine Full-Stack-Anwendung deployen — SPA-Frontend plus Edge-Worker-Backend — in einem einzigen Befehl klingt zu gut, um wahr zu sein. Mit Cloudflare Workers und Wrangler ist es tatsächlich so einfach. Lass mich dir die gesamte Pipeline von Null bis Live zeigen.
Was wir deployen
Lass uns die beweglichen Teile rekapitulieren:
- SPA (React + Vite) → gebaut nach
/dist, ausgeliefert als statische Assets - Worker (Hono) → dünner Upstash-Auth-Proxy mit SSE-Streaming
- Secrets → Upstash-REST-URL und -Token, gespeichert in Cloudflares Secret Store
- Datenbank → Upstash Redis (separat gehostet, Free Tier)
Das Ziel: Ein wrangler deploy-Befehl, der die SPA baut, den Worker bündelt, beides hochlädt und vom gleichen Origin ausliefert.
Schritt 1: Upstash Redis einrichten
Geh zu upstash.com und erstelle eine kostenlose Redis-Datenbank. Du brauchst zwei Dinge:
- REST URL —
https://your-db.upstash.io - Token — ein langer alphanumerischer String
Der Free Tier gibt dir 10.000 Commands pro Tag. Für eine Planning-Poker-App reicht das für ein Team, das mehrere Sprint-Plannings pro Woche macht. Jeder Raum-Lifecycle (erstellen, beitreten, abstimmen, aufdecken, verlassen) verbraucht ungefähr 10-20 Commands pro Spieler.
Schritt 2: Secrets in Cloudflare speichern
Secrets werden zur Laufzeit injiziert — sie erscheinen nie in deinem Code, deinen Config-Dateien oder deiner Git-History:
npx wrangler secret put UPSTASH_URL
# füge deine URL ein, wenn gefragt
npx wrangler secret put UPSTASH_TOKEN
# füge deinen Token ein, wenn gefragt
Diese werden verschlüsselt in Cloudflares Infrastruktur gespeichert und sind nur zur Laufzeit für deinen Worker über env.UPSTASH_URL und env.UPSTASH_TOKEN verfügbar. Sie existieren nicht in wrangler.jsonc, sie existieren nicht in .env, sie existieren nirgendwo, wo ein Mensch oder eine CI-Pipeline sie versehentlich exponieren könnte.
Schritt 3: Die Wrangler-Config verstehen
{
"name": "planning-poker",
"main": "worker/src/index.ts",
"compatibility_date": "2025-01-01",
"compatibility_flags": ["nodejs_compat"],
"assets": {
"directory": "./dist",
"not_found_handling": "single-page-application",
"binding": "ASSETS"
},
"observability": { "enabled": true },
"build": {
"command": "npm install --prefix worker && pnpm build"
}
}
Lass uns das aufschlüsseln:
main: "worker/src/index.ts" — Der Worker-Einstiegspunkt. Wrangler bündelt das mit esbuild vor dem Deployment.
assets.directory: "./dist" — Der Vite-Build-Output. Diese Dateien werden an Cloudflares Edge hochgeladen und über das ASSETS-Binding ausgeliefert.
assets.not_found_handling: "single-page-application" — Das sagt Cloudflare: „Wenn ein Request keine statische Datei matcht, liefere index.html aus." Kritisch für React Router — ohne das würde das direkte Navigieren zu /planning-poker/room/abc123 einen 404 ergeben.
assets.binding: "ASSETS" — Macht die statischen Assets als Cloudflare-Binding verfügbar. Der Worker kann env.ASSETS.fetch(req) aufrufen, um programmatisch statische Dateien auszuliefern (was er für den SPA-Fallback und die Cache-Steuerung tut).
build.command — Läuft automatisch vor wrangler deploy. Es installiert die eigenen Dependencies des Workers (npm install --prefix worker) und baut die SPA (pnpm build). Ein Befehl erledigt alles.
observability.enabled: true — Aktiviert Cloudflares eingebaute Worker-Analytics. Request-Zahlen, Fehlerraten, Latenz — ohne Instrumentierungs-Code hinzuzufügen.
Schritt 4: Die Build-Pipeline
Wenn wrangler deploy läuft, passiert Folgendes:
1. wrangler führt den Build-Befehl aus:
npm install --prefix worker → installiert Hono + hono/cors in worker/
pnpm build → tsc + vite build → /dist
2. wrangler bündelt worker/src/index.ts mit esbuild
→ einzelne JS-Datei für den Worker
3. wrangler lädt hoch:
→ Worker-Bundle → Cloudflare Edge (global)
→ /dist/* Assets → Cloudflare Edge (global)
4. Der Worker ist live unter:
https://planning-poker.oltionzefi.workers.dev
Der pnpm build-Schritt führt tsc && vite build aus — TypeScript-Typprüfung zuerst (Fehler abfangen, bevor sie ausgeliefert werden), dann Vites Produktions-Build mit Tree-Shaking, Minifizierung und Code-Splitting.
Schritt 5: Deployen
npx wrangler deploy
Das war’s. Ernsthaft. Ein Befehl. Die Ausgabe sieht ungefähr so aus:
🌀 Building...
✨ Compiled Worker successfully
📦 Published planning-poker (2.3 seconds)
planning-poker.oltionzefi.workers.dev
Die App ist live. URL öffnen. Raum erstellen. Link teilen. Stories schätzen.
Lokaler Entwicklungs-Flow
Für die tägliche Entwicklung deployst du nicht auf Cloudflare. Du arbeitest lokal mit direktem Upstash-Zugriff:
# .env (git-ignoriert)
VITE_UPSTASH_URL=https://your-db.upstash.io
VITE_UPSTASH_TOKEN=your-token
VITE_DEBUG_LOGGING=true
pnpm dev
Das startet Vites Dev-Server unter http://localhost:5173. Der Adapter erkennt automatisch die VITE_UPSTASH_*-Variablen und wechselt in den Direct-Modus — der Browser spricht direkt mit Upstash, kein Worker nötig.
Das VITE_DEBUG_LOGGING=true-Flag aktiviert das logger-Utility und gibt dir detaillierte Konsolenausgabe für jede SSE-Nachricht, jedes State-Update und jede Verschlüsselungsoperation. Super hilfreich zum Debuggen von Echtzeit-Sync-Problemen.
Umgebungsvariablen-Übersicht
Hier ist das Gesamtbild:
| Variable | Wo | Zweck |
|---|---|---|
VITE_UPSTASH_URL | .env (nur lokal) | Direkte Upstash-REST-URL |
VITE_UPSTASH_TOKEN | .env (nur lokal) | Direkter Upstash-Token |
VITE_WORKER_URL | .env (optional) | Worker-Base-URL überschreiben |
VITE_BASE_URL | .env (optional) | Base-Pfad (Standard /) |
VITE_DEBUG_LOGGING | .env (nur Dev) | Ausführliche Konsolenausgabe |
UPSTASH_URL | wrangler secret | Upstash-REST-URL für den Worker |
UPSTASH_TOKEN | wrangler secret | Upstash-Token für den Worker |
Produktion hat null VITE_*-Variablen. Die SPA erkennt Same-Origin-Deployment und routet alles durch /upstash. Sauber.
Sauber halten: der Pre-Commit-Workflow
Vor dem Deployen führe ich immer aus:
pnpm format # Prettier — konsistenter Code-Stil
pnpm lint # ESLint — null Warnungen
pnpm test # Vitest — alle Tests bestehen
pnpm build # TypeScript + Vite — keine Typfehler
Und wenn du auf GitHub pushst, führt die CI-Pipeline (ci.yml) automatisch format:check, lint und test bei jedem Push und PR aus. Nichts Kaputtes wird in main gemergt.
Dependabot
Das Projekt nutzt GitHubs Dependabot, um Dependencies aktuell zu halten:
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
Wöchentliche PRs für veraltete Pakete. Die mergen, die CI bestehen, die reviewen, die es nicht tun. Wenig Aufwand, großer Gewinn für Sicherheitspatches.
Kostenaufstellung
Der gesamte Stack kostet 0 € für ein kleines Team:
| Service | Free Tier | Reicht für… |
|---|---|---|
| Cloudflare Workers | 100K Requests/Tag | ~50 Sprint-Plannings/Tag |
| Upstash Redis | 10K Commands/Tag | ~10 gleichzeitige Räume |
| GitHub Actions | 2K Minuten/Monat | ~200 CI-Läufe/Monat |
Keine Kreditkarte für irgendetwas davon nötig. Wirklich.
Wenn du den Free Tier überwächst (Glückwunsch!), kostet Cloudflare Workers Paid 5$/Monat für 10M Requests. Upstash Pay-as-you-go ist 0,2$ pro 100K Commands. Immer noch quasi kostenlos.
Was wir gebaut haben — das Gesamtbild
Lass uns rauszoomen und schätzen, was wir über diese 6 Teile geschaffen haben:
🃏 Eine Echtzeit-Planning-Poker-App mit Fibonacci, T-Shirt, Zweierpotenzen und Custom-Decks
🔐 Ende-zu-Ende-verschlüsselt mit AES-GCM-256 — der Server kann deine Daten buchstäblich nicht lesen
⚡ Sofortige Updates via SSE-Streaming durch einen Cloudflare Worker
🎭 Smarte Rollen — Facilitator, Voter, Observer, mit automatischer Übergabe
⏱ Countdown-Timer mit Auto-Reveal und Preset-Chips
📊 Live-Ergebnisse mit Stimmenverteilungs-Charts und Konsens-Erkennung
📜 Session-History — jede Runde in deiner Browser-Session archiviert
🔗 Ein-Klick-Teilen — Verschlüsselungsschlüssel im URL-Hash eingebettet
🧪 Getestet — Vitest + Testing Library mit 80% Coverage-Schwellen
🚀 Deployed — ein wrangler deploy auf 300+ Edge-Standorte weltweit
🆓 Kostenlos — keine Accounts, keine Registrierung, keine Kosten
Die gesamte Codebasis umfasst etwa 2.500 Zeilen TypeScript über SPA und Worker. Keine serverseitige Geschäftslogik. Keine Datenbank-Migrationen. Keine Benutzerverwaltung. Nur ein Browser, etwas Kryptographie und eine dünne Leitung zu Redis.
Was ich als Nächstes hinzufügen würde
Wenn ich weiter bauen würde:
- Benutzerdefinierte Timer-Dauer — den Facilitator eine beliebige Sekundenzahl eingeben lassen
- Zuschauer-Zähler — anzeigen, wie viele Observer zuschauen
- Session-History exportieren — als CSV oder JSON herunterladen
- Sound-Effekte — ein dezentes Ding, wenn alle abgestimmt haben 🔔
- Benutzerdefinierte Themes — Teams ihre Akzentfarbe wählen lassen
Aber ehrlich? Es funktioniert. Das Team nutzt es. Die Daten sind privat. Und es kostet nichts.
Probier es selbst
Die App ist live unter planning-poker.oltionzefi.workers.dev.
Öffne sie. Erstelle einen Raum. Teile den Link. Schätze ein paar Stories. Wenn es für dein Team funktioniert — und ich denke, das wird es — hast du gerade ein kostenloses, verschlüsseltes, Echtzeit-Planning-Poker-Tool bekommen. Ohne Haken.
Weiter voran und genieße jeden Schritt deiner Coding-Reise.
