|

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:

  1. SPA (React + Vite) → gebaut nach /dist, ausgeliefert als statische Assets
  2. Worker (Hono) → dünner Upstash-Auth-Proxy mit SSE-Streaming
  3. Secrets → Upstash-REST-URL und -Token, gespeichert in Cloudflares Secret Store
  4. 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 URLhttps://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:

VariableWoZweck
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_URLwrangler secretUpstash-REST-URL für den Worker
UPSTASH_TOKENwrangler secretUpstash-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:

ServiceFree TierReicht für…
Cloudflare Workers100K Requests/Tag~50 Sprint-Plannings/Tag
Upstash Redis10K Commands/Tag~10 gleichzeitige Räume
GitHub Actions2K 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.