Pick a role to highlight the most relevant experience and skills.

Summary

BI developer with 14+ years in Business Intelligence and data analytics across finance, telecommunications, and iGaming. Specialised in Power BI semantic models and SQL data engineering on BigQuery, SQL Server, and Oracle, with cloud work on Azure Synapse. I use AI-assisted engineering (Claude Code, Codex, MCP) to speed up model development, code review, and documentation.

Career at a glance

Experience

Lottomart

Gibraltar · Remote
BI DeveloperJun 2024 – Present
  • Designed and delivered 30+ Power BI dashboards and semantic models in PBIP format, serving 50–200 stakeholders across marketing, product, and operations.
  • Built and optimised BigQuery data pipelines, evolving from stored procedures and scheduled queries to dbt models orchestrated with Dagster; partitioned tables progressively reduced scanned data volumes and reporting costs.
  • Delivered iGaming analytics on deposits, withdrawals, and player activity, including dynamic New vs Existing segmentation and promotion performance models (before vs after campaigns) informing bonus budgets. Case study
  • Maintained a full Git-based development lifecycle in Bitbucket: branching strategy, pull requests, and code reviews for a clean, auditable BI codebase.
  • Used Tabular Editor, DAX Studio, Bravo, and ALM Toolkit for model management, DAX performance analysis, measure documentation, and incremental deployments of model changes instead of full model republishing.
  • Introduced AI-assisted BI engineering: Claude Code integrated with the Bitbucket repo and VS Code for PBIP/TMDL changes, DAX refactoring, SQL review, and documentation; LLM agents connected to semantic models via Power BI Modeling MCP Server. Case study
  • Delivered work in 2-week Agile sprints using Jira; collaborated with data engineering and product teams on end-to-end reporting solutions.

British Council Foundation

Remote
Power BI DeveloperNov 2022 – May 2024
  • Built Power BI dashboards, embedded applications, and analytical tools for international stakeholders, with full use of DAX, Power Query (M), RLS, deployment pipelines, and shared dataflows.
  • Designed Azure Synapse Analytics pipelines ingesting data from SQL Server and Snowflake into Azure Data Lake Storage Gen2, using PySpark notebooks and serverless SQL pools.
  • Automated operational processes with Power Apps and Power Automate, reducing manual reporting overhead across teams.
  • Deployed database changes via VS Code with Git source control and Azure DevOps CI/CD pipelines.

Lumen Technologies Poland

Poznań, Poland · Remote
Senior Business Applications AnalystMay 2021 – Oct 2022
  • Delivered Power BI reports and applications for EMEA business teams (DAX, Power Query, M, ETL, RLS); recognised by management for exceptional output quality despite minimal transition time.
  • Designed and launched an On-net Building Usage Dashboard showing the geographic distribution of network infrastructure across EMEA, adopted by multiple operational departments.
  • Used Oracle SQL Developer, SQL Server Management Studio, and the ServiceNow reporting module for operational queries and analytics.

Waldi Sp. z o.o.

Poznań, Poland
BI Data AnalystMay 2012 – Apr 2021
  • Delivered end-to-end BI reporting with Power BI and Oracle BI, covering financial results, cost control, revenue tracking, and financial bonus calculations.
  • Progressed from analyst to lead BI developer over 9 years, introducing OLAP cubes and a Data Warehouse architecture for enterprise-level analytics.
  • Worked with finance and operations to define reporting requirements and deliver self-service analytical solutions.
  • Acted as internal IT advisor bridging business and technology for non-technical colleagues.

Case studies

How I approach problems, told without client data. Code on this page is written for illustration; no production code, data, or internal names are shown.

iGaming · BigQuery · dbt · Power BI Did the bonus campaign change player behaviour? A before-vs-after promotion performance model with period-aware New vs Existing segmentation. Read case study

Problem

An online gaming operator runs bonus campaigns every week. Marketing could see what each campaign cost, but not whether it changed what players did afterwards. Without that, budgets went to the campaigns that looked busiest, not to the ones that moved deposits.

Constraints

  • Player-level transactional data in BigQuery: deposits, withdrawals, and wagering, with gaps on days a player is inactive.
  • "New player" depends on the period being analysed. A static flag on the player table gives the wrong answer as soon as someone changes the date filter.
  • Results had to be explainable to non-technical stakeholders.

Approach

  • Data layer. Daily activity per player built in BigQuery, first as a stored procedure, now as dbt models orchestrated with Dagster. Missing activity counts as zero, so inactive days pull averages down instead of silently disappearing.
  • Comparison windows. Equal-length windows before and after each campaign, per participating player.
  • Semantic model. Power BI model on a shared date dimension. New vs Existing is calculated in DAX from the selected dates, so the split always matches the period on screen.
  • Safeguards. A change is shown only when both windows have data, and measures return blank unless the date dimension is filtered.

Pattern in DAX

New Players =
VAR PeriodStart = MIN ( dim_date[Date] )
VAR PeriodEnd = MAX ( dim_date[Date] )
RETURN
    IF (
        ISFILTERED ( dim_date ),
        CALCULATE (
            DISTINCTCOUNT ( dim_player[PlayerId] ),
            dim_player[RegistrationDate] >= PeriodStart,
            dim_player[RegistrationDate] <= PeriodEnd
        )
    )

Deposit Increase =
VAR AvgBefore = [Avg Daily Deposits Before]
VAR AvgAfter = [Avg Daily Deposits After]
RETURN
    IF (
        NOT ISBLANK ( AvgBefore ) && NOT ISBLANK ( AvgAfter ),
        AvgAfter - AvgBefore + 0
    )

Outcome

Marketing got one consistent view per campaign, split by new and existing players, and used it in bonus budget decisions. The same model now answers the follow-up questions ("which segment responded?") without a new query each time.

PBIP / TMDL · Claude Code · MCP · ALM Toolkit An AI-assisted workflow for Power BI semantic models Treating the model as code: agent-assisted changes, human review, and deployments that ship only what changed. Read case study

Problem

Large Power BI models change constantly: new measures, renames, format strings, descriptions. Done by hand in Power BI Desktop, that work is slow and hard to review, documentation falls behind, and republishing a whole large model for a small change is risky.

Setup

  • Model as text. Models are saved in PBIP format, so tables, relationships, and measures live as TMDL files in a Bitbucket repository. Every change is a readable diff.
  • Claude Code in VS Code. The agent works in the repository: refactoring DAX, applying naming and formatting conventions across many measures, writing measure descriptions, and reviewing SQL and dbt changes before a pull request.
  • Power BI Modeling MCP Server. Connects the agent to the open model, so it can inspect tables and relationships, create or bulk-edit measures, and run DAX queries to check results.
  • ALM Toolkit. Compares the local model with the published one and deploys only the changed objects, instead of republishing the full model.

Guardrails

  • Every agent change goes through a branch, a pull request, and my review. Nothing reaches production without a human reading the diff.
  • Conventions (measure naming, blank handling, date-filter rules) are written down once and given to the agent, so output is consistent across the model.
  • Production deployment stays a deliberate, scoped ALM Toolkit step.

What changed

Bulk edits that used to mean clicking through dozens of measures became one reviewed commit. Documentation is written as part of the change, not afterwards. Deployments are smaller and easier to roll back because they contain only what changed.

JavaScript · Python · telemetry · Claude Code StreamScope: from raw streaming logs to a repeatable benchmark A local-first analytics app that parses, aligns, and scores game-streaming sessions from three log formats. Read case study

Problem

My home game-streaming setup (gaming PC as host, a mini PC as client, a TV as display) showed occasional micro-stutter. Diagnosing it meant reading large host JSON exports and client logs by hand, or pasting them into a chatbot and hoping the numbers were right.

Approach

  • Local-first. A static web app with no backend. Files are processed in the browser and never leave the device.
  • Three sources, one timeline. Parsers for host session JSON (Sunshine-based host), client logs (Moonlight-based clients), and Steam Remote Play logs. Clocks are aligned from file-name epochs plus a measured residual offset.
  • Correct counters. Host counters are cumulative per connection and reset on reconnect, so the app sums per-connection deltas instead of reading raw totals.
  • Deterministic statistics. Average, P50, P5, and P1 FPS with interpolated percentiles; share of time at target FPS; bitrate and encode latency P95.
  • Rule-based diagnostics. A median FPS baseline, episode grouping, and rules that separate "host overloaded" from "nothing to send" from loading screens. Gameplay is detected automatically from rolling CPU, FPS, and bitrate features.
  • Explainable scores. 1–10 scores for FPS, stability, latency, network, and image, each shown with the numbers it was built from.
  • Automation. A Python agent (standard library only) collects new logs and serves the app on the home network, so a phone sees the same sessions.

How AI was used

I drafted the specification with ChatGPT, kept a handoff document of decisions and confirmed file formats, and built the app with Claude Code. One rule from the start: AI writes code, but never produces the numbers. Every statistic is computed in plain JavaScript. The diagnostic rules were checked against real session files before being kept.

Core of the statistics

// Linear-interpolated quantile, used for P1 / P5 / P50 / P95
const quantile = (a, p) => {
  if (!a.length) return null;
  const s = sorted(a), i = (s.length - 1) * p,
        lo = Math.floor(i), hi = Math.ceil(i);
  return s[lo] + (s[hi] - s[lo]) * (i - lo);
};

Outcome

One drag-and-drop now gives a benchmark for a chosen stretch of gameplay, a diagnosis of the whole session, and a short report ready to share. Sessions can be saved and compared over time. About 3,300 lines of JavaScript and Python, open source.

Why it is on a BI CV: messy sources, metric definitions, reconciliation of counters, and outputs a non-expert can trust. It is the same work as BI, in a different domain.

Personal projects

StreamScope

2026 – Present · open source · JavaScript, Python

Local-first analytics web app for game-streaming telemetry: multi-source log parsing with clock synchronisation, percentile-based performance benchmarks, a rule-based diagnostics engine, and a Python agent for automated log collection. Deployed via GitHub Pages.

Built with Claude Code from an LLM-drafted specification Read the case study

GameRadar

2026 – Present · TypeScript, React, Node.js, SQL

Local-first job discovery and application tracking app combining Gmail alerts and company career listings, with email parsing, deduplication, application outcome tracking, and evidence-based CV fit scoring.

Built with OpenAI Codex

Additional

Electronic Arts (EA) · Data EditorJan 2012 – Present

Part-time contract. Collecting, analysing, and editing Polish Ekstraklasa player data for FIFA / EA FC titles in the EA Web Tool, in line with milestone schedules.