Supabase self-hosted: Was zwischen Docker Compose und Produktion fehlt

Die Compose-Vorlage von Supabase läuft in Minuten, deckt aber den Betrieb nicht ab. Für Produktion brauchst du fünf Dinge zusätzlich: eine Datenbank mit eigenem Lebenszyklus, eine Schlüsselverwaltung außerhalb von Git, externen Objektspeicher, Backups, die du zurückspielen kannst, und feste Versionen. Ob Compose, Kubernetes oder die Supabase Cloud passt, entscheidet dein Team, nicht die Technik.
12 Min. LesezeitMatthias RadscheitMatthias Radscheit
Happycodingde-DE

TL;DR

Die Compose-Vorlage von Supabase läuft in Minuten, deckt aber den Betrieb nicht ab. Für Produktion brauchst du fünf Dinge zusätzlich: eine Datenbank mit eigenem Lebenszyklus, eine Schlüsselverwaltung außerhalb von Git, externen Objektspeicher, Backups, die du zurückspielen kannst, und feste Versionen. Ob Compose, Kubernetes oder die Supabase Cloud passt, entscheidet dein Team, nicht die Technik.

  • Supabase self-hosted besteht aus rund zehn Diensten. Die Datenbank ist der einzige, den du nicht einfach neu startest.
  • Läuft Postgres über einen Operator wie CloudNativePG, führt niemand die Init-Skripte des Supabase-Images aus: Du spielst sie einmalig selbst ein.
  • Den pgsodium-Schlüssel sicherst du mit den Daten, sonst sind Vault-Geheimnisse nach einem Restore unlesbar.
  • Dateien gehören in einen externen S3-Bucket, Datenbank-Backups in einen zweiten. Ein Backup im selben Bucket ist keins.
  • Pinne jedes Image mit Digest und aktualisiere eine Komponente pro Tag.

Docker Compose startet Supabase, betreiben musst du es trotzdem

Vorab die Ausgangslage: Supabase liefert für das Self-Hosting eine fertige Docker-Compose-Vorlage. Auf einem frischen Server läuft der komplette Stack damit in wenigen Minuten, samt Studio, Anmeldung und REST-API. Genau das verführt zu einer falschen Rechnung. Wer die Vorlage startet, hat eine Entwicklungsumgebung, aber noch keinen Betrieb.

Was fehlt, steht in keiner Compose-Datei. Wer sichert die Datenbank, und wie spielt man sie zurück? Wo liegen die Schlüssel, und wer darf sie lesen? Was passiert beim nächsten Upgrade, wenn ein Dienst einen neueren Datenbankstand erwartet? Wir haben diese Fragen in Runbooks für den Produktivbetrieb beantwortet. Dieser Leitfaden fasst zusammen, was zwischen docker compose up und einem System liegt, dem du Kundendaten anvertrauen kannst.

Für wen das gilt: für Teams, die Supabase aus Gründen der Datenhoheit selbst betreiben wollen, etwa auf Hetzner, im eigenen Rechenzentrum oder auf Kubernetes. Wer mit der Supabase Cloud in Frankfurt arbeitet, bekommt den Betrieb mitgeliefert. Für dich ist dieser Text eine Checkliste dessen, was du dort mitbezahlst.

Was im Stack läuft: zehn Dienste statt eines Servers

Zum Thema Umfang: Supabase ist keine einzelne Anwendung, sondern ein Verbund aus Open-Source-Diensten rund um Postgres. Die Compose-Vorlage startet sie als getrennte Container (Stand Oktober 2026):

  • Postgres: die Datenbank, ergänzt um Supabase-Erweiterungen wie pg_net, pgsodium und supabase_vault.
  • Auth (GoTrue): Anmeldung, Registrierung und die Ausgabe von Tokens.
  • PostgREST: erzeugt aus deinem Datenbankschema die REST-API.
  • Realtime: überträgt Datenbankänderungen per WebSocket an die Clients.
  • Storage und imgproxy: Dateiablage samt Bildtransformationen.
  • Edge Runtime: führt deine Edge Functions auf Deno-Basis aus.
  • Supavisor: bündelt viele gleichzeitige Datenbankverbindungen zu wenigen.
  • Studio und postgres-meta: das Dashboard und seine Schnittstelle zur Datenbank.
  • Envoy: das API-Gateway, das alle Pfade unter einer Adresse zusammenführt. Ältere Anleitungen zeigen an dieser Stelle noch Kong.

Logflare und Vector für die Protokolle liegen in einer zweiten, optionalen Compose-Datei. Für den Start kannst du sie weglassen, solange du Logs auf anderem Weg einsammelst. Wer die Anmeldung über einen eigenen Identity-Provider abwickeln will, findet den Aufbau in unserem Artikel zu Supabase und Keycloak.

Die Pointe: Jeder dieser Dienste hat eigene Versionen, eigene Konfiguration und eigene Fehlerbilder. Wer Supabase selbst betreibt, betreibt zehn Dienste, die sich auf dieselbe Datenbank und dieselben Schlüssel verlassen. Das ist beherrschbar. Aber es ist Betrieb und kein Hosting.

Postgres zuerst: der einzige Dienst, den du nicht neu startest

Alle anderen Dienste sind austauschbar: Fällt Realtime aus, startest du den Container neu. Bei Postgres funktioniert das nur, solange die Daten unversehrt sind. Deshalb bekommt die Datenbank einen eigenen Lebenszyklus mit eigenem Speicher, eigenem Backup und eigenen Upgrade-Regeln. Wie du Zugriffsrechte direkt in der Datenbank regelst, beschreibt unser Artikel zu Row Level Security.

Container, Operator oder Managed Service?

Du hast drei Wege. Der Postgres-Container aus der Compose-Vorlage ist der einfachste, verlangt aber Backups in Eigenregie. Auf Kubernetes übernimmt ein Operator wie CloudNativePG die Einrichtung, die fortlaufende Archivierung und die Wiederherstellung. Ein externer Managed-Postgres-Dienst nimmt dir den Betrieb ab, erlaubt aber oft nicht die Erweiterungen, die Supabase voraussetzt.

Der Grund für die Einschränkung: Erweiterungen wie pgsodium und pg_net müssen beim Start der Datenbank geladen werden und brauchen weitreichende Rechte. Viele Managed-Angebote erlauben beides nicht oder nur für eine feste Liste. Prüf deshalb vor der Entscheidung, ob jede Erweiterung, die Supabase nutzt, bei deinem Anbieter verfügbar ist.

Die Init-Skripte, die niemand ausführt

Hier liegt der Stolperstein, den kaum eine Anleitung erwähnt. Das Image supabase/postgres legt beim ersten Start über sein Startskript Rollen, Schemata und Erweiterungen an. Ein Operator wie CloudNativePG richtet die Datenbank aber selbst ein und überspringt dieses Startskript. Ohne Gegenmaßnahme fehlen danach das Schema auth, die Rolle supabase_admin und alles, worauf Auth und Storage aufbauen.

Unsere Lösung: Wir kopieren die Init-SQL-Dateien aus genau dem Image-Tag, den wir betreiben, und spielen sie einmalig über einen Migrationsjob ein. Jede angewendete Datei erhält einen Eintrag in einer Protokolltabelle. Ein zweiter Lauf überspringt sie, ein abgebrochener Lauf setzt an der fehlerhaften Datei wieder an.

Daraus folgt eine harte Regel: Ein neuer Image-Tag bringt neue Init-Dateien mit. Tag und eingespielte SQL wechseln deshalb immer gemeinsam, nie einzeln.

Drei Details, die über den ersten Start entscheiden

  • Benutzerkennung: Der Datenbankprozess muss als Benutzer postgres laufen. Im Tag 17.6.1.136 ist das die UID 100 mit der GID 101. Wer hier 0 einträgt, startet Postgres als root, und die Prüfung des Datenverzeichnisses schlägt fehl.
  • Vorab geladene Bibliotheken: pg_net, pgsodium, pg_cron und supabase_vault funktionieren nur, wenn sie in shared_preload_libraries stehen. Die Liste übernimmst du aus der postgresql.conf des Images, nicht aus dem Gedächtnis.
  • pgsodium-Schlüssel: Supabase Vault verschlüsselt Geheimnisse mit einem Hauptschlüssel, den ein Skript beim ersten Start erzeugt. Dieser Schlüssel muss neben den Daten liegen und mit ihnen gesichert werden. Ein neu erzeugter Schlüssel entschlüsselt keine alten Vault-Einträge.

Verdichtet: Bei Supabase ist die Datenbank nicht nur Speicher, sondern Teil der Anwendung. Wer sie wie ein beliebiges Postgres behandelt, merkt es spätestens beim ersten Login, der nicht funktioniert.

Schlüssel: ein Dutzend Werte, die zusammenpassen müssen

Supabase lebt von Schlüsseln, und sie hängen voneinander ab. Die mitgelieferten Skripte generate-keys.sh und add-new-auth-keys.sh schreiben sie in eine .env-Datei. Für die Entwicklung ist das in Ordnung. In Produktion gehört diese Datei weder auf den Server noch in Git.

Was es zu verwalten gibt

  • JWT-Geheimnis und abgeleitete Schlüssel: das gemeinsame Geheimnis, die Anon- und Service-Role-Schlüssel, die asymmetrischen Schlüssel samt JWKS-Dokument sowie Publishable und Secret Key.
  • Datenbankpasswort: Die Vorlage nutzt ein Passwort für alle Systemrollen. Wir behalten das bei, weil die Init-SQL genau diesen einen Wert erwartet.
  • Dienstschlüssel: Realtime, Supavisor und postgres-meta brauchen eigene Werte, das Dashboard ein eigenes Passwort.
  • Objektspeicher: Zugangsschlüssel für den Datei-Bucket und, getrennt davon, für den Backup-Bucket.

Wo die Schlüssel liegen sollten

In unseren Runbooks liegt jeder Wert in einem Passwortmanager und gelangt über den External Secrets Operator in den Cluster. Der Operator liest die Felder und legt daraus Kubernetes-Secrets an. Im Git-Repository stehen nur Verweise, nie Werte.

Ob die Quelle Bitwarden, HashiCorp Vault oder der Dienst eines Cloud-Anbieters ist, entscheidet dein Team. Entscheidend ist, dass es genau eine Quelle gibt und dass ihr Export getrennt von den Servern liegt.

Eine Ausnahme bleibt: Der Zugang, mit dem der Cluster den Passwortmanager entsperrt, kann nicht selbst darin liegen. Diesen einen Wert legen wir einmalig von Hand an und nutzen dafür ein eigenes Konto, das nur die Werte dieser Plattform enthält. Wer dieses Secret lesen kann, kann das Konto entsperren. Deshalb ist der Lesezugriff darauf im Cluster eng begrenzt.

Ein typischer Fehler aus der Praxis: Auth und PostgREST prüfen Tokens mit unterschiedlichen Schlüsseln. Die Anmeldung klappt, jede Abfrage über /rest/v1 scheitert mit einem JWT-Fehler. Ursache ist fast immer ein Dienst, der noch einen alten Wert hält. Deshalb tauschen wir Schlüssel immer für alle Dienste gleichzeitig aus.

Was öffentlich erreichbar sein darf

Das API-Gateway führt alle Pfade auf einem Port zusammen. Öffentlich erreichbar sein müssen davon nur die API-Pfade: Auth, REST, GraphQL, Realtime, Storage und Functions unter /auth/v1, /rest/v1 und so weiter. Alles andere gehört ins interne Netz.

  • Studio: das Dashboard mit Vollzugriff auf die Datenbank. Wir schützen es doppelt: mit einer Passwortabfrage per HTTP Basic Auth am Gateway und mit einer IP-Freigabe nur für das Büro- oder VPN-Netz.
  • postgres-meta: die Schnittstelle, über die Studio als Superuser arbeitet. Sie bekommt nie eine öffentliche Route.
  • Postgres und Supavisor: Die Ports 5432 und 6543 bleiben intern. Externe Werkzeuge verbinden sich über einen Tunnel oder ein VPN.
  • TLS: Zertifikate automatisch über Let's Encrypt. Zum Testen zuerst gegen die Staging-Umgebung, weil die Produktivumgebung fehlgeschlagene Versuche begrenzt.

Eine Kleinigkeit mit großer Wirkung: Damit eine IP-Freigabe greift, muss der Ingress die echte Absenderadresse sehen. Auf Kubernetes heißt das externalTrafficPolicy: Local am Ingress-Service. Ohne diese Einstellung prüft die Freigabe die Adresse des Knotens, und Studio ist entweder für alle offen oder für niemanden.

Dateien gehören nicht auf den Datenbankserver

Die Compose-Vorlage legt hochgeladene Dateien standardmäßig auf der lokalen Festplatte ab. Für einen Testbetrieb reicht das. In Produktion verknüpft es zwei Dinge, die getrennt gehören: Fällt der Server aus, sind Datenbank und Dateien gleichzeitig weg. Und wachsen die Dateien, läuft die Platte der Datenbank voll.

Wir setzen deshalb immer einen S3-kompatiblen Objektspeicher außerhalb des Servers ein, etwa Hetzner Object Storage, Cloudflare R2 oder AWS S3. Storage und imgproxy lesen und schreiben in denselben Bucket.

Die Unterschiede zwischen den Anbietern stecken im Detail. Bei AWS bleibt der Endpunkt leer, alle anderen brauchen ihre Adresse und die Path-Style-Adressierung. Bei Cloudflare R2 musst du zusätzlich die S3-Tags für fortsetzbare Uploads abschalten, sonst antwortet Storage mit dem Fehler 500.

Und der Satz, den wir in jedes Runbook schreiben: Ein Backup, das im selben Bucket liegt wie die Live-Daten, ist kein Backup. Für die Datenbanksicherung gibt es deshalb einen zweiten Bucket mit eigenem Zugangsschlüssel.

Backups, die du zurückspielen kannst

Zum Thema Sicherung zuerst die unbequeme Frage: Wann hast du zuletzt ein Backup zurückgespielt? Ein Dump, der jede Nacht entsteht, beweist nur, dass ein Dump entsteht. Ob daraus wieder ein funktionierendes Supabase wird, zeigt erst die Wiederherstellung.

Was gesichert werden muss

  • Postgres: fortlaufende Archivierung der Write-Ahead-Logs plus tägliches Basis-Backup in den Backup-Bucket. Damit stellst du auf einen beliebigen Zeitpunkt wieder her, nicht nur auf die letzte Nacht.
  • pgsodium-Schlüssel: liegt im Datenverzeichnis und ist damit Teil der Datenbanksicherung.
  • Dateien: liegen bereits im Objektspeicher. Eine zweite Kopie entsteht über die Replikation des Anbieters oder eine Synchronisation in einen dritten Bucket.
  • Schlüssel und Konfiguration: ein verschlüsselter Export des Passwortmanagers und, auf Kubernetes, der Zustand des Clusters samt dem Schlüssel, mit dem er seine Secrets verschlüsselt.

Die Probe aufs Exempel

Eine Wiederherstellungsprobe läuft bei uns in fünf Schritten: frische Umgebung aufsetzen, Datenbank aus dem Backup wiederherstellen, die Dienste darauf zeigen lassen, den Migrationsjob starten und in Studio eine Zeile lesen, die vor dem Backup geschrieben wurde.

Der Migrationsjob muss dabei nichts tun, weil seine Protokolltabelle mitgesichert wurde. Tut er doch etwas, stimmt etwas nicht. Diese Prüfung kostet eine Minute und erspart dir die Überraschung im Ernstfall.

Ein Detail mit Folgen: Scheitert die Archivierung der Write-Ahead-Logs, bewahrt Postgres die Dateien auf, bis sie archiviert sind. Eine falsch eingerichtete Sicherung füllt so unbemerkt die Platte, bis die Datenbank stehen bleibt. Wir schalten Backups deshalb erst ein, wenn die Grundinstallation läuft, und lösen danach sofort eine erste Sicherung von Hand aus.

Verdichtet: Ein Restore, den du nie geprobt hast, ist eine Hypothese. Ob du die Probe regelmäßig machst oder nur vor großen Upgrades, ist eine Kostenfrage. Dass du sie mindestens einmal machst, ist keine.

Upgrades: feste Versionen und eine Komponente pro Tag

Die Compose-Vorlage verweist auf Image-Tags, und Supabase veröffentlicht häufig neue. Die Versuchung ist groß, regelmäßig alles auf den neuesten Stand zu ziehen. Wir machen das Gegenteil: Jede Version ist festgeschrieben, jedes Image zusätzlich über seinen Digest, also die Prüfsumme seines konkreten Inhalts. Ein Tag kann neu vergeben werden, ein Digest nicht.

Drei Regeln aus dem Betrieb

  • Gemeinsam wechseln, was zusammengehört: Postgres-Tag und eingespielte Init-SQL ändern sich nur zusammen. Gemischte Stände sind der häufigste Grund, warum Auth und PostgREST sich über Token-Algorithmen uneinig sind.
  • Eine Komponente pro Tag: Betriebssystem, Kubernetes, Datenbank-Operator und Supabase-Images nie am selben Nachmittag aktualisieren. Sonst weißt du nicht, welcher Wechsel den Fehler ausgelöst hat.
  • Alle Release-Notes lesen: nicht nur die der Zielversion, sondern die aller übersprungenen Versionen dazwischen.

Schemaänderungen laufen über Migrationen

Tabellen, Policies und Funktionen änderst du im Produktivsystem nicht per Klick in Studio, sondern über Migrationsdateien im Repository. Die Supabase CLI legt sie lokal an, etwa mit supabase migration new. Die lokale config.toml dient nur der Entwicklungsumgebung, der Server liest sie nicht.

In Produktion spielt derselbe Migrationsjob, der die Init-SQL einspielt, auch deine Migrationen ein: in fester Reihenfolge und jede genau einmal. Eine Tabelle merkt sich, welche Version angewendet wurde. Seed-Daten bleiben standardmäßig aus, weil sich ein Seed selten zweimal ausführen lässt, ohne Schaden anzurichten.

Der Gewinn zeigt sich doppelt: Nach einem Restore kennt die Datenbank ihren eigenen Stand. Und jede Änderung ist in Git nachvollziehbar, mit Autor, Datum und Review.

Edge Functions gehören ins Image

Im Self-Hosting lädt die Edge Runtime deine Funktionen aus einem Verzeichnis. Wir bauen sie deshalb in ein eigenes Image auf Basis von supabase/edge-runtime, versioniert wie jede andere Software. So läuft in Produktion genau der Code, der getestet wurde.

Eine Einschränkung solltest du kennen: Die JWT-Prüfung gilt im Self-Hosting für alle Funktionen gemeinsam. Die Einstellung verify_jwt je Funktion aus der lokalen config.toml greift dort nicht. Braucht eine einzelne Funktion eine Ausnahme, prüfst du das Token in der Funktion selbst.

Docker Compose, Kubernetes oder Supabase Cloud?

Damit zur Frage, die eigentlich am Anfang stehen sollte: Welcher Betriebsweg passt zu deinem Team? Unsere Standardempfehlung ist entweder die Supabase Cloud in Frankfurt oder Supabase self-hosted auf einem Hetzner-Server. Kubernetes kommt dazu, wenn dein Team Kubernetes ohnehin betreibt oder Deployments vollständig aus Git steuern will.

Supabase Cloud (Frankfurt)Docker Compose auf einem ServerKubernetes mit GitOps
Betriebübernimmt Supabasedein Team oder wirdein Team oder wir
DatenhoheitEU-Region, Vertragspartner Supabase Pte. Ltd.vollständig bei dirvollständig bei dir
Backupsim Tarif enthalten, Umfang je nach Tarifselbst einrichten und probenüber den Operator, Probe trotzdem nötig
Upgradesdurch Supabaseper Hand, eine Komponente nach der anderenper Commit, rücksetzbar
Einstiegshürdegeringmittelhoch
Sinnvoll, wenndu schnell starten willstein kleines Team volle Kontrolle willKubernetes schon da ist oder kommen soll

Ehrlich gesagt: Ein einzelner Kubernetes-Knoten ist keine Hochverfügbarkeit. Er bringt dir reproduzierbare Deployments und eine saubere Schlüsselverwaltung. Fällt der Server aus, steht der Dienst aber genau wie bei Docker Compose.

Wer echte Ausfallsicherheit braucht, braucht mehrere Knoten und eine Datenbank-Replik auf getrennter Hardware. Damit steigt der Betriebsaufwand deutlich. Für die meisten Projekte, die wir begleiten, ist ein sauber gesicherter einzelner Server mit geprobtem Restore die ehrlichere Wahl.

Wann wir vom Self-Hosting abraten

Zur Ehrlichkeit gehört die Gegenrichtung. Wir raten vom Self-Hosting ab, wenn niemand im Team die Verantwortung für Backups und Upgrades dauerhaft übernehmen kann. Ein System, das nach dem Weggang einer Person keiner mehr versteht, kostet mehr als jede Cloud-Rechnung.

Ebenso raten wir ab, wenn Hochverfügbarkeit Pflicht ist, das Budget aber nur einen Server hergibt. Dann ist die Supabase Cloud die ehrlichere Wahl. Und schließlich, wenn Datenhoheit gar nicht der Grund ist: Wer nur Kosten sparen will, setzt die eigene Arbeitszeit meist zu niedrig an.

Was du an Ressourcen einplanen solltest

Für die Planung ein paar feste Zahlen. Supabase nennt für die reine Compose-Variante 4 GB Arbeitsspeicher als Untergrenze. Auf Kubernetes kommen Cluster-Dienste hinzu: Ingress, Zertifikatsverwaltung, GitOps, Secret-Operator und Datenbank-Operator.

Unsere Runbooks setzen dafür mindestens 4 vCPU, 16 GB Arbeitsspeicher und 100 GB SSD an. Empfohlen sind 8 vCPU, 32 GB und 200 GB SSD, damit Studio, Realtime und ein Migrationsjob gleichzeitig laufen können, ohne dass der Speicher knapp wird.

Der größere Posten ist selten der Server, sondern die Arbeitszeit für Einrichtung, Proben und Upgrades. Wie sich Server, Speicher und Betrieb gegen die Cloud rechnen, steht in unserer ehrlichen TCO-Betrachtung.

Nächste Schritte

Wenn du Supabase selbst betreiben willst, klär zuerst die Betriebsfrage und dann die Technik: Wer ist für Backups, Proben und Upgrades zuständig, auch in zwei Jahren noch? Die Betriebswege, unsere Preisrahmen und die Fälle, in denen wir abraten, findest du auf unserer Supabase-Seite.

Du willst wissen, welcher Weg zu deinem Projekt passt? Im Videogespräch gehen wir deine Anforderungen an Datenhoheit, Verfügbarkeit und Team durch. Danach weißt du, ob Cloud, Compose oder Kubernetes die richtige Wahl ist. Supabase-Erstgespräch vereinbaren

Häufige Fragen

Ist Supabase self-hosted kostenlos?
Die Software ist Open Source und frei von Lizenzkosten. Du bezahlst Server, Objektspeicher und vor allem die Arbeitszeit für Einrichtung, Backups, Proben und Upgrades. Ob das günstiger ist als die Cloud, hängt von Größe und Team ab. Die Rechnung steht in unserer [TCO-Betrachtung](/de/blog/was-supabase-in-der-produktion-wirklich-kostet).
Kann ich Supabase self-hosted auf Kubernetes betreiben?
Ja. Supabase pflegt offiziell die Docker-Compose-Vorlage. Für Kubernetes gibt es Community-Charts, oder du überträgst die Dienste in eigene Deployments. Wir betreiben Postgres dabei über den Operator CloudNativePG und spielen die Init-SQL des Supabase-Images einmalig über einen Migrationsjob ein.
Welche Funktionen fehlen beim Self-Hosting?
Eine selbst betriebene Instanz entspricht einem Projekt. Plattformfunktionen der Cloud wie Branching, mehrere Projekte in einer Organisation oder verwaltete Backups gibt es nicht. Die Dienste selbst, also Datenbank, Auth, API, Realtime, Storage und Edge Functions, sind dieselben.
Wie oft sollte ich ein Supabase-Backup zurückspielen?
Mindestens einmal nach der Einrichtung und vor jedem größeren Upgrade. Verarbeitest du Kundendaten, legst du die Probe am besten in einen festen Rhythmus, etwa einmal im Quartal.
Brauche ich für Supabase self-hosted Kubernetes?
Nein. Für die meisten Teams reicht ein Server mit Docker Compose, sauber gesicherten Backups und festen Versionen. Kubernetes lohnt sich, wenn du es ohnehin betreibst, mehrere Anwendungen auf derselben Plattform führst oder Deployments vollständig aus Git steuern willst.

Quellen

Ähnliche Artikel

Offen für ausgewählte Projekte

Lassen Sie uns über Ihr Projekt sprechen

Buchen Sie einen unverbindlichen Termin, schreiben Sie uns eine E-Mail oder nutzen Sie das Formular – wir freuen uns auf Ihre Nachricht.

150+
Abgeschlossene Projekte
15
Jahre Erfahrung
7
Senior‑Level Teammitglieder