Tim: Belmin Durmo · Harun Goralija · Amar Hodžić · Harun Mioč
Predmet: Napredne Web Tehnologije — Mart 2026.
Mikroservisna platforma za upravljanje sportskim centrom: rezervacije terena, najam opreme, plaćanje karticom (Stripe), notifikacije i loyalty program.
- Arhitektura
- Preduvjeti
- Brzi start (Docker)
- Lokalni razvoj (bez Dockera)
- Konfiguracija
- API pregled
- Stripe integracija
- JWT ključevi
- Asinhrona komunikacija (Saga)
- Frontend
- Testiranje
- Tech stack
Browser / React SPA
│
▼ HTTP :8080
┌─────────────────┐
│ API Gateway │ JWT validacija · CORS · Rate limiting
└────────┬────────┘
│ Eureka service discovery
┌──────┼──────────────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ User │ │ Resource │ │ Booking │ │ Payment │
│:8081 │ │ :8082 │ │ :8083 │ │ :8084 │
└───┬────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘
│MySQL │MySQL │MySQL │MySQL
:3307 :3308 :3309 :3310
┌───────────────────────────────────┐
│ RabbitMQ :5672 │ Saga choreography
└───────────────────────────────────┘
Config Server :8888 ← config-repo/ (central .properties files)
Eureka :8761 ← service registry
| Servis | Port | Opis |
|---|---|---|
| API Gateway | 8080 | JWT auth, RBAC routing, CORS, rate limiting |
| User Service | 8081 | Korisnici, autentifikacija (RS256 JWT), loyalty bodovi, achievements |
| Resource Svc | 8082 | Tereni, oprema, dinamičko cijene (pricing rules) |
| Booking Svc | 8083 | Rezervacije, grupne/ponavljajuće, recenzije, najam opreme |
| Payment Svc | 8084 | Plaćanja (Stripe), saved cards, notifikacije, dokumenti, sporovi |
| Config Server | 8888 | Spring Cloud Config — centralni .properties fajlovi |
| Eureka | 8761 | Service discovery — registar svih mikroservisa |
| Frontend | 80 | React SPA (Vite + TypeScript + TailwindCSS), nginx u Dockeru |
| RabbitMQ | 5672 | Message broker — AMQP; Management UI na :15672 |
| Alat | Minimalna verzija |
|---|---|
| Docker & Docker Compose | Docker 24+, Compose v2 |
| Java | 17+ (samo za lokalni razvoj bez Dockera) |
| Node.js | 20+ (samo za lokalni razvoj) |
| pnpm | 9+ (samo za lokalni razvoj) |
Maven wrapper (
./mvnw) je uključen u svaki servis — globalni Maven nije potreban.
git clone <repo-url>
cd SportsCenterSystem
cp .env.example .envOtvori .env i po potrebi postavi:
STRIPE_SECRET_KEYiSTRIPE_PUBLISHABLE_KEY(opciono — bez ključeva radi u fallback modu)INTERNAL_SECRET(promijeni na production)
docker compose up --build -dDocker će:
- Pokrenuti 4 MySQL baze + RabbitMQ
- Buildati i pokrenuti Config Server, Eureka, API Gateway
- Buildati i pokrenuti 4 mikroservisa
- Buildati React frontend i servirati ga nginxom na portu 80
docker compose psSvi kontejneri trebaju imati status healthy. MySQL kontejnerima treba ~30 sekundi za inicijalizaciju.
| URL | Šta je |
|---|---|
http://localhost |
React frontend |
http://localhost:8080 |
API Gateway |
http://localhost:8761 |
Eureka dashboard |
http://localhost:15672 |
RabbitMQ Management (guest/guest) |
docker compose logs -f # Živi logovi svih servisa
docker compose logs -f booking-service # Logovi jednog servisa
docker compose restart payment-service # Restart jednog servisa
docker compose up --build -d payment-service # Rebuild i restart jednog servisa
docker compose down # Gasi sve (podaci ostaju)
docker compose down -v # Gasi sve + briše podatke (fresh start)docker compose down -v
docker compose up --build -dZa lokalni razvoj backend servisa i Vite dev servera:
docker compose up -d mysql-user mysql-resource mysql-booking mysql-payment rabbitmq# Terminal 1
cd config-server && ./mvnw spring-boot:run
# Terminal 2
cd discovery-server && ./mvnw spring-boot:run# svaki u zasebnom terminalu
cd "User Service" && ./mvnw spring-boot:run
cd "Resource Service" && ./mvnw spring-boot:run
cd "Booking Service" && ./mvnw spring-boot:run
cd "Payment Service" && ./mvnw spring-boot:run
cd "API Gateway" && ./mvnw spring-boot:runcd frontend
pnpm install
pnpm dev # http://localhost:5173Sve se konfigurira kroz .env fajl. Centralne Spring konfiguracije za svaki servis nalaze se u config-repo/:
config-repo/
├── application.properties # Globalne postavke
├── api-gateway-dev.properties # Gateway: rute, JWT, rate limit, CORS
├── user-service-dev.properties # User Service: JWT ključevi, baza
├── resource-service-dev.properties # Resource Service: baza
├── booking-service-dev.properties # Booking Service: Feign, Resilience4j
└── payment-service-dev.properties # Payment Service: Stripe ključ, baza
| Varijabla | Default | Opis |
|---|---|---|
DB_USER |
sportcenter |
MySQL korisnik za sve servise |
DB_PASSWORD |
sportcenter123 |
MySQL lozinka |
STRIPE_SECRET_KEY |
(prazno) | Stripe server ključ (sk_test_...) |
STRIPE_PUBLISHABLE_KEY |
(prazno) | Stripe browser ključ (pk_test_...) |
INTERNAL_SECRET |
CHANGE_ME... |
Dijeljeni secret za /internal/revoke |
JWT_ACCESS_EXPIRATION |
900 |
JWT access token TTL (sekunde) |
RATE_LIMIT_MAX |
5 |
Max login pokušaja po IP/prozoru |
JPA_HIBERNATE_DDL_AUTO |
update |
Hibernate DDL — koristiti validate ili none u produkciji |
Svi zahtjevi idu kroz API Gateway (http://localhost:8080).
Zaštićeni endpointi zahtijevaju Authorization: Bearer <token>.
POST /api/auth/register Registracija novog korisnika
POST /api/auth/login Login → {accessToken, refreshToken}
POST /api/auth/refresh Refresh access tokena
POST /api/auth/logout Opoziv tokena
POST /api/auth/validate Validacija tokena (interno)
GET /api/users Svi korisnici
GET /api/users/{id} Korisnik po ID-u
GET /api/users/search?role=&q= Pretraga (paginovana)
POST /api/users Kreiranje korisnika
PUT /api/users/{id} Update korisnika
PATCH /api/users/{id} Parcijalni update (RFC 6902 JSON Patch)
DELETE /api/users/{id} Brisanje korisnika
GET /api/loyalty/user/{userId} Loyalty info
PATCH /api/loyalty/user/{userId}/add-points?points= Dodavanje bodova
GET /api/achievements Svi achievements
POST /api/achievements Kreiranje
GET /api/user-achievements/user/{id} Achievements korisnika
POST /api/user-achievements Dodjela achievementa
GET /api/facilities Svi tereni
GET /api/facilities/{id} Teren po ID-u
GET /api/facilities/type/{type} Po tipu (FOOTBALL, TENNIS, PADEL...)
POST /api/facilities Kreiranje terena (OWNER/ADMIN)
PUT /api/facilities/{id} Update terena
DELETE /api/facilities/{id} Brisanje terena
GET /api/equipment Sva oprema
GET /api/equipment/facility/{id} Oprema za teren
POST /api/equipment Kreiranje opreme
GET /api/pricing-rules/facility/{id} Cijene za teren
GET /api/pricing-rules/calculate?facilityId=&start=&end= Izračun cijene
POST /api/pricing-rules Kreiranje cjenovnog pravila
GET /api/bookings Sve rezervacije (filterable/paginovane)
GET /api/bookings/{id} Rezervacija po ID-u
GET /api/bookings/user/{userId} Rezervacije korisnika
GET /api/bookings/facility/{facilityId} Rezervacije za teren
GET /api/bookings/facility/{id}/conflicting?start=&end= Konfliktni slotovi
POST /api/bookings Nova rezervacija (obična)
POST /api/bookings/orchestrated Nova rezervacija + plaćanje + loyalty (Z5)
POST /api/bookings/recurring?pattern=WEEKLY&occurrences=4 Ponavljajuće rezervacije
POST /api/bookings/group Grupna rezervacija (split iznosa)
PUT /api/bookings/{id} Update
PATCH /api/bookings/{id} Parcijalni update
DELETE /api/bookings/{id} Brisanje
GET /api/reviews Sve recenzije
POST /api/reviews Nova recenzija
GET /api/reviews/entity/{type}/{id} Recenzije za entitet
GET /api/rentals/user/{userId} Najam opreme za korisnika
POST /api/rentals Novi najam
GET /api/payments Sva plaćanja (filterable/paginovana)
GET /api/payments/{id} Plaćanje po ID-u
GET /api/payments/booking/{bookingId} Plaćanja za rezervaciju
POST /api/payments/{id}/refund?recipientUserId= Refund
GET /api/payments/revenue?from=&to= Prihod u periodu
GET /api/payments/saved-cards/user/{userId} Sačuvane kartice korisnika
DELETE /api/payments/saved-cards/{id} Brisanje kartice
GET /api/notifications/user/{userId} Notifikacije
PATCH /api/notifications/{id}/read Označiti kao pročitano
GET /api/disputes Sporovi
POST /api/disputes Novi spor
PATCH /api/disputes/{id}/resolve Rješavanje spora
GET /api/documents/user/{userId} Dokumenti korisnika
| Username | Lozinka | Rola |
|---|---|---|
admin |
password123 |
ADMIN |
vlasnik_teren |
password123 |
OWNER |
belmin_d |
password123 |
USER |
harun_g |
password123 |
USER |
amar_h |
password123 |
USER |
- Kreirati besplatni nalog na dashboard.stripe.com
- U Test mode preuzeti ključeve: Developers → API keys
- Upisati u
.env:STRIPE_SECRET_KEY=sk_test_... STRIPE_PUBLISHABLE_KEY=pk_test_... - Rebuild Payment Service i Frontend:
docker compose up --build -d payment-service frontend
Ako su oba ključa prazna, sve kartične transakcije se automatski odobravaju bez pozivanja Stripe API-ja. Idealno za demo i testiranje toka rezervacije.
| Broj kartice | Opis |
|---|---|
4242 4242 4242 4242 |
Uspješna transakcija |
4000 0000 0000 0002 |
Uvijek odbijena |
4000 0025 0000 3155 |
Zahtijeva 3D Secure autentifikaciju |
Datum isteka: bilo koji budući datum. CVV: bilo koja 3 cifre.
Kada korisnik čekira Save card for future payments:
- Frontend tokenizuje karticu putem
stripe.createToken()(kartica nikad ne dolazi na naš server) - Payment Service kreira Stripe Customer objekat i pohranjuje
stripeCustomerIdu tabelusaved_cards - Pri sljedećoj rezervaciji korisnik bira sačuvanu karticu — naplata ide direktno Stripe Customer-u
Sistem koristi RS256 (asimetrični RSA) — privatni ključ drži samo User Service, javni ključ koristi API Gateway za verifikaciju.
bash scripts/gen-jwt-keys.shSkripta generiše:
User Service/src/main/resources/keys/jwt-private.pemUser Service/src/main/resources/keys/jwt-public.pemAPI Gateway/src/main/resources/keys/jwt-public.pem
Privatni ključ se nikad ne dijeli s drugim servisima. Nikad ga ne commitovati u Git.
Sistem koristi Saga Choreography pattern putem RabbitMQ-a za distribuirane transakcije.
POST /api/bookings/saga
│
▼
Booking Service: kreira Booking (PENDING)
│
▼ BookingCreatedEvent → RabbitMQ
│
▼
Payment Service: kreira Payment (PENDING → PAID)
│
▼ PaymentCompletedEvent → RabbitMQ
│
▼
Booking Service: ažurira Booking (CONFIRMED)
POST /api/bookings/saga?simulateFailure=true
# → PaymentFailedEvent → Booking(CANCELLED)- Refund Saga — povrat plaćanja + notifikacija korisniku
- Rental Payment Saga — plaćanje za najam opreme
- User Deletion Saga — brisanje korisnika uz čišćenje rezervacija i plaćanja
http://localhost:15672 (guest / guest) — pregled queova, exchange-a i poruka.
React 19 + TypeScript SPA sa Vite build toolom.
frontend/src/
├── auth/ Autentifikacijski kontekst (JWT, session state)
├── components/ Zajednički UI (AppShell, AppHeader, feedback toast)
│ └── ui/ Primitivni komponenti (Button, Input, Card, Badge...)
├── features/ Feature-specifični moduli
│ ├── bookings/ BookingForm, PaymentForm, Stripe integracija
│ ├── resources/ API pozivi za terene
│ └── user/ API pozivi za korisnike
├── hooks/ Custom React hooks (data fetching, form logic)
├── pages/ Smart page komponenti (orkestriraju podatke)
│ ├── homePage.tsx
│ ├── facilityPage.tsx
│ ├── bookingPage.tsx
│ ├── dashboardPage.tsx
│ ├── ownerFacilitiesPage.tsx
│ ├── loginPage.tsx
│ └── registerPage.tsx
└── types/api.ts TypeScript tipovi za API odgovore
cd frontend
pnpm install
pnpm dev # http://localhost:5173pnpm dev # Vite dev server s HMR
pnpm build # Production build
pnpm lint # TypeScript check + Biome linter
pnpm test # Vitest unit testovi
pnpm validate # lint + test + build (sve odjednom)Svi podaci se dohvataju u Smart page komponentama putem custom hookova (useBookingData, useDashboardData…) i proslijeđuju Dumb prezentacijskim komponentama kroz props. Business logika živi u hookovima, a ne u komponentama.
Svaki mikroservis ima set testova u src/test/:
# Iz direktorija pojedinog servisa
./mvnw test
# Primjer — Booking Service
cd "Booking Service" && ./mvnw testTestovi koriste:
- H2 in-memory bazu (ne utječe na Docker baze)
- WireMock za stubiranje poziva prema drugim servisima
- Spring MockMvc za controller testove
cd frontend
pnpm test # Run once
pnpm test --watch # Watch modebash test-services.sh # Integracijski testovi svih servisa
bash scripts/security-test.sh # Security testovi (JWT, rate limiting)| Tehnologija | Verzija | Svrha |
|---|---|---|
| Spring Boot | 3.2.5 | Mikroservisni framework |
| Spring Cloud Gateway | 4.x | API gateway, routing |
| Spring Cloud Netflix Eureka | 4.x | Service discovery |
| Spring Cloud Config | 4.x | Centralizovana konfiguracija |
| Spring Cloud OpenFeign | 4.x | Deklarativni HTTP klijenti |
| Resilience4j | 2.x | Circuit breaker, time limiter |
| Spring AMQP | 3.x | RabbitMQ integracija |
| Spring Data JPA | 3.x | ORM, MySQL |
| Spring Security | 6.x | Autentifikacija i autorizacija |
| JJWT | 0.12.x | JWT generisanje i validacija |
| Stripe Java SDK | 25.1.0 | Platni gateway |
| ModelMapper | 3.2.0 | DTO mapiranje |
| JSON Patch (RFC 6902) | 1.13 | Parcijalni update resursa |
| Lombok | 1.18.38 | Redukcija boilerplate koda |
| MySQL | 8.0 | Relacijska baza (4 instance) |
| RabbitMQ | 3.13 | Message broker |
| Java | 17 | Runtime |
| Tehnologija | Verzija | Svrha |
|---|---|---|
| React | 19.2 | UI framework |
| TypeScript | 6.0 | Type safety |
| Vite | 5.4 | Build tool, HMR |
| TailwindCSS | 4.2 | Utility-first CSS |
| TanStack Query | 5.95 | Server state management |
| React Router | 7.13 | Klijentski routing |
| Stripe.js | 9.8 | Sigurno prikupljanje podataka kartice |
| Biome | 2.4 | Linter + formatter |
| Vitest | 1.6 | Unit testovi |
| MSW | 2.12 | Mock Service Worker (testovi) |
| Tehnologija | Svrha |
|---|---|
| Docker & Docker Compose | Kontejnerizacija cijelog stacka |
| nginx | Serviranje React SPA u produkciji |
SportsCenterSystem/
├── docker-compose.yml # Cijeli stack
├── .env.example # Template konfiguracije
├── build-all.sh # Build svih servisa
├── run-services.sh # Pokretanje sa health checkovima
│
├── API Gateway/ # Spring Cloud Gateway (:8080)
├── User Service/ # Auth, korisnici, loyalty (:8081)
├── Resource Service/ # Tereni, oprema, cijene (:8082)
├── Booking Service/ # Rezervacije, saga (:8083)
├── Payment Service/ # Plaćanja, Stripe, notifikacije (:8084)
├── config-server/ # Spring Cloud Config (:8888)
├── discovery-server/ # Eureka (:8761)
│
├── config-repo/ # Centralne .properties konfiguracije
├── docker/ # MySQL Dockerfile-ovi i konfiguracije
├── frontend/ # React + Vite SPA
└── scripts/ # Pomoćne skripte (JWT gen, load test...)