Przejdź do treści głównej
aiAdaptiv
Wszystkie case studies

Jak budujemy — web i mobile w jednym repozytorium

Jedno repozytorium, trzy wydania

Konsola webowa, aplikacja na iOS, aplikacja na Androida i baza danych pod spodem. Większość zespołów prowadzi to jako cztery repozytoria i cztery dni wydaniowe. My budujemy to inaczej — jedno repozytorium, dwie gałęzie i push, który wydaje wszystko naraz. Ten układ stoi dziś na produkcji i to ten sam kształt, który postawilibyśmy Wam.

  • Co to jest

    Sposób budowania, nie produkt

  • Pasuje do

    Wszystkiego z aplikacją webową i mobilną

  • Stack

    Next.js 16, Expo, Supabase, monorepo na Turborepo

  • Status

    Na produkcji, w obu sklepach

Push na główną gałąź migruje bazę, deployuje konsolę i publikuje obie aplikacje mobilne. Nie ma czegoś takiego jak dzień wydaniowy.

  • 3systemy wydawane jednym pushembaza migruje, konsola się deployuje, obie aplikacje publikują
  • 2kompletne środowiska, preview i produkcjaosobne bazy, osobne hosty, osobne aplikacje na telefonie
  • 1typecheck obejmujący wszystkie workspace'y narazzepsuty wspólny kontrakt wywala się tam, zanim cokolwiek się zbuduje
  • 5wyspecjalizowanych subagentów mieszkających w repomigracje, silnik domenowy, zgodność ze specyfikacją, scenariusze, weryfikacja

Problem: cztery bazy kodu się rozjeżdżają

Produkt z konsolą webową i dwiema aplikacjami mobilnymi buduje się zwykle jako osobne repozytoria — front, iOS, Android, backend — każde z własnym wydaniem, własnym wyobrażeniem o tym, co zwraca API, i własną kopią reguł biznesowych.

Najdroższe są te kopie. W momencie, w którym ta sama reguła jest napisana dwa razy, obie wersje zaczynają się różnić, a różnica wychodzi jako błąd widoczny tylko na jednej platformie. Każdy dzień wydaniowy schodzi wtedy na udowadnianiu, że cztery rzeczy nadal do siebie pasują.

Kształt: jedno repozytorium, cztery workspace'y

Monorepo na Turborepo, w którym obok siebie leżą konsola webowa, aplikacja mobilna, silnik domenowy i wspólny kontrakt API. Silnik to czysty pakiet TypeScriptu bez kroku budowania: konsola i serwer kompilują te same pliki źródłowe, więc wynik policzony w przeglądarce i ten sam wynik policzony na serwerze to dowodliwie ten sam kod, a nie dwie implementacje, które na razie się zgadzają.

Typecheck idzie jednym przebiegiem przez wszystkie workspace'y. Zmiana we wspólnym kontrakcie, która psuje aplikację, wywala się właśnie tam — zanim cokolwiek zostanie zbudowane, wdrożone czy zainstalowane na telefonie.

  • Konsola webowa — Next.js 16 i React 19, App Router, z własnymi trasami API
  • Aplikacja mobilna — Expo, wysyłana do App Store i Google Play z tego samego repo
  • Silnik domenowy — czysty TypeScript, deterministyczny, testowany katalogiem scenariuszy
  • Pakiet wspólnego kontraktu — kształty odpowiedzi i enumy, na które obie strony się godzą

Środowisko to gałąź gita i nic poza tym

Dwa środowiska, każde kompletne aż po własną ikonę na telefonie. Gałąź preview ma bazę preview, hosting preview i osobną aplikację Preview. Gałąź główna ma bazę produkcyjną, żywą stronę i aplikację ze sklepu. Nie ma przełącznika środowiska, flagi w configu ani serwera stagingowego, który się rozjeżdża.

To właśnie czyni wydanie nudnym, i o to chodzi: push na główną migruje bazę, deployuje konsolę i publikuje obie aplikacje. Osoba odbierająca klika po aplikacji Preview na własnym telefonie, na danych preview, a potem ten sam commit idzie na produkcję wszędzie naraz.

Skąd naprawdę bierze się tempo

To nie jest zabawkowa konfiguracja. W produkcyjnej bazie kodu, na której to policzyliśmy, układ niesie 879 commitów zrobionych w dziewięć tygodni w 1 020 plikach TypeScriptu, z 111 migracjami bazy i 37 plikami testów pgTAP za nimi.

To tempo to nie szybsze pisanie. To efekt oddania powtarzalnej, regułowej roboty specjalistom: w repozytorium mieszka pięciu subagentów, każdy z jednym zadaniem i spisanym standardem — jeden pisze migracje i ich testy, jeden implementuje silnik domenowy, jeden audytuje ten silnik wobec specyfikacji, jeden pisze scenariusze testowe, jeden weryfikuje skończony kawałek pracy wobec kodu, a nie wobec linijki w statusie.

Regułą, która trzyma to w ryzach, jest zdanie wpisane do przewodnika po repo: tracker zapisuje, co zbudowano, więc twierdzenie sprawdza się w kodzie i testach, nigdy w dokumencie, który mówi, że zrobione.

Jak zmiana trafia na telefon

Diagram: gałąź preview zasila bazę preview, hosting preview i aplikację Preview; gałąź główna zasila bazę produkcyjną, żywą stronę i aplikacje ze sklepów.
Cała topologia wydania. Dwie gałęzie, po dwa egzemplarze wszystkiego i jeden push, który rusza trzy systemy naraz.

Czego ten case nie twierdzi

To jest opis układu, nie czyjegoś produktu. Liczby są strukturalne — co zawiera repozytorium i co robi push — plus objętość policzona w produkcyjnej bazie kodu chodzącej dokładnie w tym kształcie. Żadna z nich nie jest wynikiem biznesowym: to, co produkt zbudowany w ten sposób zrobi dla swoich użytkowników, należy do jego właściciela, nie do nas, więc nie znajdziesz tu wymyślonego procentu.

Postawimy to samo u Was

Od zera albo z aplikacją webową i mobilną, które już zdążyły się rozjechać — w ten kształt je układamy. Trzydzieści minut wystarczy, żeby powiedzieć, czy Wasz produkt się w niego wpisuje.