Contract data engineer · Ponte de Lima, Portugal · EU hours

The pipeline ran green. The numbers are still wrong.

I build the staging layer, the tests and the job triggers that make a warehouse trustworthy. Most recently 34 dbt models across two markets. Before that, a livestock genomics data system.

01 / What I get called for

Four failures I have actually found and fixed.

The fact table joins on a null

Every test passes. The build is green. Then a surrogate key comes through empty on a slice of rows, the join silently drops them, and the revenue number is quietly short.

I trace it back to the staging model, fix the key, and add the test that would have caught it.

Fixed null surrogate keys on a transactions fact table and on its shop dimension

A rerun duplicates instead of repairing

An incremental model without a reliable unique key does not heal when you run it again. It doubles. The table looks fine until someone sums it.

I fix the key strategy so a rerun is safe, which is the property you actually wanted from incremental.

Fixed duplicate rows in a product attributes staging model

Text arrives as mojibake

An encoding mismatch between the source and the warehouse turns apostrophes into three characters of noise. Nothing errors. It reaches a customer facing report weeks later.

I find the boundary where the encoding breaks and fix it there, not in the presentation layer.

Fixed mojibake in string columns

A dead source keeps building

A system gets switched off. Nobody removes its models, so they keep running against a table that stopped updating, and stale rows sit next to live ones with nothing to distinguish them.

I cut the dead lineage out rather than leaving it to fail quietly.

Removed a discontinued source from the staging layer
02 / Evidence

Two engagements, with the commit history behind them.

34

dbt models, two markets

I built the staging layer of an analytics warehouse for a retail business operating in two countries, covering products, categories, shops, terminals, transactions and cart items, then the dimensional models on top of it.

I brought the second market into the core models, added a Step Function trigger for the shared product catalog, and used fuzzy matching to reconcile category ids across two countries that named things differently.

83 commits, Aug 2025 to Dec 2025 · 24 staging, 3 dimension, 1 fact, plus core and mapping models · dbt, Redshift, Step Functions, Python, SQLFluff

573

commits on a genotype data system

I worked on a livestock genomics system. Illumina IDAT files land, get detected, linked to metadata, checked for authorisation, loaded as genotypes, then checked for discordance against other samples from the same animal.

I built the sample QA framework, including the manual override path and the checks that run before a flag is allowed to change. I added the discordance trigger, wrapped the job in a transaction, and chained parentage verification off it.

573 commits across 20 repositories, Apr 2023 to Nov 2024 · 31% of the task dispatcher, 29% of the discordance analyser, 14% of core · Python, AWS Lambda, SQS, Snowflake, Terraform, SQLAlchemy, pytest, DataDog

How I lay out a warehouse

source A ─┐ source B ─┼─► staging ─────► core ──┬──► dimensions source C ─┘ one model per │ └──► facts source. renamed, │ typed, tested conformed once, not per report
Illustrative. The rule is that nothing downstream reads a raw table, so there is exactly one place to fix any given defect
03 / What I do

A narrow list, because it is what the evidence covers.

dbt

Staging layers, dimensional models, incremental strategies, tests that fail the build rather than decorate it, and linting that holds across a team.

AWS data work

Redshift and Snowflake, Lambda, SQS, Step Functions, Terraform. Ingestion that is idempotent, and jobs that say why they failed.

Python and SQL

Pipeline code, CLI tooling for the people who operate the system, pytest coverage, and the boring instrumentation that makes an incident short.

04 / Rate and terms

EUR 400 per day.

05 / What I do not do

The honest list, so you find out now rather than in week three.

06 / Before software

I spent seventeen years in professional kitchens.

Apprentice to head chef. Ski field hotels in New Zealand, fine dining on the Gold Coast, Soho House in Mayfair, and seven years at a private members club in Melbourne. I retrained in my thirties, earning a Diploma and then a Computer Science degree with a Data Science major while still working full time on the line.

It is on this page because it is the part of my background that actually shows up in the work. A kitchen teaches you that preparation is most of the job, that a service runs to a clock somebody else set, that the handover to the next shift is not optional, and that nothing broken leaves the pass. Those habits transfer to a production pipeline more directly than most of my degree did.

Soho House, Little House Mayfair, Aug 2012 to Jun 2013 · The Melbourne Club, Aug 2015 to Dec 2022 · BCompSci, Data Science major, Swinburne, 2022, GPA 3.333, 83.3% High Distinction · Two analyses published by KNIME, Nov 2021
07 / What you keep when I leave

The handover is part of the work, not a favour at the end.

Every model I write ships with its tests and its documentation in the same pull request. You get a runbook for anything that needs an operator, the reasoning behind the schema choices written down rather than carried in my head, and a session with whoever is picking it up.

I do the work myself. There is no bench behind me and nobody more junior arrives in week two.

08 / Next step

Tell me what is broken.

A short description of the stack and the symptom is enough to start. I will tell you honestly whether it is something I have done before.

hello@jamesphillipsanders.com