
Internes System
Ein internes Kontrollpanel, das die 24 von mir betreuten Projekte in einer Tabelle überwacht. Domain- und Zertifikatsablauf, Deployment-Status sowie Lücken bei Such- und Messanbindungen liegen an einer Stelle. Das Panel ändert keinen Code; es stellt fest, und die Korrektur mache ich im Repository des jeweiligen Projekts.
Wer vierundzwanzig getrennte Projekte und Domains betreut, verliert nicht den Code, sondern die Sichtbarkeit. Ein Zertifikat läuft ab, ein Deployment ist fehlgeschlagen und geblieben, auf einer Website wurde die Messung nie eingerichtet — nichts davon erscheint als Fehler; eines Tages fällt es jemandem einfach auf. Der eigentliche Teil des Problems ist nicht die Erkennung, sondern die Dauer: Ohne zu wissen, seit wann eine Lücke besteht, lässt sich nicht entscheiden, welche zuerst geschlossen wird. Der zweite Punkt: Das Überwachungswerkzeug ist selbst eine Risikoquelle — ein Schlüsselsatz, der vierundzwanzig Projekte erreicht, rückt die Frage, wo diese Schlüssel liegen, ins Zentrum des Entwurfs.
Ein Nutzer: ich. Das ist eine Randbedingung, die das Panel geformt hat — weder Mehrbenutzer-Berechtigungen noch Einladungsablauf oder Rollenverwaltung wurden geschrieben. Es gibt jedoch zwei Nutzungsmomente: den Blick am Morgen (was ist heute kaputt) und den Blick in der Woche (welche Lücke besteht am längsten). Danach ist das Panel aufgeteilt.
Einzelner Entwickler. Die Analyse der Randbedingungen, Datenmodell, Scan-Skript, Panel-Oberfläche, Benachrichtigungsschicht und Bereitstellung.
Das System ist zweigeteilt, und diese Teilung ist das Zentrum des Entwurfs. Der Sammel-Scan läuft nicht in der Umgebung des Panels, sondern außerhalb als geplanter Job: Er fragt vierundzwanzig Projekte nacheinander ab und schreibt das Ergebnis direkt in Neon Postgres. Das Panel liest nur. Beim Seitenaufbau geht keine Anfrage an einen externen Dienst; alles auf dem Bildschirm ist ein zuvor geschriebenes Scan-Ergebnis. Das Datenmodell ruht auf fünf Begriffen: das Projekt im Inventar, ein Scan-Lauf und ein einzelner Scan, der aus einem Scan entstehende Befund, die daraus abgeleitete Empfehlung und die daraus entschiedene Aufgabe. Da Änderungen in ein eigenes Protokoll geschrieben werden, lässt sich aus der Historie ablesen, wann ein Befund entstand und wie lange er besteht. Zeigt das Panel einen Befund, stellt es ein kopierbares Kommando daneben; ausgeführt wird es in meinem Terminal, nicht im Panel.
Zwei harte Randbedingungen führten dazu. Erstens der Planer: Im genutzten Hosting-Tarif läuft ein geplanter Job höchstens einmal täglich und der Auslösezeitpunkt ist unbestimmt. Zweitens die Dauer: Im selben Tarif liegt das Funktions-Timeout bei zehn Sekunden, und ein Scan über vierundzwanzig Projekte wird darin nicht fertig. Das Auslagern des Scans beseitigte beides — keine Frequenzgrenze, kein Timeout.
KompromissDas System lebt nun in zwei Umgebungen, und beide Konfigurationen müssen gemeinsam stimmen. Ein Fehler auf der Scan-Seite erscheint im Panel nicht als Fehler; die Daten sind schlicht nicht aktualisiert, und um das zu bemerken, muss man die Scan-Läufe selbst ansehen.
Die Teilung entstand aus der Planer-Randbedingung, ihr eigentlicher Wert liegt aber in der Sicherheit: Der Schlüsselsatz, der vierundzwanzig Projekte erreicht, liegt dort, wo der Scan läuft; die Umgebung des Panels trägt nur so viel Berechtigung, wie für die Abfrage eines einzelnen Projekts nötig ist. Eine Kompromittierung des Panels bedeutet keinen Zugriff auf das gesamte Portfolio.
KompromissDerselbe Schlüssel wird an zwei Stellen verwaltet, und wird einer rotiert, kann der andere vergessen werden. Eine automatische Prüfung dafür gibt es nicht; die vergessene Seite zeigt sich erst, wenn die zugehörige Funktion ausfällt.
Das Panel ist eine bereitgestellte Anwendung; es erreicht kein lokales Dateisystem und liest keine Repositories. Statt diese Randbedingung zu umgehen, wurde der Umfang danach gezogen: Das Panel zeigt das Problem samt Kontext, stellt ein kopierbares Kommando daneben, und die Korrektur mache ich in meinem eigenen Terminal. Ein Werkzeug, das automatische Korrekturen schreibt, müsste in vierundzwanzig verschiedenen Codebasen mit denselben Annahmen arbeiten.
KompromissDer Korrekturschritt ist nicht automatisiert; das Panel kann sagen, dass etwas kaputt ist, sieht die Behebung aber erst beim nächsten Scan. Bis dahin bleibt derselbe Befund auf dem Bildschirm.
Das Inventar des Panels enthält Domainnamen, Registrar- und DNS-Angaben, Verkehrszahlen und Kontaktdaten. Diese gehören der Kundschaft; ein in einem Portfolio gezeigtes Bild darf sie nicht tragen. In dieser Fallstudie erscheinen die Projekte mit nummerierten Bezeichnern.
KompromissDie Maskierung schwächt den Eindruck realer Nutzung: Der Screenshot erklärt, was das System tut, zeigt aber nicht, was eine Nutzerin sieht. Dieser Preis wird bewusst gezahlt.
Auf der Panel-Seite Next.js und Drizzle, auf der Scan-Seite ein schlichtes Node-Skript — beide teilen dasselbe Schema, denn die einzige Quelle der Wahrheit ist die Datenbank. Neon läuft im selben serverlosen Modell wie die Bereitstellung und ist auch vom extern laufenden Scan-Job erreichbar; eine zweite Kopie des Inventars gibt es nicht. Eine CI-Pipeline als Planer zu nutzen, ist keine Vorliebe, sondern Randbedingung: Sie war die einzige Option ohne Frequenz- und Zeitgrenze. Da es nur eine Person gibt, wurde kein aufwendiges Berechtigungsmodell gebaut. Web Push verkürzt die Zeit, bis ein Befund bemerkt wird — eine im Postfach verlorene Warnung ist keine Warnung.
Das Panel ist sitzungsgeschützt, und der Routenschutz läuft in der Node-Laufzeit. Sensible Inventarfelder — Registrar, DNS-Konfiguration, Kontaktdaten — sind nur im Panel sichtbar und gelangen in keine externe Ausgabe, keinen Screenshot und nicht in diese Fallstudie. Weitreichende Dienstkonto-Schlüssel liegen nicht in der Umgebung des Panels; dort besteht nur so viel Berechtigung, wie für die Abfrage eines einzelnen Projekts nötig ist. Die Berechtigungen der Dienstkonten werden je Property von Hand erteilt — automatisieren lässt sich das nicht, was zugleich verhindert, dass Berechtigungen still wachsen.
Dieses Panel ist ein geschlossenes System; da keine mit Datum versehene Lighthouse-Ausgabe vorliegt, steht hier kein Seitengeschwindigkeits-Score. Das strukturelle Maß lautet: Beim Seitenaufbau geht keine Anfrage an einen externen Dienst, jeder Wert auf dem Bildschirm wird aus der Datenbank gelesen. Da ein Scan über vierundzwanzig Projekte nicht in ein Zehn-Sekunden-Timeout passte, wurde er aus dem Panel ausgelagert; der einzige verbliebene Scan-Pfad im Panel ist der "jetzt scannen"-Endpunkt für ein einzelnes Projekt, gemessen in Sekunden.
Ursprünglich hielt ich das Inventar als YAML-Dateien im Repository und hatte geschrieben, ich würde es nicht in eine Datenbank verlagern; dann habe ich es verlagert und die YAML-Seite vollständig gelöscht. Richtig finde ich nicht die Verlagerung, sondern die Löschung: Existieren zwei Kopien derselben Information, wird irgendwann strittig, welche stimmt. Dieselbe Lehre kam aus Bergaz Operations — dort steht dieselbe Person, weil vier getrennte Systeme eigene Datensätze führen, an zwei Stellen als zwei Einträge, und die Zuordnung geschieht von Hand. Der zweite Punkt ist die Scan-Seite: Heute würde ich den Scan seine eigene Gesundheit ebenfalls in die Datenbank schreiben lassen. Derzeit unterscheidet das Panel nicht zwischen "es gibt Daten" und "die Daten sind aktuell"; ein fehlgeschlagener Scan-Lauf lässt alte Daten still korrekt aussehen.
Sagen Sie mir, was Sie bauen wollen; ich sage Ihnen vorab, wie lange es dauert und wo man anfängt.