Technologie
Die Plattform lief einmal auf über zehn Diensten in vier getrennten Stacks. In wenigen Tagen entstanden dabei rund zehn Infrastrukturprobleme — und kein einziger Datenimport. Die Diagnose war unbequem: Die Architektur war für Phase 5 gebaut, das Produkt stand in Phase 0.
Film 02 · 5 Minuten
Von der amtlichen Quelle bis zum Bildschirm. Der Umschalter stellt den Entwurf von Mai 2026 der heute laufenden Architektur gegenüber — durchgestrichen ist, was nie gebaut oder wieder ausgebaut wurde.
Was ein Mensch zu sehen bekommt.
Zugang, Verschlüsselung, Berechtigung.
Rechnen, verdichten, erzeugen.
Beschaffen, prüfen, verbuchen.
Die einzige Quelle der Wahrheit.
Alles amtlich, alles frei zugänglich.
Jede Streichung ist ein Versprechen an den Betrieb und ein Risiko für die Zukunft. Deshalb ist keine davon endgültig: das Datenmodell trägt die Haken, an denen die Komponente wieder andockt — ohne Datenmigration.
Ein Job ist bei uns eine reine Funktion mit Ergebnisobjekt: keine interne Zustandshaltung, idempotent, einzeln auslösbar. Für 16 Läufe im Monatstakt braucht das keine DAG-Maschine mit eigener Datenbank und eigener Oberfläche.
Ein Broker, ein Result-Backend, Worker-Pools und Flower für Aufgaben, die planbar sind und nicht auf Nutzerklicks reagieren. Redis blieb — als Cache, nicht als Warteschlange.
Es gibt keinen Ereignisstrom. Die Quellen veröffentlichen monatlich, quartalsweise, jährlich — als Datei. Ein Streaming-Bus hätte nichts zu transportieren.
Ein zweiter Index will befüllt, synchronisiert und überwacht werden. Für Regions- und Berufssuche über einige Tausend Einträge reicht Postgres mit Trigram-Index.
Self-Service-BI beantwortet die Frage „welche Kennzahlen sehe ich diesen Monat?“ nicht besser als eine Berichtsdefinition, die der Kunde selbst zusammenstellt — und die mandantensicher ist.
Portale zu crawlen ist rechtlich heikel und technisch brüchig. Die BA-Jobbörse hat eine dokumentierte Schnittstelle mit nativem Umkreis-Parameter — das ist der belastbarere Weg.
Kennzahlen liegen im Long-Format: eine Zeile je Messwert, mit Gebiet, Periode, Schlüssel und Berechnungsversion. Eine neue Kennzahl ist damit ein neuer Schlüsselwert, keine Schema-Änderung. Ändert sich die Berechnungsmethode, laufen alte und neue Werte nebeneinander — historische Berichte bleiben reproduzierbar. Rohdaten behalten die vollständige Original-Antwort als JSONB; ein neues Feld der Quelle kostet keine Migration.
Jeder davon hat Stunden gekostet und steht heute als Regel im Code oder in der Dokumentation. Wir führen sie hier auf, weil eine Architektur nicht daran gemessen wird, was sie verspricht, sondern daran, was sie überlebt.
Das verwendete Postgres-Abbild legt seine Daten nicht dorthin, wo das offizielle Abbild sie ablegt. Das Volume zeigte ins Leere, die Daten lagen in der Container-Schicht — und wurden bei jedem Deploy gelöscht. Neustarts überlebten sie, was den Fehler monatelang kaschiert hat.
Bei jedem Wechsel des Datenbank-Abbilds den Datenpfad des neuen Abbilds prüfen. Den Mount nie „zurück korrigieren“.
API und Frontend hängen an mehreren Docker-Netzen. Ohne ausdrückliche Angabe wählt der Proxy das Zielnetz zufällig. Erwischt er eines ohne Proxy-Anbindung, läuft jede Anfrage der Domain in einen Zeitfehler, während die Container direkt einwandfrei antworten. Der Ausfall erscheint nach einem Neuaufbau „aus dem Nichts“.
Das Proxy-Netz je Dienst festnageln. Diagnose in dieser Reihenfolge: Container gesund → Direktabfrage im Container → Labels prüfen → Proxy-Log.
Die laufende Nummer ist ein Nadelöhr, sobald zwei Menschen gleichzeitig arbeiten: beide greifen zur nächsten freien Zahl, nur eine läuft. Die andere bleibt liegen, obwohl sie im Repository steht — und eine Spalte fehlt, die der Code bereits abfragt.
Dateinamen tragen einen Zeitstempel statt einer Nummer. Eine doppelte Version bricht den Start ab und nennt beide Dateien, statt still eine zu überspringen.
Zwei Fehler, die sich gegenseitig verdeckten: das Backup-Verzeichnis gehörte root, der Datenbanknutzer durfte nicht hineinschreiben — und der Fehlerabbruch galt innerhalb der aufgerufenen Funktion nicht, sodass die Erfolgsmeldung nach dem gescheiterten Schritt trotzdem lief.
Jeder Schritt wird einzeln geprüft, ein leerer Dump zählt als Fehler. Und: Fehlerabbruch gilt in einer aufgerufenen Funktion nicht — das betrifft jeden solchen Wrapper.
Der Proxy entfernt den abschließenden Schrägstrich, die API antwortet mit einer Umleitung auf ihre interne Adresse. Der Browser folgt ihr über die Ursprungsgrenze hinweg und verwirft dabei den Berechtigungs-Header. Ergebnis: Zugriff verweigert, Zwangsabmeldung — ausgelöst vom Öffnen der Karte.
Client-Pfade nie mit abschließendem Schrägstrich; Router-Routen als leerer Pfad registrieren.
Drei Dinge wachsen im Betrieb, ohne dass jemand etwas tut. Jedes davon ist gedeckelt — zwei davon waren es bis August 2026 nicht.
| Was wächst | Grenze | Warum genau diese |
|---|---|---|
| Container-Protokolle | 20 MB × 5 je Dienst | Docker rotiert von sich aus nicht. Im Normalbetrieb sind es wenige MB am Tag — das Problem ist der Rand: eine Neustartschleife schreibt Gigabyte pro Stunde. |
| Datenbank-Sicherungen | 14 Tage | Täglich um 03:15, außerhalb des Docker-Volumes auf dem Host — bewusst getrennt vom Datenpfad, der den Fehler aus Lehre 01 verursacht hat. |
| Hochgeladene Importdateien | 7 Tage nach Abschluss | Ein INKAR- oder SDI-Satz sind bis zu 60 Dateien à 25 MB. Aufgeräumt wird beim Anlegen des nächsten Auftrags; laufende bleiben unangetastet. |
| Gemeinsamer Speicher der Datenbank | 1 GB | Fest gesetzt, weil der Standardwert für die Aggregations-Abfragen über 2,3 Mio. Zeilen zu klein war. |
Der Reiter Datenbetrieb → Lage zeigt Platte, gemeinsamen Speicher und Datenbankgröße laufend an und warnt unter 10 % frei, mit Alarm unter 5 %. Daneben steht der Systemstatus nach dem Modell Komponente × Prüfung × Stufe.
Rund 2,3 Mio. Kennzahl-Zeilen wiegen etwa 1 GB. Die Beobachtungsschwelle liegt bei 5–10 Mio. Zeilen; dann kommen Zeitreihen-Kompression und die zwei teuren Abfragepfade dran. Ein Datenbankwechsel steht nicht zur Debatte.
Heute läuft alles als eine Compose-Application auf einem Server. Das ist für den jetzigen Stand angemessen und wird hier nicht schöngeredet: Host und Sicherungen liegen auf derselben Platte. Der Ausbau ist in vier Stufen geplant, jede additiv und ohne Datenmigration.
Sicherungen ausgelagert, Transaktionsprotokoll fortlaufend archiviert. Schließt das Katastrophenrisiko.
Vorgesehen vor dem ersten zahlenden Kunden. Umschaltung von Hand.
Erst bei zugesagter Verfügbarkeit, etwa 99,9 %.
Auf absehbare Zeit überdimensioniert — genau die Falle, aus der wir kommen.
Cache weg → langsamer, nicht kaputt. Worker weg → Karte und Auswertungen laufen weiter, ein Hinweis meldet die pausierte Aktualisierung. Geocoder weg → Rückfall auf die Postleitzahl-Auflösung.
Umschaltung heißt: Läufe passieren doppelt oder brechen mittendrin ab. Migrationen, Importe und Kennzahl-Berechnung sind darauf ausgelegt — für jeden neuen Job gilt dieselbe Anforderung.
Vierteljährlicher Rückspiel-Test auf einer Wegwerf-Instanz, mit Stoppuhr und Protokoll. Erst damit sind die Zielwerte oben Tatsachen statt Hoffnung.
Weiter