Smart Parking System je data-intenzivna web aplikacija za upravljanje parkiralištem. Aplikacija omogućuje evidenciju ulazaka i izlazaka vozila, praćenje dostupnosti parkirnih mjesta u stvarnom vremenu te analitičku predikciju zauzetosti parkinga pomoću integriranog XGBoost modela.
Manual ENTRY / EXIT event
→ TicketController
→ ParkingEventPublisher
→ Redis Pub/Sub channel
→ ParkingEventConsumer
→ Redis availability update
→ parking_occupancy_log snapshot
→ FeaturePreprocessorService
→ FastAPI ML Service
→ XGBoost next-hour forecast
→ Admin dashboard
Svaki uspješan ENTRY ili EXIT događaj ažurira trenutno stanje parkinga i zapisuje novi
occupancy snapshot u tablicu:
parking_occupancy_log
- Java 25
- Spring Boot
- Maven
- REST API
- PostgreSQL primary database
- PostgreSQL read replica
- Redis key-value store
- Redis Pub/Sub za obradu parking događaja
- Nginx load balancer
- Python
- FastAPI
- scikit-learn pipeline
- XGBoost binary classifier
- joblib model serialization
- Docker
- Docker Compose
- Generiranje parkirne karte pri ulazu
- UUID identifikator karte
- Vrijeme ulaska
- Izlaz iz parkinga
- Automatski obračun cijene
- Pregled aktivnih i završenih karata
- Praćenje trenutnog broja slobodnih mjesta
- Praćenje trenutnog broja zauzetih mjesta
- Ukupni kapacitet parkinga
- Redis kao live state storage
- Event-driven update preko Redis Pub/Sub
Nakon svakog ENTRY i EXIT događaja sustav zapisuje novi snapshot u
parking_occupancy_log.
Snapshot sadrži:
lot_id- timestamp (
ts) - broj zauzetih mjesta (
occupied_count) - kapacitet (
capacity) - oznaku praznika (
is_holiday)
Primjer:
LOT_A | 2026-05-29 23:49:06 | occupied_count=101 | capacity=200 | is_holiday=0
FeaturePreprocessorService čita najnovije occupancy snapshotove i priprema feature vector
koji mora odgovarati featureima korištenima pri treniranju modela.
Model koristi:
hourday_of_weekis_holidaycapacityoccupied_countoccupancy_rate_lotoccupied_count_lag_1hoccupied_count_lag_2hoccupied_count_lag_3hoccupancy_rate_lag_1hoccupancy_rate_lag_2hoccupancy_rate_lag_3h
Integrirani model je XGBoost binary classifier.
Model ne predviđa trenutni broj zauzetih mjesta. Model predviđa vjerojatnost da će
LOT_A u sljedećem satu doseći visoku zauzetost.
Output modela:
prediction0= parking se ne predviđa kao visoko zauzet u sljedećem satu1= parking se predviđa kao visoko zauzet u sljedećem satu
probability- vjerojatnost klase
1
- vjerojatnost klase
model_usedxgboost
prediction_horizon_minutes60
target_threshold0.85
Primjer odgovora:
{
"prediction": 1,
"probability": 0.991,
"model_used": "xgboost",
"prediction_horizon_minutes": 60,
"target_threshold": 0.85,
"high_occupancy_next_hour": true
}Dashboard prikazuje:
- trenutni kapacitet
- trenutno zauzeta mjesta
- trenutno slobodna mjesta
- XGBoost next-hour forecast za
LOT_A - vjerojatnost visoke zauzetosti u sljedećem satu
- manual
ENTRY/EXITkontrole za demonstraciju live event toka - system status
Dashboard ne prikazuje arhitekturu sustava ni usporedbu modela, jer je namijenjen administratoru parkinga, a ne tehničkoj dokumentaciji.
Model je treniran kao binary classification problem.
Target varijabla u trening skripti definira se kao high occupancy u sljedećem satu:
df["target_occupancy_rate_next_hour"] = df["occupancy_rate_lot"].shift(-1)
df["target_high_occupancy_next_hour"] = (
df["target_occupancy_rate_next_hour"] >= 0.85
).astype(int)To znači:
Input: trenutno stanje + lag featurei iz prethodnih sati
Target: hoće li occupancy_rate_lot u sljedećem satu biti >= 0.85
Modeli su evaluirani offline pomoću skripte compare.py.
Uspoređeni su modeli za binary classification, a najbolji model integriran u aplikaciju je
XGBoost.
Za evaluaciju se koriste metrike:
- accuracy
- precision
- recall
- F1-score
- confusion matrix
- classification report
Napomena: točne vrijednosti metrika potrebno je navesti u završnoj dokumentaciji ili reportu
prema rezultatima iz compare.py.
Browser Dashboard
|
v
Nginx Load Balancer
|
v
Spring Boot backend instances
|
+--------------------+
| |
v v
PostgreSQL primary Redis
analytical storage live state + Pub/Sub
|
v
FeaturePreprocessorService
|
v
FastAPI ML Service
|
v
XGBoost model
Glavna relacijska baza je PostgreSQL.
Važne tablice:
ticketsreportsparking_occupancy_log
parking_occupancy_log je ključna tablica za ML pipeline jer sadrži povijesne occupancy
snapshotove koji se pretvaraju u featuree za model.
Redis se koristi za:
- trenutno stanje dostupnosti parkinga
- ukupan kapacitet
- Pub/Sub obradu
ENTRYiEXITdogađaja - cacheiranje prediction rezultata
Važni Redis ključevi:
capacity:totalavailability:total:freeprediction:LOT_A
POST /tickets/entryKreira novu parking kartu i generira ENTRY event.
PUT /tickets/exit/{ticketUuid}Zatvara parking kartu i generira EXIT event.
GET /ticketsVraća listu karata.
GET /availability/totalVraća trenutno stanje parkinga:
{
"capacity": 200,
"free": 100,
"occupied": 100
}GET /api/parking/predict/LOT_A?refresh=truePokreće svježu XGBoost predikciju za LOT_A.
POST /api/parking/predict/LOT_A/refreshEksplicitno pokreće full pipeline: DB snapshotovi → featurei → ML service → prediction.
GET http://localhost:8000/healthPrimjer:
{
"status": "ok",
"active_model": "xgboost",
"models": {
"xgboost": "ok"
}
}U folderu docker kreirati .env datoteku:
POSTGRES_DB=smart_parking
POSTGRES_USER=parking_user
POSTGRES_PASSWORD=your_password
REPLICA_PASSWORD=your_replica_password
SPRING_DATASOURCE_URL=jdbc:postgresql://postgres_primary:5432/smart_parking
SPRING_DATASOURCE_USERNAME=parking_user
SPRING_DATASOURCE_PASSWORD=your_password
SPRING_DATA_REDIS_HOST=redis
SPRING_DATA_REDIS_PORT=6379Iz foldera docker:
docker compose up -d --buildhttp://localhost:8080
curl http://localhost:8000/healthOčekivano:
{
"status": "ok",
"active_model": "xgboost",
"models": {
"xgboost": "ok"
}
}curl -X POST http://localhost:8080/tickets/entrycurl http://localhost:8080/availability/totaldocker exec -it postgres_primary psql -U parking_user -d smart_parking -c "SELECT id, lot_id, ts, occupied_count, capacity, is_holiday FROM parking_occupancy_log ORDER BY ts DESC LIMIT 10;"curl "http://localhost:8080/api/parking/predict/LOT_A?refresh=true"Prvo pronaći aktivni ticket:
curl http://localhost:8080/ticketsZatim zatvoriti ticket:
curl -X PUT http://localhost:8080/tickets/exit/{ticketUuid}Nakon toga se u parking_occupancy_log mora pojaviti novi snapshot s ažuriranim brojem
zauzetih mjesta.
Za demonstraciju se mogu ručno generirati ENTRY i EXIT događaji preko dashboarda.
U stvarnoj implementaciji isti endpointi mogli bi biti povezani s rampom, kamerom,
senzorom ili vanjskim ticketing sustavom.
Primjer demo scenarija:
- Administrator klikne
ENTRY. - Backend kreira ticket.
- Redis event se obradi.
- Redis availability se ažurira.
- Novi snapshot se upisuje u
parking_occupancy_log. - FeaturePreprocessorService priprema featuree.
- XGBoost model vraća next-hour forecast.
- Dashboard prikazuje probability i status.
Važno: probability koju model prikazuje nije trenutni postotak zauzetosti. To je vjerojatnost da će parking u sljedećem satu biti u high-occupancy stanju.