Fünf Jahre Engineering-Teams führen, und ich kenne das Warnsignal: Du hörst auf, selbst Dinge auszuliefern. Du reviewst PRs, statt sie zu schreiben. Du moderierst Retros, statt Production zu debuggen. Du beschreibst, wie guter Code aussieht, statt ihn zu schreiben. Der Job zieht dich in diese Richtung, und wenn du es nicht bemerkst, schmückst du dich irgendwann mit Arbeit, die du gar nicht mehr machst.
Diese Seite ist eine kleine Absicherung dagegen.
Ich hätte ein Template nehmen können. Framer, Webflow, ein polierter Next.js-Starter, jedes davon hätte mich an einem Nachmittag live gebracht. Ich habe mich dagegen entschieden, teils weil die Seite selbst ein Portfolio-Stück ist, das Engineers und Hiring Manager inspizieren werden, und ein Framer-Template ihnen wenig darüber verrät, wie ich denke. Teils, weil ich die Befriedigung wollte, wieder einmal etwas End-to-End zu bauen.
Die Entscheidungen, die interessant waren
Next.js 16 und React 19, nicht etwas Konservativeres. Der Server/Client-Split des App Routers ist in Produktionsgröße immer noch echtes Neuland. Ich wollte Zeit aus erster Hand mit dem RSC-Verhalten, den HMR-Eigenheiten von Turbopack und den Suspense-Patterns, die sich gegen eine Version, die die meisten Teams tatsächlich fahren, schwer nachstellen lassen. Die Seite ist klein genug, dass ich die scharfen Kanten ohne Konsequenzen absorbieren konnte.
Tailwind v4, nicht v3. Tailwind v4 ist ein nahezu vollständiges
Rewrite, CSS Custom Properties statt generierter Utility-Klassen, ein
neues Konfigurationsmodell, kein tailwind.config.ts. Es ist nicht das,
was dein Team heute fährt, aber in 18 Monaten wird es das sein. Das
mentale Modell verschiebt sich genug, dass ich in voller Tiefe damit
bauen wollte, statt in einer Produktionscodebasis nur hineinzuschnuppern,
wo die Lücke zwischen v3-Intuition und v4-Realität das Problem von
jemand anderem wäre.
Vanilla-i18n, keine Library. Englisch und Deutsch vom Launch an, ohne
Third-Party-i18n-Dependency. Zwei Locale-Dictionaries als
TypeScript-Module, eine Middleware-Datei, die Accept-Language liest und
weiterleitet. Das Typsystem fängt fehlende Translation-Keys zur
Compile-Zeit. Drei Tage Mehrarbeit im Vergleich zum Griff nach einer
Library, aber ich verstehe jede Zeile davon, und das zählt, wenn man in
Production Locale-Negotiation debuggt und die Abstraktionen einer Library
genau das sind, was im Weg steht.
Ein AI-Playground auf derselben Architektur, die ich bei der Arbeit nutze. Der CV-Chatbot auf dieser Seite ist keine Dekoration. Es ist dasselbe Pattern, das ich bei der Arbeit für ein Natural-Language-SQL-Produkt ausgeliefert habe: ein geerdeter System-Prompt, eine explizite Refusal-Policy, Prompt-Caching, um die Token-Kosten niedrig zu halten, ein Per-IP-Rate-Limiter und ein hartes tägliches Budget-Cap. Der Playground ist das Näheste, was diese Seite an „den Rechenweg zeigen" hat.
Was ich hier zu schreiben plane
Dieselben Dinge, die ich Engineers, mit denen ich arbeite, immer wieder erkläre:
- Wie man eine öffentliche GraphQL-API ohne Cutover replattformt, Strangler-Fig, Shadow-Diff, Schema-Drift auf zwei Gleisen, die Teile, die das Post-Mortem auslässt
- Welche AI-augmentierten Delivery-Wetten sich in Production ausgezahlt haben, welche ich gelöscht habe, und was die überlebenden gemeinsam haben
- Die langweilige technische Arbeit hinter einer p50-Latenz-Reduktion, die Messungen, nicht die dramatischen Momente
- Wie das Mentoring einer Engineer:in bis zur Beförderung tatsächlich aussieht, im Gegensatz dazu, wie es in einem Performance-Review beschrieben wird
Das Ziel sind keine Kriegsgeschichten. Es ist das Trade-off-Denken, das es selten in ein Postmortem oder eine Fallstudie schafft, aber der Teil ist, der es am meisten wert ist, aufgeschrieben zu werden.
Der RSS-Feed ist live, falls du lieber in deinem Reader liest.