Rozszerzenie do porównywania kursów sportowych
Rozszerzenie przeglądarki (Chrome, Firefox, Safari) porównujące kursy bukmacherskie bezpośrednio na stronach bukmacherów. Rozwijałem adaptery dla ponad 40 bukmacherów i nanosiłem poprawki w pozostałych aplikacjach produktu.
Szczegóły projektu
#Kontekst
W OddsGuard rozwijałem rozszerzenie przeglądarki do porównywania kursów bukmacherskich. Głównym obszarem była warstwa adapterów - modułów, które rozpoznawały kursy w kodzie HTML konkretnych bukmacherów i doklejały obok nich nakładkę z lepszą ofertą z innego bukmachera. Nanosiłem też poprawki w pozostałych aplikacjach produktu: w backendowym API, w serwisie zbierającym kursy od dostawców i na stronie marketingowej.
Do OddsGuard trafiłem po pracy nad regulowaną platformą gier hazardowych online dla wielu marek - kontekst rynku bukmacherskiego (regulatorzy, marki, gracze, sposób pracy z kursami i zakładami) był mi już znany, a projekt wokół porównywarki kursów okazał się naturalnym kolejnym krokiem.
Poza pracą z bieżącymi zgłoszeniami samodzielnie prowadziłem większe inicjatywy - od pomysłu, przez prototyp, po produkcyjne wdrożenie. Szczegóły w sekcji „Co dostarczyłem” niżej.
Rozszerzenie porównywało kursy bukmacherskie w czasie rzeczywistym. Kiedy użytkownik przeglądał ofertę u bukmachera, rozszerzenie wykrywało kurs bezpośrednio na stronie i pokazywało obok nakładkę z ofertą u innego bukmachera. Wspierane przeglądarki: Chrome, Firefox, Safari (w tym Safari na iPhonie) - wszystkie na standardzie Manifest V3. Sama warstwa rozszerzenia obsługiwała ponad 40 bukmacherów z rynków brytyjskiego, amerykańskiego, europejskiego i offshore.
Rozszerzenie było jedną z aplikacji większego produktu żyjącego w jednym repozytorium kodu (monorepo oparte o pnpm i Turborepo), obok backendu, serwisów danych i pozostałych aplikacji klienckich.
Moja aktywność w pierwszych 3 miesiącach
- Zamkniętych zadań
- 82 Zamkniętych zadań przypisanych do mnie i ukończonych, kwiecień - lipiec 2026
- Nowych funkcji wprowadzonych do produkcji
- 40 Nowych funkcji wprowadzonych do produkcji poza samymi poprawkami błędów i porządkami
- Adaptery napisane od zera
- 2 Adaptery napisane od zera Oddsshark, VegasInsider - porównywarki konkurencji
- Wspierane przeglądarki
- 3 Wspierane przeglądarki Chrome, Firefox, Safari (standard Manifest V3)
#Co dostarczyłem
- Adaptery napisane od zera: Oddsshark i VegasInsider - dwa adaptery pod strony, które same nie są bukmacherami, tylko porównywarkami konkurencji. Wyzwanie: strony pokazywały po kilka propozycji kursów w jednym wierszu, więc jeden adapter musiał umieć powielać nakładkę tyle razy, ile było opcji w wierszu.
- Wspólna warstwa pod tymi adapterami: wydzieliłem wspólny mixin (fragment kodu wielokrotnego użycia) dla adapterów porównywarek konkurencji - jedna zmiana szła jednocześnie na wszystkie adaptery tego typu. Analogicznie dla bukmacherów dzielących ten sam bazowy silnik do wyświetlania kursów wydzielałem wspólne pliki wspierające całą grupę.
- Pokrycie Mistrzostw Świata 2026: uruchomiłem nakładki porównawcze na stronach WC u kilku bukmacherów - theScore Bet, DraftKings, Oddschecker, William Hill - plus jedna zmiana we współdzielonym kodzie, która uruchomiła nakładki dla zakładu „kto wygra turniej” u całej grupy bukmacherów naraz. Każdy operator miał inną strukturę stron turniejowych (osobno lista meczów, osobno drabinka, osobno zakładka „zakłady długoterminowe”), więc pod każdą trzeba było przygotować osobne rozpoznanie w adapterze.
- Utrzymanie rozszerzenia w trzech przeglądarkach jednocześnie: ten sam kod źródłowy budował się do trzech różnych paczek. Każda przeglądarka miała własny proces wydawania i własne testy przed wypuszczeniem nowej wersji.
- Safari na iOS i macOS przez Xcode: rozszerzenie działało też jako natywna aplikacja Apple w projekcie Xcode ze Swift-ową powłoką. Dodałem Apple Privacy Manifests (pliki opisujące, jakich danych używa aplikacja) dla wszystkich czterech aplikacji budowanych z projektu - wymaganych przez App Store.
- Praca w pozostałych aplikacjach produktu (około 40 osobnych zmian poza samym rozszerzeniem): sekcja porównująca konkurencyjne rozszerzenia na stronie marketingowej (adresy w formie
/vs/nazwa-konkurenta), integracja chatbota AI w backendowym API, praca w serwisie zbierającym kursy. - Testy i monitoring: testy jednostkowe pilnujące, że fragmenty kodu identyfikujące elementy na stronie bukmachera (tzw. selektory) ciągle działają - żeby cicha zmiana u bukmachera była wychwytywana w automatycznych testach przed wypuszczeniem, a nie u użytkownika końcowego.
- Rygorystyczne typowanie kodu (TypeScript w trybie strict): standard projektu obowiązujący w całej bazie kodu, pilnowany w CI.
#Wyzwania
Adaptery musiały wytrzymać ciche zmiany kodu HTML u bukmachera
Strony bukmacherów zmieniały swój kod HTML bez zapowiedzi - inny identyfikator elementu, przemianowana klasa CSS, przebudowana struktura kolumn, nowy układ tabeli z kursami. Adapter, który dziś rozpoznawał notowania poprawnie, jutro pokazywał zero nakładek. Sztuka polegała na tym, żeby selektory (fragmenty kodu wskazujące, gdzie w stronie szukać kursu) były na tyle konkretne, żeby nie łapać fałszywych trafień, ale na tyle luźne, żeby przetrwać małe przebudowy. Do tego dochodziły testy sprawdzające, czy selektory ciągle działają - żeby cicha zmiana identyfikatora u operatora była wychwytywana w automatycznych testach, nie u użytkownika końcowego. Ważny był też jasny podział na „to jest błąd adaptera” versus „to jest brak danych z serwisu zbierającego kursy” - dwa różne rodzaje zgłoszeń, dwa różne obszary kodu.
Manifest V3 w trzech przeglądarkach oznaczał w praktyce trzy różne implementacje
Chrome, Firefox i Safari deklarowały wsparcie dla Manifest V3 (standardu opisującego, jak rozszerzenia mają działać w przeglądarce), ale każda przeglądarka różniła się w szczegółach: inaczej obsługiwały procesy działające w tle, inaczej rozstrzygały uprawnienia do wysyłania zapytań na obce domeny, inaczej trzymały sesję między przejściem z jednej strony na drugą, inaczej przekazywały komunikaty między częściami rozszerzenia. Safari na iOS to była osobna historia - własny sposób pakowania rozszerzenia, symulator iPhone’a trzeba było czyścić przed testem instalacji (bo zapamiętane ustawienia użytkownika maskowały scenariusz pierwszego uruchomienia), a kopiowanie paczki do projektu Xcode po każdej zmianie w głównej gałęzi kodu było codzienną higieną wydawania nowych wersji. Traktowałem każdą przeglądarkę jak osobny cel, a różnice ujmowałem w jednej wspólnej warstwie - zamiast pisać jedną wersję i liczyć, że wszędzie zadziała identycznie.
Zakłady na żywo: kod strony zmienia się bez przerwy, nie tylko przy załadowaniu
W widokach zakładów na żywo notowania aktualizowały się w czasie rzeczywistym
- kursy skakały, uczestnicy (zawodnicy lub drużyny) znikali, wydarzenie kończyło się w środku sesji użytkownika. Adaptery napisane pod widoki przed meczem (jednorazowe skanowanie strony po jej załadowaniu) nie wystarczały. Pracowałem nad rozwiązaniami, które obserwowały zmiany kodu strony na bieżąco
- uruchamiane tylko po wejściu użytkownika na konkretny adres URL z widokiem na żywo u wybranych bukmacherów. Kluczowa idea: nakładka znikała razem z uczestnikiem, a nie zostawała zawieszona na starym kursie.
Odróżnianie problemów w adapterze od braków w danych i ograniczeń regionalnych
Kiedy użytkownik zgłaszał „nie widzę porównania kursów na tym meczu”, mogło to znaczyć trzy zupełnie różne rzeczy: (a) adapter źle rozpoznawał ten konkretny widok bukmachera, (b) serwis zbierający kursy nie dostał tych notowań od dostawcy, (c) użytkownik był w regionie, w którym operator w ogóle nie oferował danego rynku. Wypracowałem procedurę diagnostyczną - najpierw sprawdzałem wymiar ograniczeń regionalnych na tle produkcyjnego kanału danych, potem wymiar serwisu zbierającego kursy pod kątem brakujących notowań, dopiero wtedy zaglądałem do adaptera w narzędziach programisty w przeglądarce. Wniosek „tu nie ma błędu w adapterze” też był pełnoprawną odpowiedzią - pod warunkiem, że stał za nim konkretny dowód.
#Wnioski
- Manifest V3 w trzech przeglądarkach to były w praktyce trzy różne implementacje pod jedną nazwą - najbezpieczniej było traktować każdą przeglądarkę jak osobny cel i uzgadniać różnice jedną wspólną warstwą, zamiast pisać jedną wersję i liczyć, że wszędzie zadziała identycznie.
- Adaptery działające na kodzie stron bukmacherów wymagały monitoringu na produkcji - bez wysyłania danych z produkcji i bez testów pilnujących, że rozpoznawanie ciągle działa, nie było wiadomo, kiedy strona bukmachera zmieniła kod. Poprawki po zgłoszeniu użytkownika były zawsze spóźnione.
- Wspólne rozwiązania (mixiny wielokrotnego użycia, pliki dla bukmacherów dzielących ten sam silnik) opłacały się najbardziej - kiedy dwudziesty adapter zaczynał wyglądać jak dwudziesty pierwszy, wydzielenie wspólnego mixina pozwalało odzyskać tempo. Wspólny mixin pod adapterami porównywarek konkurencji powstał właśnie z tej obserwacji, po dwóch pierwszych takich adapterach.
- Odróżnianie przyczyn awarii ma znaczenie w każdym produkcie, który wyświetla cudze dane: zgłoszenie „tu nic się nie pokazuje” może wskazywać na adapter, na warstwę danych albo na ograniczenie regionalne. Bez ustalonej procedury diagnostycznej łatwo naprawiać nie ten problem, co trzeba - i wypuścić „poprawkę”, która nic nie zmienia.
Pracujmy razem
Jestem senior frontend developerem. Buduję szybkie, dostępne aplikacje webowe w React i Next.js, z TypeScriptem. Zależy mi na Core Web Vitals, SSR/SSG i skalowalnej, łatwej w utrzymaniu architekturze. Jeśli szukasz kogoś takiego - daj znać.
Napisz do mnie →