Überblick¶
Du schaust gerade drauf. maexbert.de ist mein persönlicher Platz – gebaut, weil LinkedIn-Profile und GitHub-Repos allein nicht das Ganze erzählen. Hier dokumentiere ich Projekte, halte Gedanken fest und probiere Sachen aus, die mich interessieren. Kein WordPress, kein Template, kein JavaScript-Framework. Nur Flask, Markdown und ein bisschen Wahnsinn.
Es gab Hilfe¶
Auch wenn ich seit einigen Jahren bereits mit Flask und WebDev im allgemeinem arbeite, habe ich mir Hilfe dazu gezogen. Claude Opus 4.6 war mit dabei – direkt in VS Code über GitHub Copilot. Nicht als “generier mir eine Website”-Knopf, sondern als Assistent.
Ich hatte die Idee und die Architektur im Kopf. GitHub Copilot hat geholfen, das schnell und sauber umzusetzen. “Ich brauche ein Cache-System, das statische Assets ein Jahr cached, aber im Development alles frisch liefert” – und ich bekam genau das, mit den richtigen HTTP-Headern und Tests dazu. Partikel-Animation die auf iOS flackert? Mit GitHub Copilot konnte das mit einigen Iterationen gelöst werden.
Jede Entscheidung war meine, jeder Commit überprüft. Aber statt Boilerplate zu tippen, konnte ich mich auf die Dinge konzentrieren, die wirklich zählen. Das ist für mich die Zukunft des Programmierens – nicht weniger denken, sondern mehr. Dazu gibt es sicherlich irgendwann einen eigenen Post.
Was die Seite kann¶
Markdown als CMS. Alle Inhalte sind .md-Dateien mit YAML-Frontmatter in einem Ordner. Versioniert mit Git, bearbeitbar in jedem Editor. Der Parser unterstützt Syntax-Highlighting, Table of Contents, Fußnoten, Tasklisten und berechnet automatisch die Lesezeit. Blogposts und Projekte können sich gegenseitig verlinken – schreib ich einen Post zu einem Projekt, taucht er automatisch als Devlog auf der Projektseite auf.
Client-seitige Suche. Kein API-Call, kein Elasticsearch. Die Suche filtert direkt im DOM – bei meiner Content-Menge schneller als jeder Server-Roundtrip. Dazu Tag- und Kategorie-Filter als klickbare Pills.
Projektstruktur¶
maexbertde/
├── app/ # Flask-Anwendung
│ ├── __init__.py # Application Factory
│ ├── blueprints/ # Route-Handler
│ │ ├── routes.py # Startseite, Impressum, Datenschutz
│ │ ├── blog.py # Blog-Listing & Detail
│ │ └── projects.py # Projekt-Listing & Detail
│ ├── templates/ # Jinja2-Templates
│ │ ├── base.html # Basis-Layout mit Navigation
│ │ ├── index.html # Startseite
│ │ ├── blog/ # Blog-Templates
│ │ └── projects/ # Projekt-Templates
│ ├── static/
│ │ ├── css/ # Eigene Stylesheets (Theme, Animationen, Markdown)
│ │ ├── js/ # Particles, Animationen, Suche, Typewriter
│ │ ├── bootstrap/ # Lokale Bootstrap 5 Kopie
│ │ └── images/ # Header-Bilder für Blog & Projekte
│ └── utils/ # Backend-Logik
│ ├── content.py # Markdown-Parser & Frontmatter
│ ├── cache.py # Cache-Steuerung (Dev vs. Prod)
│ ├── database.py # SQLite-Anbindung
│ ├── analytics.py # Self-hosted Analytics
│ ├── security.py # Security-Header & CSP
│ └── logging.py # Request-Logging
├── content/ # Markdown-Inhalte (das "CMS")
│ ├── blog/ # Blogposts als .md
│ └── projects/ # Projektseiten als .md
├── tests/ # Testsuites
│ ├── unit/ # Unit Tests
│ ├── integration/ # Integration Tests
│ ├── e2e/ # Playwright E2E Tests
│ └── content/ # Frontmatter-Validierung
├── Dockerfile # Multi-Stage Build
├── docker-compose.yml # Dev & Prod Konfiguration
├── Makefile # Shortcuts (dev-start, test, etc.)
└── gunicorn.conf.py # Production-Server Konfiguration
Unter der Haube¶
Flask mit Blueprints. Application Factory Pattern, drei Blueprints (Startseite, Blog, Projekte), saubere Trennung. Kein ORM, kein Admin-Panel, kein Overhead. Ich war schon immer Flask-Fan und in Kombination mit Jinja hat es immer gut geklappt.
Logging im Backend. Analytics läuft als self-hosted Service in einem eigenen Thread. Kein Google, kein Cookie-Banner. Ein reines “Jemand hat folgende Seite besucht” als Event in einem Grafana Dashboard.
Docker von Dev bis Prod. Multi-Stage Build: Development mit Hot-Reload, Production mit Gunicorn. Worker-Anzahl berechnet sich dynamisch aus den CPU-Cores. Alles läuft als Non-Root User. make dev-start – fertig. Das hat sich bereits bei meinen anderen Projekten als gute Praxis entpuppt.
Ordentlich getestet. Unit Tests, Integration Tests, E2E über Playwright, plus Content-Validierung die prüft ob alle Markdown-Dateien sauberes Frontmatter haben. Somit muss ich nicht jeden Post einzeln prüfen, sondern jeder neue Post hat eine eigene, automatisierte Validierung.
tests/content/validation.py::TestContentStructure::test_blog_directory_exists PASSED [ 95%]
tests/content/validation.py::TestContentStructure::test_projects_directory_exists PASSED [ 96%]
tests/content/validation.py::TestContentStructure::test_blog_has_posts PASSED [ 96%]
tests/content/validation.py::TestContentStructure::test_projects_has_entries PASSED [ 97%]
tests/content/validation.py::TestContentStructure::test_no_non_markdown_in_blog PASSED [ 97%]
tests/content/validation.py::TestContentStructure::test_no_non_markdown_in_projects PASSED [ 98%]
tests/content/validation.py::TestContentStructure::test_at_least_one_published_blog_post PASSED [ 98%]
tests/content/validation.py::TestContentStructure::test_at_least_one_published_project PASSED [ 99%]
tests/content/validation.py::TestContentStructure::test_all_markdown_files_parseable PASSED [100%]
=========== 192 passed in 0.13s ===========
Metadaten. Jede .md Datei hat zu Beginn eigene Metadaten, die dann später durch meinen Blog analysiert und entsprechend umgewandelt werden. Dazu gehören:
---
title: "maexbert.de"
description: "Meine persönliche Website – gebaut mit Flask, Markdown-Content und einer ordentlichen Portion Canvas-Magie. Mit Claude Opus 4.6 als Entwicklungspartner."
date: 2026-03-01
status: "aktiv"
tags: ["python", "flask", "webdev", "meta", "ki", "claude", "docker", "javascript"]
techStack: ["Python", "Flask", "Bootstrap 5", "JavaScript", "Markdown", "Docker", "SQLite", "Redis"]
githubUrl: "https://github.com/maxi07"
liveUrl: "https://maexbert.de"
image: "images/projects/maexbert-website.svg"
featured: true
language: "de"
isDraft: false
---
Es war mir wichtig, kein eigenes Admin-Panel bauen zu müssen. Mir reicht eine einfache Verwaltung der Posts innerhalb der Markdown-Dateien vollkommen aus.
Design-Philosophie¶
Mir war es wichtig, dass alles lokal auf meinem Server läuft. Keine externen CDNs, keine Google Fonts, keine Tracker. Was auf maexbert.de passiert, bleibt auf maexbert.de.