ADR-002: Convex als Backend

Warum sich Owlat für Convex und gegen PostgreSQL und Firebase entschieden hat — wegen Echtzeit-Reaktivität, mitverorteter TypeScript-Logik und Skalierung ohne Konfigurationsaufwand.

  • Status: Angenommen
  • Datum: 2024-06-15

Kontext

Owlat braucht ein Backend, das Echtzeit-Updates der Oberfläche unterstützt (Zusammenarbeit im E-Mail-Editor, Live-Kampagnenstatistiken), komplexe Abfragen bewältigt (Segmentauswertung, Kontaktfilterung) und ohne Infrastrukturverwaltung skaliert.

Die wichtigsten betrachteten Optionen:

  1. Klassische REST-API + PostgreSQL — volle Kontrolle, erfordert aber das Betreiben von Servern, das Schreiben einer Echtzeit-Synchronisierung (WebSockets), den Aufbau einer ORM-Schicht und den Umgang mit Migrationen.
  2. Firebase/Firestore — Echtzeit ab Werk, aber eingeschränkte Abfragemöglichkeiten, keine Mitverortung serverseitiger Logik und Vendor-Lock-in bei schwächerer TypeScript-Unterstützung.
  3. Convex — Echtzeitfähige Serverless-Datenbank mit TypeScript-Funktionen, die beim Schema mitverortet sind, automatischer Reaktivität und ACID-Transaktionen.

Entscheidung

Convex als Backend-Plattform verwenden. Sämtliche serverseitige Logik liegt in apps/api/convex/ als TypeScript-Funktionen (Queries, Mutations, Actions und Crons).

Konsequenzen

Ermöglicht:

  • Echtzeit-Reaktivität ohne WebSocket-Boilerplate — UI-Komponenten abonnieren Queries und aktualisieren sich automatisch
  • Durchgängiges TypeScript vom Schema bis zur API — die Schemadefinition erzeugt typisierte Dokument-Interfaces
  • Mitverortete Serverlogik — Queries, Mutations und Crons liegen direkt neben dem Schema, auf dem sie arbeiten
  • Eingebautes Scheduling (Crons) für wiederkehrende Aufgaben wie Kampagnenversand und Aufräumarbeiten
  • Automatische Skalierung — kein Server-Provisioning, keine Verwaltung von Connection Pools
  • ACID-Transaktionen über mehrere Tabellen hinweg ohne manuelles Transaktionsmanagement

Trade-offs:

  • Abhängigkeit vom Anbieter Convex — eine Migration ist schwieriger als bei einem gewöhnlichen PostgreSQL-Setup
  • Die Abfragesprache ist Convex-spezifisch (kein SQL) — neue Mitwirkende müssen die Convex-API lernen
  • Kein direkter SQL-Zugriff für komplexe analytische Abfragen — die Segmentauswertung erfordert eigene Logik in conditions/segmentMatch.ts
  • Grenzen der Funktionsausführung (Zeit, Speicher) schränken Batch-Operationen ein — große Importe müssen über integrationImports/ in Blöcke zerlegt werden
  • Die lokale Entwicklung erfordert einen Convex-Account und ein aktives Deployment (kein vollständig offline nutzbarer Modus)