Przejdź do treści

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.

  1. Zadanie 115 min

    Ustawienia challenge'u

    Porządkujesz i walidujesz temat, nakładasz bezpieczny limit pytań i ustawiasz poziom trudności.

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

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

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

Mapa produktu

Jak przepływają dane przez DevChallenge

4 warstwy rdzenia · 4 funkcje Pro · Odbiór i automatyzacje n8n

Efekt i stackPubliczna aplikacja: interfejs, bezpieczne API, dane i AI.

Vue + Nuxt · Node.js + Nitro · PostgreSQL · AI SDK + Zod

Zobacz pełną architekturę i rozszerzenia Pro
Rdzeń aplikacjiKażda warstwa kończy się widocznym efektem
  1. 01

    Frontend

    Vue + NuxtKreator, challenge i wynik
  2. 02

    Backend

    Node.js + NitroAPI, limity i scoring
  3. 03

    AI

    AI SDK + ZodGenerowanie i walidacja
  4. 04

    Baza danych

    PostgreSQL + SupabaseChallenge i podejścia
Rozszerzenia ProDokładasz możliwości, które mają sens w prawdziwym produkcie
  • 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.

01

Start projektu

3 lekcje · 1 h · od 01.12.2026

Efekt: Projekt, który się uruchamia i ma jedną komendę pilnującą jakości.

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

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

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

02

Quiz na ekranie

6 lekcji · 2 h · od 01.12.2026

Efekt: Pytanie na ekranie z trzema typami odpowiedzi i obsługą klawiatury.

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

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

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

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

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

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

03

Pełna gra lokalnie

9 lekcji · 3 h · od 07.12.2026

Efekt: Pełna gra lokalnie: czas, podpowiedź, wynik i podsumowanie odpowiedzi.

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

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

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

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

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

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

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

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

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

04

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

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

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

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

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

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

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

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

  8. 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ść.

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

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

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

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

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

05

Zapis i publiczny link

7 lekcji · 2 h · od 28.12.2026

Efekt: Quiz zapisany w bazie i dostępny pod publicznym linkiem.

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

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

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

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

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

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

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

06

Uczciwy wynik na serwerze

8 lekcji · 2.5 h · od 04.01.2027

Efekt: Wynik i czas liczone przez serwer oraz bezpieczne wznowienie gry.

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

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

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

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

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

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

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

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

07

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

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

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

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

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

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

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

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

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

08

Ranking i udostępnianie

4 lekcje · 1.5 h · od 25.01.2027

Efekt: Ranking z poprawnymi remisami i wynik gotowy do udostępnienia.

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

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

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

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

09

Feedback AI na żywo

9 lekcji · 3 h · od 08.02.2027

Efekt: Feedback AI pojawiający się na ekranie na żywo.

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

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

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

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

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

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

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

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

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

10

Quiz z własnego PDF

11 lekcji · 3.5 h · od 22.02.2027

Efekt: Quiz generowany z własnego dokumentu PDF.

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

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

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

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

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

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

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

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

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

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

  11. 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ąć.

11

Quiz z asystenta AI

3 lekcje · 1 h · od 08.03.2027

Efekt: Challenge tworzony z rozmowy z asystentem przez narzędzie MCP.

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

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

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

12

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

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

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

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

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

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

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

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

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

13

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

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

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

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