Pełny program
Program kursu DevChallenge: od pustego repozytorium do wdrożonej aplikacji
To szczegółowy program kursu Full Stack z AI. Każda lekcja to jeden krok, który kończy się czymś, co działa. Przy każdym module widzisz efekt, zakres oraz datę publikacji.
- Moduł 0
- 4 zadania · 1 h · 0 zł · Od 01.10
- DevChallenge
- 7 modułów · 16.5 h
- Pro
- 6 modułów · 12.5 h
- Razem
- 13 modułów · 29 h
Moduł 0 · Przed zakupem · Premiera 01.10
Sprawdź gotowość
Cztery niezależne zadania. Wynik jest prosty: TAK albo JESZCZE NIE. Jeśli wszystkie cztery działają, ale rozwiązanie było potrzebne za często, dostajesz jedno dodatkowe zadanie w nowej wersji.
- Zadanie 115 min
Ustawienia challenge'u
Porządkujesz i walidujesz temat, nakładasz bezpieczny limit pytań i ustawiasz poziom trudności.
- Zadanie 215 min
Publiczne pytania
Filtrujesz aktywne pytania i mapujesz je na publiczną kopię bez klucza odpowiedzi i wyjaśnienia, nie mutując danych wejściowych.
- Zadanie 315 min
Pobranie challenge'u
Odrzucasz pusty slug, czekasz na wynik przez async/await i zamieniasz każdy przebieg na jawny status: sukces, brak challenge'u albo błąd.
- Zadanie 415 min
Połącz formularz z logiką
Piszesz handler gotowego formularza: czekasz na asynchroniczny zapis, pokazujesz błąd walidacji albo zapisu i zawsze wyłączasz stan ładowania, także po błędzie.
Jak przepływają dane przez DevChallenge
4 warstwy rdzenia · 4 funkcje Pro · Odbiór i automatyzacje n8n
Vue + Nuxt · Node.js + Nitro · PostgreSQL · AI SDK + Zod
Zobacz pełną architekturę i rozszerzenia Pro
- 01
Frontend
Vue + NuxtKreator, challenge i wynik - 02
Backend
Node.js + NitroAPI, limity i scoring - 03
AI
AI SDK + ZodGenerowanie i walidacja - 04
Baza danych
PostgreSQL + SupabaseChallenge i podejścia
- 05
Ranking
Wyniki → remisy → udostępnianieGracz widzi pozycję i może wysłać wynik. - 06
Feedback AI
Serwer → na żywo → ekranInformacja zwrotna pojawia się na żywo. - 07
Własny PDF (RAG)
PDF → fragmenty → pytaniaQuiz powstaje z materiału użytkownika. - 08
Asystent AI (MCP)
Rozmowa → narzędzie → publiczny linkChallenge tworzysz również z rozmowy z asystentem.
- 01
Frontend
Vue + NuxtKreator, challenge i wynik - 02
Backend
Node.js + NitroAPI, limity i scoring - 03
AI
AI SDK + ZodGenerowanie i walidacja - 04
Baza danych
PostgreSQL + SupabaseChallenge i podejścia
- 05
Ranking
Wyniki → remisy → udostępnianieGracz widzi pozycję i może wysłać wynik. - 06
Feedback AI
Serwer → na żywo → ekranInformacja zwrotna pojawia się na żywo. - 07
Własny PDF (RAG)
PDF → fragmenty → pytaniaQuiz powstaje z materiału użytkownika. - 08
Asystent AI (MCP)
Rozmowa → narzędzie → publiczny linkChallenge tworzysz również z rozmowy z asystentem.
DevChallenge · Kompletny produkt Full Stack
Zbuduj i wdróż działającą aplikację Full Stack z AI
7 modułów · 16.5 h
Zaczynasz od gotowego szkieletu projektu. Kończysz z aplikacją na własnym koncie: kreatorem AI, bazą, publicznym linkiem, grą i wynikiem liczonym przez serwer.
01Start projektu
3 lekcje · 1 h · od 01.12.2026
Efekt: Projekt, który się uruchamia i ma jedną komendę pilnującą jakości.
- L01
Deterministyczny scaffold Nuxt i pakiet kursu
Pusty projekt Nuxt (to framework, w którym powstanie aplikacja): uruchamia się i buduje. Do tego mapa 88 lekcji, po której pójdziemy. Żadnej funkcji produktu - tylko szkielet. Plan kursu i skrypty, które go pilnują, zostają w moim repozytorium; Ty dostajesz przewodnik w PDF.
- L02
Narzędzia jakości i spójna konfiguracja
Cztery pliki konfiguracji (ESLint, Prettier, ustawienia edytora) i zestaw komend, które od tej pory decydują, czy kod wchodzi do repozytorium. Kodu produktu tu nie ma - ustawiamy bramkę, przez którą przejdzie każda kolejna lekcja.
- L03
Git, sekrety i prosty workflow pracy z AI
Gdzie trzymamy klucze, żeby nigdy nie trafiły do repozytorium, i jak w tym kursie współpracujemy z AI. Ta lekcja nie zmienia kodu, tylko ustala reguły gry na całą resztę kursu.
Checkpoint: Projekt uruchamia się, buduje i przechodzi wspólną bramkę jakości.
02Quiz na ekranie
6 lekcji · 2 h · od 01.12.2026
Efekt: Pytanie na ekranie z trzema typami odpowiedzi i obsługą klawiatury.
- L04
Quiz jako dane na ekranie
Zaczynamy od tego, co produkt ma pokazać. Zapisujemy jeden przykładowy quiz jako dane w projekcie i wypisujemy go na stronie: temat i wszystkie pytania. Ten lokalny quiz to jedyne rusztowanie w całym kursie i ma wyznaczony termin usunięcia - w L38, kiedy quiz zacznie przychodzić z bazy. Do tego czasu daje nam coś, na czym da się natychmiast pracować i klikać.
- L05
Kontrakt pytania
Skąd wiemy, że quiz ma poprawny kształt? Piszemy kontrakt runtime dla pytania i całego quizu: opis kształtu danych w bibliotece Zod, sprawdzany w działającej aplikacji. Potem przepuszczamy przez niego lokalne dane. Trzy typy pytań mają różne kształty odpowiedzi, więc muszą być rozłączne - pytanie zbudowane pół na pół ma odpaść przy wejściu do aplikacji, a nie w połowie renderowania.
- L06
Oprawa wizualna i komponenty bazowe
Ta sama strona, ale wygląda jak produkt. Integrujemy Tailwinda (gotowe klasy CSS), tokeny CSS (kolory i odstępy nazwane raz) i shell aplikacji. Do tego pięć komponentów bazowych: przycisk, karta, tekst, lista i wskaźnik ładowania. Nie przepisujemy CSS z palca - czytamy, co który token i komponent gwarantuje: kontrast, widoczny focus, wyłączalne animacje i brak przewijania w poziomie na 320 px.
- L07
Odpowiedź jednokrotnego wyboru
Pierwsza interakcja w produkcie. Opisujemy kontraktem, jak wygląda odpowiedź gracza, wyciągamy etykiety A-D do jednego miejsca i piszemy panel odpowiedzi dla pytania jednokrotnego wyboru. Klikasz opcję i widzisz zaznaczenie; klawiatura działa od pierwszej wersji.
- L08
Prawda/fałsz i wielokrotny wybór
Ten sam panel obsługuje pozostałe dwa typy. Prawda/fałsz to dwie stałe etykiety, wielokrotny wybór to przełączanie kilku opcji naraz. Tu widać, po co kontrakt miał union rozłączny: każdy typ ma inny kształt odpowiedzi i inne zachowanie zaznaczenia.
- L09
Jedno pytanie na raz
Quiz przestaje być listą i staje się przejściem. Na ekranie jest jedno pytanie, panel dostaje przycisk zatwierdzenia, a nad pytaniem pasek postępu mówi graczowi i czytnikowi ekranu, gdzie właśnie jest. Ten sam pasek posłuży później jako mapa wyników.
Checkpoint: Trzy typy pytań działają myszą i klawiaturą.
03Pełna gra lokalnie
9 lekcji · 3 h · od 07.12.2026
Efekt: Pełna gra lokalnie: czas, podpowiedź, wynik i podsumowanie odpowiedzi.
- L10
Pytanie jako jeden komponent
Panel odpowiedzi i pasek postępu mamy osobno. Składamy z nich jedno pytanie: treść, opcje, postęp i przekazanie focusu tam, gdzie gracz ma zacząć. Strona przestaje układać elementy ręcznie i dostaje jeden komponent do wyświetlenia.
- L11
Przejście przez cały quiz
Pierwszy stan gry. Piszemy composable (funkcję Vue, która trzyma stan poza komponentem) z jawnymi fazami i akcjami: wybierz odpowiedź, przejdź dalej, skończ. Fazy zapisujemy wprost, bo za kilka lekcji dojdą do nich czas z serwera, zapisany wynik i wznowienie partii - wtedy zbiór flag przestałby wystarczać.
- L12
Liczenie punktów i pierwszy test
Czyste funkcje oceniające odpowiedzi (te same dane dają ten sam wynik, bez efektów ubocznych) i pierwszy test w projekcie. Tu każda pomyłka jest cicha, więc liczenie punktów dostaje dowód, a nie tylko obietnicę. Najciekawsza jest równość zbiorów w wielokrotnym wyborze: kolejność zaznaczeń nie może zmieniać wyniku, a brak jednej poprawnej odpowiedzi to zero punktów, nie połowa.
- L13
Czas gry na ekranie
Licznik czasu partii. Świadomie nazywamy go timerem widoku: pokazuje graczowi, ile gra, ale nie jest dowodem na nic. Autorytatywny czas policzy serwer i to rozróżnienie mówimy wprost już teraz, żeby później nie było zdziwienia, po co drugi pomiar.
- L14
Ekran wyniku
Domykamy pętlę gry. Po ostatnim pytaniu liczymy punkty tymi samymi funkcjami, które napisaliśmy w L12, i pokazujemy wynik razem z czasem partii. Liczy jeszcze przeglądarka - w L43 tę robotę przejmie serwer, bo gracz nie może sam sobie wystawiać ocen.
- L15
Podsumowanie odpowiedzi
Sam wynik nie mówi graczowi, gdzie się pomylił. Budujemy podsumowanie każdej odpowiedzi: co gracz wybrał, co było poprawne i dlaczego. Liczymy je z pełnych danych pytania, nie z tego, co było na ekranie, bo tę samą funkcję uruchomi później serwer.
- L16
Jedna podpowiedź na grę
Podpowiedź do pytania, ale tylko raz w całej partii. Reguła siedzi w state machine, nie w komponencie - dzięki temu żadne przełączenie widoku ani kolejne pytanie jej nie obejdzie.
- L17
Kod w pytaniach
Quiz techniczny potrzebuje fragmentów kodu w pytaniach. Integrujemy Shiki (bibliotekę do kolorowania składni) z jawną listą języków i czytamy dwie rzeczy: dlaczego ładujemy tylko wybrane języki, a nie cały katalog Shiki, i dlaczego kod z pytania zostaje tekstem, nigdy HTML-em.
- L18
Intro, nick i pełna pętla gry
Zamykamy moduł ekranem startowym: gracz podaje nick i zaczyna. Strona ma teraz trzy jawne stany: intro, gra, wynik. Przy zmianie ekranu focus przechodzi na nowy ekran, a strona przewija się do góry. Tę grę da się zagrać od początku do końca, jeszcze bez bazy i bez AI, więc bez żadnego sekretu.
Checkpoint: Quiz da się przejść lokalnie od startu do podsumowania.
04Kreator i generacja AI
13 lekcji · 4 h · od 14.12.2026
Efekt: Quiz generowany przez model, z kontrolą jakości, kosztu i błędów.
- L19
Klucz modelu w runtime serwera
Pierwsze wyjście na zewnątrz. Zakładasz klucz u dostawcy modelu i ustawiasz tam twardy limit wydatków. Integrujemy adapter modelu (bibliotekę, przez którą serwer rozmawia z modelem) i pokazujemy granicę, której nie wolno przekroczyć: klucz i nazwa modelu żyją tylko na serwerze, nigdy w przeglądarce. Brak klucza kończy się od razu błędem konfiguracji, nie błędem sieci w połowie generowania.
- L20
Endpoint generowania quizu
Pierwszy własny endpoint (adres na serwerze, pod który przeglądarka wysyła żądanie). Opisujemy kontraktem, czego wymaga generacja, budujemy prompt (instrukcję dla modelu) w osobnym pliku i prosimy model o odpowiedź zgodną z kontraktem quizu z L05. Model nie dostaje swobody: odpowiedź innego kształtu nie wychodzi z endpointu.
- L21
Strona główna jako landing produktu
Endpoint już generuje quizy, więc strona główna przestaje być wizytówką z jednym zdaniem. Integrujemy nagłówek produktu, zdanie z obietnicą pod nim i ozdobną grafikę ścieżki. Tu w L22 stanie formularz kreatora.
- L22
Formularz kreatora
Strona główna staje się kreatorem. Piszemy stan formularza - temat, poziom i liczbę pytań - ze sprawdzeniem tematu w przeglądarce (to wygoda dla użytkownika, nie zabezpieczenie) i wysyłamy go do endpointu z L20. Pierwsza wersja wywołania jest najprostsza z możliwych; status i komunikaty błędów dołożymy w L23.
- L23
Status generacji i kontrolowane komunikaty
Wywołanie z L22 nie ma stanu ani obsługi błędu. Przenosimy je do composable z jawnym statusem. Odpowiedź serwera sprawdzamy kontraktem, bo nie ufamy nawet własnemu API, a teksty błędów dla użytkownika zbieramy w jednym pliku - żeby nigdy nie zobaczył surowego błędu z serwera.
- L24
Podgląd wygenerowanego quizu
Moment, w którym produkt zaczyna istnieć. Twórca widzi wygenerowane pytania razem z poprawnymi odpowiedziami i wyjaśnieniami - bo to jego własny draft, jeszcze nieopublikowany. Skrypt piszemy razem, szablon z klasami dostajesz gotowy.
- L25
Własny czytnik body z limitem bajtów
Endpoint kosztuje pieniądze, a domyślny czytnik body (treści żądania) nie ma limitu rozmiaru. Piszemy własny: sprawdza typ treści i zadeklarowaną długość, liczy bajty w trakcie czytania i przerywa żądanie w momencie przekroczenia limitu, zamiast najpierw wczytać wszystko do pamięci.
- L26
Tryb pytań i limit czasu modelu
Twórca dostaje wybór trybu pytań, a prompt jawne reguły dla każdego z nich. Do tego ustalamy limit czasu na jedną odpowiedź modelu, żeby żądanie nie wisiało w nieskończoność.
- L27
Ponowienie próby i przerwanie
Model czasem zwróci coś niezgodnego z kontraktem albo po prostu padnie. Piszemy ponowienie próby z budżetem (limit liczby prób i czasu na jedną próbę, bo każda kosztuje) i z sygnałem przerwania: jeśli użytkownik zamknie kartę, kolejna próba nie ma prawa wystartować.
- L28
Deterministyczna kontrola jakości
Zamiast prosić model o ocenę własnej pracy, piszemy reguły. Sprawdzamy liczbę pytań i zgodność z trybem, a potem szukamy duplikatów, pytań bez treści, zdegenerowanego rozkładu poprawnych odpowiedzi i niewidocznych znaków. Ten sam quiz zawsze dostaje tę samą ocenę.
- L29
Anulowanie i bezpieczne stany kreatora
Generacja trwa kilkanaście sekund, więc użytkownik zdąży kliknąć drugi raz, zmienić temat i anulować. Każde żądanie ma własną tożsamość i tylko najnowsze może zapisać wynik; spóźniona odpowiedź nie nadpisze ekranu. Do tego blokada formularza na czas generacji i komunikat dla czytnika ekranu.
- L30
Obserwowalność wywołań AI
Skoro płacimy za wywołania modelu, musimy je widzieć - ale bez zapisywania promptu, pytań i danych użytkownika. Integrujemy jeden moduł, który dla każdej próby zapisuje w logu zużyte tokeny (jednostki, za które płacimy dostawcy), czas i kategorię błędu. Test jednostkowy tego modułu dojdzie w L72.
- L31
Finalny wygląd kreatora
Kreator ma pełną logikę, więc domykamy warstwę wizualną: formularz zostaje przy nagłówku na desktopie, a pod nim staje sekcja trzech kroków (temat i poziom, sprawdzenie pytań, wysłanie linku). Żadnych nowych żądań i żadnych nowych decyzji produktowych.
Checkpoint: Kreator zwraca poprawny quiz albo kontrolowany komunikat i nie ujawnia sekretu.
05Zapis i publiczny link
7 lekcji · 2 h · od 28.12.2026
Efekt: Quiz zapisany w bazie i dostępny pod publicznym linkiem.
- L32
Pierwsza tabela i świeża baza
Piszemy skrypt bazy w jednej transakcji (wykona się cały albo wcale) i tworzymy w nim dokładnie jedną tabelę: na zapisane quizy. Skrypt będzie rósł razem z produktem, a każda kolejna tabela pojawi się w lekcji, w której zaczyna być potrzebna. Od razu włączamy ochronę wierszy i odbieramy uprawnienia rolom publicznym: do tabeli ma dostęp tylko serwer.
- L33
Serwerowy dostęp do bazy
Integrujemy klienta bazy (obiekt, którym serwer rozmawia z bazą) i zapis błędów bazy do logu bez danych użytkownika. Granica: klient powstaje wyłącznie na serwerze, z sekretnego klucza, i nie ma go w niczym, co trafia do przeglądarki. Sama warstwa połączenia; pierwsze prawdziwe zapytanie do bazy wychodzi z endpointu zapisu w L34.
- L34
Zapis quizu i unikalny adres
Endpoint zapisu. Z tematu robimy czytelny adres i dokładamy losową końcówkę; gdy taki adres już jest w bazie (kolizja), losujemy nowy, łącznie najwyżej trzy próby. Draft zapisujemy tak, jak przyszedł; sprawdzenie, że nikt go po drodze nie podmienił, dokładamy w L48, gdy będzie czym podpisywać.
- L35
Testowanie handlerów bez prawdziwej bazy
Handler zapisu (kod endpointu) to pierwszy kawałek, którego nie sprawdzimy samym wywołaniem: potrzebuje żądania i bazy. Integrujemy mały wspólny harness (uruchamia handler bez sieci i bez bazy) i fixture (gotowy quiz testowy), a potem piszemy test kolizji adresu. Ustalamy przy tym granicę mocków: co w testach udajemy, a czego nigdy.
- L36
Zapis i kopiowanie linku z przeglądarki
Twórca zapisuje swój quiz i dostaje link do skopiowania. Piszemy klienta zapisu, obsługę schowka i kartę udostępniania. Równoległy zapis blokujemy, bo dwa kliknięcia oznaczałyby dwa quizy w bazie.
- L37
Zaufany adres publiczny
Link, który wysyłamy innym, nie może pochodzić z tego, co przeglądarka ma w pasku adresu. Piszemy walidację zaufanego originu (protokół i domena, bez ścieżki) i budowanie adresu wyłącznie z konfiguracji, z jawnym wyjątkiem dla localhost.
- L38
Publiczny quiz bez klucza odpowiedzi
Link zaczyna działać. Piszemy publiczny odczyt, który wybiera z bazy tylko to, co gracz ma prawo zobaczyć: bez poprawnych odpowiedzi i bez wyjaśnień. Strona quizu przestaje czytać lokalne dane i usuwamy je z projektu - rusztowanie znika dokładnie tam, gdzie zapowiedziałem w L04. Gracz może otworzyć quiz i przejrzeć pytania; zakończenie partii wymaga wyniku liczonego przez serwer, więc domykamy je w kolejnym module.
Checkpoint: Zapisany quiz otwiera się z publicznego adresu bez klucza odpowiedzi.
06Uczciwy wynik na serwerze
8 lekcji · 2.5 h · od 04.01.2027
Efekt: Wynik i czas liczone przez serwer oraz bezpieczne wznowienie gry.
- L39
Tabela podejść
Druga tabela w skrypcie bazy: podejścia (rozegrane partie). Podejście trzyma nick, punkty, czas, odpowiedzi i odcisk tokenu startu (skrót tokenu, który napiszemy w L40). Reguły (constraints) piszemy tak, żeby baza sama odrzuciła nonsens: punkty większe niż liczba odpowiedzi, czas poza zakresem, odcisk o złym formacie. Odcisk ma być unikalny: baza założy na nim indeks i to on gwarantuje jedno podejście na token.
- L40
Podpisany start i czas z serwera
Czas partii musi pochodzić z serwera, ale nie chcemy trzymać sesji, czyli pamiętać na serwerze, kto i kiedy zaczął grać. Piszemy token startu: zawiera moment rozpoczęcia, jest przypisany do konkretnego quizu, ma czas życia i podpis liczony z sekretu, którego przeglądarka nie zna, więc go nie podrobi. Serwer odczyta z niego czas gry bez pamiętania czegokolwiek.
- L41
Endpoint startu partii
Mały endpoint, który wydaje token startu dla konkretnego quizu, i podłączenie go do ekranu intro. Od tej chwili o początku partii decyduje serwer, nie przeglądarka, a odpowiedź z tokenem nie ma prawa wpaść do żadnego cache (pamięci podręcznej po drodze).
- L42
Wynik liczony przez serwer
Serwerowy koniec partii. Endpoint odczytuje czas z tokenu, pobiera pytania z bazy, bo to serwer ma być źródłem prawdy o poprawnych odpowiedziach, liczy punkty i podsumowanie tymi samymi funkcjami, które napisaliśmy w M03, i zapisuje podejście. Przeglądarka nie przysyła wyniku - przysyła wyłącznie odpowiedzi.
- L43
Jedno wysłanie i wynik na ekranie
Domykamy grę z publicznego linku. Przeglądarka wysyła odpowiedzi po ostatnim pytaniu i pokazuje wynik z serwera. Najważniejsza reguła: jedno aktywne wysłanie - podwójne kliknięcie i nerwowy Enter nie mogą wygenerować dwóch podejść. Odpowiedź serwera sprawdzamy kontraktem, zanim trafi do stanu gry.
- L44
Ponowione wysłanie zwraca ten sam wynik
Sieć bywa zawodna, a użytkownik naciska ponownie. Robimy z zapisu podejścia operację idempotentną, czyli taką, którą można powtórzyć bez zmiany skutku: odcisk (skrót) tokenu trzymany w bazie z zakazem duplikatów zamienia drugą próbę w odczyt już zapisanego wyniku, zamiast w drugie podejście i drugi wiersz w rankingu.
- L45
Pozycja w stawce
Sam wynik niewiele mówi. Dokładamy funkcję w bazie, która policzy, ile podejść było lepszych, ile miało identyczny wynik i ile było wszystkich - a potem zamieniamy to na zdanie zrozumiałe dla gracza. Liczenie zostaje w bazie, bo tam są dane.
- L46
Wznowienie przerwanej partii
Odświeżenie strony w środku gry nie może kasować partii. Zapisujemy stan w sessionStorage (pamięci karty przeglądarki), ale traktujemy go jak dane obce: każdy fragment sprawdzamy przed użyciem - fazę gry, numer pytania, odpowiedzi, token i czas. Stan uszkodzony albo z innego quizu odrzucamy bez rzucania błędu i bez żądania do serwera.
Checkpoint: Serwer liczy wynik i czas, a przerwana gra wraca do poprawnego stanu.
07Granice zaufania i wdrożenie
7 lekcji · 2 h · od 11.01.2027
Efekt: Zabezpieczona aplikacja wdrożona na własnym koncie i sprawdzona krótkim smoke testem.
- L47
Podpisany bilet na operację
Zapis przyjmuje dziś dowolny draft, bo nie ma czym sprawdzić, że to ten sam quiz, który wygenerował model. Powstaje bilet: podpisana przez serwer zgoda na jedną konkretną operację. Piszemy jeden wspólny rdzeń: podpis treści, jednorazowy identyfikator, czas życia i stabilny odcisk (skrót) danych. Stabilność odcisku jest tu sednem - ten sam obiekt z polami w innej kolejności musi dać ten sam odcisk, inaczej podpis raz by pasował, raz nie.
- L48
Zapis tylko podpisanego draftu
Domykamy dziurę z L34. Generator wydaje bilet do wygenerowanego draftu, a zapis przyjmuje wyłącznie draft, który ten bilet potwierdza. Ktoś, kto podmieni jedno pytanie po drodze, nie zapisze nic - i nie dowie się, dlaczego.
- L49
Licznik żądań w bazie
Limit żądań musi być atomowy, czyli sprawdzenie i zwiększenie licznika mają być jednym niepodzielnym krokiem, bo inaczej dwa równoległe wywołania mogą oba „zmieścić się" w ostatnim wolnym miejscu. Piszemy tabelę okien (przedziałów czasu, w których liczymy żądania) i funkcję w bazie, która w jednym zapytaniu podnosi licznik tylko wtedy, gdy jest jeszcze miejsce, i po drodze sprząta stare okna.
- L50
Limit na IP i zamknięta lista akcji
Podłączamy licznik do aplikacji. Nazwy limitowanych akcji trzymamy w zamkniętej liście typów, bo literówka w nazwie akcji cicho wyłączyłaby limit; teraz nie przejdzie sprawdzenia typów. Odczyt adresu klienta robimy świadomie: za proxy (pośrednikiem, przez który przechodzi ruch do serwera) trzeba wiedzieć, któremu nagłówkowi żądania wolno wierzyć. Domykamy też plik testów granic żądania.
- L51
Limity przy kosztownych operacjach
Wpinamy limit tam, gdzie boli: generacja płaci za model, zapis i start tworzą wiersze w bazie. Kolejność w handlerze (funkcji obsługującej żądanie) jest tu treścią lekcji - walidacja wejścia, limit, dopiero potem cokolwiek, co kosztuje. Test pilnuje właśnie tej kolejności.
- L52
Nagłówki bezpieczeństwa
Ostatnia warstwa obrony, egzekwowana przez przeglądarkę: nagłówki HTTP na odpowiedzi strony. Integrujemy politykę treści (skąd wolno ładować skrypty i inne zasoby), wymuszenie HTTPS, zakaz zgadywania typu pliku, zakaz osadzania strony w cudzej ramce i wyłączenie uprawnień, których nie używamy, np. kamery. Czytamy też jeden świadomy kompromis: skąd bierze się unsafe-inline w polityce skryptów i dlaczego pierwszą obroną jest to, że treść użytkownika nigdy nie idzie przez v-html (wstawianie surowego HTML do strony).
- L53
Wdrożenie DevChallenge i smoke
Zamykamy DevChallenge: aplikacja trafia pod publiczny adres. Spisujemy w README zakres produktu i drogę danych, zakładamy świeżą bazę, wdrażamy zaakceptowany commit (zielone npm run check i testy) i robimy smoke: szybkie przejście całej ścieżki od generacji do wyniku. Zapisujemy też ograniczenie, którego limity na IP z L50 nie usuwają: bez kont nie wiadomo, kim jest gracz. Procedura dla Twojego projektu: docs/course/PRODUCTION.md.
Checkpoint: Własne wdrożenie przechodzi generację, zapis, publiczny link, grę i smoke bezpieczeństwa.
To już komplet DevChallenge: aplikacja działa i jest wdrożona pod publicznym adresem. Dalej zaczynają się rozszerzenia Pro.
Zobacz ceny i Moduł 0DevChallenge Pro · Rozszerzenia gotowego produktu
Dodaj ranking, feedback AI na żywo, quiz z Twojego PDF-a, asystenta AI i odbiór gotowej wersji
6 modułów · 12.5 h
Rozwijasz wdrożoną aplikację o kolejne funkcje, a na końcu sprawdzasz pełną wersję testami E2E, SEO i produkcyjnym smoke testem. W module Automatyzacje n8n budujesz workflow wysyłki quizu mailem i cotygodniowego raportu wyników.
08Ranking i udostępnianie
4 lekcje · 1.5 h · od 25.01.2027
Efekt: Ranking z poprawnymi remisami i wynik gotowy do udostępnienia.
- L54
Endpoint leaderboardu
Top dziesięć podejść i reguła kolejności: więcej punktów wyżej, a przy równych punktach krótszy czas. Sortowanie i limit robi baza, nie aplikacja, a żeby nie musiała sortować całej tabeli przy każdym żądaniu, dokładamy indeks pod to zapytanie. Numery miejsc przy remisach liczymy w L55, razem z listą na ekranie.
- L55
Ranking na ekranie
Ranking pod wynikiem gracza, odświeżany po zapisaniu podejścia. Pozycje liczymy po sportowemu: remis dzieli tę samą pozycję, a następny gracz dostaje lukę (1, 2, 2, 4, nie 1, 2, 3, 4). Numerowanie po kolei to błąd, który wraca w każdej tabeli wyników. Dokładamy stan „wczytuję ranking" i trzymamy go poza zapisanym stanem partii, tym, który przeżywa odświeżenie strony: to informacja o trwającym żądaniu, nie o przebiegu gry.
- L56
Udostępnianie wyniku
Jeden przycisk, dwie drogi: systemowe okno udostępniania tam, gdzie przeglądarka je ma (zwykle telefon), i schowek jako fallback, czyli droga zapasowa (zwykle komputer). Najważniejszy szczegół to anulowanie: użytkownik, który zamknie okno systemowe, nie zrobił nic złego i nie może zobaczyć błędu.
- L57
Wynik warty wysłania
Udostępnianie działa, ale wysyła sam link. Budujemy treść, którą gracz naprawdę chce wysłać: punkty, czas, miejsce i siatkę trafień. Adres składamy z zaufanego origin produktu, nie z tego, co akurat jest w pasku przeglądarki.
Checkpoint: Ranking poprawnie obsługuje remisy, a wynik można udostępnić.
09Feedback AI na żywo
9 lekcji · 3 h · od 08.02.2027
Efekt: Feedback AI pojawiający się na ekranie na żywo.
- L58
Kontrakt feedbacku i miejsce w bazie
Feedback, czyli analiza odpowiedzi gracza pisana przez model po grze, ma stałą strukturę: cztery nazwane sekcje, nie wolny tekst. Opisujemy ją kontraktem, budujemy prompt z numerem wersji, w którym odpowiedzi gracza są danymi w JSON, a nie częścią polecenia, i dokładamy do tabeli podejść kolumny na wynik oraz stan generacji z constraintem, który dopuszcza tylko spójne kombinacje.
- L59
Mutacje tylko z własnej aplikacji
Mutacje z tytułu to operacje, które zmieniają dane: feedback (kosztuje pieniądze), a w M10 kasowanie dokumentów. Nie mają biletu wiążącego treść jak zapis z L48, więc przed endpointem piszemy bramkę: serwer czyta nagłówek Origin (przeglądarka wpisuje w niego adres strony, z której wyszło żądanie) i przepuszcza tylko własny adres. Drugą częścią tej obrony jest JSON w body, bo przeglądarka wymusza wtedy preflight, wstępne zapytanie o zgodę na żądanie z obcej strony. Endpoint startu z L41 body nie czyta, więc bramkę dostaje osobno.
- L60
Endpoint feedbacku i własność podejścia
Kto ma prawo poprosić o feedback do konkretnego podejścia? Nie mamy kont, więc dowodem własności jest token startu tej partii - porównujemy jego odcisk z tym zapisanym przy podejściu. Endpoint generuje feedback i zapisuje go w bazie.
- L61
Feedback na ekranie
Pokazujemy feedback pod wynikiem: sekcje z tytułami i treścią. Osobno traktujemy fragmenty kodu w tekście od modelu, te w odwrotnych apostrofach: rozbijamy tekst na zwykłe kawałki i kod, a kod pokazujemy jako kod, nigdy jako HTML. To jedyne miejsce, gdzie tekst od modelu dostaje formatowanie.
- L62
Strumieniowanie zdarzeń z serwera
Kilkanaście sekund czekania na pełny feedback to za długo. Zamieniamy jedną odpowiedź na strumień zdarzeń, czyli porcje wysyłane w trakcie pracy modelu: wynik częściowy, zakończenie i błąd. Piszemy też podział strumienia na zdarzenia, bo jeden odczyt z sieci może przynieść kilka zdarzeń albo pół zdarzenia, dokończone przy następnym odczycie.
- L63
Klient strumienia
Po stronie przeglądarki czekają cztery pułapki. Czytamy strumień i scalamy porcje w jeden wynik, obsługujemy anulowanie oraz połączenie, które kończy się bez zdarzenia zakończenia. Do tego tożsamość żądania: stary strumień nie ma prawa nadpisać nowego.
- L64
Jedna generacja na podejście
Feedback kosztuje, więc dwa równoległe żądania nie mogą zapłacić dwa razy. Robimy atomową rezerwację: jedno zapytanie oznacza podejście jako zajęte i zwraca identyfikator rezerwacji. Kto rezerwacji nie dostał, nie generuje. Gotowy feedback odtwarzamy z bazy bez ponownego kosztu.
- L65
Rozłączenie nie psuje wyniku
Gracz zamyka kartę w połowie generacji. Praca serwera ma się dokończyć i zapisać, ale zapis musi trafić tylko wtedy, gdy nadal należy do naszej rezerwacji z L64. Do tego błąd kontraktu (model oddał odpowiedź niezgodną z kontraktem) musi zwolnić rezerwację, żeby ponowienie było możliwe. Dokładamy też pomiar tego wywołania w tym samym miejscu, co pomiar generacji quizu: wpis ai.call z L30.
- L66
Finalny wygląd panelu feedbacku
Panel pokazuje sekcje, ale nie pokazuje postępu. Zamieniamy listę sekcji na ścieżkę checkpointów: szkielet wczytywania zamiast pustego miejsca, stan aktywnego etapu i kontrolowany komunikat dla czytnika ekranu. Strumień aktualizuje ekran wiele razy, więc układ nie może skakać.
Checkpoint: Feedback jest zapisany, strumieniowany i nie generuje się drugi raz dla tej samej próby.
10Quiz z własnego PDF
11 lekcji · 3.5 h · od 22.02.2027
Efekt: Quiz generowany z własnego dokumentu PDF.
- L67
Fragmenty dokumentu w bazie
Domykamy skrypt bazy. Dokładamy rozszerzenie do wektorów, tabelę dokumentów, tabelę fragmentów z osadzeniem oraz funkcję szukającą fragmentów najbliższych zapytaniu po znaczeniu, nie po słowach. Osadzenie to tekst zamieniony przez model na wektor liczb o ustalonej długości (liczbie wymiarów), więc baza sama odrzuci wektor z innego modelu.
- L68
Przyjęcie pliku z limitami
Upload przyjmuje plik od użytkownika, a jego treść idzie potem do płatnego modelu osadzeń, gdzie rachunek rośnie z liczbą fragmentów, więc zaczynamy od bramek, nie od funkcji. Cała ścieżka jest domyślnie wyłączona i włącza ją dopiero przełącznik w konfiguracji; wymaga zgody użytkownika i przyjmuje wyłącznie formularz o znanym typie i rozmiarze. Dokładamy do czytnika body obsługę formularza wieloczęściowego (multipart) z tym samym limitem bajtów.
- L69
Odczyt tekstu z PDF
Integrujemy odczyt tekstu z PDF i czytamy, dlaczego jest napisany defensywnie: sprawdzamy pierwsze bajty pliku (sygnaturę), a nie tylko nagłówek żądania, ograniczamy liczbę stron, pilnujemy przerwania i zwalniamy zasoby biblioteki także wtedy, gdy odczyt się nie udał.
- L70
Fragmentowanie i osadzenia
Tekst dzielimy deterministycznie (ten sam tekst zawsze daje te same fragmenty): najpierw po akapitach, a zbyt długie akapity rozcinamy dalej, z minimalną i maksymalną długością fragmentu. Potem liczymy osadzenia i zapisujemy wszystko w jednej operacji. Jeśli cokolwiek zawiedzie, usuwamy dokument - nie zostawiamy sierot, czyli dokumentów bez fragmentów.
- L71
Usuwanie własnego dokumentu
Kto wgrał dokument, ten może go usunąć - i nikt inny. Wydajemy bilet do dokumentu na tym samym rdzeniu podpisu, który napisaliśmy dla zapisu quizu. Bez drugiej implementacji podpisu, z osobnym przeznaczeniem i osobnym czasem życia.
- L72
Szukanie fragmentów po znaczeniu
Druga połowa mechanizmu z L70: zamieniamy temat quizu na osadzenie i prosimy bazę o najbliższe mu fragmenty jednego, konkretnego dokumentu. Bramki są zamknięte domyślnie - wyłączona funkcja i błąd dostawcy kończą się kontrolowanym błędem, a szukanie nie wychodzi poza wskazany dokument. Sprawdzanie biletu dokumentu przed szukaniem dojdzie w L75, razem z generacją.
- L73
Upload z przeglądarki
Klient uploadu: wysłanie pliku razem ze zgodą, przechowanie biletu, usuwanie i reset stanu. Do tego pole w kreatorze w najprostszej wersji, żeby całą ścieżkę było widać w przeglądarce. Porzucone żądanie przerywamy, bo upload uruchamia płatne osadzenia.
- L74
Stany pola dokumentu
Pole działa, ale nie mówi, co się z nim dzieje. Dokładamy stan wczytywania i usuwania, poprawną odmianę liczby fragmentów, powiązanie komunikatów z polem dla czytnika ekranu oraz przeniesienie focusu po zakończonej operacji.
- L75
Quiz z materiału użytkownika
Domykamy funkcję. Kontrakt generacji dostaje trzy powiązane pola: dokument, bilet i zgodę - razem albo wcale. Generator dokłada fragmenty do promptu jako wyraźnie oznaczony materiał źródłowy i nie robi tego, jeśli którakolwiek bramka nie przejdzie.
- L76
Testy ścieżki uploadu
Upload ma najwięcej ścieżek błędu w całym produkcie, więc domykamy go trzema testami: odrzucenie złego żądania i złego pliku na wejściu, poprawny przebieg mimo nieudanego sprzątania starych dokumentów oraz błąd w środku, po którym dokument musi zniknąć z bazy.
- L77
Polityka prywatności obok zgody
Zgoda przy polu dokumentu obiecuje, że użytkownik wie, co się dzieje z jego plikiem, więc musi mieć gdzie to przeczytać. Integrujemy stronę prywatności opisującą realne przepływy danych tego produktu i podłączamy do niej odnośnik z pola dokumentu.
Checkpoint: PDF staje się źródłem pytań, a dokument można bezpiecznie usunąć.
11Quiz z asystenta AI
3 lekcje · 1 h · od 08.03.2027
Efekt: Challenge tworzony z rozmowy z asystentem przez narzędzie MCP.
- L78
Osobny proces i transport
MCP to protokół, przez który asystent AI korzysta z narzędzi. Serwer MCP to osobny pakiet i osobny proces, z własnymi zależnościami i własnym TypeScriptem. Integrujemy transport przez standardowe wejście i wyjście procesu (stdin/stdout), a potem czytamy jedyną regułę tego transportu: na standardowym wyjściu jest wyłącznie protokół, więc console.log potrafi zepsuć sesję, a diagnostyka idzie na wyjście błędów (stderr).
- L79
Narzędzie tworzące challenge
Rejestrujemy narzędzie, które asystent może wywołać: waliduje wejście kontraktem, generuje quiz, zapisuje go i zwraca publiczny link. Kolejność jest nienaruszalna - najpierw generacja, potem zapis, bo zapis wymaga biletu wydanego przy generacji. W opisie narzędzia mówimy wprost, że wywołanie kosztuje pieniądze.
- L80
Test protokołu i uruchomienie
Test, który uruchamia prawdziwy proces i przechodzi prawdziwy protokół: nawiązanie sesji, walidacja wejścia i kolejność wywołań API. Do tego krótki runbook - jak uruchomić serwer i dlaczego nie dostaje żadnego sekretu aplikacji.
Checkpoint: Asystent tworzy challenge i zwraca działający publiczny link.
12Odbiór wersji Pro
8 lekcji · 2.5 h · od 22.03.2027
Efekt: Pełna wersja Pro odebrana przez E2E, SEO i końcowy smoke produkcji.
- L81
Środowisko testów przeglądarkowych
Testy całej ścieżki (e2e) muszą być powtarzalne i darmowe, więc integrujemy Playwright z jedną przeglądarką, kontrolowaną atrapę API i kontrolowaną atrapę bazy. Reguła, którą czytamy najuważniej: nieznane żądanie kończy test błędem, a nie cichym przejściem do prawdziwej usługi.
- L82
Ścieżka twórcy i gracza
Jeden test, który przechodzi cały produkt: generacja, zapis, otwarcie linku, start partii, trzy typy pytań, podpowiedź, odświeżenie w środku gry, wysłanie odpowiedzi, wynik, podsumowanie, ranking, feedback i udostępnienie. Piszemy go na zachowaniu użytkownika: test szuka elementów po roli i widocznym tekście, nie po klasach CSS.
- L83
Ścieżka z dokumentem
Drugi scenariusz przeglądarkowy: zgoda, wgranie PDF, ponowienie po błędzie, generacja z materiału i usunięcie dokumentu. Integrujemy go, bo ścieżka jest wąska, a jej wartością jest dowód, że opt-in i usuwanie działają razem.
- L84
Minimum SEO
Strona główna ma być do znalezienia w wyszukiwarce, a treści tworzone przez użytkowników nie mają być indeksowane. Integrujemy adres kanoniczny (jeden oficjalny adres strony) liczony z zaufanego originu, tytuły, opisy, statyczną grafikę podglądu i reguły dla robotów w robots.txt.
- L85
Ekran błędu i ostatnie szlify interfejsu
Ostatnia lekcja dotykająca interfejsu. Integrujemy globalny ekran błędu oraz drobne szlify, które zostały: zdanie o regule rankingu na ekranie startu i powrót listy odpowiedzi na górę po zmianie pytania.
- L86
Test SEO i nagłówków
Trzeci scenariusz przeglądarkowy, który pilnuje rzeczy najłatwiejszych do zepsucia przy zmianie konfiguracji: adres kanoniczny, indeksowanie, nagłówki bezpieczeństwa i dostępność strony prywatności.
- L87
Preview pełnej wersji Pro
Rozszerzamy procedurę z L53 o odbiór pełnej wersji Pro na Preview, czyli osobnym środowisku wdrożenia obok produkcyjnego. Wdrażamy dokładny commit z kompletem konfiguracji i świeżą bazą finalnego produktu. Smoke obejmuje funkcje DevChallenge oraz ranking, feedback na żywo, PDF i MCP.
- L88
Production i odbiór Pro
Ostatnia lekcja budowy produktu. Potwierdzamy konfigurację produkcyjną i twardy limit wydatków u dostawcy modelu, promujemy zaakceptowany commit z Preview na produkcję, bez ponownego budowania, i powtarzamy smoke pełnej wersji Pro. Domykamy README opisem gotowego produktu i pełną listą komend weryfikacji. W README zostaje miejsce na adres produkcji: wpisujesz tam swój własny. Aplikacja jest skończona; M13 dokłada do niej automatyzacje, nie zmieniając jej kodu.
Checkpoint: E2E, SEO, prywatność i pełny smoke potwierdzają gotowość rozszerzonej produkcji.
13Automatyzacje n8n
3 lekcje · 1 h · od 05.04.2027
Efekt: Automatyzacje n8n podłączone do Twojej aplikacji: workflow wysyłki quizu mailem i cotygodniowego raportu wyników. Wszystko budujesz w n8n krok po kroku, bez pisania kodu. Łączysz gotową aplikację z zewnętrznymi narzędziami, a kompletne scenariusze masz też w materiałach, żeby w razie potrzeby szybko porównać swój układ. Scenariusze działają, gdy instancja n8n jest uruchomiona; jej produkcyjny hosting nie należy do zakresu modułu.
- L89
n8n lokalnie i automat na Twoim API
Odpalasz n8n lokalnie jedną komendą - bez instalowania Dockera i bez zakładania płatnych kont. Budujesz swój pierwszy scenariusz, który według harmonogramu pobiera ranking graczy z Twojej aplikacji i wyświetla aktualne dane. Pokazuję Ci, jak Twoje API może bez żadnych zmian współpracować z zewnętrznym automatem.
- L90
Quiz wysłany mailem przez automat
Tworzysz prosty formularz do generowania quizu i łączysz go z automatyczną wysyłką e-mail. Podajesz temat, poziom i adres odbiorcy - automat generuje wyzwanie przez Twoje API, zapisuje je w bazie i wysyła gotowy link prosto do skrzynki gracza. Na koniec rozszerzasz to o wysyłkę grupową: wpisujesz listę maili i każdy dostaje swoje zaproszenie.
- L91
Cotygodniowy raport wyników
Budujesz scenariusz, który w każdy poniedziałek rano zagląda do bazy danych, zbiera statystyki i wysyła Ci podsumowanie na maila: ile osób zagrało i kto zdobył najwięcej punktów. Dostęp do bazy konfigurujesz bezpiecznie w n8n, bez pokazywania haseł w kodzie. W bonusie dostajesz też powiadomienie za każdym razem, gdy ktoś ukończy grę.
Checkpoint: Wpisujesz temat i maile, a automat tworzy quiz i wysyła zaproszenia. W poniedziałek rano dostajesz maila z podsumowaniem wyników.
Nie masz pewności, czy to dobry poziom? Odbierz Roadmapę od razu i zapisz się na premierę Modułu 0 (1 października) - cztery zadania rozstrzygną to w godzinę, zanim zapłacisz.
Odbierz Roadmapę i Moduł 0 za 0 zł