Konfigurator drzwi — od interfejsu po automatyczny import katalogu producenta

Konfigurator drzwi — od interfejsu po automatyczny import katalogu producenta

W tym artykule opiszę realny projekt wdrożony w sklepie internetowym opartym o OpenCart 3.

Klient potrzebował narzędzia, które pozwoli klientowi końcowemu samodzielnie skonfigurować drzwi wejściowe — z wyborem modelu, konstrukcji, kolorów, szyb, klamki, zamka i wymiarów — a następnie dodać gotową specyfikację do koszyka z wyliczoną ceną. Równolegle zespół sklepu musiał utrzymać katalog opcji zgodny z ofertą producenta, bez ręcznego przepisywania setek wariantów.

Artykuł jest napisany z perspektywy zespołu implementacyjnego. Opisujemy decyzje techniczne, ograniczenia, które napotkaliśmy, oraz mechanizmy, które w praktyce skracają pracę i eliminują błędy konfiguracyjne. Nie jest to ogólny opis „jak zrobić konfigurator” — skupiamy się na tym, co w tym projekcie działa inaczej niż w typowym sklepie e-commerce.

 

Kontekst biznesowy: dlaczego zwykły katalog produktów nie wystarcza

Drzwi wejściowe to produkt wysokiej wartości z ogromną liczbą wariantów. Model, kierunek otwierania, kolor, rodzaj przeszklenia, klamka wewnętrzna i zewnętrzna, zamek, wizjer, numer domu — każda z tych decyzji wpływa na cenę, kompatybilność części i poprawność zamówienia u producenta. W klasycznym sklepie internetowym każda kombinacja wymagałaby osobnego produktu w bazie. Przy kilkudziesięciu modelach i dziesiątkach opcji w każdej sekcji szybko powstaje kombinatoryczna eksplozja, którą nikt sensownie nie utrzyma ręcznie.

Dodatkowy problem: błąd konfiguracji nie ujawnia się od razu. Klient może wybrać klamkę niepasującą do modelu, podać wymiar spoza zakresu producenta albo połączyć opcje, które w realnym zamówieniu i tak zostaną odrzucone. Koszt takiego błędu to reklamacja, opóźnienie produkcji, strata marży i utrata zaufania. Sklep potrzebował więc nie tylko „ładnego formularza”, ale systemu, który aktywnie pilnuje poprawności konfiguracji na każdym kroku.

Rozwiązaniem okazał się dedykowany konfigurator osadzony w sklepie — z live podglądem, natychmiastową wyceną i wielowarstwową walidacją. Warto od razu zaznaczyć: rdzeniem platformy jest konfigurator okien, który wcześniej powstał dla tego samego klienta. Drzwi to adaptacja tego silnika, a nie osobny produkt pisany od zera. Ta decyzja architektoniczna miała ogromne znaczenie zarówno dla kosztu wdrożenia, jak i dla spójności doświadczenia użytkownika między kategoriami.

 

Platforma konfiguratorów: jeden silnik, wiele produktów

Moduł konfiguratora w sklepie obsługuje trzy linie produktowe: okna, drzwi i rolety zewnętrzne. Wszystkie korzystają z tego samego szkieletu interfejsu — sticky sidebar z podglądem i ceną, sekcje w formie kart do kliknięcia, pasek kroków u góry, specyfikacja na bieżąco budowana w panelu bocznym. Różnią się mapą sekcji, logiką wyceny i — tam, gdzie to konieczne — dedykowanymi widokami.

Dla drzwi proces klienta jest celowo uproszczony w porównaniu z oknami. Okna przechodzą przez trzy kroki: konfiguracja główna, dodatki (pakiet szyb, okucia, poszerzenia, kratki itd.), podsumowanie. Drzwi mają dwa kroki: konfiguracja i podsumowanie — bez osobnej strony dodatków. To nie jest uproszczenie „dla oszczędności”, tylko odzwierciedlenie realnej oferty: drzwi mają mniej warstw konfiguracyjnych niż okna wieloskrzydłowe z lukarnami i rozbudowanym systemem wymiarów.

Adaptacja okien → drzwi polegała głównie na:

  • zdefiniowaniu mapy 12 sekcji specyficznych dla drzwi (model, konstrukcja, kolory, szyby, klamki, zamek, akcesoria, numer domu, wizjer, wymiary),
  • wprowadzeniu dedykowanego widoku konstrukcji z zakładkami kierunku otwierania zgodnego z normą DIN (lewo/prawo),
  • uproszczeniu silnika wymiarów — stałe minima i maxima zamiast dynamicznego formularza zależnego od liczby skrzydeł,
  • osobnej macierzy cenowej opartej o parę model + konstrukcja zamiast model + profil + sposób otwierania jak w oknach,
  • podglądu opartego o statyczne zdjęcie modelu zamiast proceduralnie generowanego kompozytu PNG (w oknach ten kompozyt składa warstwy skrzydeł, klamki, zawiasów i lukarn z osobnych plików graficznych).

Dzięki temu wdrożenie drzwi nie wymagało przepisywania całego frontendu. Współdzielone są: silnik sekcji, mechanizm kompatybilności, synchronizacja sesji, kalkulator cen, generowanie PDF, integracja z koszykiem. To konkretna oszczędność — i dowód, że konfigurator warto projektować jako platformę, nie jako jednorazowy widget pod jedną kategorię.

 

Interfejs konfiguratora drzwi: co widzi klient i dlaczego to przyspiesza decyzję

Interfejs konfiguratora został zaprojektowany tak, aby klient nie musiał czytać długich opisów technicznych, żeby złożyć poprawne zamówienie. Każda decyzja jest wizualna, natychmiastowa i od razu widoczna w podsumowaniu po prawej stronie ekranu.

Struktura strony konfiguracji:

  • Pasek kroków u góry — klient wie, na jakim etapie jest proces (konfiguracja → podsumowanie).
  • Sticky sidebar — podgląd wybranego modelu, aktualna cena, rozwijana specyfikacja z linkami kotwiczącymi do poszczególnych sekcji. Kliknięcie w pozycję specyfikacji przewija stronę do odpowiedniej sekcji — nie trzeba szukać, co już wybrał.
  • Sekcje w formie kart — każda opcja to klikalna karta ze zdjęciem, nazwą i stanem zaznaczenia. Wybrana karta ma wyraźny marker wizualny. Opcje niekompatybilne z aktualnym wyborem znikają z widoku — klient nie widzi tego, czego i tak nie może wybrać.
  • Przycisk „Mehr…" / więcej informacji — przy wybranych opcjach można otworzyć modal z rozszerzonym opisem, bez opuszczania konfiguratora.
  • Przycisk dalszego kroku pojawia się dopiero wtedy, gdy konfiguracja jest kompletna i poprawna — klient nie może przypadkowo przejść dalej z brakującymi polami.
Widok pełnej strony konfiguratora drzwi — sticky sidebar po prawej (podgląd modelu, cena, specyfikacja), sekcje kart po lewej, pasek kroków u góry. Pokaż zaznaczone kilka opcji, żeby widać było marker wyboru i wypełnioną specyfikację.
Widok pełnej strony konfiguratora drzwi — sticky sidebar po prawej (podgląd modelu, cena, specyfikacja), sekcje kart po lewej, pasek kroków u góry. Pokaż zaznaczone kilka opcji, żeby widać było marker wyboru i wypełnioną specyfikację.

Kluczowa różnica względem zwykłego formularza zamówienia: klient pracuje obrazkami, a nie listami rozwijanymi. Przy produkcie, gdzie różnica między „szybą motyw" a „szybą ornament" jest wizualna, a nie tekstowa, to nie estetyka — to redukcja błędów. Handlowiec w salonie pokazuje klientowi katalog z fotografiami; konfigurator online robi to samo, tylko z natychmiastową wyceną i walidacją.

Pojedyncza sekcja konfiguratora — siatka kart opcji ze zdjęciami, jedna karta zaznaczona, reszta widoczna. Obok sekcji widać, że niekompatybilne opcje są ukryte (albo pokaż ten sam widok przed i po zmianie modelu).
Pojedyncza sekcja konfiguratora — siatka kart opcji ze zdjęciami, jedna karta zaznaczona, reszta widoczna. Obok sekcji widać, że niekompatybilne opcje są ukryte (albo pokaż ten sam widok przed i po zmianie modelu).

 

Sekcja konstrukcji: kierunek otwierania bez ryzyka pomyłki

Drzwi mają dedykowany widok sekcji konstrukcji, którego nie ma w oknach. Opcje podzielone są na dwie zakładki: „otwierane w prawo" i „otwierane w lewo" (zgodnie z normą DIN). Silnik JavaScript filtruje opcje według parametru kierunku otwierania i renderuje je w odpowiedniej zakładce. Klient nie musi znać skrótów ani kodów producenta — wybiera wizualnie.

Walidacja tej sekcji sprawdza wybór nawet w nieaktywnej zakładce, więc przełączenie taba nie resetuje poprzedniego wyboru i nie pozwala „ukryć" braku decyzji. To drobny detal implementacyjny, który w praktyce eliminuje całą klasę błędów: zamówienie drzwi otwieranych w złą stronę.

 Sekcja konstrukcji z dwiema zakładkami (lewo/prawo), widoczne karty konstrukcji w aktywnej zakładce, zaznaczona jedna opcja.
Sekcja konstrukcji z dwiema zakładkami (lewo/prawo), widoczne karty konstrukcji w aktywnej zakładce, zaznaczona jedna opcja.

 

Specyfikacja na bieżąco — klient zawsze wie, co zamawia

Panel boczny buduje specyfikację w czasie rzeczywistym. Po każdym kliknięciu opcji sesja jest zapisywana, cena przeliczana, a lista wybranych elementów aktualizowana. Klient nie musi na końcu „odgadywać", co wybrał pięć sekcji wcześniej — wszystko jest widoczne w sidebarze z linkami do edycji.

Na stronie podsumowania specyfikacja jest rozwinięta w pełną tabelę z możliwością pobrania PDF. Dokument zawiera logo sklepu, wszystkie wybrane opcje i wyliczoną cenę — gotowy do wysłania klientowi mailem lub wydruku w salonie.

Sidebar ze specyfikacją — widoczne pozycje (model, konstrukcja, kolor, klamki, wymiary), cena na dole, linki kotwiczące do sekcji.
Sidebar ze specyfikacją — widoczne pozycje (model, konstrukcja, kolor, klamki, wymiary), cena na dole, linki kotwiczące do sekcji.

 

Strona podsumowania z tabelą specyfikacji + przycisk pobrania PDF + dodania do koszyka.
Strona podsumowania z tabelą specyfikacji + przycisk pobrania PDF + dodania do koszyka.

 

Jak konfigurator eliminuje błędy i niedopasowanie części

To najważniejsza część case study z perspektywy operacyjnej. Interfejs jest ważny, ale to warstwa logiki biznesowej decyduje, czy sklep realnie zmniejsza liczbę reklamacji i błędnych zamówień u producenta.

 

Silnik kompatybilności — dwa poziomy filtrowania

Każda opcja w bazie konfiguratora ma przypisany JSON z tokenami kompatybilności, np. models_42 — oznacza „pasuje do modelu o ID 42". Sekcje deklarują, względem których innych sekcji filtrują opcje. Dla drzwi prawie wszystkie sekcje (poza modelem i wymiarami) filtrują względem wybranego modelu.

Filtrowanie działa na dwóch poziomach:

  • Serwer (SQL) — zanim opcje trafią do frontendu, zapytanie do bazy ogranicza wynik do pozycji kompatybilnych z aktualnym wyborem. Klient nigdy nie dostaje pełnej listy „wszystkich klamek producenta" — tylko te, które pasują do jego modelu.
  • Przeglądarka (JavaScript) — po każdej zmianie wyboru silnik ponownie testuje widoczność kart i ukrywa niekompatybilne. Dodatkowo: gdy klient zmienia model lub konstrukcję, system automatycznie przelicza zależne sekcje i wybiera pierwszą widoczną opcję w każdej z nich. Nie zostawia „starego" wyboru klamki, która do nowego modelu już nie pasuje.

To kaskadowe auto-przełączanie to mechanizm, którego nie da się łatwo odtworzyć w zwykłym formularzu. W formularzu klient zmienia model, a w polu „klamka" zostaje poprzednia wartość — i dopiero przy składaniu zamówienia wychodzi, że kombinacja jest niemożliwa. Tutaj taka kombinacja po prostu nie istnieje w interfejsie.

 

Walidacja wymiarów — twarde limity zamiast „prośby o wycenę"

Sekcja wymiarów drzwi akceptuje szerokość od 600 do 2000 mm i wysokość od 1800 do 2600 mm (wartości z konfiguracji produktu). Silnik walidacji:

  • sprawdza, czy wartości są numeryczne,
  • clampuje wpis do dozwolonego zakresu (klient nie może wpisać 2500 mm i iść dalej),
  • blokuje przycisk przejścia do podsumowania, dopóki wymiary nie są poprawne.

W oknach walidacja wymiarów jest znacznie bardziej złożona — zależy od liczby skrzydeł, lukarn, podziałów szerokości i wysokości. W drzwiach świadomie zastosowano prostszy model, bo produkt tego wymaga. Zasada jest ta sama: lepiej nie pozwolić na błędny wymiar, niż zbierać go i wyjaśniać później.

Sekcja wymiarów z polami szerokość/wysokość, widoczne min/max
Sekcja wymiarów z polami szerokość/wysokość, widoczne min/max

 

Bramka cenowa — nie można zamówić „za zero" ani „na zapytanie" bez świadomej decyzji

Przycisk dalszego kroku (dla okien — przejście do dodatków, dla drzwi — do podsumowania) pojawia się tylko wtedy, gdy:

  • wszystkie widoczne sekcje mają dokonany wybór,
  • wymiary są poprawne,
  • wyliczona cena jest większa od zera.

Modele oznaczone jako „Auf Anfrage" (wycena indywidualna) nie przechodzą przez macierz cenową — system nie pozwala klientowi dodać takiej konfiguracji do koszyka z ceną 0 €. To zabezpiecza sklep przed zamówieniami, których nikt nie wycenił, i przed sytuacją, w której klient „kupuje" produkt bez znanej ceny.

 

Wycena z macierzy CSV — ceny zgodne z cennikiem producenta, nie z ręcznego wpisywania

Cena bazowa drzwi liczona jest z macierzy CSV przechowywanej w module (osobna macierz per model + konstrukcja). Algorytm wyszukuje w macierzy najbliższy większy lub równy wymiar względem podanych przez klienta wymiarów — standard branżowy „zaokrąglania w górę" do najbliższego progu cenowego. Wartość z komórki macierzy jest dzielona przez 4 (jednostki ćwiartek metra kwadratowego).

Dzięki temu:

  • ceny w sklepie odzwierciedlają cennik producenta, a nie szacunki handlowca,
  • klient widzi cenę natychmiast po każdej zmianie opcji lub wymiaru,
  • nie ma rozbieżności między tym, co klient widzi online, a tym, co trafia do zamówienia.

W oknach ten sam silnik wyceny obsługuje znacznie więcej typów dopłat (procent od bazy, opłata stała, cena za m², za obwód, za szerokość/wysokość, za liczbę otwarć) — i jest współdzielony z roletami. Drzwi korzystają z uproszczonej gałęzi, ale na tym samym fundamencie.

 

Macierz kompatybilności w panelu administracyjnym

Administrator sklepu nie musi edytować JSON-ów ręcznie. W panelu admina jest dedykowany edytor macierzy kompatybilności: tabela, w której dla każdej opcji zaznacza się, z którymi opcjami z innych sekcji jest ona zgodna. Zmiany zapisują się jako JSON w bazie i natychmiast wpływają na frontend.

Kokpit administracyjny konfiguratora
Kokpit administracyjny konfiguratora

To ważne z perspektywy utrzymania: gdy producent wprowadza nowy model lub wycofuje opcję, handlowiec aktualizuje macierz w adminie — bez ingerencji programisty.

Panel administracyjny — edytor macierzy kompatybilności (zaznaczone checkboxy między sekcjami).
Panel administracyjny — edytor macierzy kompatybilności (zaznaczone checkboxy między sekcjami).

 

Panel administracyjny konfiguratora — jak sklep zarządza katalogiem opcji

Frontend konfiguratora to połowa systemu. Druga połowa to panel administracyjny OpenCart z pełnym CRUD-em dla każdej sekcji: modele, konstrukcje, kolory, szyby, klamki, zamki, akcesoria, cenniki CSV, opisy wielojęzyczne, zdjęcia opcji.

Admin pracuje w języku polskim (panel sklepu), klient końcowy widzi niemiecki interfejs sklepu — oba moduły językowe są niezależne. Każda opcja ma: kod, nazwę, zdjęcie, kolejność sortowania, parametry JSON (np. liczba slotów kolorystycznych, strona otwierania), macierz kompatybilności.

Lista modeli drzwi w panelu admina z miniaturami i podstawowymi danymi.
Lista modeli drzwi w panelu admina z miniaturami i podstawowymi danymi.

 

Formularz edycji pojedynczej opcji (np. klamka) — zdjęcie, nazwa, parametry, kompatybilność.
Formularz edycji pojedynczej opcji (np. klamka) — zdjęcie, nazwa, parametry, kompatybilność.

 

Problem, którego nie da się rozwiązać ręcznie: synchronizacja katalogu z portalem producenta

Konfigurator w sklepie jest tak dobry, jak dane, które do niego trafiają. Producent drzwi udostępnia publiczny konfigurator online — rozbudowany, z setkami modeli i dziesiątkami opcji w każdej kategorii (konstrukcja, kolory, szyby dekoracyjne, klamki, zamki, akcesoria). Sklep chciał odzwierciedlić tę ofertę w swoim konfiguratorze, żeby klient miał ten sam wybór co na stronie producenta.

Ręczne przepisanie tego katalogu jest niewykonalne w rozsądnym czasie. Przy skali do 3000 modeli i dziesięciu sekcji opcji na model — mówimy o dziesiątkach tysięcy pozycji ze zdjęciami, nazwami i powiązaniami kompatybilności. Potrzebny był automatyczny importer.

Pierwsza próba była oczywista i szybka: pobrać HTML strony producenta standardowym żądaniem HTTP (curl, file_get_contents) i sparsować DOM. Nie zadziałało. W ogóle.

 

Dlaczego zwykły odczyt strony nie wystarczył

Portal producenta to aplikacja jednostronicowa (SPA) renderowana po stronie klienta w JavaScript. Adresy używają routingu hash (#/home/0,0,0,...). Żądanie HTTP dostaje pustą lub minimalną powłokę HTML — prawdziwa treść (lista modeli, opcje konfiguratora, zdjęcia) pojawia się dopiero po wykonaniu JS w przeglądarce.

Konkretne problemy, które napotkaliśmy:

  • Lazy loading siatki modeli — kafelki modeli ładują się dopiero po przewinięciu strony. Pusty DOM po pierwszym załadowaniu zawiera ułamek katalogu.
  • Lazy loading obrazów — miniatury siedzą w atrybutach data-src, data-lazy, data-original, srcset albo w background-image CSS, a nie w zwykłym src.
  • Asynchroniczne sekcje konfiguratora — po wybraniu modelu sekcje (konstrukcja, kolory, szyby, klamki) renderują się kolejno, po zakończeniu żądań XHR.
  • Zakładki i karuzele w sekcji szyb — wzory szkła dekoracyjnego (motyw i ornament) są w osobnych zakładkach; ornament wymaga kliknięcia karuzeli Slick, żeby załadować wszystkie slajdy.
  • URL-e modeli z parametrami konfiguracji — prawidłowy link do modelu to hash z parametrami oddzielonymi przecinkami (/#/home/.+,.+/). Statyczne linki z listy nie wystarczają — trzeba „kliknąć" model w przeglądarce, żeby uzyskać pełny URL stanu konfiguracji.

Wniosek był jednoznaczny: importer musi zachowywać się jak prawdziwy użytkownik w prawdziwej przeglądarce — przewijać, klikać, czekać na render, przechodzić między zakładkami. Nie chodzi o omijanie zabezpieczeń ani logowanie — konfigurator producenta jest publiczny. Chodzi o to, że bez silnika JS i interakcji użytkownika strona po prostu nie istnieje w formie, którą można sparsować.

 

Crawler do importu opcji: architektura i sposób działania

Importer powstał jako osobny moduł administracyjny OpenCart, współpracujący z konfiguratorem drzwi. Jego zadanie: pobrać katalog modeli i opcji z portalu producenta, przetworzyć go i załadować do tabel konfiguratora (configurator_section, configurator_item, configurator_description) wraz ze zdjęciami i powiązaniami kompatybilności.

Playwright + headless Chromium — udawanie użytkownika, nie omijanie zabezpieczeń

Most technologiczny: PHP (OpenCart) uruchamia skrypty Node.js z biblioteką Playwright, które otwierają headless Chromium. Przeglądarka:

  • ładuje stronę producenta (waitUntil: 'domcontentloaded'),
  • przewija stronę wielokrotnie (do 10 iteracji na liście modeli), żeby wymusić lazy load kafelków,
  • klika przycisk modelu i czeka, aż hash URL się zmieni,
  • weryfikuje, czy nazwa wybranego modelu w DOM zgadza się z oczekiwaną (polling do ~25 sekund),
  • w trybie pełnego skanowania konfiguratora: czeka na selektory sekcji (.select-construction, .select-color, .select-glass), przewija konfigurator, klika zakładki szyb (motyw / ornament), przewija karuzelę ornamentów (do 6 slajdów), czeka na networkidle,
  • zrzuca finalny HTML (page.content()) do pliku tymczasowego, który PHP parsuje dalej.

Dwa skrypty Node.js pełnią różne role:

  • Fetcher — pobiera i renderuje stronę, zwraca HTML.
  • Model probe — na liście modeli znajduje kafelek po nazwie (trzy strategie dopasowania: atrybut value kontenera, tekst spana, tekst przycisku), klika go, czeka na zmianę URL i zwraca JSON z docelowym linkiem hash, diagnostyką i czasem wykonania.

HTTP (curl) używany jest wyłącznie do pobierania binariów zdjęć — po tym, jak Playwright odkryje ich URL-e w wyrenderowanym DOM.

Zrzut z panelu admina importera — zakładka Sandbox z listą modeli, statusami URL, przyciskami skanowania.
Zrzut z panelu admina importera — zakładka Sandbox z listą modeli, statusami URL, przyciskami skanowania.

 

Mapowanie sekcji i konfigurowalne selektory CSS

Importer mapuje 10 sekcji konfiguratora producenta na sekcje sklepu:

  • konstrukcja → construction
  • kolory → colors
  • szyba motyw → glass_motive
  • szyba ornament → glass_ornament
  • klamka zewnętrzna → handle_outer
  • klamka wewnętrzna → handle_inner
  • zamek → locks
  • akcesoria → accessories
  • numer domu → house_number
  • wizjer → peephole

Ekstrakcja DOM opiera się o selektory CSS — około 40 kluczy konfigurowalnych z panelu admina (inotherm_model_selector). Administrator może korygować selektory, gdy producent zmieni strukturę HTML, bez wdrożenia nowego kodu. Dla sekcji z powtarzającymi się strukturami list (klamki, akcesoria) stosujemy ekstrakcję XPath scoped do nagłówka sekcji — np. znajdź h3 zawierający „zewn", a potem następujący po nim ul.door-handle-list.

Panel admina importera — zakładka Settings z edytorem selektorów CSS.
Panel admina importera — zakładka Settings z edytorem selektorów CSS.

 

Staging, cache URL-i i bezpieczne aktualizacje

Importer nie zapisuje danych prosto do produkcyjnego konfiguratora bez kontroli. Pipeline ma warstwę stagingu:

  • Sandbox (inotherm_model_item) — lista modeli pobrana z portalu producenta (nazwa, miniatura, URL hash). Pełny refresh przez TRUNCATE + ponowny scrape listy.
  • Cache URL modelu — po udanym probe URL hash zapisywany jest w sandboxie. Kolejne skany tego modelu pomijają fazę probe i ładują od razu znany URL konfiguracji.
  • Upsert opcji — opcje identyfikowane po kodzie (np. models-aae-1705). Jeśli istnieją — aktualizacja; jeśli nie — insert. Macierze compatible i parms są mergowane, nie nadpisywane w całości.
  • Historia uruchomień — ostatnie 10 runów z podsumowaniem (ile modeli, ile obrazów zapisano / nie udało się pobrać).

Ceny nie są importowane — importer celowo zostawia pole price puste. Cenniki CSV zarządza sklep osobno w module konfiguratora. Importer dostarcza strukturę katalogu (modele, opcje, zdjęcia, kompatybilność), a wycenę — z macierzy, które handlowiec kontroluje.

 

Skala operacji i batch processing

System zaprojektowano z myślą o dużej skali:

  • limit batch queue: do 3000 modeli,
  • 10 sekcji opcji na model (bez limitu liczby opcji w sekcji — każdy dopasowany węzeł DOM staje się pozycją katalogu),
  • timeouty: 40 s na listę modeli, 55 s na probe URL, 60 s na pełny scrape konfiguratora, 600 s limit PHP na krok batcha,
  • batch scanner w UI: kolejka AJAX przetwarza modele sekwencyjnie (jeden na raz), żeby nie przeciążyć instancji Playwright/Chromium.

Przy ~1–2 minutach na pełny skan jednego modelu (probe + render konfiguratora + pobranie zdjęć), import 3000 modeli to wielogodzinna operacja batch — świadomie uruchamiana ręcznie z panelu admina, nie w tle przez cron. To decyzja operacyjna: admin widzi postęp krok po kroku, może przerwać, ponowić pojedynczy model, zresetować URL do ponownego probe.

Batch scanner w trakcie działania — log kolejnych modeli ze statusem sukces/błąd, pasek postępu.
Batch scanner w trakcie działania — log kolejnych modeli ze statusem sukces/błąd, pasek postępu.

 

Obsługa błędów i diagnostyka

Importer nie udaje, że wszystko zawsze działa. Panel diagnostyczny pokazuje:

  • wynik probe URL (diagnostyka: liczba przycisków, strategia dopasowania nazwy, potwierdzenie modelu w DOM, czas wykonania),
  • liczbę dopasowanych opcji per sekcja (lub komunikat „Brak dopasowań" gdy selektor nie znalazł węzłów),
  • statystyki obrazów: zapisane vs. nieudane pobrania,
  • retry weryfikacji modelu — jeśli wyrenderowana nazwa modelu nie zgadza się z oczekiwaną, system ponawia probe URL i ponownie pobiera stronę.

Gdy producent zmieni DOM (nowa klasa CSS, inna struktura listy klamki), admin koryguje selektor w Settings i ponawia skan — bez angażowania developera.

Zakładka Diagnostics — wyniki probe, liczba opcji per sekcja, ewentualne błędy.
Zakładka Diagnostics — wyniki probe, liczba opcji per sekcja, ewentualne błędy.

 

Po imporcie: jak dane trafiają do konfiguratora klienta

Po udanym skanie modelu importer:

  • tworzy lub aktualizuje rekord modelu w configurator_item (ze zdjęciem, kodem, parametrami JSON — np. liczba slotów kolorystycznych),
  • dla każdej z 10 sekcji tworzy/aktualizuje opcje ze zdjęciami pobranymi do catalog/configurators/door/{sekcja}/,
  • linkuje kompatybilność każdej opcji do models_{id} — dzięki czemu silnik kompatybilności od razu filtruje opcje per model,
  • zapisuje opisy we wszystkich językach sklepu w configurator_description.

Efekt końcowy: klient w sklepie widzi te same modele i opcje co na portalu producenta — w interfejsie konfiguratora z walidacją, wyceną i specyfikacją PDF. Handlowiec nie przepisywał ręcznie tysięcy pozycji.

Porównanie — ta sama opcja (np. klamka lub szyba ornament) w portalu producenta i w konfiguratorze sklepu.
Porównanie — ta sama opcja (np. klamka lub szyba ornament) w portalu producenta i w konfiguratorze sklepu.

 

Co ten projekt daje w praktyce — podsumowanie korzyści

Dla klienta końcowego

  • Samodzielna konfiguracja drzwi online — bez telefonu do handlowca, bez ryzyka „domyśliliśmy się".
  • Wizualny wybór opcji ze zdjęciami — mniej pomyłek niż przy formularzu tekstowym.
  • Natychmiastowa cena po każdej zmianie — transparentność decyzji zakupowej.
  • PDF ze specyfikacją — gotowy dokument do wglądu, wydruku, wysłania.
  • Niemożliwość wyboru niekompatybilnych opcji — system nie pokazuje tego, co i tak nie da się zamówić.

Dla sklepu i handlowca

  • Skrócenie czasu obsługi zapytania — klient przychodzi z gotową konfiguracją i ceną, nie z listą pytań.
  • Eliminacja błędów konfiguracji (zła klamka, zły kierunek otwierania, wymiar poza zakresem) — zanim zamówienie trafi do producenta.
  • Spójność cennika — macierze CSV, nie ręczne szacunki.
  • Jeden silnik dla okien, drzwi i rolet — niższy koszt utrzymania i rozwoju.
  • Możliwość masowego odświeżenia katalogu z portalu producenta — bez tygodni ręcznej pracy.

Dla zespołu technicznego

  • Platforma konfiguratorów, nie jednorazowy moduł — kolejne kategorie to mapa sekcji + adapter, nie nowy projekt.
  • Importer oparty o Playwright — odporny na SPA, lazy load i interaktywne UI producenta.
  • Selektory konfigurowalne z admina — odporność na drobne zmiany DOM bez deployu kodu.
  • Staging i upsert — bezpieczne aktualizacje bez kasowania ręcznie skonfigurowanych danych (ceny, customowe opisy).

 

Lessons learned — czego nauczyliśmy się w trakcie projektu

1. Konfigurator to system reguł, nie formularz. Wartość nie leży w UI samym w sobie, tylko w silniku kompatybilności, kaskadowym przełączaniu zależnych sekcji i bramkach walidacyjnych. Bez tego nawet najładniejszy interfejs generuje błędne zamówienia.

2. Projektuj platformę, jeśli planujesz więcej niż jedną kategorię. Drzwi kosztowały ułamek tego, co kosztowałyby od zera, bo dziedziczyły 90% infrastruktury po oknach. Rolety doszły trzecie na tym samym fundamencie.

3. Import danych od producenta wymaga przeglądarki, nie curl-a. W 2025 roku coraz więcej katalogów B2B i konfiguratorów producentów to SPA z lazy loadingiem. Planuj Playwright/Puppeteer od początku, jeśli wiesz, że źródłem danych jest frontend producenta.

4. Oddziel strukturę katalogu od wyceny. Importer dostarcza modele, opcje, zdjęcia i kompatybilność. Ceny zostają w macierzach CSV zarządzanych przez sklep. To daje kontrolę marży i możliwość negocjacji cennika niezależnie od tego, co producent pokazuje w swoim konfiguratorze.

5. Diagnostyka i konfigurowalne selektory to ubezpieczenie na zmiany DOM. Producenci zmieniają layout bez powiadomienia. Admin, który może sam poprawić selektor CSS i ponowić skan jednego modelu, oszczędza dni oczekiwania na developera.

6. Sekwencyjny batch lepszy niż równoległy przy Playwright. Jeden Chromium na raz jest wolniejszy, ale przewidywalny. Równoległe uruchomienie 10 instancji headless na typowym hostingu sklepu kończy się timeoutami i niestabilnością.

 

Techniczne zestawienie stosu

Dla czytelników technicznych — skrót tego, co stoi pod spodem:

  • CMS / e-commerce: OpenCart 3, motyw designcart
  • Backend konfiguratora: PHP, MVC OpenCart (controllers, models), sesja PHP do przechowywania stanu konfiguracji
  • Frontend konfiguratora: Twig templates, jQuery, Bootstrap 5, Font Awesome, product-specific JS adapters (sections-door-core.js, door.js, door_size_validation.js)
  • Wycena: macierze CSV, algorytm findClosestGreaterOrEqual, wspólny model cenowy (standardPrice) z typami: %, stała, m², obwód, szerokość, wysokość
  • PDF: mPDF (Composer), konwersja WEBP → PNG dla logo sklepu
  • Podgląd okien: PHP GD — kompozycja warstw PNG (skrzydła, klamki, zawiasy, lukarny) z cache na dysku
  • Importer: PHP → exec → Node.js + Playwright 1.52+ (headless Chromium), simple_html_dom + DOMXPath do parsowania, curl do pobierania obrazów
  • Baza danych konfiguratora: configurator_section, configurator_item, configurator_description, configurator_featured, configurator_pricelist
  • Baza staging importera: inotherm_model_item, inotherm_model_run, inotherm_model_result, inotherm_model_selector
  • Admin: język polski; storefront: język niemiecki

 

Podsumowanie

Konfigurator drzwi w tym projekcie to adaptacja dojrzałej platformy konfiguratorów okiennych — z dedykowaną mapą sekcji, widokiem konstrukcji DIN, uproszczoną wyceną i dwuetapowym flow klienta. Interfejs oparty o karty wizualne, sticky sidebar z live specyfikacją i ceną oraz wielowarstwową walidację realnie skraca drogę od „chcę drzwi" do „gotowe zamówienie z poprawną specyfikacją".

Równolegle powstał importer oparty o headless Chromium (Playwright), który — udając użytkownika przewijającego, klikającego i czekającego na render SPA — pozyskuje z portalu producenta modele, dziesiątki sekcji opcji, zdjęcia i powiązania kompatybilności. Zwykły odczyt HTTP nie wchodził w grę. Skala: do 3000 modeli, 10 sekcji na model, sekwencyjny batch z pełną diagnostyką.

Razem te dwa moduły tworzą zamknięty ekosystem: importer utrzymuje katalog aktualny względem oferty producenta, konfigurator pilnuje poprawności wyboru klienta i wyceny względem cennika sklepu. Handlowiec pracuje szybciej, klient nie składa błędnego zamówienia, a zespół techniczny ma platformę gotową na kolejne kategorie produktowe.