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
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.
