08 — Stack i technologie
Złota zasada altytudy zastosowana do wyboru narzędzi: najprostsze, co uniesie wymaganie; złożoność dokładasz, gdy metryka ją wymusi (→ 12).
Doktryna jest agnostyczna co do języka — ale wybór stacku decyduje, jak tani jest błąd i jak łatwo to przetestować. Ten rozdział to rozsądny default dla projektu prowadzonego z Claude: uniwersalny, prosty, elastyczny i skalowalny. Nie dogmat — punkt wyjścia, od którego odchodzisz świadomie (i zapisujesz dlaczego jako ADR).
Domyślny stack (sensowny start)
| Warstwa | Default | Kiedy zmienić |
|---|---|---|
| Backend / skrypty | Python — Popularny, czytelny język programowania — domyślny wybór The Craft do skryptów, danych i backendu. Sprawdzony default: dużo gotowych narzędzi i bibliotek, łatwy do prowadzenia z AI. (+ FastAPI dla API — Umówiony sposób, w jaki dwa programy gadają ze sobą — jeden prosi, drugi odpowiada w ustalonym formacie. Przez API Twoja aplikacja łączy się z cudzymi usługami (płatności, mapy, AI). Klucz API traktuj jak hasło.) | Front i back dzielą TypeScript → Node |
| Baza | SQLite — Najprostsza baza danych — cała mieszka w jednym pliku, bez osobnego serwera. Świetny default na start: zero konfiguracji, łatwy backup (kopiujesz plik). Przy wzroście migrujesz wyżej. | Współbieżny zapis / role / relacje / skala → PostgreSQL — Solidna, „dorosła” baza danych do większych aplikacji — działa jako osobny serwer. Domyślny krok po SQLite, gdy potrzebujesz wielu równoczesnych użytkowników i zaawansowanych funkcji. |
| Web / front | Server-rendered HTML + trochę JS | Bogaty, interaktywny UI → Next.js |
| API | REST/JSON z jawnym kontraktem (OpenAPI) | gRPC dopiero przy realnej potrzebie |
| Cache — Tymczasowo zapamiętany wynik, żeby nie liczyć tego samego od nowa przy każdym pytaniu. Przyspiesza aplikację, ale bywa pułapką: nieświeży cache pokazuje stare dane. / kolejka | brak → dołóż Redis, gdy profil ruchu wymusi | nie „na zapas” |
| Pakowanie | Docker / kontener — Zapakowanie aplikacji razem ze wszystkim, czego potrzebuje, żeby działała tak samo na każdym komputerze. Eliminuje „u mnie działa, u Ciebie nie” — to samo środowisko lokalnie i na serwerze. (powtarzalność) | trywialny skrypt bez zależności → bez kontenera |
| Hosting | jeden VPS — Wynajęty kawałek serwera w chmurze „tylko dla Ciebie”, na którym stawiasz aplikację „na żywo”. Przewidywalny koszt i pełna kontrola. Jeden VPS spokojnie uniesie kilka małych projektów. (Hetzner — Tani, solidny dostawca serwerów (hosting), na którym stawia się aplikację „na żywo”. Domyślny wybór serwera w kodeksie — przewidywalny koszt i wydajność bez przepłacania.) + nginx — Program na froncie serwera, który przyjmuje ruch z internetu i kieruje go do Twojej aplikacji. Obsługuje HTTPS, podaje pliki statyczne, rozkłada ruch — sprawdzona „recepcja” serwera. | nierówny/globalny ruch → Serverless — Model, w którym nie zarządzasz serwerem — kod odpala się sam, gdy ktoś go potrzebuje, i śpi, gdy nie. Płacisz za użycie, skaluje się sam. Pułapka: „zimny start” — pierwsze wywołanie bywa wolniejsze. (scale-to-zero) |
Reguła nadrzędna: nudna, dojrzała technologia bije modną. Liczy się ekosystem, dokumentacja i testowalność — nie hype.
Sprawdzony zestaw (konkretny baseline)
Zestaw przerobiony w boju na realnym projekcie — bierz z niego to, czego wymaga zadanie, resztę pomiń. Wszystko dojrzałe, dobrze udokumentowane, łatwe do testowania i hostowania na jednym VPS:
| Warstwa | Narzędzia |
|---|---|
| Narzędzie główne / proces | Anthropic Claude — Claude Desktop / Claude Code (agent, którym budujesz; prowadź go dobrze → 16) · Git (historia, → 05) · GitHub (zdalne repo, PR) · GitHub Issues (taski, → 07) |
| Format / treść | HTML5 (server-rendered), Markdown (docs), JSON (API, config), XML gdy wymusza integracja |
| Dane / zapytania | SQL — Język zapytań do bazy danych — sposób, w jaki „pytasz” bazę o dane albo je zmieniasz. Uniwersalny standard rozmowy z bazą. Źle napisane zapytanie potrafi zamulić całą aplikację. — SQLite (WAL — Write-Ahead Log: tryb bazy, w którym zmiany najpierw trafiają do dziennika, a potem do danych. Daje bezpieczeństwo (odtwarzalność po awarii) i lepszą równoczesność odczytu/zapisu.) na start → PostgreSQL przy skali; Migracja (bazy danych) — Kontrolowana zmiana układu bazy — dodanie kolumny, tabeli czy przeniesienie danych — krok po kroku. Jak remont według planu: przebudowa danych w ustalonej kolejności, żeby nic się nie „zawaliło”. forward-only |
| Backend / skrypty | Python (dane, scrapery, migracje na stdlib) · Node.js + Express (web/API) · EJS (szablony serwerowe) |
| Frontend | minimalny JS (vanilla), marked do renderu MD; ikony SVG: wyłącznie Lucide (jedno źródło geometrii, spójność); fonty self-host |
| Sesje / bezpieczeństwo | trwały store sesji (osobny plik, → 14), helmet, rate-limit, bcrypt, OAuth (passport) |
| Poczta | SMTP (587 STARTTLS), zweryfikowana domena nadawcy (→ 14) |
| Media / obraz | konwersja do WebP (Pillow); porównania obrazów (OpenCV) tylko gdy realnie trzeba |
| Ingest / Scraping — Automatyczne zbieranie danych ze stron internetowych przez program zamiast ręcznego kopiowania. Potężne do pozyskiwania danych, ale wymaga kultury: szanuj cudze zasady (robots.txt), nie przeciążaj serwera. | requests + BeautifulSoup (+lxml), fuzzy-match (rapidfuzz), Playwright gdy trzeba przeglądarki (→ 14) |
| LLM | klient API (Claude / Anthropic SDK), odpowiedzi streamowane SSE (→ 13) |
| Testy | pytest (Python) · Jest + supertest (Node) · Playwright (e2e) (→ 03) |
| Build / dev | esbuild, nodemon; Docker dla powtarzalności |
| Serwer / ops | jeden VPS (Hetzner) + nginx (TLS, reverse proxy) + pm2/systemd; analityka GA4 |
Reguła ikon: dla SVG trzymaj się jednego zestawu — Lucide (geometria w <symbol>/sprite,
reszta to styl). Mieszanie bibliotek ikon = niespójny UI i rozjazd wag/stroke’ów.
Python jako domyślny język
- Dlaczego: czytelność (kod jak proza — łatwy review przez człowieka i agenta), baterie w zestawie, jeden język na API + skrypty + dane/LLM. Mniej kontekstów do trzymania w głowie.
- FastAPI dla API: typy + walidacja (Pydantic) + auto-OpenAPI = darmowy kontrakt granicy front↔back (→ 12). pytest dla testów (→ 03).
- Reproducible env: wirtualne środowisko + pinned deps (lock). „Działało wczoraj” znika.
- Format i typy jako kontrakt:
ruff/black, type hints. Spójny styl = tańszy review (→ 02).
Baza danych — od prostego do skali
- Start: SQLite. Zero-ops, jeden plik, świetne do MVP i always-on VPS. Nie zaczynaj od rozproszonej bazy „bo kiedyś urośnie”.
- Skala: PostgreSQL — gdy boli współbieżny zapis, role, złożone relacje, rozszerzenia. Migrację SQLite→PG przewiduj w modelu od początku (→ 11).
- Reguły niezależne od silnika: migracje forward-only + backup przed każdą (→ 04), Slug — Czytelna, krótka część adresu strony, opisująca jej treść słowami zamiast tajemniczego numeru. Lepszy dla człowieka i SEO; trwały slug nie psuje linków przy zmianach. zamiast ID w odniesieniach user-danych, Indeks (bazodanowy) — Skorowidz w bazie danych, dzięki któremu wyszukiwanie idzie błyskawicznie, zamiast przeglądać wszystko po kolei. Pierwszy ruch przy wolnych zapytaniach — jak indeks na końcu książki zamiast czytania 400 stron. po pomiarze, nie z przeczucia (→ 13).
- NoSQL / rozproszone — dopiero gdy relacyjna realnie nie wystarcza, nie wcześniej.
Web i API — kontrakt jako granica
- Im mniej JS, tym lepiej. Server-rendered HTML domyślnie; SPA/Next.js tylko gdy interakcja tego naprawdę wymaga. Lekki front = szybszy i tańszy w utrzymaniu (→ 13).
- Kontrakt API (OpenAPI) jest granicą między front a back — pozwala wymienić jedną stronę bez dotykania drugiej (→ 12). Wersjonuj go; błędy zwracaj ustrukturyzowane.
- Streaming — Wysyłanie dużej odpowiedzi kawałkami, na bieżąco, zamiast ładowania wszystkiego naraz do pamięci. Aplikacja nie zatyka się przy wielkich danych — użytkownik widzi wynik szybciej. / SSE dla długich odpowiedzi (czat, LLM token-by-token) — user widzi efekt od razu, nie pustkę (→ 13).
Docker — powtarzalność, nie kult
- Po co: ten sam obraz lokalnie / w CI / na prodzie. „U mnie działa” przestaje istnieć.
- Higiena: mały obraz (multi-stage, slim base, pinned wersje),
.dockerignore, proces non-root.docker-composedo lokalnego złożenia (app + baza). - Nie konteneryzuj na siłę pojedynczego skryptu. Docker tam, gdzie zależności bolą — nie jako rytuał.
Serwer i hosting — jeden box, dobre nawyki
Monolit — Aplikacja zbudowana jako jedna całość (jeden deploy, jedna baza), a nie zlepek osobnych usług. Prosty, tani default na start — łatwy do ogarnięcia. Rozbijasz go dopiero, gdy skala naprawdę tego wymaga. jest domyślną architekturą — promuj go jako najłatwiejszy w utrzymaniu. Jedna aplikacja (web + API + zadania) i jedna baza na jednym VPS to coś, co ogarniasz w głowie: jeden deploy, jeden log, jeden backup, jeden Rollback — Cofnięcie zmiany do poprzedniego, działającego stanu — „Ctrl+Z” dla wdrożenia. Gdy nowa wersja psuje produkcję, rollback przywraca poprzednią w sekundy zamiast naprawiać w panice.. Debug to czytanie jednego procesu, nie korelowanie śladów po sieci. Rozbicie na usługi/serverless dokłada sieć, wersjonowanie kontraktów i klasę nowych awarii (→ 14) — sięgaj po nie dopiero, gdy metryka (ruch, zespół, izolacja awarii) realnie tego wymaga, nie „bo tak się robi”.
- Default: jeden VPS (Hetzner) + nginx (reverse proxy, TLS) +
systemd/pm2/Docker do procesów. Tani, przewidywalny, pełna kontrola, zero cold startu. Wiele projektów na jednym boxie = osobny vhost + osobny katalog, te same reguły deployu (→ 05). - Scale-to-zero (Cloud Run / serverless) gdy ruch nierówny/globalny, a cold start akceptowalny; always-on VPS gdy ruch przewidywalny. Świadomy tradeoff koszt/latencja, zapisany jako ADR (→ 12).
- Usługi zarządzane (baza, mail, storage) gdy zdejmują ops taniej, niż kosztuje samodzielne utrzymanie.
- Sekrety w env / secret store — nigdy w repo (→ 09).
TDD i pokrycie zmian — twardy rdzeń
Najważniejsze kryterium doboru stacku: ma być testowalny od pierwszej linijki. Technologia, której nie umiesz łatwo objąć testem (test-first, szybki i deterministyczny suite, CI bramkujące), jest złym wyborem — nawet jeśli modna. Mechanika TDD — Test-Driven Development: najpierw piszesz test (czego oczekujesz), potem kod, który go spełnia. Test zostaje w projekcie i pilnuje, że zmiana niczego nie zepsuła — dowód zamiast „chyba działa”. i pokrycie zmian = kanon w → 03; tu tylko twarda konsekwencja: wybieraj tech, która to umożliwia, i traktuj „commit bez testu” jako niekompletny (→ 00).
Reguła wyboru technologii
- Najprostsze, co uniesie dzisiejsze wymaganie, z jawną ścieżką wzrostu (SQLite→PG, VPS→serverless).
- Testowalność i ekosystem ważniejsze niż nowość.
- Każdy nietrywialny wybór = ADR: jedno „dlaczego” + odrzucone alternatywy. Następna sesja (człowiek albo agent) ma wiedzieć, czemu tak.
Anty-wzorce
- 🚫 Mikroserwisy / Kubernetes / rozproszona baza na MVP — złożoność, której nikt jeszcze nie potrzebuje (→ 12).
- 🚫 Stack pod CV/modę zamiast pod problem i testowalność.
- 🚫 Zmiana zachowania bez testu („dodam później” — nie dodasz).
- 🚫 Sekrety w repo; brak pinów wersji → „działało wczoraj”.
- 🚫 SPA / ciężki JS tam, gdzie wystarczy serwerowy HTML.
- 🚫 Docker/Cloud jako kult zamiast narzędzia dobranego do problemu.