I build web applications end-to-end: from idea to production.
Production web software since 2018: Angular, Vue, React and TypeScript. On the server: Java and Play with MySQL at my current job, a TypeScript Node.js API before that, and Hono, Workers and PostgreSQL in my own builds. I build component libraries and design systems, carry big migrations through step by step, establish testing cultures that developers actually keep to, and lead technical decisions, code reviews and planning for other developers. Alongside my job, I build LLM systems.
Senior Fullstack Developer · Berlin
English and German (C1) · German residence and work permit · On-site in Berlin, hybrid or remote
At a crisis-communication company: a reporting module in Angular and Java, an Android app for vehicle crews on a radio link, a multilingual emergency web app for residents on local Wi-Fi, and a public display system.
A workplace language-learning product: an Angular web app for learners and admins, a Node.js API that also served the mobile apps, a manager statistics view, and a Jest test modernization.
A microfrontend admin console: a zoneless Angular 21 shell loads three separately deployed apps (IAM, Feature Flags, Audit Logs) at runtime from a manifest; an edge BFF checks JWTs. No LLM. Live, real sign-in, mock data.
Figures from my jobs are reported from the job and labelled as such; personal builds say whether they are live or in build. All case studies, including the volunteer work and the LLM builds, are on the work index.
What I work on.
Technical leadership
At my current job I make technical decisions, review code and plan the work of the developers who report to me. At an earlier job I reviewed code and planned work for junior developers. At a university I led the migration strategy for nine institute sites.
Product engineering
At my current job I made the decisions on every part of the UI overhaul, on web and Android, and of a public-facing web app, sometimes taking feedback from customers directly. TruthBase, a personal build, went from idea to a live public demo.
Angular
Daily work since 2025: a component library that the Angular web app and the Android app share, and the web app migrated step by step from Angular 10 to 19. Before that, Angular with a Node.js backend at an e-learning company. In my own build, a zoneless Angular 21 shell on signals that loads microfrontends at runtime, each remote with its own NgRx Signal Store.
Vue and React
Vue since 2018: nine university institute sites migrated from Vue 2 to Vue 3, with accessibility brought to WCAG compliance, and a Vue and Quasar design system built at an e-commerce platform. React and Next.js on a volunteer privacy project.
Design systems
Component libraries and design systems, built or revived at nearly every stop. At my current job, design tokens with theming across new and legacy modules; before that, reusable components built from Figma designs.
Migrations
Big migrations, done incrementally: Vue 2 to 3, run in a parallel repository and live only once proven; Angular 10 to 19 step by step; and an Android app from Android 6 to 13 with a full UI overhaul.
Testing and CI
Testing cultures developers keep to: Jest brought into an Angular codebase, a stale Vitest setup rebuilt, Cypress integration tests introduced, and Playwright and axe in my own builds. CI/CD on GitHub Actions.
Backend
Java and Play with MySQL at my current job: live updates over WebSockets and safe concurrent editing. Before that, a TypeScript Node.js API behind web and mobile clients. In my own builds: Hono, Nitro and Cloudflare Workers with Durable Objects, PostgreSQL, and an edge BFF that verifies JWTs.
Alongside the job: LLM systems.
In my own projects I build the system around the model: retrieval, agents, evals and the interface on top. Each project says whether it is live or still in build, and its numbers appear only once they are measured. I build on foundation models; I don't train them, and I won't pretend to. How I build them.
How this works, and how well it works: measured numbers
The corpus is small and worth stating plainly: 137 sections across 11 documents (the case studies and the CV), embedded at build time with Xenova/bge-small-en-v1.5 (q8). In your browser, the same model embeds your query and ranks sections by cosine similarity. No server, no request leaves the page. The numbers below come from a committed golden set of 77 queries, 39% of them deliberate paraphrases that avoid the corpus’s own words.
Read the Section column first. On this golden set a random ranker scores about 0.30 on doc recall@3 across 11 documents, so the document is the easier half. Choosing the right section out of 137 is the part that takes real retrieval, and the number that has to hold as the corpus grows.
Retrieval quality (measured)
Metric
Doc
Section
recall@1
0.86
0.75
recall@3
0.95
0.92
recall@5
0.96
0.94
MRR@10
0.90
0.84
On-device latency (measured)
WASM
WebGPU
model load (cold)
2473.1 ms
2865.4 ms
query embed p50
34 ms
85.1 ms
query embed p95
41 ms
97.4 ms
rank 137 sections
<0.1 ms
0.1 ms
Measured on Apple M5 MacBook, Chrome. Your hardware may vary. WebGPU is available on this hardware and measurably slower. At 384 dimensions and one short query per call, dispatch and buffer transfer cost more than the compute they save, so the WASM path wins.
A score floor of 0.52 suppresses weak matches, but it cannot do the whole job. Measured on this corpus, the weakest legitimate query scores 0.569 and the strongest out-of-domain one 0.602: the bands overlap, so no single threshold rejects every off-topic question without also suppressing real answers. The floor is set to protect real answers. Questions about me rather than the work (salary, notice period, references) score in the same band as legitimate ones and will return results. Retrieval quality is gated in CI; a pull request that drops recall@3 or MRR@10 below the committed baseline fails.