Rynek · ogłoszenia

Admister — siedem marketplace'ów, które dzielą jeden silnik

Ogłoszenia, samochody, nieruchomości, rynek towarów z sklepami, klucze cyfrowe, kupony i agregator cen. Siedem usług działa na swoich subdomenach, a każda z nich to ta sama aplikacja: usługa jest wybierana na podstawie nazwy hosta, a katalog, konta, pieniądze, moderacja i wyszukiwanie są wspólne. Zaprojektowaliśmy model, napisaliśmy silnik i wdrożyliśmy wszystkie siedem.

Kategoria
Marketplace · ogłoszenia
Szacowany koszt
od 32 000 €
Usługi
siedem, jeden kod źródłowy
Języki
EN, UK · cztery waluty wyświetlania
Stos
PHP 8.3, MariaDB, bez frameworka
admister.org
Admister
Strona projektu — admister.org

01Przegląd projektu

Admisterjest wielowektorowym rynkiem. Pod jednym dachem prowadzi ogłoszenia, tablicę samochodową i części, nieruchomości na sprzedaż i wynajem, rynek towarów z sklepami sprzedawców, dobra cyfrowe, usługę kuponową i agregator cen. Każdy z nich ma swoją własną subdomenę, swoją własną stronę główną i własny pomysł na to, czym jest przedmiot.

Z zewnątrz wyglądają jak siedem oddzielnych produktów. Od wewnątrz są jedną aplikacją: usługa jest określana przez nazwę hosta żądania, a wszystko, co pod spodem — konta, pieniądze, moderacja, wyszukiwanie, media, powiadomienia — jest współdzielone. Projekt był nasz od początku do końca: model, silnik, interfejs i uruchomienie każdej pionowej.

02Kontekst i problem

Zwykły sposób uruchamiania kilku rynków to uruchomienie kilku stron internetowych. Działa to do drugiego: teraz są dwie tabele użytkowników, dwie kolejki moderacji, dwie integracje płatności i dwa miejsca, w których ten sam błąd musi być naprawiony dwa razy — i naprawiony inaczej, ponieważ do tego czasu kod się rozjechał.

Przeciwna skrajność jest równie zła. Jedna strona z kategorią „Samochody” nie może pytać o przebieg, silnik i tablicę rejestracyjną w sposób, w jaki musi to robić tablica samochodowa, a wyszukiwanie nieruchomości, które nie może filtrować według piętra i pokoi, nie jest wyszukiwaniem nieruchomości. Zadaniem było utrzymanie jednego silnika, nie udając, że siedem bardzo różnych katalogów to ten sam katalog.

03Cele projektu

  • jedna baza kodu i jedno konto dla wszystkich pionów, z usługą wybieraną przez nazwę hosta;
  • atrybuty i filtry per-pionowe: dziesiątki pól dla samochodów i nieruchomości, żadne z nich nie przeniesione do innych usług;
  • pieniądze, którym właściciel może zaufać — saldo, faktury kryptowalutowe, idempotentne kredytowanie i uzgadnianie zablokowanych płatności;
  • powody, dla których kupujący wracają: zapisane wyszukiwania z powiadomieniami, odznaki sprzedawców, aukcje i zakupy grupowe;
  • dwa języki i cztery waluty wyświetlania bez duplikowania treści;
  • aplikacja mobilna, która komunikuje się z backendem dla frontendu, a nie zeskrobuje strony.

04Co zrobiliśmy

Zbudowaliśmy rejestr usług w sekwencji uruchamiania. Przybywa żądanie, nazwa hosta jest dopasowywana do rejestru, a od tego momentu aplikacja wie, w jakim pionie się znajduje: które moduły załadować, który zestaw atrybutów użyć, która strona główna i które menu renderować. Nagie domeny to tablica ogłoszeń, więc najkrótszy adres jest również najbardziej ogólny.

Wszystko, co nie jest specyficzne dla pionu, zostało napisane raz: konta i sesje, saldo i płatności, przyjmowanie mediów, moderacja, zapisane wyszukiwania, powiadomienia, mapa witryny i API. Dodanie siódmej usługi polegało głównie na napisaniu jej atrybutów i strony głównej — nie kolejnego rynku.

05Siedem usług, siedem katalogów

  • Ogłoszenia — ogólna tablica: wszystko, od roweru po sofę, darmowe do zamieszczenia.
  • Samochody — pojazdy, tablice rejestracyjne i części, z dedykowanym zestawem atrybutów składającym się z kilku tuzinów pól i filtrów.
  • Nieruchomości — sprzedaż i wynajem, własny zestaw atrybutów, mapy i wyszukiwanie według dzielnic.
  • Rynek — towary z sklepami sprzedawców: witryna dla każdego sprzedawcy, zapasy, zamówienia.
  • Cyfrowe — klucze, karty podarunkowe i eSIM: towary, które są dostarczane, a nie wysyłane.
  • Oferty — kupony i kody promocyjne sklepów partnerskich.
  • Cena — agregator cen: ten sam produkt w różnych sklepach, porównany, z policzonymi kliknięciami wychodzącymi.

Dzielą się kontem, saldem, kolejką moderacyjną i indeksem wyszukiwania — i nie dzielą się niczym w swoich atrybutach, co jest istotą.

06Pieniądze: saldo, faktury kryptowalutowe, uzgadnianie

Płatne funkcje — promocja, plany sklepów, dobra cyfrowe — są opłacane z wewnętrznego salda, a saldo jest doładowywane kryptowalutą przez Payora, naszą własną bramkę. Treść faktury jest budowana w dokładnie jednej funkcji, ponieważ ta sama treść jest odtwarzana przez cron uzgadniający pod tym samym kluczem idempotencji: pojedyncze pole, które różni się między dwoma, spowodowałoby konflikt i pozostawiłoby płatność w zawieszeniu.

Dwa szczegóły, które powtórzylibyśmy na każdej bramce. Faktura zawiera lokalizację kupującego wziętą z jego wiersza konta, a nie z żądania sieciowego — cron nie ma żądania i w przeciwnym razie wysłałby wszystkim angielski. I zawiera adres zwrotny, który prowadzi z powrotem do konta na podstawowej domenie, więc kupujący, który rozpoczął na pionie samochodowym, wraca zalogowany, a nie na stronę, która prosi ich o ponowne zalogowanie się.

07Zaufanie: moderacja, odznaki, spory

Rynek oceniany jest przez najgorsze ogłoszenie, więc moderacja nie jest tutaj sprawą drugorzędną. Każda decyzja — zatwierdzenie, odrzucenie, usunięcie — przechodzi przez jednego operatora, a «odrzucenie» celowo nie jest tym samym co «usunięcie»: pierwsze to odpowiedź do autora z uzasadnieniem, drugie usuwa coś, co już było aktywne. Dwa czasowniki, dwa różne litery, dwa różne stany w rejestrze.

Sprzedawcy i sklepy noszą odznaki, które są zdobywane, a nie kupowane: jak długo konto istnieje, ile transakcji zostało zamkniętych, czy telefon i e-mail są potwierdzone. Kupujący widzi tę samą odznakę wszędzie tam, gdzie pojawia się sprzedawca, ponieważ jest ona obliczana w jednym miejscu.

09Aplikacja mobilna z własnym zapleczem

Aplikacja nie zaciąga danych ze strony internetowej. Rozmawia z własnym backendem dla frontendów: małym zestawem punktów końcowych, które odpowiadają w kształtach, których potrzebują ekrany, z tokenami wydawanymi oddzielnie od sesji internetowych. Dwie ścieżki są otwarte bez tokena — dane referencyjne, których aplikacja potrzebuje przed zalogowaniem się, oraz punkt końcowy zdrowia.

Ten punkt zdrowotny to osobny adres celowo. Rejestr, który monitoruje flotę, wcześniej pytał punkt odniesienia, a ten zbiera każdy słownik i każdą stawkę — sprawdzenie żywotności nie powinno kosztować więcej niż praca. Odpowiada również z wersją kontraktu, więc klient zbudowany dla starszego kontraktu jest zauważany zanim jego użytkownicy to zauważą.

10Siedem frontów SEO

Siedem usług na jednej domenie oznacza siedem map witryn, siedem zestawów danych strukturalnych i jeden bardzo łatwy sposób na produkcję duplikatów. Każdy pion publikuje swoją własną mapę witryn z pamięci podręcznej, strony z listami deklarują swój własny typ danych strukturalnych, a strony wyników wyszukiwania nigdy nie twierdzą, że są kanoniczne dla listy.

Strona z treścią jest również zautomatyzowana: strumień redakcyjny przychodzi z Astrina, platformy, którą zbudowaliśmy dokładnie w tym celu, a w momencie, gdy artykuł ląduje, pamięć podręczna mapy witryn dla jego pionu jest usuwana — w przeciwnym razie nowa strona czekałaby na następne odbudowanie i nikt by nie wiedział, dlaczego jej brakuje.

11Jeden kanał outboundowy

Wszystko, co aplikacja wysyła na zewnątrz — wywołania API, webhooki, kanały partnerów, obrazy, które pobiera, maile — przechodzi przez jeden moduł powiązany z proxy wyjściowym SOCKS5, z DNS rozwiązywanym przez proxy. Moduł jest zamykany na błąd: jeśli proxy jest niedostępne, żądanie jest blokowane, a nie cicho wysyłane z własnego adresu serwera.

To nie jest dekoracja. Rynek pobiera kanały partnerów i zdalne obrazy przez cały dzień; każde z nich to żądanie, które w przeciwnym razie przeniosłoby adres źródłowy witryny do strony trzeciej. Maile idą w ten sam sposób, przez YourTrend, więc listy są podpisane, a nazwa hosta serwera nigdy nie pojawia się w nagłówku.

12Stos technologiczny

  • PHP 8.3 bez frameworka, cienki wrapper PDO i przygotowane zapytania wszędzie;
  • MariaDB, schemat przechowywany jako numerowane pliki migracji, a nie jako czyjaś pamięć;
  • media przechowywane poza katalogiem głównym i serwowane przez kontroler, więc przesyłanie nigdy nie jest ścieżką wykonywalną;
  • krok budowy, który hashuje zasoby i nie wstawia nic, co powinno być buforowane, z wyłącznikiem awaryjnym na wypadek, gdyby coś poszło nie tak;
  • wyjście SOCKS5 dla każdego połączenia wychodzącego, poczta przez YourTrend SMTP;
  • Payora do faktur kryptowalutowych, Astrina do logowania i treści redakcyjnych, Adgora do reklamy wewnętrznej.

13Wynik

Siedem aktywnych usług na jednej bazie kodu, jedno konto i jeden bilans we wszystkich z nich, z atrybutami i filtrami, które różnią się tak bardzo, jak katalogi. Nowa pionowa to zestaw atrybutów i strona główna — nie nowy projekt, nie druga tabela użytkowników, nie druga integracja płatności.

To, co właściciel dostaje na co dzień, to jedno miejsce do patrzenia. Moderacja, pieniądze, sprzedawcy i treści są zarządzane z wspólnego panelu kontrolnego całej grupy, a rynek udostępnia je przez podpisane API administratora, a nie przez drugą stronę administracyjną.

14Wnioski

Lekcja, którą przyniesiemy do następnego rynku: dziel się maszyną, nie znaczeniem. Konta, pieniądze, moderacja i wyszukiwanie to ten sam problem w każdej branży i muszą być napisane raz. Atrybuty, filtry i kształt ogłoszenia to sam produkt, a zmuszanie ich do jednego uniwersalnego stołu sprawia, że rynki stają się nieużyteczne dla wszystkich jednocześnie.

Druga lekcja dotyczy pieniędzy. Miejsce, w którym opisuje się płatność, musi być jedną funkcją, ponieważ coś innego to powtórzy — cron, ponowna próba, uzgadnianie — a dwa opisy jednej płatności to najtańszy sposób na ciche straty.

Jeśli budujesz rynek, tablicę ogłoszeń lub platformę wielobranżową na jednym silniku, to jest to rodzaj pracy, którą wykonujemy od początku do końca.