Work About Contact CV ↓

I build pipelines that run when nobody’s watching.

See the work ↓ Get in touch
Based
Abuja, NG
Mode
Remote · International
Stack
Python · SQL · Airflow
dbt · BigQuery
Cloud
GCP · AWS
Status
Open to remote roles
(01)   Proof, not adjectives

Most pipelines run.
Fewer are trusted.

MARTS
STAGING
RAW
10S–1M
Detection to published post, live news pipeline
101K
Records through idempotent BigQuery MERGE loads
30K
Synthetic transactions, corridor-weighted, log-normal
24 TASKS
Single orchestrated DAG, production Airflow
(02)   Selected work

Anyone can move data.
The job is moving it on time.

01

Due FX Analytics Platform

An end-to-end GCP ELT stack for a Nigerian remittance startup.
POSTGRES AIRFLOW GCS DBT BIGQUERY METABASE
30,000 synthetic transactions · log-normal amounts · evening-peaked intraday curve

PostgreSQL → Airflow → GCS → dbt → BigQuery → Metabase. Corridor-weighted synthetic transactions seed the warehouse; dbt models turn raw events into FX corridor margins analysts can query. Loads are idempotent, so a re-run is never a duplicate.

Airflow dbt BigQuery GCS Source
02  ·  Personal project

News Desk Pipeline

Market news detected and published inside a minute.
RSS / API CLASSIFY DRAFT PUBLISH
Detection-to-publish latency · tight sub-minute mode · bursty market hours

An independent side project running on a single AWS EC2 box: RSS and API monitors poll for market movement, an LLM classifies and drafts, systemd keeps the whole thing alive. Detection to published post lands between 10 seconds and a minute, fully automated end-to-end.

Python AWS EC2 Claude API systemd Source
03

DataTel

101,000 telecom records, one DAG, no duplicates.
EXTRACT STAGE MERGE BIGQUERY
101,000 usage records · volume by daypart · peak-hour concentration

A 24-task Airflow DAG ingests telecom usage data and lands it in BigQuery through idempotent MERGE loads. Task-level retries and dependency ordering mean a partial failure resumes rather than restarts.

Airflow BigQuery GCP Source
(03)   Things I build anyway

Dashboards are the easy part.

Canton Network  ·  Personal project

Canton / DAML

The rule lives in the contract, not the frontend.
DAML CANTON JSON API REACT
DAML SDK 3.4.11 · Canton LocalNet · JSON Ledger API v2 · React 19

Three full-stack apps on a local Canton node — a marketplace, a two-admin treasury, an airline loyalty programme — each a set of DAML templates with a React front end talking to the JSON Ledger API. The point of all three is the same: a treasury release cannot execute until both admins have countersigned, and redeeming more points than you hold fails at the ledger, not in a form validator. Behind them is the DAML work they grew out of — lending, onboarding, and the privacy model that decides who can even see a contract.

DAML Canton React Multi-party
Full-stack
Marketplace
Seller lists, buyer offers, seller accepts. The receipt is signed by both, so neither side can quietly archive it.
Listing → PendingOffer → SaleReceipt
Full-stack
Treasury
Multi-sig fund release. One admin proposes, the second countersigns or vetoes, and only then can the recipient execute.
ReleaseProposal → TreasuryRelease
Full-stack
Loyalty
Airline points programme. The balance is contract state, not a database row — over-redeeming fails the transaction.
CLPApplication → CLPAccount
DAML model
Lending
Borrower requests, lender approves with a due date. The agreement needs both signatures; only the borrower can repay it.
LoanRequest → LoanAgreement
DAML model
Onboarding
Applicant submits, admin approves and allocates a wallet. The same shape as onboarding in live Canton ecosystem apps.
UserApplication → ApprovedUser → UserWallet
Goody’s
Surprise call service — Paystack checkout into a WhatsApp delivery flow.
Paystack WhatsApp API
iLearn / EdTain
React Native learning platform with four distinct user roles.
React Native Auth
Results on Chain
Academic records system with blockchain-backed verification.
Solidity Web3
Letters
Encrypted private journal, written for one reader only.
React Native Encryption

It ran at 3am.
Nobody noticed.

scheduler · due_fx_elt · 03:14 WAT
that is the whole job
(04)   About

Statistics first.
Then the plumbing.

with DAG(
    dag_id="due_fx_elt",
    schedule="15 * * * *",
    catchup=False,
    default_args={"retries": 3, "retry_delay": timedelta(minutes=5)},
) as dag:

    extract = PostgresToGCSOperator(
        task_id="extract_transactions",
        sql=INCREMENTAL_SQL,  # bounded by data_interval_start
        bucket=RAW_BUCKET,
        export_format="parquet",
    )

    load = GCSToBigQueryOperator(
        task_id="load_staging",
        write_disposition="WRITE_TRUNCATE",
        destination_project_dataset_table=f"{PROJECT}.staging.transactions",
    )

    merge = BigQueryInsertJobOperator(
        task_id="merge_core",
        configuration={"query": {"query": MERGE_SQL, "useLegacySql": False}},
    )

    transform = BashOperator(task_id="dbt_run", bash_command="dbt build --target prod")

    extract >> load >> merge >> transform
Chinedum Sunday
Abuja, NG WAT / UTC+1

I came to data engineering from statistics, which is why I care less about the dashboard and more about whether the number behind it can be trusted at 3am. I build pipelines that are boring on purpose: idempotent, observable, and easy for the next person to read.

I’m in Abuja and work with teams anywhere.

Currently: News Editor at MyTradingLand · Community Moderator at Cantor8
B.Sc. Statistics — University of Nigeria, Nsukka
Professional Diploma, Data Engineering — AltSchool Africa
DataCamp Professional Data Engineer — certified
(05)   Contact

Got a pipeline that needs to be trusted?

chinedumsunday5@gmail.com