Rezerwacja i zakup biletów na spektakle
Translation pending
CommerceTypeScript · JavaScriptGitHub @SzymonWegrzynekOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Projekt zespołowy z przedmiotu Projektowanie i Architektura Systemów. Klient wybiera spektakl i miejsce, rezerwuje je na 15 minut, a potem kupuje bilet i dostaje kod. Etap I działa bez płatności online.
| Osoba | Zakres |
|---|---|
| Szymon | kontrakt wewnętrzny, setup, baza, rezerwacja i zakup (backend) |
| Olek | dane przykładowe, repertuar, plan widowni, ekran biletu |
| Paweł | lista spektakli (backend), walidacja, formularz z licznikiem, integracja, testy |
Zadania: Trello → workspace BiletowyProjekt, tablica Taski.
| Co | Czym |
|---|---|
| Front + API | Next.js (App Router) + TypeScript |
| Baza danych | MongoDB Atlas (darmowy klaster) + oficjalny sterownik mongodb |
| Wygląd | Tailwind CSS |
| Walidacja | Zod |
| Testy | Vitest |
| Jakość kodu | ESLint + Prettier |
| Paczki | pnpm |
| Hosting | Vercel |
Wszystko jest w jednym projekcie i jednym repo. Front i backend (app/api) działają razem w Next.js.
teatr-kasa/
├── app/
│ ├── page.tsx # repertuar
│ ├── spektakl/[id]/page.tsx # plan widowni
│ ├── rezerwacja/[id]/page.tsx # licznik + zakup
│ ├── bilet/[code]/page.tsx # bilet
│ └── api/
│ ├── events/route.ts # GET /api/events
│ ├── events/[id]/route.ts # GET /api/events/:id
│ ├── reservations/route.ts # POST /api/reservations
│ └── reservations/[id]/purchase/route.ts # POST /api/reservations/:id/purchase
├── components/ # komponenty UI
├── lib/
│ ├── db.ts # połączenie z MongoDB
│ ├── schemas.ts # schematy Zod + typy
│ ├── errors.ts # kody i format błędów
│ ├── reservation.ts # zasady ważności rezerwacji
│ └── stubs.ts # zaślepki danych (do usunięcia po podpięciu bazy)
├── scripts/
│ └── setup-db.ts # indeksy + dane przykładowe
├── tests/ # testy API (Vitest)
├── .github/workflows/ci.yml # CI: lint, formatowanie, testy, build
├── .env.example
└── pnpm-lock.yaml
corepack enable
pnpm -v
⚠️ Używamy tylko pnpm. Nie uruchamiamy
npm installaniyarn. Commitujemypnpm-lock.yaml, nie commitujemypackage-lock.json.
git clone <url-repo>
cd teatr-kasa
pnpm install
cp .env.example .env # wklej MONGODB_URI od Szymona
pnpm dev # http://localhost:3000
Baza jest wspólna, w chmurze (Atlas) — nie trzeba niczego instalować lokalnie.
| Komenda | Co robi |
|---|---|
pnpm dev | uruchamia aplikację |
pnpm build | buduje wersję produkcyjną |
pnpm lint | sprawdza kod |
pnpm format | formatuje kod (Prettier) |
pnpm test | testy API |
pnpm db:setup | tworzy indeksy i wgrywa dane przykładowe |
pnpm add <paczka> | dodaje zależność |
⚠️
pnpm db:setupusuwa wszystkie dokumenty z kolekcjieventsireservationsw bazie wskazanej przezMONGODB_DB, a następnie wgrywa dane przykładowe. Na wspólnej bazieteatrmoże go uruchamiać tylko osoba odpowiedzialna za setup (Szymon). Do własnych prób używajMONGODB_DB=teatr-test.
| Zmienna | Opis |
|---|---|
MONGODB_URI | adres klastra Atlas (z hasłem) |
MONGODB_DB | wspólna baza aplikacji: teatr |
MONGODB_DB_TEST | baza dla pnpm test: teatr-test (domyślnie) |
RESERVATION_TTL_MINUTES | czas ważności rezerwacji w minutach (15) |
RESERVATION_RATE_LIMIT | rezerwacje z 1 IP na 10 s, potem 429 (30) |
.env nie commitujemy. Adres bazy przekazujemy sobie prywatnie..env.example.pnpm test zawsze działa na bazie z MONGODB_DB_TEST, żeby nie czyścić danych reszcie zespołu. Jeśli wskazuje tę samą bazę co MONGODB_DB, testy w ogóle nie ruszą.expiresAt w bazie, a nie czekając na upływ czasu.pnpm db:setup na wspólnej bazie uruchamia tylko Szymon.| Kolekcja | Pola |
|---|---|
events | _id, title, date, time, stage |
reservations | _id, eventId, seatId, customerName, email, status (held / purchased), expiresAt, code |
Indeksy (tworzone przez pnpm db:setup):
reservations: unikalny { eventId: 1, seatId: 1 } — jedno miejsce, jedna rezerwacjareservations: unikalny { code: 1 } (tylko dla kupionych)Wspólny dla wszystkich zespołów — nie zmieniamy nazw endpointów ani pól.
| Endpoint | Wysyłamy | Dostajemy |
|---|---|---|
GET /api/events | — | lista spektakli |
GET /api/events/:id | — | { event, takenSeats } |
POST /api/reservations | { eventId, seatId, customerName, email } | { reservationId, expiresAt } |
POST /api/reservations/:id/purchase | — | { code } albo odmowa |
takenSeats = miejsca kupione + miejsca z ważną rezerwacjąseatId = rząd + numer, np. "F7" (rzędy A–H, miejsca 1–10)Błędy: { "error": "opis", "code": "SEAT_TAKEN" }
| Kod | Kiedy |
|---|---|
| 400 | błędne dane (walidacja Zod) |
| 404 | brak spektaklu / rezerwacji |
| 409 | miejsce zajęte |
| 410 | rezerwacja wygasła |
Pilnuje ich baza, a nie same if-y w kodzie:
| Zasada | Jak |
|---|---|
| Podwójna rezerwacja | unikalny indeks + transakcja (usuń wygasłą → wstaw nową) |
| Zakup tylko ważnej rezerwacji | findOneAndUpdate({ _id, status: "held", expiresAt: { $gt: now } }, …) |
| Podwójny zakup | ponowienie zwraca ten sam kod |
| Błędne dane | schematy Zod w każdym POST |
Dlaczego unikalny indeks wystarczy na podwójną rezerwację: nie sprawdzamy w kodzie, czy miejsce jest wolne. Od razu próbujemy zapisać rezerwację, a MongoDB przy indeksie unikalnym { eventId, seatId } przepuści tylko jeden dokument dla danego miejsca, nawet gdy 20 requestów przyjdzie w tej samej milisekundzie. Pozostałe dostają błąd duplikatu E11000, który zamieniamy na 409 SEAT_TAKEN. Transakcja jest potrzebna tylko po to, żeby usunąć wygasłą rezerwację tego miejsca i wstawić nową jako jedną niepodzielną operację.
main — zawsze działająca wersja, zmiany tylko przez Pull Request. Nie commitujemy na nim bezpośrednio, GitHub i tak odrzuci push.mainNazwa gałęzi: prefiks/krotki-opis
| Prefiks | Kiedy | Przykład |
|---|---|---|
feat/ | nowa funkcja lub ekran | feat/plan-widowni |
fix/ | poprawka błędu | fix/licznik-po-odswiezeniu |
test/ | same testy | test/kontrakt-api |
docs/ | tylko dokumentacja (README.md, CLAUDE.md) | docs/przeplyw-ekranow |
chore/ | konfiguracja, paczki, CI, porządki — bez funkcji | chore/setup |
-, bez polskich znaków i spacji (plan-widowni, nie Plan_Widowni ani plan-widowni-ąę)fix/..., nie wracamy do starej| Szymon | Olek | Paweł |
|---|---|---|
feat/kontrakt-wewnetrzny | feat/seed | feat/api-events |
chore/setup | feat/repertuar | feat/walidacja |
feat/wygasanie | feat/plan-widowni | feat/formularz-rezerwacji |
feat/api-rezerwacja | feat/ekran-biletu | feat/integracja |
feat/podwojna-rezerwacja | test/kontrakt-api | |
feat/api-zakup |
feat: dodaj endpoint rezerwacji
fix: blokuj przycisk zakupu w trakcie wysyłania
maingit switch main && git pull
git switch -c feat/plan-widowni
# ...praca...
git add . && git commit -m "feat: plan widowni"
git pull origin main # zaciągnij zmiany innych
pnpm install # jeśli zmienił się pnpm-lock.yaml
git push -u origin feat/plan-widowni
# otwórz Pull Request na GitHubie
Kiedy otworzyć:
ReviewTytuł i opis:
feat: plan widowni/spektakl/dziady, kliknij F7 → 409”)Wymagania do merge (pilnuje ich ruleset na main):
lint, format, test, build) musi być zielonelib/db.ts, lib/schemas.ts, scripts/ i kontrakcie API — review Szymonapnpm-lock.yaml w tym samym PRReview:
Approve albo Request changesgit commit + git push) — nowe commity same trafiają do PR, nowego PR nie otwieramyKonflikty / „This branch is out-of-date”:
git switch feat/plan-widowni
git pull origin main # rozwiąż konflikty w edytorze, jeśli są
pnpm install # jeśli zmienił się pnpm-lock.yaml
git add . && git commit # tylko gdy były konflikty
git push
Bez konfliktów wystarczy przycisk Update branch w PR.
Merge:
main ląduje jeden commit z tytułem PRDoneKiedy zamknąć PR bez merge (Close pull request): zmiana okazała się niepotrzebna, kierunek się zmienił albo PR zastępuje inny — wtedy w komentarzu napisz dlaczego i podlinkuj nowy PR.
Gałąź usuwamy zaraz po merge — jest już w main, a stara gałąź tylko myli.
git switch main && git pull
git branch -d feat/plan-widowni # -d odmówi, jeśli coś nie jest zmergowane
git fetch --prune # usuwa lokalne odnośniki do skasowanych gałęzi zdalnych
Po Squash and merge git branch -d może zgłosić, że gałąź „nie jest w pełni zmergowana” (bo na main jest nowy, spłaszczony commit). Jeśli PR na GitHubie ma status Merged, usuń ją przez git branch -D.
Nie usuwamy main i gałęzi z otwartym PR.
main = wersja produkcyjna, każdy PR = podgląd0.0.0.0/0 (Vercel nie ma stałego IP)To Do → Doing → Review (otwarty PR) → Done (zmergowane)
Karta jest Done, gdy kod jest na main, testy przechodzą, a checklista w karcie jest odhaczona.