Hier schreibe ich über meinen Weg – Gelerntes, Gebautes, Gedanken.
Offen, ehrlich, mutig.
Alle Beiträge
9. September 2026Projekt
Ein Dashboard, das mitdenkt: neue Mitglieder auf einen Blick
Bisher musste ich in jede meiner Apps einzeln hineinschauen, um
zu sehen, ob sich jemand Neues angemeldet hat. Heute habe ich
dem ein Ende gesetzt: ein zentrales Admin-Dashboard, das
LernyTube, Whisky-Kuratorium und EIS Schuh-Atelier automatisch
im Hintergrund abfragt und mir übersichtlich anzeigt, wer sich
wann mit welcher E-Mail-Adresse angemeldet hat – inklusive dem
Speicherplatz, den jemand mit eigenen Fotos belegt. Ein Klick auf
einen der App-Buttons sortiert die Liste sofort auf die jeweilige
Anwendung. Ein Hintergrund-Agent prüft alle zwei Minuten von
selbst nach, ganz ohne dass ich manuell nachschauen muss.
Nebenbei ist mir aufgefallen, dass mein Schuh-Atelier bei der
Registrierung bisher gar keine E-Mail-Adresse abgefragt hat –
das habe ich gleich mit ergänzt. Und weil mir wichtig war,
dass ich als Betreiberin trotzdem nicht in die privaten
Fotosammlungen meiner Nutzer:innen hineinschauen kann, überträgt
das Dashboard bei EIS bewusst nur die Summe der Dateigrößen,
nie die Bilder selbst. Jede:r hat ihren eigenen Schuh-Schrank.
Die größte Geduldsprobe kam beim Einrichten der neuen
Domains dashboard.eiskopani.de und bewerbungsmappe.eiskopani.de:
kaum war der DNS-Eintrag gesetzt, hat mein Server-Zertifikat-Dienst
mich mit einem Rate-Limit ausgebremst, weil er es kurz zuvor
schon zu oft ohne gültige DNS-Antwort versucht hatte. Dazu kam
noch, dass mein eigener Server eine "nicht gefunden"-Antwort
eine Weile zwischengespeichert hatte, obwohl die Adresse längst
korrekt eingetragen war. Am Ende half nur eins: abwarten, bis
die Zwischenspeicherung von selbst ablief, und den Reverse-Proxy
einmal neu anstoßen. Beide Seiten laufen jetzt sauber über
HTTPS.
9. September 2026KI & Automatisierung
Das Lernbuch: mein eigener KI-Lehrer sortiert sich selbst
In LernyTube ist heute eine neue Funktion entstanden, die mir
richtig Freude macht: das "Lernbuch". Ich kann dort eine Frage
stellen, Claude antwortet wie ein Lehrer – und sortiert Frage
und Antwort danach von selbst in einen Themenbaum ein, ganz
ohne dass ich etwas anlegen oder aufräumen muss. Im Test habe
ich zwei verwandte Python-Fragen gestellt, die korrekt im
gleichen Thema landeten, und eine Geschichtsfrage, die sich
automatisch ein eigenes neues Thema geschaffen hat. Vorerst ist
die Funktion nur für meinen eigenen Account freigeschaltet.
Danach habe ich gezielt Tests dafür geschrieben, unter
anderem zwei Sicherheitstests: einen, der prüft, dass
wirklich niemand außer mir an die Funktion herankommt, und
einen sogenannten IDOR-Test. IDOR steht für "Insecure Direct
Object Reference" – im Klartext: Was passiert, wenn jemand
einfach die ID eines fremden Lernbuch-Eintrags in der
Adresse ausprobiert? Der Test stellt sicher, dass genau das
ins Leere läuft.
Beim Versuch, alles zu pushen, kam eine unangenehme
Überraschung zutage: Die GitHub-Actions-Pipeline lief seit
einer Branch-Umbenennung gar nicht mehr automatisch, weil der
Trigger noch auf den alten Namen "main" zeigte, während ich
längst auf "clean-main" arbeite. Das habe ich korrigiert –
der automatische Deploy bleibt bewusst weiter deaktiviert,
nur die Tests sollen wieder laufen. Und kaum lief die
Pipeline wieder, förderte sie gleich einen zweiten, älteren
Bug zutage: Meine eigene 404-Fehlerseite griff auf einen
Ordner zu, der nur auf meinem eigenen Server existiert, und
stürzte deshalb in jeder anderen Umgebung bei jedem "Seite
nicht gefunden"-Fehler ab. Auch das ist jetzt robust gemacht.
Am Ende lief die komplette Testsuite grün auf GitHub, alles
committed und gepusht.
9. September 2026Projekt
Meine Bewerbungsmappe: ein KI-Kollege für die Jobsuche
Heute ist ein komplett neues Projekt entstanden: die
"Bewerbungsmappe" unter bewerbungsmappe.eiskopani.de. Die Idee
ist simpel und kam aus meinem eigenen Alltag – für jede
interessante Stellenanzeige lege ich eine eigene digitale
Mappe an, mit Stellentitel, Firma, Link zur Anzeige und einem
Status von "Interessant" bis "Zusage". Das Herzstück ist ein
Chat mit einem KI-Job-Agenten direkt in jeder Mappe, der meine
Stellenanzeige und meinen Lebenslauf kennt und mir gezielt bei
der Vorbereitung auf Vorstellungsgespräche hilft.
Technisch steckt dahinter FastAPI mit einer eigenen
PostgreSQL-Datenbank, alles in einem eigenen Docker-Container
mit Traefik und Let's-Encrypt-Zertifikat live geschaltet.
Man kann PDFs hochladen – Stellenanzeige, Lebenslauf,
Anschreiben – der Text wird automatisch daraus extrahiert
und dem KI-Agenten als Kontext mitgegeben, damit die Antworten
wirklich zur konkreten Bewerbung passen. Dazu kommen 19
automatisierte Tests und eine GitHub-Actions-Pipeline, damit
das Projekt von Anfang an auf einem stabilen Fundament steht.
Der spannendste Moment war aber ein Bug im Live-Betrieb:
beim Chatten blieb die App plötzlich einfach hängen, ohne
Fehlermeldung. Grund war eine fehlerhafte Fallback-Logik auf
dem Server – wenn ein Datei-Pfad falsch aufgelöst wurde, gab
der Server stillschweigend eine HTML-Seite statt einer
echten Fehlermeldung zurück. Das Frontend-JavaScript wusste
damit nichts anzufangen und brach unbemerkt ab. Nach meiner
Fehlerbeschreibung war der Fehler schnell gefunden und
behoben – ein gutes Beispiel dafür, dass "es hängt einfach"
oft ein sehr konkretes technisches Problem im Hintergrund hat.
Auf mein Feedback hin kamen noch ein paar Dinge dazu, die
den Unterschied machen: editierbare Mappen-Details, ein
"Speichern & Schließen"-Button, ein Notizen-Feld, mit
dem ich den KI-Agenten pro Mappe individuell trainieren kann
– meine eigenen Hinweise fließen dann direkt in seine
Antworten ein – und ein Mappen-Wechsler, um schnell zwischen
verschiedenen Bewerbungen zu springen. Am Ende habe ich
jetzt ein Werkzeug, das mir bei der Jobsuche wirklich hilft,
statt nur eine weitere Liste zu sein.
9. September 2026Entwicklung
Luft raus: warum meine Seiten jetzt kürzer wirken
Heute habe ich mir die style.css dieser Seite
vorgenommen und quer über alle Unterseiten die Abstände
verkleinert – Sections, Karten, Hero-Bereich, Rechtstexte,
Lebenslauf-Timeline und Gästebuch, überall zwischen 25 und 40
Prozent weniger Margin, Padding und Gap. Keine Inhalte oder
Struktur angefasst, nur der Leerraum dazwischen.
Der Auslöser war simpel: Beim Durchklicken kam mir fast jede
Seite unnötig lang vor, obwohl der eigentliche Inhalt gar
nicht so viel ist. Die Section-Paddings standen zum Beispiel
pauschal auf 80px oben und unten – auf jeder Seite, egal wie
kurz der Abschnitt war. Ich habe das auf 56px reduziert, den
Hero-Bereich der Unterseiten von 442px Mindesthöhe auf 340px
gebracht und auch kleinere Dinge wie den Abstand zwischen
Absätzen oder den Grid-Gap bei Bildergalerien und
Skill-Karten angepasst. In Summe wirkt jede Seite jetzt
spürbar kompakter, ohne dass sie gedrängt aussieht.
Die eigentliche Lektion kam danach: CSS-Änderungen allein
reichen nicht, wenn style.css mit
Cache-Busting-Parameter eingebunden ist. Ich musste
anschließend in allen 20 HTML-Dateien den Query-Parameter
?v= hochzählen, sonst hätten Browser
wochenlang weiter die alte, gecachte Version ausgeliefert
und niemand hätte den Unterschied gesehen. Ein Detail, das
man leicht vergisst, wenn man nur an der CSS-Datei selbst
arbeitet – aber ohne den zweiten Schritt wäre die ganze
Arbeit für die Besucher unsichtbar geblieben.
1. September 2026Projekt
Vom Debug-Build zum Play Store
Meine Android-App EIS Schuh-Atelier ist technisch fertig für die
Veröffentlichung – eigener Signierungsschlüssel, signiertes
.aab, mit apksigner geprüft. Trotzdem liegt zwischen
"fertig gebaut" und "im Play Store" noch ein ganzes Stück Weg, das
nichts mit Code zu tun hat. Heute habe ich mir dafür einen
Fahrplan mit sieben Phasen erstellt, von Rechtlichem bis
Rollout.
Die Phasen im Überblick: Grundsatzentscheidung, Rechtliches,
Play-Konto anlegen, Store-Eintrag gestalten,
Datensicherheit-Formular ausfüllen, Technik (größtenteils schon
erledigt) und zum Schluss Testen & Rollout. Am meisten
überrascht hat mich, wie viel davon Papierkram ist und wie
wenig Programmieren: Impressumspflicht nach §5 DDG gilt auch
für eine kostenlose Hobby-App, sobald sie öffentlich im Store
steht – die Ausnahme für "rein private Nutzung" greift dann
praktisch nicht mehr. Dazu kommt eine Datenschutzerklärung
nach DSGVO, die per URL erreichbar sein muss, und seit Februar
2025 zusätzlich ein DSA-Trader-Status in der Play Console.
Die eigentlich wichtige Entscheidung kommt aber noch vor all
dem: Aktuell kann sich über die Registrierung jede beliebige
Person ein Konto in meiner App anlegen. Bleibt das so, bin ich
rechtlich Verantwortliche für fremde Nutzerdaten – mit vollem
DSGVO-Umfang. Beschränke ich die Registrierung stattdessen auf
mich selbst oder auf Einladung, sinkt das Risiko deutlich,
auch wenn ein Impressum trotzdem Pflicht bleibt. Diese
Entscheidung habe ich heute bewusst noch offengelassen – sie
bestimmt, wie viel von Phase 1 ich wirklich brauche, und
verdient es, in Ruhe getroffen zu werden statt nebenbei.
Für das Play-Konto selbst reicht mir als Hobby-Projekt ein
Einzelperson-Konto (25 USD einmalig, Ausweis-Verifizierung),
auch wenn das 14 Tage Closed Testing mit zwölf Testpersonen vor
der Produktion verlangt. Eine Organisation mit
D-U-N-S-Nummer wäre für ein Lernprojekt völlig überdimensioniert.
Das ist übrigens kein Rechtsrat, nur meine eigene Recherche –
Impressum und Datenschutzerklärung lasse ich im Zweifel noch
von jemandem gegenchecken, der sich damit auskennt.
1. September 2026Entwicklung
Der Fuchs zieht in die letzten beiden Zimmer
Heute habe ich Kontakt- und Gästebuch-Seite auf das einheitliche
Hero-Design umgestellt, das mein Fuchs-Maskottchen trägt – Bild
links, Titel und Text rechts. Damit haben jetzt alle sechs
Hauptseiten meiner Website dasselbe wiedererkennbare Gesicht.
Angefangen hatte das Muster vor ein paar Wochen auf der
"Wer bin ich"-Seite: ein KI-generiertes Fuchsbild links, daneben
Überschrift und kurzer Text. Danach ist es Stück für Stück
gewandert – zu den Projekten (ein Fuchs am Rechner), zum Blog
(ein Fuchs mit Tablett) und zur Weiterbildung (ein Fuchs mit
Doktorhut). Heute kamen Kontakt (ein telefonierender Fuchs am
Bahnsteig) und Gästebuch (ein Fuchs, der Gäste begrüßt) dazu –
beide Bilder mit Gemini erstellt und passend zum jeweiligen
Seiteninhalt ausgesucht.
Technisch steckt dahinter nur eine einzige CSS-Klasse,
page-hero-media, die ich einmal sauber gebaut und
seitdem einfach wiederverwendet habe: Bild und Textblock stehen
nebeneinander in einer Flexbox, auf dem Handy klappt das Ganze
automatisch untereinander. Genau deshalb waren die letzten
beiden Seiten heute auch in zwei kleinen, schnellen Commits
erledigt, statt jede Seite einzeln neu zu layouten.
Meine kleine Erkenntnis dabei: Konsistenz-Arbeit wird gern
aufgeschoben, weil sich jede einzelne Seite nach "nur eine
Kleinigkeit" anfühlt – aber wenn man das Muster einmal richtig
baut, kostet das Nachziehen der letzten Ecken kaum noch Zeit.
Und ein wiederkehrendes Maskottchen gibt der Seite plötzlich
eine Persönlichkeit, die reine Text-Überschriften nie hatten.
20. August 2026Entwicklung
Vom Chip zum Dropdown: Wie ich meiner Android-App das letzte fehlende Puzzleteil eingebaut habe
Heute war ein großer Tag für mein „EIS Schuh-Atelier" – die Android-App, an der ich
gerade Flutter lerne, hat zwei wichtige Meilensteine geschafft: den ersten echten Test
auf einem physischen Handy und ein Feature, das ich mir schon länger gewünscht hatte.
Endlich: Test auf einem echten Gerät
Bisher lief meine App nur im Browser (Flutter Web-Modus) – praktisch zum schnellen
Testen, aber eben nicht das, wofür ich sie eigentlich baue. Heute habe ich sie zum
ersten Mal auf meinem Pixel 8 Pro laufen lassen, per USB-Debugging direkt vom
Windows-Rechner aus.
Der komplette Kreislauf, den ich durchgespielt habe:
Einloggen mit meinem Test-Konto
Einen neuen Schuh anlegen – inklusive echtem Foto von der Handykamera
Nach Saison, Stil, Modell und Farbe filtern und sortieren
Einen Eintrag bearbeiten (Preis, Kaufdatum, Notizen)
Einen Eintrag wieder löschen
Alles hat auf Anhieb funktioniert. Kein CORS-Ärger wie im Browser, keine
Überraschungen bei der Kamera-Integration – einfach eine App, die tut, was sie soll.
Ein Bug, der sich als Geschenk entpuppt hat
Beim Aufräumen ist mir aufgefallen, dass mein Test für den App-Start
(widget_test.dart) plötzlich hängen blieb, statt einfach durchzulaufen.
Der Grund: Ich hatte vor einer Weile ein „Angemeldet bleiben"-Feature eingebaut, das
die Zugangsdaten verschlüsselt auf dem Gerät speichert. In der Testumgebung gibt es
aber gar kein echtes Gerät – und statt sich sauber zu beschweren, blieb der Aufruf
einfach für immer hängen. Ein echter Deadlock, kein netter Fehler mit Stacktrace.
Die Lösung war zum Glück einfach, sobald ich sie gefunden hatte: Ich musste dem Test
eine Fake-Version des Speichers unterschieben, genau wie ich es bei anderen
Netzwerkzugriffen schon mache. Danach liefen wieder alle 40 Tests grün durch.
Das Merkmale-Feature: Backend und App gemeinsam
Der zweite Teil des Tages war größer: Ich wollte schon länger die Merkmale eines
Schuhs (Größe, Saison, Stil, Modell, Farbe) auch nachträglich ändern können – bisher
konnte man die nur beim Anlegen festlegen, danach waren sie eingefroren.
Das Problem: Mein Backend (eine separate FastAPI-Anwendung, die auch meine Web-App
versorgt) kannte dieses Feld beim Aktualisieren eines Eintrags gar nicht. Also musste
ich zum ersten Mal in dieser Session auch am Backend arbeiten:
Backend-Repo geklont und den PUT /update-ordner-Endpunkt um ein merkmale-Feld erweitert – genau nach dem Muster, das beim Neuanlegen schon existierte.
Isoliert getestet, gegen eine separate Test-Datenbank auf meinem Server, bevor überhaupt irgendetwas an die echte, produktive App ging. Sicher ist sicher.
Deployed – was sich als kleines Abenteuer entpuppte, weil der automatische Reload meines Servers die Codeänderung aus irgendeinem Grund nicht selbst aufgegriffen hat. Ein kurzer, gezielter Neustart des Containers hat's dann aber gebracht.
Live verifiziert, mit meinem Test-Konto: Eintrag anlegen, Merkmale ändern, prüfen, wieder aufräumen.
Erst danach ging's an die App-Seite: Aus der reinen Anzeige der Merkmale (kleine
Chips, nicht anklickbar) wurden fünf richtige Dropdown-Felder im Detail-Screen – genau
wie ich sie schon beim Anlegen eines neuen Schuhs verwende. Wer ein altes Merkmal
ändern will, tippt einfach das Dropdown an und wählt einen neuen Wert.
Was ich mitnehme
Der Tag hat mir nochmal gezeigt, wie viele kleine Bausteine so eine App eigentlich
hat: UI, Service-Schicht, Backend-Endpunkt, Datenbank, Tests auf mehreren Ebenen, und
dann noch die Deployment-Infrastruktur dahinter. Besonders gemerkt habe ich mir:
immer zuerst gegen eine isolierte Testumgebung prüfen, bevor irgendwas
an eine live laufende Anwendung geht – auch wenn's die eigene Hobby-App ist.
Als Nächstes steht bei mir an, die kaputte CI/CD-Pipeline meines Backends aufzuräumen
(sie zeigt aktuell auf einen Branch, den es gar nicht gibt – läuft also nie
automatisch). Aber das ist eine Geschichte für einen anderen Tag.
20. August 2026Entwicklung
Blueberry trifft Cream Soda: Ein Farbtest nur für die Startseite
Heute habe ich mich getraut, mit der Farbwelt von eiskopani zu
spielen. Nur auf der Startseite, nur zum Testen: Kopfzeile, Hero
und Kontaktbereich in einem satten Blau ("Blueberry", #243B8F),
der Rest in einem warmen Cremeton ("Cream Soda", #FFF0C9) – ohne
dass ich dafür das komplette Design der Seite anfassen musste.
Der Trick dabei: Statt die zentrale style.css zu ändern, die
für die ganze Website gilt, habe ich in der index.html einen
kleinen, extra gekennzeichneten Style-Block eingefügt, der nur
dort wirkt. Damit kann ich risikofrei ausprobieren, wie sich
neue Farben anfühlen, ohne dass Blog, Projekte- oder
Weiterbildungsseite plötzlich anders aussehen. Fällt mir der
Test nicht zu, lösche ich einfach die paar Zeilen wieder – die
restliche Seite bleibt unberührt. Eine kleine, aber angenehme
Erkenntnis: Man muss nicht gleich das ganze Haus umstreichen,
um zu wissen, ob einem eine Farbe gefällt.
Nebenbei ist heute auch der Kurs-Badge auf der
Weiterbildungsseite konkreter geworden: Aus "Geplant" für den
IHK-Zertifikatslehrgang Technische/-r KI-Manager/-in ist jetzt
"Start 23.11.2026" geworden. Kleiner Textwechsel, aber für mich
ein gutes Gefühl – aus einer vagen Absicht wird ein festes
Datum im Kalender.
12. August 2026Entwicklung
Von "Neu" zu "Live" – und die Abschlussdoku gleich mit dazu
Zweite kleine Aufräumrunde heute an der Desktop-App: Der Badge auf
der Projekte-Seite heißt jetzt nicht mehr „Neu", sondern „Live" –
und direkt neben dem Download der .exe-Datei gibt es jetzt auch
einen Button für meine offizielle IHK-Projektdokumentation als PDF.
Klingt nach Kleinkram, war für mich aber ein kleiner
Meilenstein-Moment. Die Desktop-Version des Schuh-Ateliers lief
schon eine Weile stabil, trug aber immer noch das Etikett „Neu"
– als wäre sie gerade erst aus der Werkstatt gekommen. Jetzt,
wo ich weiß, dass sie zuverlässig läuft und ich sie selbst
benutze, habe ich mich getraut, den Status zu ändern. Ein Badge
ist ja nichts Technisches, sondern ein Versprechen an
Besucher:innen der Seite: „Das hier kannst du dir anschauen,
das ist fertig." Diesen Schritt bewusst zu gehen, fühlte sich
ehrlicher an, als eine App ewig als „neu" laufen zu lassen.
Die IHK (Industrie- und Handelskammer) verlangt für die
Abschlussprüfung eine schriftliche Projektdokumentation – bei
mir dreht sich die um genau dieses Schuh-Atelier-Projekt. Bisher
lag die PDF nur bei mir auf der Platte. Jetzt liegt sie, neben
Hero-Bereich und Fazit der Desktop-Seite, direkt neben dem
App-Download – für alle sichtbar, die nicht nur sehen wollen,
was ich gebaut habe, sondern auch, wie ich es begründet und
dokumentiert habe. Zwei Zeilen Code, aber ein Türöffner mehr.
12. August 2026Projekt
Nach Web und Desktop jetzt aufs Handy: Das Schuh-Atelier lernt Flutter
Heute habe ich dem EIS Schuh-Atelier eine dritte Gestalt gegeben:
Nach der Web-App und der Windows-Desktop-App kommt jetzt eine
eigene Android-App dazu. Ich habe dafür eine neue Projektseite
gebaut und meine Projekte-Übersicht gleich mit aufgeräumt, damit
sie zu den inzwischen elf Projekten passt.
Für die Android-Version steige ich in Flutter und Dart ein –
komplettes Neuland für mich. Reizvoll finde ich, dass ich mit
einer einzigen Codebasis eine native App fürs Handy bauen kann,
und dass sie sich am Ende wie eine kleine Familie mit der
Desktop-App anfühlen soll: gleiches dunkles Holzbraun-Gold-Design,
gleiches Backend im Hintergrund. Schuhe erfassen, Foto pro
Eintrag, Live-Suche, Kaufdatum und Schätzwert – die Liste der
geplanten Funktionen kenne ich schon aus den anderen Versionen,
nur die Sprache und der Bildschirm sind neu.
Beim Aufräumen der Projekte-Seite ist mir aufgefallen, dass ich
mit der Zeit angefangen hatte, mich selbst zu wiederholen: Es
gab oben eine Extra-Sektion „Was läuft gerade?“ mit vier
Kacheln, die dieselben Themen noch einmal zusammenfasste, die
weiter unten als eigene Projektkarten schon längst existierten.
Die habe ich komplett entfernt und stattdessen alle elf Projekte
sauber in eine einzige, durchnummerierte Reihenfolge gebracht.
Eine Übersicht ist nur dann eine Übersicht, wenn sie nicht zwei
verschiedene Versionen derselben Wahrheit erzählt.
10. August 2026Entwicklung
Die Galerie war fertig – nur die Lupe fehlte
Heute habe ich auf meiner Hobbys-Seite eine neue Sektion gebaut:
„Meine Lieblings-KI-Bilder", fünf Bilder zum Anklicken und
Vergrößern. Alles sah gut aus, das Grid stand, die Bilder luden –
und trotzdem passierte beim Klick auf ein Bild: nichts. Keine
Fehlermeldung, kein Absturz, einfach gar keine Reaktion.
Für die Vergrößerung nutze ich ein kleines JavaScript-Werkzeug
namens GLightbox – es öffnet angeklickte Bilder groß in einer
Art Dia-Show über der Seite. Das Skript dafür war eingebunden
und lief auch technisch korrekt. Was fehlte, war eine einzige
Zeile: die passende CSS-Datei, die dem Werkzeug sagt, wie die
vergrößerte Ansicht überhaupt aussehen soll. Ohne sie hat
GLightbox im Hintergrund brav funktioniert, aber alles war
unsichtbar – kein Rahmen, keine Überlagerung, keine Animation.
Ein Feature, das komplett fertig gebaut, aber für niemanden
sichtbar war.
Der Fix war am Ende trivial: eine `link`-Zeile im Header
ergänzt, die die GLightbox-CSS lädt. Die eigentliche Lektion
war eine andere: Ich hatte nach dem Bauen nur geprüft, ob das
Grid und die Bilder da sind – nicht, ob die Interaktion, die
den ganzen Sinn der Sektion ausmacht, auch wirklich klickbar
ist. „Sieht fertig aus" und „funktioniert wie gedacht" sind
zwei verschiedene Dinge, und nur das zweite zählt für die
Besucher meiner Seite.
10. August 2026Erkenntnis
„Wie soll ich dabei was lernen?" – ein Satz, der mich gestoppt hat
Meine Flutter-App ist heute zwei Schritte weitergekommen: Der
Register-Screen ist fertig, und gleich danach der Katalog-Screen,
der meine Schuh-Sammlung als Kachel-Übersicht zeigt. Eigentlich
ein guter Tag. Aber der eigentliche Lernmoment war ein anderer –
und der hatte nichts mit Code zu tun.
Zwischendurch ist mir aufgefallen, dass ich nur noch Ergebnisse
abgenickt habe: „passt", „weiter", nächster Schritt. Also habe
ich kurz gebremst und gesagt, dass mir das so nichts bringt –
wenn ich nur zusehe, wie fertiger Code entsteht, lerne ich kein
Flutter, sondern trainiere mich höchstens im Zustimmen. Der
Code war ja sogar ausführlich auf Deutsch kommentiert, aber im
Gespräch selbst kamen die Erklärungen zu kurz, weil viele
Schritte einfach zügig hintereinander liefen.
Danach wurde es besser: vor jedem Bauschritt kurz erklärt,
welches Flutter-Konzept gerade dran ist und warum – etwa, dass
der Register-Screen einen Navigations-Bug hatte, weil der
„Zurück"-Pfeil einen alten Login-Screen im Verlauf noch fand,
obwohl ich schon angemeldet war. Erst als das benannt wurde,
habe ich wirklich verstanden, warum die Lösung heißt: den
gesamten alten Verlauf löschen statt nur eine Seite zu
ersetzen. Kleine Sache, aber genau der Unterschied zwischen
„App funktioniert jetzt" und „ich weiß jetzt auch, warum".
10. August 2026Weiterbildung
Mein erster Login-Screen – und eine Überraschung beim Testen
Ich baue gerade eine Android-Version meiner Schuh-Galerie, um dabei
Flutter zu lernen – learning-by-doing statt trockener Grundkurs.
Heute ist der Login-Screen fertig geworden: Benutzername und
Passwort eintippen, die App fragt beim bestehenden Server nach,
und bei Erfolg geht's weiter. Klingt simpel, war aber mein erster
richtiger Ausflug in Ladezustände, Fehlermeldungen und
Server-Kommunikation in einer echten App.
Ein Konzept, das mir besonders eingeleuchtet hat: Man baut den
Screen so, dass er nicht fest an den echten Server gekoppelt
ist, sondern der "Dienst", der die Anfragen verschickt, von
außen hineingereicht werden kann. Für Tests ersetzt man ihn
dann einfach durch eine Attrappe, die vorgibt, ein Server zu
sein – ohne dass man wirklich einen erreichen muss. So laufen
alle Tests schnell und zuverlässig, auch offline.
Die eigentliche Überraschung kam beim manuellen Test im
Browser: Flutter zeichnet seine komplette Oberfläche als eine
Art Bild (Canvas), nicht als normale Webseite mit anklickbaren
Textfeldern und Knöpfen. Ein Testwerkzeug, das sonst nach
Buttons "mit dem Namen Login" sucht, findet dort schlicht
nichts – man muss stattdessen auf exakte Pixel-Koordinaten
klicken. Ein kleiner Moment, der mir gezeigt hat, wie
unterschiedlich "im Browser laufen" für eine Flutter-App und
eine normale Website eigentlich bedeutet.
5. August 2026Gedanken
Kennzeichnungspflicht für KI – und warum ich sie längst freiwillig befolge
Seit dem 2. August 2026 gelten in der EU die Transparenzpflichten
des AI Act – des ersten großen KI-Gesetzes der Welt. Kurz gesagt:
Wer Inhalte von einer KI erzeugen lässt – Texte, Bilder, Stimmen,
Videos – muss das unter bestimmten Umständen kenntlich machen. Als
jemand, der KI täglich als Werkzeug nutzt, habe ich mir die Regeln
genauer angesehen.
Grob gibt es zwei Richtungen. Anbieter von KI-Systemen müssen ihre
synthetischen Ausgaben maschinenlesbar markieren – also so, dass
auch andere Programme erkennen können: Das kommt von einer KI. Und
wer KI-Inhalte veröffentlicht – etwa täuschend echte „Deepfakes"
oder KI-Texte zu Themen von öffentlichem Interesse – muss offenlegen,
dass sie künstlich erzeugt wurden. Auch Chatbots müssen sagen, dass
man mit einer Maschine spricht, wenn es nicht ohnehin offensichtlich
ist. Für erkennbar künstlerische oder satirische Werke gibt es
Ausnahmen. (Ich bin keine Juristin – das ist mein Verständnis
als Nutzerin, keine Rechtsberatung.)
Für mich ändert das wenig – und das freut mich. Meine
KI-Musikexperimente mit Suno, die KI-Experimente-Seite, sogar große
Teile dieser Website sind mit KI-Unterstützung entstanden, und ich
schreibe das offen dazu. Ich sehe Kennzeichnung nicht als Bürde,
sondern als Ehrlichkeit: Wer mein Portfolio liest, soll wissen, wo
ich selbst Hand angelegt habe und wo eine KI mein Werkzeug war.
Transparenz nimmt der Technik nichts – sie gibt ihr Vertrauen.
5. August 2026Entwicklung
28 echte Zertifikate ziehen ein – die Platzhalter-Idee zahlt sich aus
Vor zwei Wochen hatte ich eine Zertifikate-Seite gebaut, die mit 20
Platzhaltern funktioniert und sich automatisch aktualisiert, sobald
ich echte PDFs nachliefere. Heute war es so weit: Ich habe alle
Nachweise zusammengesucht, gescannt und hochgeladen – 28 echte
Dateien statt der alten Platzhalternamen wie
zertifikat-3.pdf. Und die Seite hat sie sich, wie
geplant, einfach selbst gezogen.
Der größere Umbau passierte auf der „Wer bin ich?"-Seite: Aus
einer losen Liste wurde ein Karten-Grid mit 32 Karten in sechs
Kategorien – Abschlüsse & Prüfungen, Künstliche Intelligenz &
Entwicklung, Microsoft Power Platform, Requirements Engineering
& Agile, und so weiter.
Kniffliger als gedacht war das Verlinken selbst: Viele
Original-Dateinamen enthalten Leerzeichen und Umlaute
(„Copilot Führerschein - Power Apps.pdf"), und Browser mögen
solche Zeichen in Links nicht. Also mussten alle Pfade
URL-kodiert werden – Leerzeichen werden zu %20,
„ü" zu %C3%BC und so weiter. Am Ende habe ich alle
28 Live-Links noch einmal einzeln per HTTP-Anfrage geprüft, ob
der Server wirklich mit „gefunden" antwortet, bevor ich
hochgeladen habe. Nichts ist ärgerlicher als eine Zertifikate-Seite
voller Links, die ins Leere laufen.
22. Juli 2026Entwicklung
Eine Zertifikate-Seite, die sich selbst aktualisiert
Heute habe ich meine Website etwas aufgeräumt: Die Lieblingsvideos
und der Text über meine Musik-Experimente mit Suno sind von der
Startseite in die Hobby-Seite gewandert, und der Abschnitt „Was
läuft gerade?" ist von „Wer bin ich?" zur Projekte-Seite gezogen.
Klingt banal, war aber überfällig – Inhalte sollten dort stehen,
wo Besucher sie thematisch erwarten, nicht dort, wo sie zufällig
zuerst entstanden sind.
Der eigentliche Kern des Tages war aber eine neue Seite:
zertifikate.html, eine Galerie für alle meine
Zertifikate und Seminarnachweise. Jede Karte zeigt eine
PDF-Vorschau, und ein Klick vergrößert sie über eine
„Lightbox" (ein Overlay-Fenster, das das Dokument groß über der
Seite anzeigt, ohne dass man die Seite verlässt). Bisher habe
ich aber noch nicht alle 20 Zertifikate als Datei vorliegen –
also musste die Seite auch mit Lücken funktionieren, ohne dass
ich sie später nochmal anfassen muss.
Die Lösung: Für jede der 20 Karten schickt das Skript im
Hintergrund eine kurze Anfrage ("HEAD-Request") an den
erwarteten Dateipfad, um zu prüfen, ob die PDF schon existiert –
ohne sie komplett herunterzuladen. Antwortet der Server mit
„gefunden", ersetzt das Skript den Platzhalter automatisch durch
die echte Vorschau. Antwortet er mit „nicht gefunden", bleibt
einfach ein kleines Papier-Symbol mit „folgt" stehen. Das
Ergebnis: Ich kann in den nächsten Wochen einfach PDFs in einen
Ordner legen, benannt nach einem festen Schema, und die Seite
zieht sie sich selbst – kein Code-Update, kein erneutes
Deployment nötig.
Die kleine Erkenntnis dahinter: Es lohnt sich, eine Seite so zu
bauen, dass unvollständige Daten kein Blocker sind. Statt zu
warten, bis alle 20 Zertifikate eingescannt sind, existiert die
Struktur schon heute – und füllt sich von allein, sobald die
Dateien nach und nach dazukommen.
4. Juli 2026CI/SecCD
Ein Not-Passwort ist schlimmer als gar keins
Heute nur eine einzige Zeile Code geändert – aber sie hatte es in sich.
Im Backend vom Whisky-Kuratorium hing der Login seit Monaten an einem
Fallback-Secret, das direkt im Quellcode stand. Fehlte die
Umgebungsvariable mit dem echten Passwort, sprang stillschweigend ein
Ersatzwert ein – mitsamt dem Kommentar „DO_NOT_USE_IN_PRODUCTION",
den in dem Moment niemand mehr liest.
Zum Hintergrund: Ein JWT (JSON Web Token) ist so etwas wie ein
digitaler Ausweis, den sich der Server nach dem Login selbst
ausstellt. Damit niemand einen falschen Ausweis fälschen kann,
wird er mit einem geheimen Schlüssel signiert – dem
SECRET_KEY. Im Code stand bisher
os.getenv("JWT_SECRET", "FALLBACK_SECRET_DO_NOT_USE_IN_PRODUCTION").
Das klingt harmlos, ist aber ein stiller Notausgang: Wird die
Umgebungsvariable beim Deployment aus Versehen nicht gesetzt,
stürzt nichts ab – die App läuft einfach weiter und signiert
Logins mit einem Wort, das jeder im öffentlichen Git-Verlauf
lesen kann. Wer den Code kennt, kann sich gültige Tokens selbst
basteln.
Die Lösung ist absichtlich unbequem: SECRET_KEY =
os.environ["JWT_SECRET"] – ohne Fallback. Fehlt die
Variable jetzt, wirft Python sofort einen KeyError
und die App startet gar nicht erst. Das nennt sich „Fail Fast":
lieber ein lauter Absturz beim Deployment als ein leiser
Sicherheits-Kompromiss im Betrieb. Dazu habe ich das echte
Produktions-Secret rotiert, falls der alte Fallback-Wert doch
irgendwo aktiv war.
Die eigentliche Erkenntnis: Ein Ein-Zeilen-Diff sagt nichts über
seine Wichtigkeit aus. Während ich nebenbei an einem größeren
Feature für die Kassenbon-Funktion in LernyTube saß, bin ich über
diese Altlast gestolpert – und es hat sich gelohnt, kurz
abzubiegen und sie sofort zu fixen, statt sie auf die
To-do-Liste zu schieben.
27. Mai 2026KI & Automatisierung
Reddit hat gelogen – aber das RAG funktioniert trotzdem
Ein Reddit-Post versprach: NotebookLM als kostenloses RAG-Backend in
Claude Code, inklusive Mindmaps und Quizzes per MCP-Wrapper. Ich habe
es ausprobiert. Der Post hatte halb Recht – und halb nicht. Das
Ergebnis ist trotzdem das Nützlichste, was ich diese Woche gebaut habe.
RAG bedeutet grob: dem KI-Assistenten eigene Dokumente als
Nachschlagewerk geben, damit er aus echten Quellen antwortet statt
aus seinem Trainingsgedächtnis. NotebookLM ist Googles Tool dafür –
man lädt Texte oder URLs hoch, und es indiziert sie. Der MCP-Wrapper
verbindet das mit Claude Code, sodass Claude direkt in NotebookLM
suchen kann, ohne den Chat verlassen zu müssen.
Ich habe zwei Wrapper verglichen und mich für
jacob-bd/notebooklm-mcp-cli entschieden (Python, 39
Tools). Installation: pip install notebooklm-mcp-cli,
dann nlm login (öffnet den Browser für Google-OAuth),
dann nlm setup add claude-code – das legt den
MCP-Eintrag automatisch in der Claude-Konfiguration an. Nach einem
Neustart zeigt /mcp den Server als „connected" mit 39
Tools. Kein manuelles JSON-Editieren nötig.
Der Live-Test: Notebook „LernyTube Dokumentation" angelegt,
mein GitHub-Repo als einzige Quelle indiziert. Frage an Claude:
„Welche Datenbank nutzt LernyTube?" – Antwort: „MongoDB", mit
direktem Zitat auf die Tech-Stack-Tabelle in der README. Kein
Raten, kein Halluzinieren – echtes Nachschlagen. Das hat mich
ehrlich überrascht, wie schnell das end-to-end lief.
Was der Reddit-Post verschwieg: Mindmaps und Quizzes unterstützt
keiner der populären Wrapper. Nur Audio Overviews (das
gesprochene Zusammenfassungs-Feature von NotebookLM). Es gibt
einen Wrapper mit 20 Stars, der das angeblich kann – aber 20 Stars
heißt: kaum jemand hat es ernsthaft getestet. Ich hab's gelassen.
Außerdem: Google sieht alles, was hochgeladen wird – also keine
sensiblen Geschäftsdaten rein. Und die Auth-Cookies laufen alle
zwei bis vier Wochen ab, dann ist ein erneutes
nlm login nötig. Kleiner Aufwand, kein Drama, weil
das Setup lokal auf meinem Windows-Laptop läuft und nicht auf dem
VPS – Browser ist einfach da.
Mein Fazit: Den Hype ignorieren, die Technik selbst prüfen.
RAG aus Claude Code heraus funktioniert und ist für mein
Lerntempo gerade genau richtig – ich kann Fragen zu eigenem Code
stellen, ohne alles im Kontext mitzuschleppen.
18. Mai 2026KI & Automatisierung
Der Agent, der selbst entscheidet, ob er schreibt
Heute habe ich einen kleinen Agenten fertiggestellt, der diese Website
mitschreibt – buchstäblich. Er prüft zunächst selbst, ob überhaupt
etwas Blogwürdiges passiert ist, bevor er auch nur einen Satz formuliert.
Kein Material, kein Post. Fertig.
Das klingt selbstverständlich, ist es aber nicht. Die meisten
Automatisierungen, die ich bisher gebaut habe, tun einfach, was man ihnen
sagt – immer, bedingungslos, egal ob es sinnvoll ist. Dieser Agent hat
eine Selbstprüfung eingebaut: Er schaut nach Git-Commits, geänderten
Dateien, Session-Notizen. Wenn weniger als zwei Commits oder fünf
relevante Dateiänderungen vorliegen, schweigt er. Das Tageslimit von
drei Posts pro Tag respektiert er ebenfalls – und prüft es aktiv, bevor
er weitermacht.
Die eigentliche Arbeit war das Prompt-Design: dem Agenten beizubringen,
wann „genug" genug ist, und wie er das Datum auf Deutsch formatiert
(das System liefert englische Monatsnamen – eine kleine Falle, in die
man leicht tappt). Dazu gehört auch das genaue HTML-Template für
die Blog-Karte, damit neue Einträge strukturell zu den alten passen
und der Auf/Zuklapp-Mechanismus korrekt funktioniert.
Was ich dabei gelernt habe: Ein Agent wird erst dann nützlich, wenn
er auch „Nein" sagen kann. Ein Werkzeug, das immer einen Output
produziert, erzeugt Rauschen. Eines, das erst prüft und dann handelt,
erzeugt Signal. Dieser Unterschied klingt philosophisch, macht in der
Praxis aber den ganzen Unterschied.
18. Mai 2026Erkenntnis
Warum ein Kassenbon das ehrlichste Feedback der Welt ist
Ich habe heute über etwas nachgedacht, das jeder kennt und keiner
beachtet: den Kassenbon. Sekunden nach dem Bezahlen liegt da ein
Stück Papier mit einer brutal ehrlichen Zusammenfassung – Datum,
Position, Menge, Summe. Kein Geschwafel, kein „demnächst", keine
Ausreden. Das ist eines der wirkungsvollsten Feedback-Formate, die
wir im Alltag haben – und ich habe es heute zu einem Lern-Werkzeug
umgebaut.
Hintergrund: Ich arbeite an meinem Lern-Projekt LernyTube,
einer kleinen Plattform, in der ich YouTube-Videos in echten
Lern-Sessions strukturiere, Notizen mache und Snapshots setze.
Das funktioniert gut – aber am Ende einer Session ist mein Kopf
voll, und das Wichtigste verflüchtigt sich, wenn ich es nicht
sofort festhalte. Ein freies Tagebuch hilft mir da nicht: zu viel
Spielraum, zu wenig Druck zur Verdichtung.
Deshalb gibt es jetzt am Session-Ende einen Lern-Kassenbon.
Fünf Felder, mehr nicht: Dauer, Konzentration, was konkret entstanden ist,
die eine Erkenntnis, und der nächste Schritt. Der Bon sieht
aus wie ein echter Kassenzettel – Monospace-Schrift, Papier-Optik,
gezackte Kante. Das ist nicht Deko, sondern Tonfall: Der Stil sagt
„kurz, ehrlich, fertig" – und genau so möchte ich nach einer Session
reflektieren.
Der spannendste Teil sind die Smart-Defaults: Die
Dauer schätzt das System aus dem Abstand zwischen erstem und letztem
Snapshot – ich muss nur korrigieren, nicht raten. Die Erkenntnis-Zeile
wird mit dem Text der letzten Snapshot-Notiz vorbelegt – meistens ist
genau dort schon das Wichtigste formuliert, ich muss es nur bestätigen
oder verdichten. Die Hürde, den Bon zu erstellen, ist damit auf zwei
Klicks geschrumpft – und genau deshalb wird er auch tatsächlich
genutzt.
Was bleibt als Erkenntnis: Verdichtung ist anstrengender und
wertvoller als freies Schreiben. „Was bleibt hängen?" in einem Satz
ist ein härteres Werkzeug als drei Absätze Tagebuch. Und gute
UX-Patterns finde ich nicht in Tech-Blogs, sondern an der Supermarkt-Kasse.
11. Mai 2026KI & Automatisierung
Zehn kleine Assistenten – und ein Türsteher
Ich habe heute meinem KI-Assistenten ein Team gegeben. Statt einem
Allrounder, der alles ein bisschen kann, gibt es jetzt zehn Spezialisten –
jeder mit einer klar umrissenen Aufgabe und genau den Werkzeugen, die er
dafür braucht.
Vier davon sind global, also in jedem Projekt verfügbar: ein
Secret-Auditor, der vor jedem Push die gesamte
Git-Historie nach Passwörtern und API-Keys durchforstet. Ein
Safe-Backup, das vor riskanten Operationen schnell
einen lokalen Commit anlegt. Ein CI-Predictor, der die
GitHub-Workflows einmal mental durchspielt, bevor ich pushe – damit
ich nicht reaktiv auf rote Builds reagieren muss. Und ein
Deletion-Guardian, mein Lieblings-Agent: ein digitaler
Türsteher, der bei jedem rm -rf oder DROP TABLE
zuerst klassifiziert, was gelöscht werden soll, und im Zweifel
einfach stoppt.
Dazu kamen sechs projekt-spezifische Helfer: Tester für Whisky-Kuratorium,
LernyTube und EIS Schuh-Atelier, ein Excel-Importer für die Whisky-Vorlage,
und für vita.eiskopani.de gleich zwei – einer für die Playwright-Tests,
einer der direkt zu Hostinger deployt, ohne Rückfragen. Der zehnte ist
der Blog-Autor: er entscheidet selbst, ob heute genug
passiert ist, prüft mein Tageslimit (maximal drei Beiträge), und postet
erst, wenn die HTML-Struktur konsistent ist. Er hängt am Session-Ende-Hook
und meldet sich anschließend per Telegram.
Die Erkenntnis, die mich heute am meisten gefreut hat: ein Türsteher
schlägt einen Schadensbegrenzer. Lieber einmal mehr stoppen als einmal
zu viel löschen.
29. April 2026CI/SecCD
Tests grün heißt nicht sicher – was mir der Audit beigebracht hat
Für mein neues Umfrage-Projekt hatte ich 67 Tests, davon 26 explizit als
Security-Tests, dazu Bandit (statische Code-Analyse) und Safety
(CVE-Scan) im GitHub-Actions-Pipeline. Alles grün. Trotzdem fragte mich
der User: „Hast du an die Sicherheit gedacht?" – und hatte recht.
Die unangenehme Wahrheit: Tests prüfen nur, was sie testen. Sie ersetzen
keinen Audit. Konkret hatte ich drei Lücken übersehen:
1. Der echte Anthropic-API-Key stand im Klartext in der
docker-compose.yml. Nicht im Git-Repo, aber jeder
mit Server-Zugriff hätte ihn lesen können. Fix: Schlüssel in eine
.env mit chmod 600, im Compose nur noch
${ANTHROPIC_API_KEY} referenziert. Gleiches gilt für das
DB-Passwort.
2. XSS im Frontend. Der KI-Output (Kernaussage,
Stichworte, Bewertung) wurde direkt per innerHTML in das
Dashboard gerendert. Wenn ein User in seine simulierte E-Mail
<script>-Tags einschmuggelt und Claude diese im
extrahierten Text spiegelt – Code-Ausführung im Browser. Fix: eine
winzige esc()-Funktion, die HTML-Sonderzeichen escapt,
und konsequent vor jedem dynamischen Wert anwenden.
3. Keine Schutz-Header. Keine Content-Security-Policy,
kein X-Frame-Options, kein X-Content-Type-Options,
keine Referrer-Policy. Fix: eine FastAPI-Middleware, die alle vier auf
jede Antwort setzt – fünf Zeilen Code.
Was ich daraus mitnehme: Security-Audit ist eine eigene Phase, kein
Nebenprodukt grüner Tests. Tests sichern App-Logik ab –
Deployment-Artefakte (Compose, .env, Workflows) und Frontend-Rendering
müssen separat durchgesehen werden. Ich habe dafür jetzt eine eigene
Memory-Regel angelegt: „Bandit/Tests grün ≠ sicher; docker-compose,
.env, Frontend-XSS, HTTP-Header explizit prüfen."
Bonus-Lektion am gleichen Tag: Drei Push-Zyklen, weil ich nach jedem
CI-Fehler einzeln gefixt habe statt vorher den Workflow + die
Repo-Struktur einmal zu lesen. Auch das ist jetzt eine Memory-Regel.
Manchmal ist die teuerste Zeit die, in der man sich für „schnell mal
pushen" entscheidet.
27. April 2026KI-Projekt
Wie ich eine E-Mail-Umfrage-Orchestrierung gebaut habe – ohne eine einzige echte E-Mail
Ausgangslage: Ein Use-Case aus dem öffentlichen Sektor, in dem
iterativ E-Mail-Umfragen an Seminar-Teilnehmer rausgehen sollen.
Antworten kommen frei formuliert zurück, eine KI extrahiert daraus
strukturierte Daten, ein Mensch bestätigt – und überfällige Fälle
werden eskaliert. Frage: Lässt sich so etwas als Prototyp bauen,
ohne sofort an Outlook und SMTP zu hängen?
Antwort: Ja, wenn man das E-Mail-System komplett simuliert.
Die KI-Extraktion bleibt echt (Claude Haiku 4.5), alles andere –
Versand, Posteingang, Antwort – passiert im Browser. Damit lässt
sich der gesamte Workflow demonstrieren, ohne externe
Abhängigkeiten.
Architektur: FastAPI + PostgreSQL im Docker-Container,
fünf Tabellen (Umfragen, Teilnehmer, Zuordnung, Antworten,
Seminar-Referenzen), ein einseitiges Vanilla-JS-Dashboard. Jede
Umfrage bekommt eine ID im Format UMF-2026-001. Wer
eine Antwort simuliert, gibt sie als „E-Mail" mit dieser ID im
Betreff ein – das System parst die ID per Regex, schickt den
Freitext an Claude und speichert das JSON-Resultat als JSONB.
Human-in-the-Loop: Jede KI-Extraktion landet zuerst
im Status PENDING. Erst nach manueller Freigabe geht
die Antwort in die Auswertung – wird sie abgelehnt, ist die Extraktion
verworfen. Ein simpler, aber wichtiger Schritt: Die KI ist hier
ein Vorschlag, kein Urteil.
Eskalation: Ein zusätzlicher Endpoint
/eskalieren findet alle überfälligen Versendungen
(Frist überschritten, keine Antwort) und markiert sie. Das passt
gut zum Use-Case, in dem regelmäßig Erinnerungen rausgehen
müssen.
Tests: 18 Unit-Tests (ID-Generierung, Betreff-Parsing,
KI-Output-Validierung), 23 Integrationstests gegen eine echte
Postgres-Test-DB (alle API-Endpunkte), 26 Security-Tests
(SQL-Injection-Payloads, Input-Validierung, HTTP-Methoden,
XSS-Regression, Schutz-Header). Dazu Bandit für statische
Code-Analyse und Safety für CVE-Checks – alles in einer
GitHub-Actions-Pipeline mit vier parallelen Jobs.
Das Schöne an dem Ansatz: Wenn Outlook oder ein anderer
Mail-Connector irgendwann tatsächlich angedockt werden muss, ist
das nur eine Eingangsroute mehr. Die Logik dahinter – Parsen,
KI-Extraktion, Review, Eskalation – bleibt unverändert. Simulation
war hier kein Notnagel, sondern die ehrliche Antwort auf die Frage,
welcher Teil der Wertschöpfung tatsächlich neu ist: nicht
das Versenden, sondern das Verstehen der Antworten.
23. April 2026Security
Idempotency Key, Rate-Limit, Throttling – was davon brauche ich wirklich?
In meinem Notizbuch standen drei Begriffe, die mir in einem Interview-Kontext begegnet waren:
Idempotency Key, Rate Limit, IP-Throttling. Klang wichtig. Aber
brauche ich das für meine drei kleinen Projekte überhaupt?
Also erst mal sortiert: Ein Idempotency Key sorgt dafür, dass ein doppelt
abgeschickter Request nicht zweimal ausgeführt wird – klassisch bei Zahlungen, damit 50 €
nicht versehentlich zweimal abgebucht werden. Da ich keine Payment-Flows habe, fällt das
weg. Rate-Limit und IP-Throttling dagegen schützen
öffentliche Endpoints vor Brute-Force und Flood-Angriffen – und genau das hat mir gefehlt.
Der kritische Punkt auf meinem Server ist der Musik-Upload-Proxy (FastAPI + SFTP), über den
die Admin-Seite MP3-Dateien auf Hostinger
schickt. Er ist zwar per Bearer-Token geschützt, aber SHA-256 ist schnell zu brute-forcen,
und bei jedem fehlgeschlagenen Versuch würde der Server bis zu 50 MB Upload-Body
entgegennehmen, bevor überhaupt die Auth greift. Klassisches DoS-Risiko.
Die Lösung: Rate-Limit-Middleware direkt auf Traefik-Ebene – kein Code-Rebuild nötig,
blockt schon, bevor der große Body durchkommt. Vier Zeilen im docker-compose.yml:
average=20, period=1m, burst=40 pro IP. Für mich
beim Hochladen völlig unkritisch – für einen Angreifer bedeutet das, dass Brute-Force auf
den Token statistisch unmöglich wird.
Seitenfund beim Reinschauen ins docker-compose.yml: Das SFTP-Passwort stand dort im
Klartext. „Nicht heute" habe ich kurz gedacht – dann korrigiert vom User: „Warum nicht
heute?" Gute Frage, kein guter Grund. Also gleich hinterher: Passwort in eine
.env-Datei mit chmod 600, .gitignore daneben,
env_file-Referenz im Compose-File. Damit ist auch ein späterer Git-Push
des Verzeichnisses safe.
Lektion: Security-Fachbegriffe sind keine Checkliste, die man komplett abhaken muss. Erst
verstehen, welches Problem sie lösen, dann prüfen, ob man dieses Problem überhaupt hat.
Und wenn man dann doch etwas absichert: richtig, nicht halb.
22. April 2026Infrastruktur
Ein zentraler MCP-Hub – und warum Ollama wieder rausflog
Gestern waren zwei Themen dran: Ich wollte, dass jede Claude-Session direkt auf alle meine
Projekte zugreifen kann, ohne dass ich jedes Mal den Kontext erkläre. Und ich wollte meine
Telegram-Pipeline endlich stabil bekommen – bis dahin stolperte sie regelmäßig über
RAM-Fehler.
Lösung für Teil eins: ein eigener MCP-Hub-Server unter
mcp.eiskopani.de. MCP steht für Model Context Protocol – der Standard, über den
Claude Tools von außen einbinden kann. Der Hub läuft als Docker-Container, hat die vier
Projektverzeichnisse (LernyTube, Whisky, EIS, vita) read-only eingebunden und stellt Tools
bereit wie list_projects, read_project_file oder
run_shell. Jede neue Claude-Session kennt ab sofort alle Projekte automatisch.
Authentifizierung per Secret im URL-Query, HTTPS via Traefik + Let's Encrypt.
Teil zwei war härter. Meine Telegram-Pipeline – ich schicke eine Nachricht ans Bot, und
Claude Code erledigt die Aufgabe auf dem Server – hatte bisher ein Zwischenglied: Ein
lokales Ollama-Modell (Qwen 2.5 Coder 7B) sollte die Nachricht in einen strukturierten
Task formatieren. Klang clever, war in der Praxis aber ein Problem: Das Modell braucht
4,3 GB RAM, mein VPS hat nur 3,4 GB frei. Jeder zweite Aufruf endete mit Memory-Error.
Die ehrliche Erkenntnis: Claude Code selbst ist das smarte LLM. Warum soll ein
zweites, kleineres Modell davor versuchen, Dinge zu „verstehen", wenn das eigentliche
Modell dahinter das viel besser kann? Also Ollama komplett aus dem Workflow entfernt.
Die Telegram-Nachricht geht jetzt direkt als Markdown-Datei in den Claude-Inbox-Ordner,
ein systemd-Watcher pollt alle fünf Sekunden, Claude Code übernimmt, antwortet via
Stop-Hook zurück an Telegram. Kein RAM-Problem, kein Memory-Error, und die
Reaktionszeit ist spürbar schneller.
Beide Änderungen teilen eine Lektion: Komplexität ist kein Qualitätsmerkmal. Ein Layer,
der Ressourcen frisst ohne Mehrwert zu bringen, muss raus – auch wenn er am Anfang
schlau wirkte.
19. April 2026Recht & Technik
Cookie-Banner: Brauche ich das überhaupt?
Jeder kennt sie, niemand mag sie: Cookie-Banner. Bevor ich blind einen einbaue,
wollte ich erst mal prüfen, ob meine Seiten überhaupt Cookies setzen.
Also habe ich alle meine Projekte durchsucht – vita.eiskopani.de, das Whisky-Kuratorium
und LernyTube. Das Ergebnis: Keines davon setzt Browser-Cookies. Was ich im Code gefunden
habe, sind ausschließlich serverseitige Datenbank-Sessions (SQLAlchemy Session) – die haben
mit Browser-Cookies nichts zu tun.
Kein Google Analytics, kein Tracking, keine Third-Party-Cookies. Das bedeutet: Ein
Cookie-Banner wäre nicht nur unnötig, sondern sogar fragwürdig. Consent für etwas abfragen,
das gar nicht stattfindet? Das verwirrt Besucher und ist rechtlich unsauber.
Die Lektion: Nicht jede „Best Practice" passt zu jedem Projekt. Erst prüfen, was
technisch tatsächlich passiert – dann entscheiden. Falls ich später mal Login-Cookies
oder Analytics einbaue, kommt der Banner dazu. Bis dahin bleibt er weg.
19. April 2026Entwicklung
Mein Retro-Musik-Player spielt jetzt wirklich – und der Upload geht automatisch
Auf meiner Hobbys-Seite gibt es einen Retro-Player im Winamp-Stil
mit 25 KI-generierten Songs. Das Problem: Die Songs waren nie wirklich auf dem Server – nur die
Playlist war da, die Dateien fehlten. Heute habe ich das endlich gefixt.
Die Ursache war, dass meine Upload-Admin-Seite die Dateien nur
lokal im Browser gespeichert hat (localStorage), aber nie auf den Server hochgeladen hat. Das habe
ich komplett umgebaut: Jetzt gibt es einen Upload-Proxy auf meinem VPS, der die MP3-Dateien per
SFTP direkt an den Hostinger-Webserver schickt. Drag & Drop in die Admin-Seite → Fortschrittsbalken
→ fertig auf dem Server. Löschen geht auch direkt über den Button.
Technisch ist das ein kleiner FastAPI-Service mit Paramiko (Python SFTP-Bibliothek), der hinter
Traefik unter lernytube.eiskopani.de/music-api/ erreichbar ist. Die Authentifizierung
nutzt denselben Passwort-Hash wie die Admin-Seite – keine doppelte Pflege.
Und weil „es funktioniert" nicht reicht, habe ich 14 Playwright-Tests geschrieben, die den
Player automatisiert prüfen: Ist die Playlist da? Funktioniert
Next/Prev? Kann man die Lautstärke ändern? Und vor allem: Sind alle 25 MP3-Dateien
auf dem Server erreichbar (kein 404)? Alle Tests grün.
16. April 2026Architektur
Monolith oder Microservices? Warum ich mich bewusst gegen den Hype entscheide
Microservices sind in aller Munde – jedes zweite Architektur-Diagramm auf LinkedIn sieht aus
wie ein U-Bahn-Netzplan. Aber brauche ich das wirklich? Ich betreibe drei Projekte auf einem
einzigen VPS mit begrenztem RAM. Heute habe ich mir die Frage ehrlich gestellt: Was passt zu
meiner Situation – und was ist nur Cargo Cult?
Die Antwort war überraschend klar. Microservices lösen ein Teamproblem: Wenn fünf Teams
gleichzeitig an einem Produkt arbeiten, braucht man unabhängige Deployments. Wenn ein
Service 100-mal mehr Last bekommt als der Rest, will man ihn separat skalieren. Beides
trifft auf mich nicht zu. Ich arbeite allein, meine Projekte haben überschaubare Last,
und mein Server hat nicht mal genug RAM für Ollama ohne Swap.
Was Microservices kosten würden: mehr Container, mehr RAM-Verbrauch, Service Discovery,
Health Checks, Retry-Logik, Distributed Tracing statt einfachem Logging. Jeder dieser
Punkte ist ein eigenes Rabbit Hole – und keiner davon macht meine Schuh-Galerie oder
mein Whisky-Kuratorium besser.
Mein Ansatz: Ein sauberer Monolith pro Projekt. Whisky-Kuratorium, LernyTube und EIS
Schuh-Atelier sind bereits getrennte Repositories mit eigenen Containern – das ist die
richtige Schnittlinie. Innerhalb jedes Projekts sorgen Router, Services und Models für
Ordnung, ohne dass ich dafür Netzwerk-Calls zwischen Containern brauche.
Die wichtigste Erkenntnis: Architektur-Entscheidungen sollten von den eigenen
Rahmenbedingungen ausgehen, nicht vom letzten Conference Talk. Ein Solo-Projekt auf
einem VPS ist kein Netflix. Und wenn ein Projekt irgendwann wirklich wächst, kann ich
Module immer noch extrahieren – aber dann aus einer funktionierenden Codebasis heraus,
nicht aus einer vorzeitig zerlegten.
16. April 2026Entwicklung
127 Tests und eine Pipeline – alle drei Projekte abgesichert
Heute war der Tag, an dem aus „es funktioniert auf meinem Server" ein echtes Sicherheitsnetz
wurde. Für alle drei Projekte – LernyTube,
Whisky-Kuratorium und EIS Schuh-Atelier – habe ich
automatisierte Tests geschrieben: Unit-Tests, Integrationstests und End-to-End-Tests mit
Playwright. Insgesamt 127 Stück.
Dazu kamen GitHub-Actions-Pipelines, die bei jedem Push automatisch loslaufen – mit echten
Datenbanken als Service-Container, nicht mit Mocks. Denn genau da hatten wir vorher ein
Problem: Mock-Tests bestanden, aber die echte Datenbank verhielt sich anders. Diese Lektion
sitzt jetzt im Code statt nur im Kopf.
15. April 2026Vita
Vom Zahlungsverkehr zur IT – mein Werdegang bekommt eine Seite
Heute ist der Lebenslauf auf meiner Vita-Seite live gegangen – nicht als trockene Auflistung,
sondern als Timeline, die zeigt, wie sich mein Weg von der Sparkasse über die Deutsche Bahn
bis in die IT-Welt entwickelt hat.
Was dabei sichtbar wird: Testmanagement und Release-Steuerung beim InGe-Tool, agiles
Projektmanagement mit Scrum und SAFe, Prozessautomatisierung mit Power Apps und Power Automate,
Stakeholder-Kommunikation quer durch den Konzern. Dazu kommen Seminare wie IREB, ITIL und
Leading SAFe – und natürlich die laufende Weiterbildung zur Software Developerin (IHK) mit
Python, SQL und Web-Entwicklung.
Besonders spannend finde ich, wie sich der rote Faden zieht: Egal ob Kreditvergabe digitalisieren,
Formulare in Form.io bauen oder heute eigene Docker-Container auf dem VPS betreiben –
es ging immer darum, Abläufe zu verstehen und dann besser zu machen.
14. April 2026Projekt
LernyTube bekommt ein Zuhause – Admin-Panel, Forum und Kalender
Heute hat LernyTube einen großen Sprung gemacht: Aus der reinen Lern-App ist eine kleine
Community-Plattform geworden. Ein komplett neues Admin-Panel ermöglicht die Verwaltung
im Browser, und ein Forum mit Threads, Nachrichten und Emoji-Picker lädt zum Austausch ein.
Dazu kam ein Mini-Kalender auf dem Dashboard, der die eigenen Lernsessions tagesgenau
anzeigt und filtert – so sieht man auf einen Blick, wann man wie viel gelernt hat.
Über 900 neue Zeilen Code an einem Tag, verteilt auf 15 Dateien: Routen, Modelle,
HTML-Templates und JavaScript. Es fühlt sich gut an, wenn aus einer Idee Schritt für
Schritt ein echtes Produkt wird.
8. April 2026Design
Old Money trifft Champagner-Gold – die Seite bekommt einen neuen Anstrich
Heute ging es nicht um neue Funktionen, sondern um Stil. Die ganze Seite hat einen einheitlichen
Old-Money-Look bekommen: Karten im Blog-Stil – weiß, mit goldener Linie obenauf und einem zarten
Schatten – ziehen jetzt durch alle Seiten. Projekte, Weiterbildung, KI-Experimente, alles wirkt
wie aus einem Guss.
Im Header leuchtet ab sofort die aktuell besuchte Seite in Champagner-Gold mit einem weichen
Glow und einer dunklen Patina-Linie darunter – wie ein Messingschild in einer alten Bibliothek.
Die roten Trennlinien unter den Überschriften sind goldenen gewichen, alle Buttons tragen nun
Kupfer-Gold mit Navy-Schrift, und das Motto-Band auf der Startseite hat das schreiende Rot gegen
ein cremefarbenes Band mit goldenen Linien getauscht.
Drei Vorschläge habe ich Claude machen lassen, eine Test-Seite gebaut, im Browser verglichen,
entschieden – und dann lief alles automatisch durch: CSS angepasst, Cache-Buster gebumpt,
per SFTP deployt, in GitHub gesichert. Zum Abschluss noch das Portrait auf wer-bin-ich
ausgetauscht. Manchmal ist ein guter Tag einfach ein Tag, an dem die Seite endlich so aussieht,
wie sie sich anfühlen soll.
8. April 2026KI & Automatisierung
„Mach weiter, ohne mich zu fragen" – ein Experiment
Heute habe ich Claude eine ungewöhnliche Anweisung gegeben: Mach weiter, auch wenn ich nicht
antworte. Erledige alles, was du allein erledigen kannst. Schreib mir am Ende eine Liste, was
wirklich nur ich entscheiden kann. So entstand eine Session, in der ich quasi nur zugeschaut habe.
Das Ergebnis: Sichere Passwörter generiert (64 Zeichen, kryptografisch zufällig), Datenbank
mit den neuen Credentials neu aufgesetzt, ein zentrales Auth-Modul gebaut, alle Routen auf
saubere Bearer-Token im Header umgestellt (statt Token in der URL), CORS auf die richtige
Domain eingegrenzt, Passwort-Validierung serverseitig verschärft, der Excel-Upload auf
10 MB begrenzt – und am Ende ein Git-Push und ein neuer Blog-Eintrag.
Was übrig blieb: drei Punkte, die wirklich meine Entscheidung brauchen – ein DNS-Eintrag
beim Provider, meine echte Admin-Email, und der erste visuelle Test im Browser.
Genau die Art von Arbeitsteilung, die ich mir vorgestellt hatte: Die KI macht das Stumpfe
und Mechanische, ich treffe die Entscheidungen, die nur ein Mensch treffen kann.
8. April 2026Projekt
Vom Backend zum echten Erlebnis – das Kuratorium bekommt sein Gesicht
Heute ist das Whisky-Kuratorium von einer reinen API zu einer echten Anwendung gewachsen.
Das komplette Frontend ist gebaut: eine Galerie mit Filtern nach Region, Kategorie und ABV,
Detail-Ansichten zu jeder Flasche und ein Admin-Dashboard mit Tabs für Nutzerverwaltung,
Excel-Import und das schnelle Hinzufügen einzelner Whiskys. Alles im Old-Money-Stil –
Anthrazit, Gold, Playfair Display.
Im zweiten Teil des Tages ging es um Sicherheit: Sichere Passwörter generiert,
CORS auf die Domain eingegrenzt, der Login-Mechanismus von URL-Parametern
auf richtige Bearer-Token im Header umgestellt, Passwort-Validierung serverseitig
verschärft. Aus einem Prototyp wird langsam ein produktionsreifes System.
6. April 2026Projekt
Ein digitales Kuratorium für Whisky – von Null auf API
Heute ist ein neues Projekt geboren: das Whisky-Kuratorium. Die Idee? Eine exklusive,
einladungsbasierte Plattform, auf der eine Whisky-Sammlung nicht nur katalogisiert,
sondern mit Stil präsentiert wird. Dunkles Design, goldene Akzente – Old Money trifft
auf moderne Technik.
In einer einzigen Session haben wir die komplette Infrastruktur aufgebaut: Docker-Container,
PostgreSQL-Datenbank, Nutzer-System mit Einladungs-Hierarchie (man muss freigeschaltet werden),
JWT-Authentifizierung und eine vollständige API für die Sammlung. Das Highlight: Ein Excel-Import,
der eine ganze Sammlung per Drag-and-Drop einlesen kann – mit automatischer Erkennung,
ob eine Flasche bereits existiert. Manchmal passiert an einem Tag mehr, als man für eine Woche plant.
4. April 2026KI & Automatisierung
Von der Idee direkt in die Aufgabenliste – per Telegram
Heute stand ein ehrgeiziges Ziel auf dem Plan: Aufgaben per Telegram-Nachricht an Claude Code übergeben –
vollautomatisch, ohne Umweg. Was simpel klingt, entpuppte sich als Detektivarbeit durch SSL-Zertifikate,
N8N-Interna und Docker-Berechtigungen.
Das Ergebnis: Ein funktionierender Workflow, der eine Nachricht wie „Baue einen Logout-Button"
entgegennimmt, per lokalem KI-Modell (Ollama) in eine strukturierte Entwicklungsaufgabe verwandelt
und in eine Warteschlange schreibt. Neu dazu kam ein /status-Befehl, der auf Knopfdruck
zeigt, welche Aufgaben offen und erledigt sind. Kleine Nachricht, große Wirkung.
30. März 2026KI & Automatisierung
Ordnung im Chaos – ein System das mitdenkt
Heute haben wir etwas gebaut, das man nicht sieht – aber das jede zukünftige Arbeitssession einfacher macht.
Ein Session-Management-System für meine KI-Zusammenarbeit: eine Start-Datei, die Claude beim Öffnen
sofort weiß, welche Projekte laufen und wo er weitermachen soll.
Und eine Ende-Datei, die sicherstellt,
dass am Schluss nichts verloren geht.
Die echte Herausforderung? Alle laufenden Projekte, Zugangsdaten, Infrastrukturdetails und
Arbeitsregeln so zu strukturieren, dass eine KI in Sekunden einsatzbereit ist – ohne dass ich
jedes Mal von vorne erklären muss. Das ist wie ein perfektes Briefing für einen neuen Kollegen,
den man immer wieder frisch begrüßt.
30. März 2026Entwicklung
Mein Blog geht live – und der Header wächst
Heute habe ich meiner vita-Website zwei neue Navigationspunkte gegeben: Blog und Gästebuch.
Klingt klein – aber dahinter steckt mehr als ein paar Links.
Es ist der Entschluss,
meinen Lernweg öffentlich zu machen. Nicht als Hochglanz-Portfolio, sondern als echtes Tagebuch
meiner Entwicklung.
Dieser Blog wird von mir und meinem KI-Assistenten Claude gepflegt. Nach jeder Arbeits-Session
entsteht hier ein Eintrag – damit nichts verloren geht und du nachvollziehen kannst,
wie Projekte wirklich entstehen.