Projekt aplikacji SaaS
8 godz. 8 min · Next.js · Full-stack i Programowanie
Daniel NoworytaFull stack DeveloperNaucz się tworzyć bezpieczne systemy uwierzytelniania i autoryzacji, korzystając z Clerk. Pokażę Ci, jak to robić krok po kroku, aby Twoje aplikacje były bezpieczne i profesjonalne.
Zrozumiesz, jak skutecznie i bezboleśnie połączyć swoją aplikację Next.js z bazą danych PostgreSQL na DigitalOcean. Pokażę Ci, jak używać Prismy, aby ułatwić ten proces.
Dowiesz się, jak zarządzać routingiem i nawigacją w swojej aplikacji, aby użytkownicy mogli łatwo i intuicyjnie poruszać się po Twojej stronie.
Pokażę Ci, jak z łatwością wdrożyć swoją aplikację na Vercel, jednym z najpopularniejszych środowisk hostingowych dla aplikacji Next.js.
Nauczysz się zarządzać stanem aplikacji i jak wykorzystać server actions w praktyce, co pozwoli Ci na tworzenie bardziej zaawansowanych i dynamicznych funkcji.
Ten kurs jest dla osób, które już mają pewne doświadczenie z JavaScript i chcą zgłębić swoje zrozumienie Next.js. Zakładamy, że znasz podstawy TypeScript, TailwindCSS, ale nie potrzebujesz doświadczenia z Next.js - wszystko wyjaśnię Ci od podstaw!
Kolejną rzeczą, którą musimy zrobić to zainstalować clienta Primy tak żebyśmy
mogli wchodzić w interakcje z naszą bazą danych.
Jeżeli chodzi o klienta
jest to paczka dostarczona nam przez Prime, która pozwala nam wchodzić w
interakcje z bazą danych za pomocą schematu, który sobie przygotowaliśmy.
Schematu naszej bazy danych także.
W tym celu musimy sobie zainstalować naszego klienta.
Przejdźmy teraz do terminala poleceniem npm install prisma.
Klient Zainstalujemy sobie naszego klienta w naszym projekcie.
W tym momencie w naszym pliku pkt powinien pojawić się Prisma Client.
Mamy już Prisma Client.
Teraz możemy wchodzić w interakcję naszego klienta.
Natomiast jeszcze zanim będziemy wchodzić
sobie w interakcje, musimy przygotować połączenie naszego klienta z naszą bazą
danych i w tym celu stworzymy sobie osobny moduł w naszej aplikacji.
Zróbmy sobie folder lib, gdzie stworzymy sobie moduł db TS.
To jest połączenie, które musimy sobie
skonfigurować w takim celu, żebyśmy mogli łączyć się aplikacją Nexus ze sobą, z
naszym klientem Prima Client i wchodzić w interakcje z naszą bazą danych.
Nie ma to tak naprawdę nic nadzwyczajnego.
Tworzymy globalnego klienta Prisma Client.
Jeżeli to jest na produkcji, to chcemy
stworzyć Global for Prisma Prisma o takim samym typie jak Prisma.
To już teraz możemy wchodzić w interakcje z naszym klientem.
Natomiast zanim to zrobimy, oczywiście
musimy zmiksować naszą bazę danych, żeby stworzył nam się klienta Apex Prisma
TF i możemy sobie powtórzyć migrację i dzięki temu już nasz klient powinien się
nam stworzyć w naszym w naszym systemie wyczyści to okienko.
W tym momencie możemy przejść do naszego edytora kodu i możemy zająć się tworzeniem
modułu, który będzie decydował naszą bazę danych.
W tym celu stworzymy sobie plik w folderze Prisma o nazwie Sites
i będzie to nic innego jak plik, w którym będziemy sobie cytowali naszą bazę danych.
Generalnie większość takich plików wygląda w taki sposób, że ma główną funkcję main,
którą później eksportujemy, czyli async function main.
I tutaj w środku mamy całą logikę tworzenia naszych użytkowników.
W naszym przypadku chcemy sobie stworzyć użytkownika już z predefiniowane
subskrypcje sami i opłatami na te subskrypcje.
Dlatego też robimy sobie const user
i tutaj już możemy sobie wykorzystać Prisma, czyli klienta.
Z tego połączenia, które sobie tutaj stworzyliśmy zauważ, że importujemy Prisma
właśnie z lib db czyli z tego folderu DB mamy Prisma.
I tutaj teraz user.
Zauważ, że mamy już podpowiadanie typów.
Dzięki temu, że mamy silnie typowane to wszystko w interakcji z bazą danych.
Dzięki Prisma, dzięki klientowi my także
user i absurd, bo w naszym przypadku chcemy albo tworzyć nowego usera, albo go
update jeżeli już istnieje w naszej bazie danych.
I teraz pierwsza rzecz, którą musimy zrobić jeżeli chodzi o absurd musimy
filtrować, musimy go jakoś wyselekcjonować.
Czyli zrobimy sobie worek i za pomocą email email.
Jest to rzecz, która jest jeżeli chodzi o naszych userów i ma unikatową rzecz.
Czyli możemy sobie wykorzystać to do selekcji naszego użytkownika, którego
będziemy chcieli czy to stworzyć czy update w naszej bazie danych.
I tutaj ja sobie skorzystam z mojego prywatnego maila gmail com.
Jeżeli chodzi o selekcję użytkownika, którego chcemy stworzyć.
To będzie wszystko.
Kolejne rzeczy, którymi musimy się zająć to na pewno
będzie update, jeżeli chcemy update na rzecz użytkownika.
No i na pewno będzie Create.
Jeżeli chcemy stworzyć nowego użytkownika musimy podać odpowiednie dane, które są
niezbędne do tego, żeby stworzyć użytkownika w naszym systemie.
Kolejna rzecz, która będzie też potrzebna
to include, bo chcemy sobie pobrać tego użytkownika na końcu z subskrypcji sami.
Zacznijmy najpierw od danych, które będą
niezbędne do tego, by stworzyć naszego użytkownika.
I tutaj ideę będzie nam bardzo fajnie
podpowiadało, jeżeli chodzi o rzeczy, które musimy dostarczyć.
Jest to email id name.
Tutaj już widzimy, że coś jest nie tak jak powinno być.
Subskrypcje z małej litery.
Sprawdźmy sobie jak wygląda nasz model, czy nie powinniśmy błędu.
Tak, jak najbardziej. Tutaj mamy błąd.
Generalnie rzecz biorąc powinno być z
małej literki, czyli wszystkie subskrypcje powinny być małą literę.
Za każdym razem kiedy wprowadzasz zmianę
swój plik print na Steama musisz albo wygenerować klienta.
Jeżeli jeszcze nie chcesz robić migracji do bazy danych, żeby tylko pracować po
stronie swojej R, bo zrobić całą migrację, która automatycznie
generalnie wygeneruje Ci nowego klienta po stronie Twojej tutaj next Czy jest okej?
My w tym przypadku skorzystamy z tej pierwszej opcji czyli MPX firma Generate.
Na chwilkę obecną nie chcemy robić żadnej migracji.
W tym momencie powinny nam się wygenerować
już nowe typy, czyli przejdziemy do tego SID.
TS To jeżeli weźmiemy sobie to co chcemy budować to mamy subskrypcję mamy
z małej litery, także jak najbardziej możemy sobie już zrobić wyselekcjonować,
że chcemy subskrypcję pobierać razem z użytkownikiem.
I teraz dane, które będziemy wykorzystywać
tutaj do do kreacji naszego nowego użytkownika.
Pierwsza rzecz na pewno potrzebujemy jakieś imię, email i ID.
Zróbmy sobie ID i niech to będzie test.
1.2.3.
Jeżeli chodzi o e-mail to możemy to pole tak naprawdę skopiować
stąd, bo chcemy stworzyć sobie takiego użytkownika jeżeli będziemy go tworzyli.
Jeżeli chodzi o imię to ja sobie użyję mojego imienia i nazwiska.
No i w tym momencie mamy podstawowe informacje, które są potrzebne nam do
stworzenia użytkownika w naszej bazie danych.
Natomiast to nie wszystko, bo każdy użytkownik ma jakieś subskrypcje.
Chcielibyśmy sobie jakoś
predefiniowane subskrypcje w naszym systemie, żebyśmy mieli na czym pracować,
czyli już stworzymy je, jako że to jest opcjonalne.
Mamy tutaj subskrypcję i tutaj w obiekcie możemy sobie.
Ja przygotowałem dane testowe, które
możemy sobie wykorzystać, skopiować wszystkie subskrypcje
i w tym momencie pojawiają się pewne błędy związane z prawdopodobnie z typami.
Natomiast najpierw przejdźmy sobie przez
wszystkie importy, żeby wszystko to było zgodnie ze sztuką.
Czyli tutaj możemy sobie zaimportować subskrypcję Billing period.
Jest to typ, który już powinien zostać dla
nas stworzony, dlatego, że mamy go w naszym.
W naszej SCM jest Prime, czyli możemy spokojnie to zaimportować.
Jeżeli chodzi o karencji to też możemy sobie zaimportować to tutaj.
Jeżeli chodzi o Random Day to musi być funkcja, którą napiszemy teraz.
Chcemy tutaj jako start date, jako że chcemy żeby te dane były
jak najbliżej sytuacji, którą symuluje używanie naszej aplikacji.
Chcemy, żeby te dane były jakąś randomowo
datą, powiedzmy od pierwszego stycznia tego roku do dnia dzisiejszego, w
zależności od tego kiedy użytkownik założył konto, kiedy sobie dodał nową
subskrypcję do tego systemu, start będzie się różnił.
Dlatego chcemy tę sytuację jak najlepiej zasymulować.
Ja tutaj na boku przygotowałem funkcję,
która pozwoli nam wygenerować randomowo datę z dwóch dat start i end.
Prosta funkcja, która przyjmuje dwie daty
start i end i daje nam z tego zakresu jakąś randomowo datę.
I teraz możemy sobie ten random date tutaj wykorzystać.
Natomiast cały czas mamy tutaj jakieś
błędy i jest to związane prawdopodobnie z tym, że coś zrobiliśmy jeszcze źle w
naszym systemie jeżeli chodzi o typy status.
Zastanówmy się.
Jeżeli chcemy dodawać jakąś jakąś subskrypcję do naszego systemu, to
domyślnie powinna ona mieć tak naprawdę status aktywny.
Sprawdźcie sobie nasz schema schema w w
naszych danych i czy mamy tutaj aktywny status jako domyślny.
No widać, że coś jest nie tak, bo tak naprawdę
status naszej subskrypcji powinien być jako domyślny, jako aktywny.
Czyli musimy sobie jeszcze troszeczkę tutaj zmodyfikować naszą bazę danych.
Przy okazji dodamy sobie dni frontowe
wartości dla innych rzeczy w tym kinie, o których zapomnieliśmy na początku.
Dlatego jeżeli chodzi o sad krótszym
karencji możemy tutaj wykorzystywać default i niech to będzie polska złotówka.
Jeżeli chodzi o
starty możemy sobie zaznaczyć, że to jest pole date w bazie danych.
Jeżeli chodzi o NBP też możemy sobie zaznaczyć to jest pole date.
W bazie danych. Tutaj jeszcze silniej typujemy
te pola mówiąc, że to jest data, ale data tego typu.
Jakiego typu jest nasza baza danych jeżeli chodzi o billing?
Zróbmy sobie, że to będzie default monthly w zależności od tego,
żeby tego nie musieć na zewnątrz podawać naszych danych testowych.
Jeżeli chodzi o DateTime możemy sobie
zrobić tutaj DB date tak samo jak mieliśmy to tutaj.
Tutaj nie potrzebujemy żadnych default nowych wartości.
Powinny one być dostarczone przez naszego użytkownika.
Jeżeli chodzi o subskrypcję status no to
chcielibyśmy żeby default był to status aktywny.
Bo tak naprawdę jeżeli użytkownik wprowadza nową subskrypcję do naszego
systemu, to chcemy, żeby ta subskrypcja była generalnie aktywna.
Na razie nie umożliwiamy naszym
użytkownikom wprowadzenia danych na temat subskrypcji, które są gdzieś tam
z czasu przeszłego w celach statystycznych.
Tylko i wyłącznie na razie skupiamy się na tym, żeby użytkownik może stawiać sobie
swoje aktywne subskrypcje, żeby mógł sobie śledzić opłaty za te aktywne subskrypcje.
No i teraz jak przejdziemy sobie do CIT, to tutaj tak naprawdę jeszcze nam się nic
nie zmieniło, bo jak widzisz status cały czas jest wartością wymaganą.
Co musimy zrobić?
Musimy sobie wygenerować nowego klienta czyli Mpx rate.
I w tym momencie mamy klienta wygenerowanego.
Natomiast jako że wprowadziliśmy zmiany w.
Zobacz, że tutaj wszystko mamy zielone.
Super, Ale tak naprawdę to co zrobiliśmy
tutaj jeszcze nie jest odzwierciedlone w naszej bazie danych.
Żeby to wszystko, czyli te zmiany z tego
modelu, który mamy tutaj, były odzwierciedlone w naszej bazie danych.
No, musimy sobie wykonać migrację do naszej bazy danych, czyli w tym momencie
przejdziemy NPS i może być nazwa i możemy sobie zmienić tą nazwę.
Ja tak naprawdę będę cały czas tutaj.
Na razie to sobie instalujemy nasz schemat.
Tutaj wykonamy nową migrację.
W tym momencie już te zmiany powinny być też odzwierciedlone w naszej bazie danych.
Mamy to wszystko już za sobą jeżeli chodzi o plik.
Jeżeli chodzi o część Create mamy za sobą jeżeli chodzi o naszego usera.
No na pewno musimy też zrobić.
Jeżeli chodzi o część update też musimy zrobić to samo
jeżeli chodzi o tą część UPDATE Czyli możemy sobie przekopiować dane na temat
subskrypcji, które mamy tutaj poniżej i wrzucimy je tutaj do tego użytkownika.
Żeby był.
Jeżeli ten użytkownik już istnieje, to chcemy mu stworzyć subskrypcje, żeby je.
Chcemy się upewnić, żeby je po prostu miał.
Teraz przejdźmy sobie do dalszej części tego skryptu znajdującego, bo tak naprawdę
mamy tylko subskrypcję, ale nie mamy jeszcze danych związanych z tymi.
Subskrypcja, czyli płatności, to co jest
tak naprawdę najważniejsze, co chcemy sobie tutaj śledzić?
No to zróbmy sobie nowy Connect Update subskrypcję.
I tutaj jest bład.
Prom jest niemal.
Teraz żeby update ować wszystkie
subskrypcje to musimy sobie mapować przez nie wszystkie i dla każdej subskrypcji
stworzyć jakiś payment i z update tą subskrypcje na końcu.
Czyli zrobimy sobie właśnie dla tego
promise all żeby teraz móc zrobić user subskrypcje IMAP.
Dzięki temu będziemy mieli dostęp do pojedynczej, pojedynczej subskrypcji.
To jest pojedyncza subskrypcja w naszej mapie i tutaj.
Teraz jeżeli chodzi o wartości, które musimy wygenerować, to na
pewno każda subskrypcja musi mieć jakiś payment payment potrzebuje datę i status.
Musimy sobie tutaj stworzyć dwa koncerty.
Jeżeli chodzi o typy payment status to jak najbardziej możemy sobie zaimportować, bo
są to typy, które już są w naszej Steamie w naszej prośbie.
I tutaj jeżeli chodzi o is before jest to funkcja, która pochodzi z Date Events.
Jako, że nie mamy jeszcze zainstalowanego
data w naszym systemie, to możemy teraz przeskoczyć do naszego
terminala i zainstalować sobie paczkę dat do pracy z datami.
W naszym projekcie npm Install Data save zainstalujemy naszą paczkę
i jest to paczka, której ja bardzo często korzystam jeżeli chodzi o data framework.
Myślę, że bardzo fajna paczka do pracy z datami w swoim projekcie.
Mają bardzo fajny helper.
Twórcy tej paczki przygotowali helper jak i student, który jest bardzo przydatny.
Czy możemy dodać sobie po prostu
specyficzną liczbę miesięcy do daty, którą podajemy jako parametr do tej funkcji?
Bardzo fajna paczka, Polecam.
Jeżeli pracujesz ze swoimi projektami, potrzebujesz pracować na danych na datach.
Myślę, że warta wykorzystania.
Ja sobie teraz to po prostu importuje i z tej paczki jeżeli chodzi
Get random date cannon musimy sobie stworzyć taką taką funkcję.
Będzie ona generalnie wyglądać bardzo
podobnie do tej funkcji, którą sobie już tutaj wcześniej stworzyliśmy Random date.
Natomiast tutaj będziemy potrzebować dwóch rzeczy.
Musimy sobie zawsze wziąść dzisiejszą datę
jeżeli startujemy, bo jeżeli chodzi o kalendarz to musimy mieć jako dana
wyjściowa dzień dzisiejszy start miesiąca i koniec miesiąca
pobierzemy sobie za pomocą właśnie paczki date, która pozwala nam bardzo łatwo
wykorzystać datę dzisiejszą do tego, żeby uzyskać start i end miesiąca.
Jeżeli chodzi o
ostatnią część, no to jeżeli potrzebujemy randomowe daty
w obecnym miesiącu to użyjemy start i end i wypisujemy tak jak to było tutaj.
Tak naprawdę
datę z przedziału start i end i w tym momencie uzyskamy Get random dating month.
Już mamy przygotowaną get random dating month.
Jeżeli chodzi o tą funkcję to musi być
to funkcja tak naprawdę synchroniczna jeżeli chodzi o te mapowanie.
Czyli musimy zrobić ASAP.
No i przejdźmy teraz do.
Jeżeli chodzi o payment to stworzenia tych pigmentów, czyli potrzebujemy user.
What price ma payment triad?
Musimy stworzyć jakiś payment.
Jeżeli chodzi o select to
nie musimy tak naprawdę tego w żaden sposób selekcjonować.
Na razie musimy sobie po prostu stworzyć
prosty model payment, czyli potrzebujemy jakąś datę, która będzie przyjmowała.
Jeżeli chodzi o ideę, też mamy bardzo fajnie podpowiedzi.
Jest to związane z tym, że już określiliśmy sobie model, który
mamy, model naszych danych, który jest określony w Schema Prisma Amount.
Niech to będzie subskrypcja on price.
Sprawdzimy dlaczego nie mamy podpowiadania typów.
Oczywiście musimy sobie.
Jeżeli chodzi o absurd, jest to promise, czyli musimy sobie zrobić VAT.
Dzięki temu będziemy mieli tutaj już typ subskrypcji a subskrypcji.
Oczywiście wyskoczyliśmy sobie poza naszą
mapę, co jest niedopuszczalne, bo musimy zostać w zakresie naszej mapy.
Dlatego też teraz już mamy wszystko będzie dobrze.
Podpowiadanie typy.
Kolejna rzecz, którą musimy sobie zrobić to na pewno musimy z update Nasze
subskrypcje, czyli tutaj już możemy zrobić sobie return.
To będzie ostatnia akcja, która będzie
wymagała od naszego skryptu budującego Prisma subskrypcji Update.
No i tutaj już musimy sobie
wyselekcjonować, którą subskrypcję chcemy w update ować, czyli we subskrypcję ID.
W naszym przypadku to będzie ID subskrypcji i kropka ID.
To jest tego z tej mapy, którą sobie na pójdziemy, które już mamy.
Jeżeli chodzi o dane to jest data i tutaj co potrzebujemy na pewno
potrzebujemy z update eksperymentalnie, czyli next payment.
Niech to będzie.
Niech to będzie bazowało na zasadzie payment status.
No bo tutaj stworzyliśmy sobie logikę, która bierze
randomowy update z naszego obecnego miesiąca.
Jeżeli dzisiejsza data jest przed tą datą,
to musimy powiedzieć, że jeszcze jakby opłata nie jest, że jest
zapłacona, że jeżeli data płatności data płatności tego pigmentu jest przed
dniem dzisiejszym to znaczy, że payment domyślnie już będzie zapłacony.
Wychodzimy z założenia, że użytkownicy
opłacają swoje subskrypcje jeżeli chodzi o dane do cytowania.
Natomiast jeżeli data płatności będzie np.
jutro czy pojutrze to chcemy status, że jeszcze nie jest paid.
Żeby to też odzwierciedlało w naszych danych testowych realną sytuację.
Dlatego też tutaj jeżeli chodzi o next
payment date możemy sobie to bazować też na statusie to jeżeli.
Jeżeli status równa się Payment status
payment status i załóżmy, że będzie paid to chcemy dodać miesiące.
No bo jeżeli już coś jest zapłacone, czyli było np.
wczoraj, przedwczoraj, no to musimy zrobić plus 1 miesiąc czy plus billing period.
Do tego, żeby wygenerować dane na temat
następnej płatności, czyli w naszym przypadku będzie to funkcja month.
Inne Experiment Month Generator Musimy tą funkcję stworzyć.
Armand to jest funkcja date, więc jest
natomiast next Payment monety Generator jest to nic innego jak prosta instrukcja
switch, która będzie nam przeskakiwała tutaj przez period.
Mamy tutaj różne rodzaje.
Sprawdzimy czy rzeczywiście mamy poprawnie
to w naszym sabacie, czyli tutaj jest niepoprawne.
Powinno być tak zapiszemy to.
Oczywiście zmieniliśmy schema, dlatego nowa migracja by się przydała.
Emigracje?
Ah, jeszcze tak, oczywiście chcemy tą migrację.
Mamy quarterly.
A jeżeli jest pat to musimy dodać 1 miesiąc.
Natomiast jeżeli nie jest to tak naprawdę data następnej płatności to będzie tak.
Już w tym momencie mamy zrobiony cały skrypt, który zasila naszą bazę danych.
Jeszcze ostatnia rzecz, która jest niezbędna to musimy sobie wywołać tą
funkcję w naszym skrypcie main i tutaj robimy ten.
I jeżeli chodzi o funkcje to jest
asynchroniczne funkcja i tutaj sobie ułatwić ma.
I tutaj możemy zrobić disconnect.
Jeżeli chodzi o jakieś błędy to chcemy tak
naprawdę je obsłużyć sobie i jeżeli chodzi o obsługę błędów to chcemy
sobie logować tak naprawdę wszystkie błędy, które się nam pojawią.
Także usuń Control Error i Prisma Disconnect i chcemy wyjść z procesu.
To jest cały nasz skrypt znajdujący, który
będzie dostępny w branch do rozwiązania tego.
Do rozwiązania tej części tego warsztatu.
Natomiast kolejna rzecz, którą potrzebujemy, żeby w ogóle ten skrypt
wykorzystać, potrzebujemy skrypt w naszym pliku packages,
który będzie odpowiedzialny właśnie za SID naszej bazy danych.
I generalnie rzecz biorąc to wszystko jest opisane w dokumentacji.
Natomiast ja żeby skrócić mamy plik SID, który pobiera nam teraz
config sid potrzebujemy ten nowy plik ts config, który będzie
skonfigurowany pod serwowanie naszej bazy danych.
I tutaj mamy adres pliku
z którego chcemy zbudować, czyli w naszym przypadku jest to Prisma Sid Sites.
I jeszcze jedna rzecz, której nie mamy w
naszym naszym folderze to tez config side on.
Jest to plik z konfiguracją tego skryptu specjalnie pod side.
Niestety w projekcie Next musimy sobie coś takiego zrobić czyli ts config.
Sid Jackson i wklejamy sobie tutaj specjalny config.
Jeżeli chodzi o SID chcemy sobie cytować właśnie z tym config.
W tym momencie jeżeli przejdziemy sobie do
naszej przeglądarki i odpalimy localhost 5000
to sprawdzimy sobie, że nie mamy jeszcze żadnych danych w naszej bazie danych.
Natomiast jeżeli wszystko udało nam się
zrobić poprawnie, to jeżeli uruchomimy sobie npm Prisma Sid to powinno
to skutkować tym, że pojawią się informacje w naszej bazie danych.
Mpx.
Zobacz.
Skrypt poprawnie przeszedł.
Nie dostaliśmy żadnego błędu.
Jeżeli teraz sobie przejdziemy do naszej przeglądarki, odświeżamy okienko.
To już mamy naszego usera,
który ma 11 subskrypcji, które są podane z naszych danych testowych.
Czyli co już są dane, na których będziemy mogli sobie
dalej w naszej aplikacji pracować i które będziemy mogli sobie dalej obrabiać.
Jeżeli chodzi o Payments.
Zobaczmy jakie prezenty nam wygenerowało.
Jeżeli chodzi o mamy kilka momentów, że
już są zapłacone, mamy bardzo dużo jeszcze niezapłaconych.
Jeżeli chodzi o dzisiejszą datę, to u mnie jest 17 czerwiec, także te, które były
przed 17 czerwca zobacz drugi czerwca 15 czerwca 14 czerwca są już zapłacone.
Te, które są po 17 czerwca 25, 30, 20, 18 są niezapłacone.
Także mamy poprawną poprawne usytuowanie naszej bazy danych.
Teraz przejdziemy do routingu naszej aplikacji.