Startify
Wszystkie artykuły
  • AI
  • Vibe coding
  • Proces

Vibe coding to tylko wierzchołek. Co naprawdę dzieje się między promptem a działającą aplikacją

Interfejs powstaje w kilka minut, ale między promptem a działającą aplikacją są jeszcze repozytorium, sekrety, wdrożenie, domena, monitoring i utrzymanie.

Autor: Mateusz Madura

Niezależny Product Designer · LinkedIn (otwiera się w nowej karcie)

24 min czytania

Otwierasz Claude Code, Codex albo jedno z narzędzi do generowania aplikacji. Opisujesz pomysł. Po kilku minutach widzisz stronę główną, panel użytkownika, formularz logowania i kilka ekranów połączonych nawigacją.

Kolory się zgadzają. Przyciski działają. Można nagrać demo.

To jest moment, który najczęściej oglądamy w internecie — i który najłatwiej pomylić z ukończonym produktem.

W praktyce powstał klikalny interfejs uruchomiony na komputerze autora. To duży krok, ale nadal tylko widoczny fragment znacznie większego systemu. Pod powierzchnią znajdują się repozytoriumProjekt wraz z historią zmian zarządzaną przez system kontroli wersji, najczęściej Git., zależności, środowiska, baza danych, autoryzacjaSprawdzenie, co rozpoznany użytkownik może zrobić i do jakich danych ma dostęp., sekretyPoufna wartość używana przez aplikację, np. hasło, token albo prywatny klucz. Nie powinna trafić do kodu, historii Git ani przeglądarki., zewnętrzne usługi, wdrożenieUmieszczenie określonej wersji aplikacji w środowisku, w którym może zostać uruchomiona., domena, monitoringAutomatyczne sprawdzanie dostępności, szybkości, błędów, kolejek, limitów albo innych sygnałów działania systemu., kopie zapasowe i proces aktualizacji.

Ten artykuł nie będzie więc kolejną historią o aplikacji stworzonej jednym promptem. Interesuje mnie to, co wydarzyło się po tym prompcie.

Jako przykład wykorzystam niewielką aplikację, którą rozwijam po godzinach jako side-project. Nazwa nie jest istotna. Ważne jest to, że projekt nie ma wielkiego zespołu ani osobnego działu DevOps. Są pomysł, kod, usługi zewnętrzne, AI pomagające w implementacji oraz jedna osoba, która ostatecznie odpowiada za całość.

To bardzo dobry model do pokazania całej góry lodowej.

Przekrój góry lodowej. Nad wodą małe okno aplikacji, pod wodą repozytorium, terminal, baza danych, sekrety, serwery, pipeline wdrożeniowy, monitoring i skrzynka narzędzi do utrzymania.
Nad powierzchnią widać działający ekran. Pod nią są repozytorium, backend i dane, sekrety, wdrożenie i utrzymanie — to właśnie te warstwy zajmują kolejne części tekstu.

Wierzchołek: coś, co wygląda jak produkt

Pierwsza wersja mojego side-projectu pojawiła się szybko. AI pomogło utworzyć strukturę projektu, zbudować komponenty i połączyć ekrany. Po uruchomieniu lokalnego serwera mogłem wejść w przeglądarce na adres podobny do:

Kod
http://localhost:3000

To nie był statyczny projekt w Figmie. Interfejs naprawdę reagował, formularze przyjmowały dane, a kolejne widoki można było otwierać. Różnica pomiędzy takim prototypem a gotowym produktem nie zawsze jest widoczna na ekranie.

To, co widać w demoPytanie ukryte pod powierzchnią
Formularz rejestracjiGdzie powstaje konto, kto wysyła wiadomość weryfikacyjną i jak odzyskać dostęp?
Przycisk „Zapisz”Gdzie trafiają dane, jak są walidowane i co się stanie po dwukrotnym kliknięciu?
Panel użytkownikaSkąd aplikacja wie, które dane należą do zalogowanej osoby?
Przesyłanie plikuGdzie plik jest przechowywany, jaki ma limit i kto może go pobrać?
Wynik operacjiCo się stanie, jeśli zewnętrzne API nie odpowie albo zwróci błąd?
Ładna domenaJak ruch trafia do aplikacji, gdzie kończy się HTTPS i jak wrócić do poprzedniej wersji?

Wygenerowany interfejs odpowiada przede wszystkim na pytanie: jak produkt może wyglądać i jaką ścieżkę ma przejść użytkownik?

Gotowa aplikacja musi jeszcze odpowiedzieć na drugie pytanie: co dokładnie wydarzy się w systemie na każdym etapie tej ścieżki?

Granica, której nie widać: localhost

localhost oznacza w uproszczeniu „ten komputer”. Aplikacja uruchomiona pod lokalnym adresem może korzystać z plików i konfiguracji dostępnych tylko na maszynie autora. Może działać dlatego, że wcześniej ręcznie zainstalował on odpowiednią wersję środowiska, zalogował się do narzędzia, utworzył lokalny plik z kluczami i uruchomił kilka procesów w odpowiedniej kolejności.

Osoba oglądająca demo nie widzi żadnej z tych zależności.

Typowy powrót do projektu zaczyna się nie od promptu, ale od terminala:

Bash
git pull
pnpm install
cp .env.example .env.local
pnpm db:migrate
pnpm dev

Nazwy poleceń mogą być inne — projekt może korzystać z npm, yarn albo bun, a migracjeWersjonowana zmiana struktury bazy danych, wykonywana tak, aby istniejące informacje pozostały użyteczne. mogą działać przez osobne narzędzie. Sens pozostaje ten sam:

  1. pobierz właściwą wersję kodu,
  2. zainstaluj dokładnie te zależności, których oczekuje projekt,
  3. dostarcz lokalną konfigurację,
  4. przygotuj strukturę danych,
  5. uruchom proces aplikacji.

Jeżeli któregoś elementu brakuje, interfejs może nadal się otworzyć, ale konkretna funkcja przestanie działać. Brak klucza do usługi e-mail nie popsuje strony głównej. Ujawni się dopiero po próbie rejestracji. Błędny adres bazy danych może nie przeszkadzać na ekranach wypełnionych przykładową treścią. Problem pojawi się przy pierwszym prawdziwym zapisie.

Co naprawdę trzeba mieć na komputerze

Nawet mała aplikacja internetowa wymaga lokalnego łańcucha narzędzi:

WarstwaDo czego służyCo może pójść źle
Runtime, np. Node.jsUruchamia kod aplikacji i narzędzia budująceInna wersja lokalnie i na serwerze może dawać różne wyniki
Menedżer pakietówInstaluje biblioteki zapisane w lockfileInstalacja bez lockfile może pobrać inne wersje zależności
GitPrzechowuje historię zmian i umożliwia powrótPraca bez punktu bazowego utrudnia ustalenie, co zepsuło aplikację
CLI usługLogowanie, migracje, podgląd logów i wdrożeniaŁatwo wykonać operację na złym środowisku
Pliki środowiskoweDostarczają lokalne adresy, identyfikatory i sekretyPrzypadkowy commit może ujawnić działające klucze
Narzędzia testoweSprawdzają typy, logikę i zachowanie w przeglądarceDemo może działać, mimo że build produkcyjny się nie powiedzie

To pierwszy fragment pod powierzchnią: aplikacja jest nie tylko zbiorem ekranów, lecz także powtarzalnym sposobem uruchomienia tych ekranów.

Repozytorium: pamięć, której nie zapewnia rozmowa z AI

AI może w jednej sesji utworzyć kilkanaście plików i przebudować znaczną część projektu. Bez historii Git trudno jednak odpowiedzieć na proste pytania:

  • co dokładnie zostało zmienione,
  • która zmiana wprowadziła błąd,
  • czy można bezpiecznie wrócić do poprzedniego stanu,
  • czy agent zmienił również pliki spoza uzgodnionego zakresu,
  • jaka wersja kodu działa obecnie na produkcji.

Dlatego jednym z pierwszych kroków po wygenerowaniu prototypu powinno być utworzenie repozytorium i punktu bazowego.

Bash
git status
git add .
git commit -m "Establish working prototype baseline"

Nie chodzi wyłącznie o „wrzucenie kodu na GitHuba”. Repozytorium staje się źródłem prawdy dla kodu, dokumentacji, konfiguracji bez wartości poufnych i procesu wydawania kolejnych wersji.

Dobry minimalny zestaw obejmuje:

Kod
README.md            sposób uruchomienia projektu
.env.example         nazwy wymaganych zmiennych bez ich wartości
.gitignore           pliki lokalne, sekrety, cache i artefakty
package.json         skrypty i zależności
lockfile             dokładne wersje zainstalowanych paczek
docs/                decyzje, architektura i procedury wdrożenia

Lockfile wygląda nudno, dopóki go nie zabraknie

Deklaracja typu framework: ^16.0.0 nie oznacza jednej konkretnej wersji. Pozwala menedżerowi pakietów wybrać wydanie mieszczące się w zadanym zakresie. LockfilePlik zapisujący dokładne wersje wszystkich zainstalowanych zależności, aby różne środowiska korzystały z tego samego zestawu. zapisuje rzeczywisty zestaw wersji całego drzewa zależności.

Dzięki temu komputer autora, automatyczne testy i serwer produkcyjny mogą zainstalować tę samą kombinację paczek. Bez tego zdanie „u mnie działa” może być prawdziwe dokładnie dlatego, że „u mnie” działa inna wersja biblioteki.

Bez lockfile

  • Laptopzestaw A
  • CIzestaw B
  • Serwerzestaw C

Z lockfile

  • Laptopten sam zestaw
  • CIten sam zestaw
  • Serwerten sam zestaw
Bez lockfile każde środowisko może otrzymać nieco inne wersje paczek i skończyć z innym wynikiem. Z lockfile wszystkie trzy instalują jeden zestaw zależności.

Backend: ekran nie przechowuje danych

W prototypie lista elementów może być zwykłą tablicą umieszczoną w kodzie:

TypeScript
const projects = [
  { id: 1, name: "Pierwszy projekt" },
  { id: 2, name: "Drugi projekt" }
]

Taki ekran wygląda poprawnie, dopóki użytkownik nie oczekuje, że utworzone przez niego dane pozostaną dostępne po odświeżeniu strony, zalogowaniu na innym urządzeniu albo publikacji nowej wersji aplikacji.

Wtedy potrzebny jest backendCzęść systemu wykonująca logikę poza przeglądarką: komunikuje się z bazą, pilnuje uprawnień i łączy aplikację z usługami. i trwały magazyn danych. Może to być własny serwer połączony z PostgreSQL, usługa typu backend-as-a-service albo zestaw funkcji uruchamianych na żądanie. Niezależnie od dostawcy trzeba zaprojektować co najmniej:

  • model danych i relacje pomiędzy rekordami,
  • walidację danych wejściowych,
  • sposób identyfikowania użytkownika,
  • reguły odczytu, tworzenia, edycji i usuwania,
  • migracje zmieniające strukturę bez utraty istniejących danych,
  • kopie zapasowe oraz procedurę ich odtworzenia.
Okno przeglądarki z prostym ekranem aplikacji stoi obok otwartej metalowej szafy, w której widać bazę danych, kłódkę, przewody, rury i koła zębate.
Interfejs jest tylko frontem maszyny. Za ekranem działają dane, reguły dostępu i procesy, których użytkownik nie widzi.

Jeden przycisk może uruchomić pięć systemów

Weźmy zwykłe założenie konta. W interfejsie to dwa pola i jeden przycisk. Pod powierzchnią przepływ może wyglądać tak:

KrokSystemZadaniePrzykładowy problem
1PrzeglądarkaZbiera dane i wykonuje podstawową walidacjęUżytkownik wysyła formularz dwukrotnie
2Backend aplikacjiPonownie waliduje dane i inicjuje rejestracj꯹danie jest niekompletne albo zmodyfikowane ręcznie
3System tożsamościTworzy konto i bezpiecznie obsługuje hasło lub logowanie zewnętrzneAdres już istnieje albo dostawca nie odpowiada
4Baza danychTworzy profil i przypisuje mu właściwe uprawnieniaKonto powstało, ale zapis profilu się nie udał
5Usługa e-mailWysyła potwierdzenie lub link logowaniaWiadomość trafia do spamu albo przekroczony zostaje limit API

Jeżeli czwarty krok zawiedzie po powodzeniu trzeciego, system zostaje z kontem bez profilu. To właśnie takie stany — niewidoczne na przygotowanym wcześniej demo — zajmują dużą część pracy nad produktem.

  1. Przeglądarka zbiera dane i waliduje
  2. Backend aplikacji waliduje ponownie
  3. System tożsamości tworzy konto
  4. Baza danych tworzy profil
  5. Usługa e-mail wysyła potwierdzenie
Droga jednego kliknięcia „Utwórz konto”: jeśli czwarty krok zawiedzie po powodzeniu trzeciego, system zostaje z kontem bez profilu.

Autoryzacja jest ważniejsza niż ukrycie przycisku

Interfejs może nie pokazywać przycisku „Usuń” osobie bez odpowiednich uprawnień. To poprawia użyteczność, ale nie stanowi zabezpieczenia. Użytkownik może ręcznie wysłać żądanie do serwera z pominięciem interfejsu.

Każda operacja wykonywana po stronie serwera powinna więc osobno sprawdzić:

  1. czy użytkownik jest zalogowany,
  2. do jakiego zasobu próbuje uzyskać dostęp,
  3. czy jest właścicielem tego zasobu albo ma odpowiednią rolę,
  4. czy operacja jest dozwolona w aktualnym stanie danych,
  5. czy nie przekroczył limitu zapytań.

Dokumentacja produkcyjna Next.js zwraca uwagę, że sprawdzenie dostępu na poziomie layoutu lub warstwy pośredniej nie wystarcza: autoryzację należy weryfikować również w każdej akcji serwerowej i przy dostępie do danych.

Sekrety: plik, którego nie wolno „po prostu wysłać”

W miarę dodawania funkcji projekt zaczyna korzystać z kolejnych usług. Baza danych, logowanie, poczta, przechowywanie plików, płatności, monitoring czy zewnętrzne APIUstalony sposób komunikacji pomiędzy programami. Aplikacja może przez API wysłać wiadomość, pobrać dane albo zlecić operację zewnętrznej usłudze. wymagają adresów, identyfikatorów i kluczy dostępowych.

Lokalnie często trafiają one do pliku .env.local:

dotenv
# Wartości publiczne — mogą trafić do kodu przeglądarki
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_ANALYTICS_ID=example-public-id

# Wartości wyłącznie serwerowe — poniżej są tylko atrapy
DATABASE_URL=postgresql://user:password@example.invalid/app
AUTH_SECRET=replace-with-a-long-random-value
EMAIL_API_KEY=example_email_key
STORAGE_SECRET_KEY=example_storage_key
ERROR_REPORTING_DSN=example_server_dsn

Sam podział nazw ma znaczenie. W Next.js zmienne z prefiksem NEXT_PUBLIC_ są wstawiane do paczki JavaScript wysyłanej do przeglądarki. To oznacza, że użytkownik może je odczytać. Prefiks nie jest sposobem zabezpieczania wartości — jest świadomą deklaracją, że wartość może być publiczna.

Sekretny klucz nigdy nie powinien otrzymać takiego prefiksu ani zostać użyty w komponencie wykonywanym po stronie klienta.

Duży klucz opiera się o sejf, z którego trzy przewody prowadzą do trzech oddzielnych szklanych kapsuł: z rośliną, z kołami zębatymi i z serwerami.
Jeden projekt może korzystać z wielu zestawów konfiguracji, ale każdy sekret powinien trafiać wyłącznie do właściwego środowiska.

.env.example jest mapą, a nie schowkiem

Do repozytorium warto dodać plik pokazujący, jakiej konfiguracji potrzebuje aplikacja:

dotenv
NEXT_PUBLIC_APP_URL=
NEXT_PUBLIC_ANALYTICS_ID=
DATABASE_URL=
AUTH_SECRET=
EMAIL_API_KEY=
STORAGE_SECRET_KEY=
ERROR_REPORTING_DSN=

Plik zawiera nazwy, ale nie prawdziwe wartości. Dzięki temu nowa osoba — albo agent uruchomiony w świeżym środowisku — wie, czego brakuje, a klucze nie trafiają do historii Git.

To ważne, bo usunięcie sekretu z aktualnej wersji pliku nie usuwa go automatycznie z wcześniejszych commitówZapisany punkt w historii Git opisujący konkretny zestaw zmian.. Jeżeli działający klucz został opublikowany, należy potraktować go jako ujawniony, unieważnić i wygenerować nowy.

Według raportu GitGuardian za 2026 rok w publicznych commitach na GitHubie wykryto w 2025 roku około 29 milionów nowych sekretów. W commitach wspomaganych przez AI odsetek wycieków miał być około dwukrotnie wyższy od ogólnego poziomu GitHuba. To dane dostawcy narzędzi bezpieczeństwa, ale skala dobrze pokazuje, że wklejanie kluczy do kodu lub rozmowy z agentem nie jest teoretycznym problemem.

Jeden projekt, trzy zestawy konfiguracji

Lokalny plik .env.local nie powinien być kopiowany na każdy serwer. Development, stagingNiepubliczne lub ograniczone środowisko możliwie podobne do produkcji, służące do sprawdzenia wydania przed publikacją. i produkcja pełnią inne role i powinny mieć rozdzielone dane oraz klucze.

ObszarDevelopmentStagingProdukcja
Adreslocalhosttechniczna lub chroniona domenapubliczna domena produktu
Bazalokalna albo developerskaosobna baza testowabaza z prawdziwymi danymi
E-mailskrzynka testowa lub ograniczona wysyłkatestowi odbiorcyprawdziwi użytkownicy
Płatnościtryb testowytryb testowyklucze produkcyjne
Storagetestowy bucket/kontenerosobny stagingprodukcyjny magazyn
Monitoringopcjonalny lub ograniczonypełny, oznaczony jako stagingpełny z alertami
Dostępdeveloperzespół i testerzyużytkownicy
Skutki błędumożna wyczyścić danemożna odtworzyć scenariuszmożliwa utrata danych lub zaufania

To rozdzielenie nie służy wyłącznie porządkowi. Zmniejsza ryzyko, że eksperymentalny kod wyśle wiadomość do prawdziwych użytkowników, obciąży kartę, usunie produkcyjny plik albo zmieni strukturę właściwej bazy.

OWASP zaleca ograniczanie dostępu do sekretów zgodnie z zasadą najmniejszych uprawnień, rotację kluczy oraz oddzielenie poświadczeń pomiędzy środowiskami. Narzędzie wdrożeniowe powinno otrzymywać tylko te uprawnienia, które są potrzebne do konkretnego zadania.

Jedna funkcja, kilka paneli

W interfejsie aplikacji mobilnej płatność to jeden przycisk. Za nim stoi konfiguracja rozłożona na kilka paneli, a każdy z nich ma własne konta, identyfikatory i środowiska. Poniższy przykład jest zanonimizowany i opiera się na doświadczeniu z side-projectu na iOS; nie zawiera żadnych kluczy ani identyfikatorów.

Wklejenie klucza trwa minutę. Czas zabiera ustalenie, z którego panelu pochodzi, do jakiego środowiska należy, jakie ma uprawnienia i czy identyfikatory oraz callbacki zgadzają się po obu stronach.

  1. Umowa, konto i produkt

    Zanim cokolwiek da się kupić, potrzebne są dwa odrębne elementy konfiguracji: członkostwo w Apple Developer Program oraz właściwe, zaakceptowane w App Store Connect umowy, w tym Paid Applications Agreement dla płatnych aplikacji i zakupów w aplikacji. Dopiero potem w App Store Connect można utworzyć zakup w aplikacji albo subskrypcję. To samo trzeba odwzorować w systemie płatności.

  2. Identyfikatory i mapowanie

    Bundle ID aplikacji oraz product ID produktu muszą być takie same w App Store Connect, w kodzie aplikacji i u dostawcy płatności. Po stronie dostawcy powstaje mapowanie: sklep, aplikacja, produkt i uprawnienie, które ten produkt odblokowuje.

  3. Klucze i identyfikatory

    Apple Developer i App Store Connect wystawiają własne klucze, a dostawca płatności ma osobne klucze i identyfikatory projektu. Każdą wartość trzeba przenieść we właściwe miejsce: do aplikacji, backendu albo panelu dostawcy.

  4. Publiczne i prywatne

    Publiczny identyfikator może trafić do aplikacji, a klucz prywatny wyłącznie na serwer lub do panelu dostawcy. Obie grupy wartości przypisujemy osobno do development, staging i production.

  5. Callbacki i powiadomienia serwerowe

    WebhookiŻądanie wysyłane automatycznie przez zewnętrzną usługę, kiedy wydarzy się określone zdarzenie, np. opłacenie zamówienia. dostawcy oraz App Store Server Notifications wymagają adresów, sekretów weryfikujących i jasnego przypisania do środowiska. Powiadomienie z sandboxa nie może zmieniać danych produkcyjnych.

  6. Sandbox i TestFlight

    Zakup, odnowienie, anulowanie, przywrócenie zakupów (restore), błąd płatności i powiadomienie serwerowe trzeba sprawdzić na kontach testowych oraz w kompilacji TestFlight, zanim dotkną prawdziwych użytkowników.

  7. Produkcja

    Przejście na produkcję oznacza produkcyjne produkty, klucze i endpointy, sprawdzenie, że żadna wartość testowa nie została w konfiguracji, oraz monitoring pierwszych prawdziwych zakupów i powiadomień.

Najczęstsza awaria w takim łańcuchu rzadko jest jedną złą wartością. Zwykle to rozjazd między dwiema stronami: identyfikator produktu wpisany inaczej w sklepie i u dostawcy, klucz z innego środowiska albo adres callbacku, który wskazuje nie ten serwer, co trzeba.

Zewnętrzne usługi: aplikacja staje się siecią zależności

Mały side-project bardzo szybko przestaje być jednym programem. Często składa się z kodu aplikacji oraz kilku usług:

Kod
repozytorium kodu
        ↓
hosting aplikacji ───── baza danych
        │               system logowania
        │               storage plików
        │               wysyłka e-mail
        │               zewnętrzne API
        └────────────── monitoring błędów

Mapa narzędzi side-projectu

Zanim integracje zaczną się mnożyć, warto spisać narzędzia projektu jako mapę odpowiedzialności, a nie listę rekomendacji. Zestawienie jest zanonimizowane i opiera się na doświadczeniu z side-projectu.

ObszarNarzędzieRolaCo trzeba skonfigurować
Projektowanie interfejsuNarzędzie projektowe, np. FigmaŹródło kierunku wizualnego, układów i zasobówDostęp do plików, biblioteka komponentów, eksport zasobów
Implementacja wspierana przez AIClaude Code, CodexGenerują i zmieniają kod, piszą testy, analizują błędyZakres zadania, dostęp do repozytorium, zasady dla sekretów i poleceń wymagających zgody
Kod i historia zmianGit, GitHubHistoria, gałęzie, przegląd zmian i automatyzacjaZdalne repozytorium, ochrona gałęzi, środowiska i sekrety w CI, .gitignore
Praca lokalnaTerminal, runtime, menedżer pakietów, CLI usługUruchamiają aplikację i narzędzia na komputerze autoraWersje narzędzi, lockfile, zalogowane CLI, lokalny plik zmiennych
Tożsamość i dystrybucja iOSApple Developer, App Store ConnectKonto, identyfikatory, certyfikaty, kompilacje i zakupy w aplikacjiUmowy, bundle ID, produkty i subskrypcje, klucze, TestFlight, powiadomienia serwerowe
PłatnościDostawca płatności lub warstwy uprawnieńŁączy produkty ze sklepu z uprawnieniami użytkownikaMapowanie sklep–aplikacja–produkt–uprawnienie, klucze, webhooki, osobne środowiska
Backend i daneBaza danych, uwierzytelnianie, storageTrwałe dane, tożsamość użytkownika i plikiSchemat i migracje, reguły dostępu, osobne środowiska, kopie zapasowe
Build i wydaniaUsługa buildów i dystrybucjiBuduje wersje, podpisuje je i wysyła do testerów oraz sklepuPoświadczenia podpisywania, zmienne budowania, kanały dystrybucji, powiązanie z repozytorium
Monitoring i analitykaUsługa raportowania błędów i analitykiPokazuje awarie, zachowania użytkowników i wersje wydańKlucze projektu, identyfikator wydania, filtrowanie danych wrażliwych, alerty

Część nazw jest celowo uogólniona. Ważniejsza od rekomendacji konkretnego dostawcy jest odpowiedzialność narzędzia i zakres jego konfiguracji.

Każda integracja dodaje co najmniej:

  • konto i konfigurację po stronie dostawcy,
  • osobne klucze dla środowisk,
  • pakiet albo klienta API,
  • limity zapytań i koszty,
  • obsługę błędów oraz ponowień,
  • procedurę na wypadek niedostępności usługi,
  • dokumentację pokazującą, gdzie dana zależność jest używana.

To również zmienia sposób projektowania interfejsu. Jeśli zewnętrzna operacja może trwać kilkanaście sekund, aplikacja potrzebuje stanu oczekiwania. Jeżeli może zakończyć się w tle, potrzebuje mechanizmu sprawdzania statusu. Jeżeli kosztuje za każde wywołanie, potrzebuje limitów i ochrony przed przypadkowym powtórzeniem.

„Spróbuj ponownie” nie zawsze jest bezpieczne

Ponowienie odczytu zazwyczaj nie jest problemem. Ponowienie płatności, wysyłki wiadomości albo utworzenia zasobu może wykonać operację drugi raz.

Dlatego backend często potrzebuje identyfikatora operacji albo mechanizmu idempotencjiWłaściwość operacji, dzięki której jej bezpieczne powtórzenie nie tworzy drugiej płatności, wiadomości ani rekordu.: to samo żądanie wysłane ponownie powinno zwrócić wcześniejszy rezultat zamiast tworzyć drugi rekord czy drugą płatność.

To szczegół całkowicie niewidoczny w klikalnym prototypie. Staje się istotny dopiero wtedy, gdy użytkownik ma wolne połączenie, dwukrotnie kliknie przycisk albo przeglądarka ponowi żądanie.

Build: moment, w którym lokalny projekt staje się artefaktem

Środowisko developerskie jest wyrozumiałe. Produkcyjny buildProces zamieniający kod źródłowy w wersję przygotowaną do uruchomienia na produkcji. jest znacznie lepszą kontrolą tego, czy aplikację rzeczywiście da się opublikować.

Przed wdrożeniem typowy zestaw kontroli może wyglądać tak:

Bash
pnpm lint
pnpm typecheck
pnpm test
pnpm build

Każde polecenie odpowiada na inne pytanie:

KontrolaPytanie
LintCzy kod łamie ustalone reguły albo zawiera podejrzane konstrukcje?
TypecheckCzy dane przekazywane pomiędzy częściami aplikacji mają oczekiwany kształt?
TestyCzy opisana logika i kluczowe scenariusze nadal działają?
BuildCzy framework potrafi przygotować produkcyjną wersję całej aplikacji?

Klikalny ekran może działać mimo błędu na trasie, której akurat nie otworzyliśmy. Build analizuje szerszą część projektu i często znajduje problemy niewidoczne podczas krótkiego demo: brakujący import, nieprawidłowy typ, kod serwerowy uruchamiany w przeglądarce albo zmienną dostępną lokalnie, lecz nieobecną w środowisku budowania.

Wdrożenie: kod nie teleportuje się na serwer

Wygodna platforma hostingowa potrafi ukryć wiele szczegółów pod jednym przyciskiem „Deploy”. To dobra abstrakcja, ale nie oznacza, że proces zniknął.

W uproszczeniu wdrożenie wykonuje kilka osobnych operacji:

  1. pobiera wskazany commit z repozytorium,
  2. uruchamia czyste środowisko budowania,
  3. instaluje zależności z lockfile,
  4. dostarcza zmienne potrzebne podczas builda,
  5. wykonuje testy i produkcyjny build,
  6. tworzy artefaktGotowy wynik procesu budowania, który można uruchomić lub wdrożyć: np. paczka plików, obraz kontenera albo skompilowana aplikacja. albo obraz aplikacji,
  7. uruchamia go z konfiguracją produkcyjną,
  8. kieruje do nowej wersji ruch użytkowników,
  9. zachowuje logiTechniczny zapis zdarzeń pozwalający ustalić, co działo się w systemie przed błędem i podczas jego wystąpienia. oraz historię wydań.

Własny serwer wymaga jawnego zorganizowania większej części tej listy. Platforma zarządzana realizuje ją automatycznie, ale nadal trzeba poprawnie skonfigurować projekt, środowiska, domenę i sekrety.

Minimalny pipeline

Kod
commit
  ↓
automatyczne kontrole
  ↓
build
  ↓
staging
  ↓
test dymny
  ↓
zgoda na publikację
  ↓
produkcja
  ↓
monitoring + możliwość rollbacku

GitHub pozwala przypisać wdrożenia do środowisk takich jak staging i production, ograniczyć dostęp do sekretów, wskazać dozwolone gałęzie oraz wymagać zatwierdzenia przed uruchomieniem zadania produkcyjnego. Nawet w jednoosobowym projekcie rozdzielenie tych etapów utrudnia przypadkowe opublikowanie nieprzetestowanej wersji.

Staging odpowiada na inne pytanie niż localhost

Lokalnie pytamy: czy funkcja działa podczas developmentu?

Na stagingu pytamy:

  • czy aplikacja buduje się w czystym środowisku,
  • czy ma komplet wymaganych zmiennych,
  • czy współpracuje z usługami dostępnymi przez internet,
  • czy migracja działa na bazie przypominającej produkcyjną,
  • czy routing, cookies, callbacki logowania i wiadomości e-mail korzystają z właściwej domeny,
  • czy da się przejść kluczową ścieżkę bez narzędzi developerskich.

Staging powinien być odizolowany od wyszukiwarek i przypadkowych użytkowników. Nie powinien natomiast być atrapą, która omija wszystkie elementy wymagające prawdziwej konfiguracji.

Migracje: zmiana kodu to czasem zmiana danych

Dodanie pola do formularza może wymagać dodania kolumny w bazie. Zmiana modelu kont może wymagać przeliczenia istniejących rekordów. Nowa relacja pomiędzy obiektami może wymagać indeksu, bez którego zapytania staną się zbyt wolne.

Takie zmiany powinny być zapisane jako migracje: wersjonowane instrukcje przeprowadzające bazę ze starego schematu do nowego.

Kod
001_create_users
002_create_projects
003_add_project_status
004_add_owner_index

Najważniejsza różnica względem prototypu polega na tym, że produkcyjnej bazy nie można po prostu wyczyścić po każdej zmianie pomysłu.

Bezpieczne wydanie wymaga odpowiedzi na pytania:

  • czy nowy kod potrafi przez chwilę działać ze starym schematem,
  • czy migracja blokuje tabelę i na jak długo,
  • co stanie się z istniejącymi rekordami,
  • czy można wycofać kod po wykonaniu migracji,
  • czy przed operacją istnieje sprawdzona kopia zapasowa.

Domena i HTTPS: publiczny adres jest częścią infrastruktury

Po udanym wdrożeniu platforma zazwyczaj udostępnia techniczny adres. Własna domena wymaga połączenia kilku systemów:

Kod
przeglądarka
   ↓ zapytanie DNS
operator DNS
   ↓ wskazanie hosta
platforma lub serwer
   ↓ certyfikat TLS
aplikacja

Trzeba ustalić wersję kanoniczną domeny, skonfigurować rekordy DNSSystem tłumaczący nazwę domeny, np. example.com, na miejsce, do którego ma trafić ruch., potwierdzić własność, uzyskać certyfikat i dopilnować przekierowań pomiędzy wariantami adresu. Zmiana nie zawsze jest natychmiastowa, ponieważ odpowiedzi DNS mogą pozostawać w pamięci zgodnie z wartością TTL.

W aplikacjach z logowaniem i integracjami domena występuje również w konfiguracji usług zewnętrznych:

  • adresach callback po logowaniu,
  • dozwolonych originach CORSReguły określające, z jakich domen przeglądarka może wysyłać żądania do danego serwera.,
  • linkach umieszczanych w wiadomościach,
  • webhookach,
  • polityce cookies,
  • ustawieniach analityki i monitoringu.

Dlatego przejście z localhost na publiczną domenę nie jest wyłącznie zmianą jednego adresu.

Obserwowalność: skąd wiadomo, że aplikacja działa

Na lokalnym komputerze błąd pojawia się w terminalu. Na produkcji może wystąpić wyłącznie dla jednej osoby, w jednej przeglądarce i przy konkretnej kombinacji danych.

Jeżeli aplikacja nie zbiera żadnych sygnałów, właściciel dowie się o problemie tylko wtedy, gdy użytkownik zdecyduje się go zgłosić.

Podstawowy zestaw obserwowalności obejmuje:

SygnałOdpowiada na pytanie
Logi aplikacjiCo system robił tuż przed błędem?
Raportowanie wyjątkówJaki błąd wystąpił, w której wersji i ilu osób dotyczy?
Monitoring dostępnościCzy publiczny adres w ogóle odpowiada?
Metryki czasu odpowiedziCzy aplikacja działa, ale stała się zbyt wolna?
Metryki zadań w tleCzy kolejka jest przetwarzana, czy tylko rośnie?
Alarmy kosztowe i limityCzy błąd lub nadużycie nie generuje niekontrolowanych kosztów?

Logowanie również wymaga projektu. Zbyt mało informacji uniemożliwia diagnozę. Zbyt dużo może ujawnić dane użytkowników albo sekrety. Dobre logi zawierają identyfikator żądania, typ operacji, czas, rezultat i bezpieczny kontekst — nie pełne hasła, tokeny czy zawartość prywatnych formularzy.

Wersja aplikacji powinna być możliwa do ustalenia

Każdy błąd produkcyjny dobrze jest powiązać z konkretnym commitem lub identyfikatorem wydania. Bez tego agent może poprawiać kod, który nie odpowiada wersji rzeczywiście uruchomionej na serwerze.

Minimalna informacja diagnostyczna może zawierać:

Kod
environment: production
release: 4f7a2c1
route: /api/example
request_id: req_01...
duration_ms: 842
result: external_service_timeout

To nie jest efektowna funkcja. Jest jednak różnicą pomiędzy „coś czasem nie działa” a błędem, który można odtworzyć i naprawić.

Testy: prompt nie wie, co zepsuł poza aktualnym ekranem

Agent otrzymujący polecenie „popraw formularz” może zmienić współdzielony komponent, regułę walidacji albo typ danych używany również w innym miejscu. Jeśli ocena ogranicza się do ponownego otwarcia tego formularza, regresja pozostanie niewidoczna.

Dlatego warto rozdzielić kilka poziomów kontroli:

PoziomPrzykładCo chroni
Statycznylint i TypeScriptskładnię, typy i część błędów konstrukcyjnych
Jednostkowytest funkcji naliczającej limitmałe reguły biznesowe
Integracyjnyzapis do testowej bazy i obsługa błędu APIwspółpracę kilku modułów
End-to-endrejestracja i pierwsze logowanie w przeglądarcepełną ścieżkę użytkownika
Wizualnyporównanie zrzutów kluczowych ekranówniezamierzone zmiany layoutu
Produkcyjny smoke testotwarcie publicznej strony i bezpieczna operacja testowapodstawowe działanie po wdrożeniu

Nie każda aplikacja potrzebuje od pierwszego dnia setek testów. Każda powinna jednak mieć automatyczną kontrolę najdroższych awarii: utraty dostępu, zapisu danych, kluczowej operacji produktu i możliwości zbudowania wersji produkcyjnej.

Koszty: darmowy prototyp może mieć płatną architekturę

Większość usług pozwala rozpocząć pracę bez opłat albo z niewielkim limitem. To ułatwia prototypowanie, ale nie usuwa modelu kosztowego.

Rachunek może zależeć od:

  • liczby aktywnych użytkowników,
  • czasu pracy serwera albo funkcji,
  • wielkości bazy i liczby zapytań,
  • przechowywania i transferu plików,
  • liczby wysłanych wiadomości,
  • liczby wywołań zewnętrznego API,
  • liczby zdarzeń i czasu przechowywania logów,
  • ruchu generowanego nie przez użytkowników, lecz przez boty lub błąd.

Warto przed publikacją przygotować prostą mapę kosztów:

UsługaJednostka rozliczeniaCo ogranicza nadużycie
Hostingczas/wywołania/transferlimity platformy
Bazarozmiar/zapytania/computepooling, indeksy, limity
StorageGB + transfertypy i rozmiar plików
E-mailliczba wiadomościrate limit i weryfikacja
Zewnętrzne APIzapytania lub jednostki użyciaquota per użytkownik
Monitoringzdarzenia i retencjasampling i filtrowanie

Samo przygotowanie takiej mapy wymusza odpowiedź na pytanie, co stanie się po nagłym wzroście ruchu albo zapętleniu jednego żądania.

Bezpieczeństwo nie jest jedną funkcją do dodania na końcu

W małym projekcie bezpieczeństwo łatwo sprowadzić do zdania „korzystam z bezpiecznego dostawcy logowania”. To ważny element, ale nie obejmuje całego systemu.

Trzeba również kontrolować:

  • dostęp jednego użytkownika do danych drugiego,
  • walidację danych po stronie serwera,
  • limity operacji kosztownych lub podatnych na spam,
  • typ i rozmiar przesyłanych plików,
  • zakres uprawnień kluczy API,
  • aktualizacje zależności,
  • zabezpieczenie webhooków,
  • wygasanie sesji i tokenów,
  • treść logów i komunikatów błędów,
  • możliwość usunięcia lub eksportu danych.

Najbardziej praktyczna zasada brzmi: przeglądarka użytkownika nie jest zaufanym środowiskiem. To, że interfejs nie pokazuje jakiejś możliwości, nie oznacza, że nie da się wysłać odpowiadającego jej żądania ręcznie.

Drugą zasadą jest minimalny zakres. Klucz używany wyłącznie do wysyłania wiadomości nie powinien mieć uprawnień administracyjnych do całego konta. Środowisko stagingowe nie powinno korzystać z klucza produkcyjnego tylko dlatego, że tak było szybciej.

Utrzymanie: aplikacja zaczyna się zużywać od dnia premiery

Po wdrożeniu kod nie pozostaje w próżni. Biblioteki publikują aktualizacje. Dostawcy zmieniają API. Certyfikaty wygasają albo odnawiają się nieprawidłowo. Limity bezpłatnych planów się zmieniają. Dane rosną, zapytania zwalniają, a użytkownicy znajdują ścieżki, których autor nie przewidział.

Minimalny rytm utrzymania side-projectu może wyglądać tak:

CzęstotliwośćKontrola
Po każdym wdrożeniusmoke test, logi, błędy i wersja produkcyjna
Co tydzieńbłędy użytkowników, kolejki, wykorzystanie limitów i nietypowe koszty
Co miesiącaktualizacje zależności, dostępność kopii, konta i uprawnienia
Co kwartałpróbne odtworzenie danych, rotacja wybranych sekretów, przegląd usług i kosztów
Przed większą zmianąpunkt bazowy, plan migracji, staging i droga powrotu

Nie wszystkie kontrole muszą być ręczne. Monitoring, automatyczne aktualizacje, testy i pipeline mogą wykonać dużą część powtarzalnej pracy. Ktoś nadal musi jednak zdecydować, które alarmy są ważne, czy aktualizacja jest bezpieczna i kiedy zaakceptować ryzyko.

Otwarta szafa serwerowa z wskaźnikiem monitoringu i ikoną alarmu, z przewodami i nośnikami kopii zapasowych w środku; obok stoją skrzynka narzędziowa, klucz płaski oparty o szafę, zwinięty przewód i dwa dyski.
Po premierze aplikacja nadal wymaga monitoringu, aktualizacji, kopii zapasowych i regularnych napraw.

Cała droga: od promptu do produktu

Po złożeniu wszystkich warstw proces wygląda inaczej niż popularna opowieść o aplikacji stworzonej w jeden wieczór.

EtapRezultatCzy użytkownik może już bezpiecznie korzystać?
1. Prompt i wygenerowany interfejsKierunek wizualny i klikalne ekranyNie
2. Lokalne uruchomienieFunkcje działają na komputerze autoraNie
3. Repozytorium i lockfilePowtarzalna historia i zależnościJeszcze nie
4. Backend, dane i autoryzacjaFunkcje mają trwały model działaniaCzęściowo
5. Sekrety i rozdzielone środowiskaIntegracje nie zależą od jednego lokalnego plikuCzęściowo
6. Testy i produkcyjny buildZnane zachowania mają automatyczne bramkiPrawie
7. Staging i migracjeSystem jest sprawdzony w środowisku zbliżonym do produkcjiPrawie
8. Wdrożenie, domena i HTTPSAplikacja jest publicznie dostępnaTak, ale wymaga kontroli
9. Monitoring, backup i rollbackAwarie można wykrywać i obsługiwaćTak
10. UtrzymanieProdukt może być bezpiecznie rozwijanyProces trwa cały czas

Co w tym procesie nadal robi AI

Opis części pod powierzchnią nie oznacza, że AI nadaje się tylko do generowania interfejsu. Może pomóc niemal na każdym etapie:

  • przygotować strukturę bazy i pierwsze migracje,
  • zintegrować dostawcę logowania,
  • utworzyć .env.example oraz walidację konfiguracji,
  • napisać testy jednostkowe i przeglądarkowe,
  • przygotować workflow CI,
  • zbudować konfigurację hostingu lub kontenera,
  • przeanalizować logi i znaleźć źródło błędu,
  • sprawdzić zależności i zasugerować aktualizacje,
  • przygotować checklistę wdrożenia oraz rollbackuPowrót do wcześniejszej, działającej wersji po nieudanym wdrożeniu. Nie zawsze automatycznie cofa zmiany danych..

Zmienia się jednak charakter pracy. Wierzchołek góry lodowej można ocenić wzrokiem: przycisk jest za mały, kolor niewłaściwy, a układ rozpada się na telefonie.

Pod powierzchnią wynik bywa znacznie trudniejszy do oceny. Kod może wyglądać przekonująco i jednocześnie używać produkcyjnego klucza po stronie klienta. Migracja może przechodzić na pustej bazie, ale blokować tabelę z prawdziwymi danymi. Pipeline może kończyć się zielonym wynikiem, choć nie testuje najważniejszej ścieżki użytkownika.

Im głębiej schodzimy, tym ważniejsze są:

  1. precyzyjny zakres zadania,
  2. dostęp do właściwego kontekstu,
  3. historia zmian,
  4. test lub pomiar potwierdzający rezultat,
  5. człowiek podejmujący decyzję o wdrożeniu.

AI nadal może wykonać dużą część pracy. Nie może jednak samo nadać swoim odpowiedziom statusu prawdy.

Checklista: mam prototyp — co dalej?

Krótka lista kontrolna do przejścia przed publikacją aplikacji i po niej.

Kod i środowisko lokalne

  • Projekt uruchamia się z instrukcji zapisanej w repozytorium.
  • Wersja runtime i menedżera pakietów jest określona.
  • Zależności mają lockfile.
  • Istnieje commit bazowy oraz zdalna kopia repozytorium.
  • Pliki lokalne, cache i sekrety są ignorowane przez Git.

Dane i backend

  • Dane nie są wyłącznie atrapą wpisaną w komponenty.
  • Model danych ma migracje.
  • Autoryzacja jest sprawdzana po stronie serwera.
  • Operacje częściowo zakończone mają zdefiniowane zachowanie.
  • Istnieje kopia zapasowa oraz sposób jej odtworzenia.

Konfiguracja i sekrety

  • Repozytorium zawiera .env.example bez prawdziwych wartości.
  • Development, staging i produkcja używają osobnych sekretów.
  • Żaden prywatny klucz nie trafia do paczki przeglądarki.
  • Klucze mają minimalny potrzebny zakres uprawnień.
  • Ujawnione lub nieużywane klucze można szybko unieważnić.

Jakość i publikacja

  • Lint, typy, testy i build przechodzą w czystym środowisku.
  • Kluczowe ścieżki zostały sprawdzone na stagingu.
  • Migracja produkcyjna ma plan oraz drogę powrotu.
  • Domena, HTTPS, callbacki i przekierowania są poprawnie skonfigurowane.
  • Wiadomo, jaki commit działa na produkcji.

Po wdrożeniu

  • Błędy trafiają do logów lub systemu raportowania.
  • Monitoring sprawdza dostępność aplikacji.
  • Ustawione są limity albo alerty kosztowe.
  • Rollback został opisany i nie zależy od pamięci autora.
  • Istnieje rytm aktualizacji zależności i przeglądu uprawnień.

Nie „aplikacja z jednego promptu”, tylko początek z jednego promptu

Vibe coding naprawdę skraca drogę od pomysłu do pierwszej działającej wersji. To ogromna wartość. W przypadku mojego side-projectu pozwolił szybko sprawdzić interfejs, przetestować przepływ i rozpocząć implementację bez wielotygodniowego przygotowania.

Nie usunął jednak żadnego z pytań, które pojawiają się po wpisaniu localhost:3000.

Gdzie trafiają dane? Kto ma do nich dostęp? Jak aplikacja otrzymuje klucze? Co dzieje się podczas wdrożenia? Jak zmieniam strukturę bazy? Co zobaczę, gdy usługa przestanie odpowiadać? Ile może kosztować błąd? Jak wrócę do poprzedniej wersji?

Interfejs może powstać w kilka minut, ponieważ wiele decyzji pozostaje jeszcze niepodjętych. To nie zarzut wobec prototypu. Taka jest jego rola.

Problem zaczyna się dopiero wtedy, gdy wierzchołek góry lodowej sprzedajemy jako całą górę.

Jednym promptem można rozpocząć budowanie aplikacji. Produkt powstaje dopiero wtedy, gdy zajmiemy się również tym, czego nie da się pokazać na pierwszym screenshotcie.

Materiały źródłowe

Pojęcia z tego artykułu, wyjaśnione prostym językiem

Mateusz MaduraNiezależny Product Designer

Porozmawiajmy dalej na LinkedInie

Publikuję tam krótsze obserwacje o projektowaniu, AI i budowaniu produktów.

Odwiedź mój profil (otwiera się w nowej karcie)

Udostępnij artykuł

Powiązane artykuły