Stos technologiczny SEOJuice: technologie stojące za narzędziem

Vadim Kravcenko
Vadim Kravcenko
· Updated · 5 min read

Kiedy zabierałem się za budowę SEOJuice, pierwsza naprawdę ważna decyzja nie dotyczyła funkcji ani modelu cenowego. Wracało do mnie jedno pytanie: sięgnąć po stos technologiczny, który już dobrze znam, czy po taki, który świetnie wygląda w wpisie typu „How We Built It”? Wybrałem nudę. I zrobiłbym to jeszcze raz, bo nudna technologia, którą rozumiesz od podszewki, niemal zawsze wygra z modną technologią, której uczysz się w biegu. (Zapytaj mnie o te trzy tygodnie stracone na testowanie bazy grafowej, zanim w końcu przyznałem, że PostgreSQL potrafi zrobić wszystko, czego potrzebowałem.)

Ten artykuł to szczere spojrzenie na każdą warstwę infrastruktury SEOJuice — nie tylko na końcowe wybory, ale też na kompromisy, które za nimi stały. Jeśli jako założyciel oceniasz własny stos technologiczny, mam nadzieję, że sposób myślenia okaże się cenniejszy niż same etykietki technologii.

Filozofia stosu technologicznego

Moja filozofia sprowadza się do trzech zasad, których nauczyłem się metodą prób i błędów, prowadząc projekty poboczne przez lata, zanim powstało SEOJuice:

Zasada 1: kontroluj krytyczną ścieżkę. Jeśli kluczowa funkcjonalność twojego produktu zależy od zewnętrznego API, to oddałeś komuś innemu możliwość wyłączenia cię jednym ruchem. Silnik indeksowania, analiza linków i algorytmy oceny w SEOJuice działają na infrastrukturze, którą sam kontroluję. Gdy zlecasz na zewnątrz swoją kluczową przewagę, przestajesz tworzyć produkt, a zaczynasz tylko odsprzedawać cudze rozwiązanie.

Zasada 2: wybieraj technologie, które umiesz debugować o 2 w nocy. Rozważałem FastAPI jako zaplecze aplikacji. W benchmarkach jest szybsze, nowocześniejsze i lepiej radzi sobie z asynchronicznością. Ale Django piszę od 2016. Kiedy Sentry odpala alert o północy, nie chcę spędzać 40 minut na czytaniu dokumentacji — chcę od razu wiedzieć, który middleware się wysypał. Znajomość technologii to nie lenistwo; to dojrzałość operacyjna.

Zasada 3: ograniczaj liczbę ruchomych części. Każda dodatkowa usługa w architekturze to kolejna rzecz, która może się zepsuć, kolejna rzecz do monitorowania i kolejna zależność do aktualizacji. Usługi w moim pliku docker-compose liczę tak, jak backpacker liczy każdy dodatkowy gram w plecaku.

Back-End Stack

Sercem SEOJuice jest Django. Wybrałem je zamiast Flaska (zbyt surowy jak na produkt o takiej złożoności), FastAPI (świetne do API, ale potrzebowałem panelu administracyjnego Django, ORM i silnika szablonów) oraz Railsa (nie znam Ruby na tyle dobrze, żeby debugować go na ślepo). Filozofia Django „batteries-included” sprawiła, że nie spędziłem pierwszych trzech miesięcy na składaniu systemu logowania, panelu administracyjnego i frameworka migracji z osobnych paczek. Kompromis jest taki, że Django bywa ciężkie przy prostych mikroserwisach — ale SEOJuice nie jest prostym mikroserwisem. To monolit z ponad 15 aplikacjami i Django radzi sobie z tym bardzo dobrze.

A realistic photo of a developer building or maintaining backend infrastructure, with code on screens and a professional workspace that supports the article's discussion of pragmatic stack decisions, Django, ASGI, and Nginx.
A realistic photo of a developer building or maintaining backend infrastructure, with code on screens and a professional workspace that supports the article's discussion of pragmatic stack decisions, Django, ASGI, and Nginx.. Source: Semrush Blog

Aplikacja działa w ASGI na Uvicornie, za Nginx pełniącym rolę reverse proxy. Przesiadłem się z Gunicorn (WSGI) na Uvicorn mniej więcej po roku, kiedy dodałem WebSockety dla powiadomień w czasie rzeczywistym i serwera MCP. Ta migracja była zaskakująco bezbolesna — to jedna z zalet stopniowego wdrażania ASGI w Django. Cloudflare stoi przed całością i odpowiada za DNS, kończenie połączeń SSL/TLS oraz ochronę przed atakami DDoS. Widziałem, jak Cloudflare bez najmniejszego wysiłku przejmował skoki ruchu, które inaczej położyłyby moje serwery.

Wszystkie serwery działają na Linuksie w Hetznerze. Dlaczego Hetzner zamiast AWS? Szczerze: koszt. Dedykowany serwer Hetzner z 64GB RAM kosztuje mniej więcej tyle, ile porównywalna instancja EC2 kosztuje za jeden tydzień. Dla bootstrappowanego produktu ta różnica ma ogromne znaczenie. Minusem jest mniejsza automatyzacja — brak auto-scalingu, brak managed Kubernetes. Wdrożenia obsługuję za pomocą Dockera i kilku skryptów powłoki. To nie jest seksowne, ale działa, a pieniądze, które oszczędzam, mogę przeznaczyć bezpośrednio na rozwój produktu.

Baza danych to PostgreSQL z rozszerzeniem pgvector. Na początku oceniałem MongoDB (w 2022 używał go prawie każdy) i szybko dotarło do mnie, że dane SEO są mocno relacyjne — strony należą do serwisów, słowa kluczowe należą do stron, linki łączą strony ze sobą. Baza dokumentowa oznaczałaby konieczność ręcznego odtwarzania połowy tego, co Postgres daje od ręki. O wyborze ostatecznie przesądził pgvector: mogę przechowywać i odpytwać embeddingi bezpośrednio obok danych relacyjnych, co napędza dopasowanie podobieństwa treści i funkcje AI bez potrzeby stawiania osobnej bazy wektorowej.

Do zadań w tle używam Celery z Redis jako brokerem. Celery dostaje sporo krytyki w społeczności Pythona i część z niej jest zasłużona — dokumentacja jest porozrzucana, opcji konfiguracji jest za dużo, a debugowanie błędów zadań potrafi doprowadzić do szału. Ale nie znalazłem nic lepszego do skali pracy w tle, jaką wykonuje SEOJuice: indeksowanie tysięcy stron, analiza NLP, generowanie raportów, monitorowanie backlinków. Rozważałem Dramatiq i Huey jako lżejsze alternatywy. Dramatiq jest naprawdę dobry, ale ekosystem Celery (beat scheduler, flower monitoring, django-celery-results) ostatecznie wygrał.

Logowanie i uwierzytelnianie realizuję przez Auth0. W poprzednim projekcie zbudowałem własny system logowania i spędziłem żenująco dużo czasu na przypadkach brzegowych związanych z resetem hasła, rate limitingiem i przepływami MFA. Auth0 bierze to wszystko na siebie. Koszt rośnie wraz z liczbą użytkowników, co przy pewnych progach boli, ale czas inżynierski, który to oszczędza, jest wart wielokrotności abonamentu.

Wszystko działa w kontenerach Dockera. Moje środowisko deweloperskie i produkcyjne uruchamiają identyczne kontenery. To wyeliminowało całą klasę błędów typu „u mnie działa”, które męczyły moje wcześniejsze projekty. Sentry monitoruje wyjątki w czasie rzeczywistym — potrafię prześledzić błąd zgłoszony przez użytkownika od jego sesji do konkretnej linijki kodu w mniej niż minutę.

Front-End Stack

Świadomie postanowiłem unikać Reacta, Vue i każdego innego frameworka JavaScript. Dashboard SEOJuice to HTML renderowany po stronie serwera z Tailwind CSS i Alpine.js do interaktywności. To decyzja, za którą najczęściej spotykam się z krytyką ze strony innych programistów, i rozumiem dlaczego — to trochę jak budowanie ręcznymi narzędziami, kiedy obok leżą elektronarzędzia.

Moje uzasadnienie jest proste: SEOJuice to dashboard z dużą ilością danych. Użytkownicy patrzą na tabele, wykresy i raporty. Nie potrzebują współdzielonej edycji w czasie rzeczywistym ani skomplikowanego zarządzania stanem po stronie klienta. Renderowanie po stronie serwera oznacza, że każda strona ładuje się szybko, początkowy pakiet danych jest niewielki, a ja nie utrzymuję osobnego pipeline'u buildów frontendu, warstwy API ani biblioteki do zarządzania stanem. Alpine.js obsługuje dropdowny, modale i interaktywne filtry. W kilku miejscach, gdzie potrzebuję bogatszej interakcji (dashboard monitoringu w czasie rzeczywistym), używam htmx do podmieniania fragmentów HTML bez pełnego przeładowania strony.

Statyczne assety lecą przez CDN Bunny.net. Testowałem CDN od Cloudflare (którego i tak używam do DNS), ale uznałem, że model rozliczania za każde żądanie w Bunny jest bardziej przewidywalny przy moim profilu ruchu. Różnica jest niewielka — oba rozwiązania by się sprawdziły.

Processing and AI

Duża część tego, co sprawia, że SEOJuice jest użyteczne, polega na przetwarzaniu dużych wolumenów danych i wykorzystywaniu AI do funkcji, których ręcznie po prostu nie dałoby się zbudować.

A high-quality stock photo showing a technical professional analyzing data or AI-driven processing on a laptop or workstation, visually matching the section about processing pipelines and AI systems.
A high-quality stock photo showing a technical professional analyzing data or AI-driven processing on a laptop or workstation, visually matching the section about processing pipelines and AI systems.. Source: Semrush Blog

Jeśli chodzi o modele językowe, integruję OpenAI i Claude. Po miesiącach testów doszedłem do prostego wniosku: różne modele nadają się do różnych zadań. GPT-4o wykorzystuję do ekstrakcji danych strukturalnych, bo bardziej niezawodnie trzyma się schematów JSON. Claude wolę do analizy treści i sugestii, bo pisze naturalniej i lepiej wyłapuje niuanse. Próbowałem uruchamiać modele open source lokalnie — najpierw Llama 2, potem Llama 3 — ale różnica jakościowa w zastosowaniach produkcyjnych nadal była zbyt duża, żeby uzasadnić koszt infrastruktury. Ten rachunek zmienia się co kilka miesięcy, więc regularnie do niego wracam.

Do wyszukiwania embeddingów używam pgvector, a nie dedykowanej bazy wektorowej takiej jak Pinecone czy Weaviate. Trzymanie wektorów w PostgreSQL obok reszty danych oznacza, że mogę łączyć wyniki podobieństwa embeddingów z zapytaniami relacyjnymi w jednym poleceniu SQL. Przy naszej skali wydajność jest w pełni wystarczająca. Gdybym operował na miliardach wektorów, potrzebowałbym czegoś bardziej wyspecjalizowanego. Przy milionach Postgres daje radę bez problemu.

Po stronie NLP ciężką robotę wykonują NumPy, NLTK i Scikit-learn — przy ekstrakcji słów kluczowych, ocenie treści i klasyfikacji. Te biblioteki nie są ekscytujące, ale są sprawdzone w boju. Kiedy odpalam analizę TF-IDF na 50,000 stron, potrzebuję poprawnego wyniku, a nie technologicznej nowinki.

Do indeksowania serwisów mocno opartych na JavaScript używam Playwright uruchamianego w osobnym kontenerze. Jest bardziej zasobożerny niż zwykłe requesty HTTP, ale współczesne strony często renderują kluczową treść przez JavaScript. Jeśli nasz crawler tego nie widzi, nie możemy tego analizować. Playwright radzi sobie ze SPA, treścią doładowywaną leniwie i routingiem po stronie klienta, które dla tradycyjnego crawlera byłyby niewidoczne.

Dodatkowe narzędzia i usługi

To właśnie w infrastrukturze wspierającej najchętniej korzystałem z usług zewnętrznych, bo żadna z tych rzeczy nie jest moim kluczowym wyróżnikiem:

Crisp do live chatu. Najpierw testowałem Intercom — był za drogi i zbyt rozbudowany jak na jednoosobowy support. Crisp robi to, czego potrzebuję, za ułamek ceny.

Customer.io do emaili. Maile transakcyjne (reset hasła, dostarczanie raportów), sekwencje onboardingowe i aktualizacje produktu działają przez Customer.io. Przesiadłem się z prostszego setupu (wbudowany email w Django z SendGrid), bo potrzebowałem triggerów behawioralnych — „wyślij maila z poradą, jeśli użytkownik nie podłączył swojej strony WordPress w ciągu 3 dni”.

Paddle do płatności. Zaczynałem od Stripe i przeszedłem na Paddle jako Merchant of Record. Powód był całkowicie praktyczny: Paddle obsługuje wyliczanie VAT, pobór i odprowadzanie podatku dla każdego kraju. Jako bootstrappowany europejski założyciel sprzedający globalnie, budowanie własnego systemu zgodności podatkowej byłoby pracą na pełen etat. Paddle bierze większą prowizję niż Stripe, ale eliminuje całą kategorię operacyjnego bólu.

ChartMogul do analityki przychodów. MRR, churn rate, LTV, expansion revenue — potrzebuję tych liczb dokładnych i aktualizujących się automatycznie. Mógłbym liczyć je sam z API Paddle, ale ChartMogul robi to lepiej i pokazuje trendy, których sam pewnie nie sprawdzałbym regularnie.

Do analityki odwiedzających uruchamiam self-hostowaną instancję Plausible. Bez cookies, bez banerów zgód, bez wysyłania danych odwiedzających do Google. Pokazuje mi źródła ruchu, topowe strony i referrale — i to naprawdę wszystko, czego potrzebuję. (Pisałem o Plausible szerzej w naszym przewodniku po open-source SEO tools.)

Co bym zmienił

Żaden stack nie jest idealny i nauczyłem się już na tyle dużo, żeby wiedzieć, co zrobiłbym inaczej, gdybym startował od zera:

Wcześniej zainwestowałbym w Kubernetes. Nie pierwszego dnia — to byłby overkill dla MVP — ale mniej więcej wtedy, gdy doszedłem do 10 workerów w tle. Orkiestracja kontenerów skryptami powłoki i systemd działa… aż przestaje działać, a przejście na porządną orkiestrację przy jednoczesnym obsługiwaniu ruchu produkcyjnego jest stresujące.

Szybciej oddzieliłbym API od monolitu. To, że dashboard, publiczne API, API pluginu WordPress i serwer MCP współdzielą jeden proces Django, oznacza, że skok ruchu na API może spowolnić dashboard. Stopniowo wyciągam te elementy do osobnych usług, ale czyściej byłoby zaprojektować to tak od samego początku.

Nie zmieniłbym natomiast podstawowych wyborów — Django, PostgreSQL, Celery, HTML renderowanego po stronie serwera. Te technologie obroniły się przez dwa lata ruchu produkcyjnego, a prostota, którą dają, jest dla mnie więcej warta niż potencjalne zyski wydajności z modniejszych alternatyw.

Podsumowanie

Jako founder działający solo najgroźniejszą pułapką jest budowanie stacku pod publiczność z Hacker News zamiast pod realne wymagania własnego produktu. Każdy wybór technologiczny, który tu opisałem, wynikał z konkretnej potrzeby, był oceniany na tle alternatyw i został podjęty dlatego, że pozwalał mi szybciej dowozić produkt i z mniejszą liczbą niespodzianek. Efektem jest system, który mogę obsługiwać samodzielnie, szybko debugować i rozwijać bez przepisywania wszystkiego od nowa.

Ale to dopiero początek. Stack ewoluuje razem z produktem — cały czas pracuję nad tym, żeby SEOJuice było lepsze, a infrastruktura musi za tym nadążać. Jeśli jesteś założycielem i podejmujesz podobne decyzje, mam nadzieję, że zobaczenie mojego toku rozumowania oszczędzi ci przynajmniej części prób i błędów, przez które sam przeszedłem.

Działajmy dalej.

Pozdrawiam,
Vadim

Powiązane materiały:

SEOJuice
Stay visible everywhere
Get discovered across Google and AI platforms with research-based optimizations.
Works with any CMS
Automated Internal Links
On-Page SEO Optimizations
Get Started Free

no credit card required

More articles

No related articles found.