I make sure a model doesn't stay a demo: it ends up in a sales rep's daily workflow, on data that can be trusted.
01
Fig. 1.1
Data → model → CRM
AI prototypes on Azure
Prototypes that take sales teams from manual work to automated workflows, built on Azure and shipped into the tools people already use.
Replaced third-party SaaS with in-house AI tooling
Azure
Python
Machine Learning
Databricks
02
Fig. 1.2
Medallion pipeline
Data platforms & pipelines
Reliable, tested pipelines from raw data to business-ready models, with quality gates that catch bad data before it reaches a dashboard.
320M records processed for under $10 of compute
Databricks
Snowflake
dbt
Airflow
Kafka
03
Fig. 1.3
Org-to-org sync
Salesforce engineering
Lightning Web Components, Apex and real-time integrations that remove manual data entry for large B2B sales organisations.
1.4M customer accounts on LWC + Apex
Salesforce
LWC
Apex
REST
02Selected work
6 projects · 2023–2026
Projects I've shipped.
Personal and lab projects across data engineering, machine learning and blockchain identity.
Featured · P.01
2026
Jersey City Bikeshare
230K
Trips processed
24
Automated tests
3
Environments
Raw + stream
Validation
Silver
Gold
Marts
A production-style data platform for Citibike trip data: medallion architecture in dbt, Kafka streaming, Snowflake provisioned with Terraform and orchestrated by Airflow. A quarantine layer isolates bad rows instead of letting them break downstream models.
Seven years of New York yellow taxi trips moved through a Bronze, Silver and Gold pipeline on Snowflake and dbt. Warehouses auto-suspend after every load, which kept the total compute bill under ten dollars.
Built in Telefónica's innovation lab: a Next.js sign-on that proves a user is a unique human with World ID, comparing on-chain and cloud verification side by side.
An ordinary least squares model for Apple's share price, and an honest look at why strong backtest numbers did not survive contact with real future data.
{{ config( materialized = 'incremental', schema = 'QUARANTINE', on_schema_change = 'fail') }}WITH source AS ( SELECT * FROM {{ ref('stg_yellow_taxi') }} {% if is_incremental() %} WHERE _loaded_at > (SELECT MAX(_loaded_at) FROM {{ this }}) {% endif %}),validation AS ( SELECT *, CASE WHEN dropoff_datetime <= pickup_datetime THEN 'dropoff_datetime <= pickup_datetime (trip ends before it starts)' WHEN trip_distance > 500 THEN 'Unrealistic trip_distance > 500 miles: ' || CAST(trip_distance AS VARCHAR) WHEN passenger_count > 9 THEN 'passenger_count exceeds max capacity: ' || CAST(passenger_count AS VARCHAR) -- … 8 more rules ELSE NULL END AS _rejection_reason FROM source),-- Only the INVALID rows (opposite of silver_trips.sql)invalid_only AS ( SELECT * FROM validation WHERE _rejection_reason IS NOT NULL)
Notes
1
Append-only by designL1–5
Incremental without a unique key: once a row is rejected, its record is kept permanently.
2
Only new dataL7–12
A load-time watermark means each run only checks Bronze rows that arrived since the last one.
3
A reason for every rejectionL17–26
Each bad row says why it failed, so quarantine can be queried for root causes instead of guessed at.
4
Same rules, opposite filterL30–33
Silver keeps the rows that pass and Quarantine the rows that fail, so every row lands in exactly one.
tests/assert_silver_plus_quarantine_equals_bronze.sqldbt test · SQL · 28 lines
WITH bronze AS ( SELECT COUNT(*) AS cnt FROM {{ source('taxi_raw', 'RAW_YELLOW_TAXI') }}),silver AS ( SELECT COUNT(*) AS cnt FROM {{ ref('silver_trips') }}),quarantine AS ( SELECT COUNT(*) AS cnt FROM {{ ref('quarantine_trips') }}),comparison AS ( SELECT b.cnt AS bronze_count, s.cnt + q.cnt AS silver_plus_quarantine_count, s.cnt AS silver_count, q.cnt AS quarantine_count, b.cnt - (s.cnt + q.cnt) AS difference FROM bronze b, silver s, quarantine q)-- Return a row only if there's a discrepancy.SELECT bronze_count, silver_plus_quarantine_count, -- … difference, -- …FROM comparisonWHERE ABS(difference) > 200000
Notes
1
Count every layerL1–9
Raw Bronze rows, validated Silver rows and rejected Quarantine rows, side by side.
2
Conservation of massL10–18
Data may be split or transformed but never lost: Bronze has to equal Silver plus Quarantine.
3
Fails loudlyL20–28
The test returns a row only when data vanishes or duplicates. The tolerance covers natural source duplicates, about 0.06% of volume.
contracts/NFTFactory.solSolidity · 24 lines
function createNFT( string memory name, string memory symbol, string memory baseURI) external returns (address) { // Create new NFT contract with factory as temporary owner CustomNFT nft = new CustomNFT(name, symbol, address(this)); address nftAddress = address(nft); // Mint first NFT (token ID 0) to the creator nft.safeMint(msg.sender, baseURI); // Transfer ownership to the actual user nft.transferOwnership(msg.sender); // Track the NFT userNFTs[msg.sender].push(nftAddress); allNFTs.push(nftAddress); emit NFTCreated(nftAddress, msg.sender, name, symbol); return nftAddress;}
Notes
1
Deploy a new collectionL6–7
A fresh ERC-721 contract, with the factory as temporary owner so it is allowed to mint.
2
Mint token 0L11–12
The first token goes straight to the caller in the same transaction.
3
Hand over controlL14–15
Ownership moves to the creator, so the factory keeps no rights over the collection.
4
Index and announceL17–21
Collections are tracked per user and an event lets the frontend pick them up.
From freelance web projects and internships in Munich and London to AI engineering at one of Germany's largest telecom providers.
Telefónica Germany
CS Development
Giesecke+Devrient
Avast Software
Fig. 3 — Timeline
2018201920202021202220232024202520262027
R.01
2021 – Today
Current role
Telefónica Germany
AI Engineer
Full-time since Sep 2024 · dual study 2021–2024
Mannheim, Germany
Shorten B2B sales cycles with AI prototypes on Azure that connect Databricks pipelines to Salesforce, freeing sales capacity for revenue-critical work.
Reduce vendor dependency by replacing third-party SaaS with purpose-built in-house AI tooling, cutting costs while keeping full control over data and models.
Removed manual data entry with a real-time Salesforce-to-Salesforce REST integration and Lightning Web Components managing 1.4M customer accounts.
Presented blockchain identity in the corporate innovation lab with a World ID single sign-on application built in Next.js.
R.02
2019 – 2021
CS Development
Founder & Lead Developer
Part-time
Munich, Germany
Won 15+ e-commerce clients alongside my studies, delivering custom full-stack web applications.
Grew organic traffic and conversion through SEO metadata, structured data and faster page loads.
R.03
2019 – 2020
Giesecke+Devrient
Software Development Intern
Munich, Germany
Streamlined operating-system installation for payment card production with a cross-platform Python desktop application.
R.04
2018
Avast Software
Software Engineering Intern
London, United Kingdom
Built a Chrome extension with secure authentication and a dashboard that shows users which websites track them.