Webdev.
AtelierCMS, Zeiterfassung, the alpineminds site. Things that ship.
Self-hosted web apps for Swiss contexts. PHP where it makes sense, Astro where it shines. No framework churn — just tools that stay out of the way.
AtelierCMS: drag-to-reorder gallery without a JS framework
Implemented drag-and-drop image ordering in the CMS admin using the HTML5 Drag and Drop API. No Sortable.js, no React. Saves order to a JSON sidecar file.
AtelierCMS: asset pipeline fix — images were being served unoptimised
Discovered that AtelierCMS was serving original uploads directly. Added a simple on-demand resize pipeline. 80% size reduction on average.
AlpineTime: frontend — Vue 3, composables, i18n from day one
Vue 3 + TypeScript + PrimeVue. Silent token refresh, error codes mapped to i18n keys, composables keeping pages under 100 lines. German UI from the first component.
AlpineTime: backend — FastAPI, async ORM, rate resolution
FastAPI with SQLAlchemy 2.0 async. The interesting parts: overlap detection with user-driven resolution, rate snapshotting, and MWST applied at report total rather than per line.
AlpineTime: what the spec went through before touching code
Seven versions of the spec before the first commit. The Swiss constraints — MWST, nDSG, Europe/Zurich, German UI — decided most of the architecture before any code was written.
AtelierCMS: multilingual routing without a framework
Added DE/FR/IT language switching to AtelierCMS using path prefixes and a dead-simple URL rewrite. No i18n library needed.
Zeiterfassung: CSV export that accounting could actually open
The CSV export worked. Excel couldn't open it. The fix was two lines and deeply annoying.