Come calcoliamo la puntualità.
BusZilla è onesta: nessuna formula segreta, nessun algoritmo proprietario. Ecco esattamente come trasformiamo i check-in degli studenti in indicatori di affidabilità per ogni fermata e linea.
1. Il check-in
Ogni check-in è composto da: fermata, linea, orario teorico di passaggio (preso dal GTFS ufficiale dell'azienda) e stato osservato dichiarato dallo studente. Lo stato è uno tra:
- Puntuale — il bus è passato entro ±3 minuti dall'orario teorico.
- Ritardo lieve — tra 3 e 8 minuti di ritardo.
- Ritardo grave — più di 8 minuti.
- Non passato — corsa saltata.
- Sovraffollato — bus passato ma non si è potuti salire.
2. Validazione geofence: il cuore anti-furbetti
Un dato sulla puntualità vale solo se chi lo segnala è davvero alla fermata. Per questo ogni check-in passa da un controllo geografico chiamato geofence: un recinto invisibile attorno alla fermata. Se sei dentro, la segnalazione conta. Se sei fuori, la buttiamo via.
Dentro i 200 m — il check-in è accettato e contribuisce alle statistiche.
Fuori dal cerchio — il check-in è rifiutato. Niente segnalazioni dal divano.
Come funziona, passo per passo
- Al tap, e solo al tap. Quando premi "check-in", l'app legge la tua posizione GPS una volta sola, in quel preciso istante. Nessun tracciamento continuo, nessuna posizione in background.
- Il controllo è server-side. Le coordinate vengono inviate al nostro backend, che non si fida mai del client: è il server a decidere se sei dentro il recinto, non l'app sul tuo telefono. Così nessuno può falsificare l'esito modificando l'app.
-
La matematica. MongoDB calcola se il tuo punto cade dentro
un cerchio di 200 metri di raggio centrato sulla fermata,
usando l'operatore geospaziale
$geoWithincon$centerSpheresull'indice2dsphere. È lo stesso meccanismo che le mappe usano per le ricerche "nelle vicinanze", quindi è preciso anche tenendo conto della curvatura terrestre. - Poi la posizione sparisce. Appena il controllo dà esito (dentro / fuori), le tue coordinate vengono scartate: non finiscono mai nel database. Salviamo solo quale fermata hai segnalato, non dove eri tu.
- Chi prova a barare ci rimette. Un check-in fuori geofence non solo viene rifiutato, ma abbassa anche il punteggio di reputazione dell'account: i recidivi pesano sempre meno nelle statistiche.
In altre parole: non puoi segnalare un ritardo dal divano. E noi non sapremo mai dov'era il tuo divano.
Perché 200 metri e non meno? Il GPS degli smartphone ha un margine di errore tipico di 10–50 metri, che peggiora tra palazzi alti e pensiline coperte. Un raggio di 200 metri lascia passare chi è onestamente alla fermata anche con segnale ballerino, ma resta abbastanza stretto da fermare chi è a casa o dall'altra parte della città.
3. Aggregazione
Per ogni coppia (fermata, linea, giorno_settimana, fascia_oraria)
calcoliamo continuamente:
| Metrica | Formula |
|---|---|
| Tasso di puntualità | (# check-in "puntuale") / (# check-in validi) |
| Ritardo mediano | mediana dei minuti di ritardo dichiarati |
| Tasso di soppressione | (# "non passato") / (# corse teoriche attese) |
L'aggregazione viene ricalcolata ogni 10 minuti dal job
StopLineStatsAggregationJob. Le statistiche di un bucket
vengono pubblicate solo se basate su almeno 15 check-in validi
negli ultimi 14 giorni: sotto questa soglia mostriamo "Dati insufficienti".
4. Le fasce di affidabilità
I tier visualizzati sulla mappa derivano dal tasso di puntualità sugli ultimi 7 giorni:
- Alta affidabilità: puntualità > 85%.
- Affidabilità media: puntualità tra 70% e 85%.
- Bassa affidabilità: puntualità < 70%.
- Dati insufficienti: meno di 15 check-in nella finestra.
5. Il "mood" di BusZilla
La mascotte cambia espressione in base alla qualità del servizio percepito,
con regole esplicite (file StatsService.ComputeMood()):
- Happy — puntualità > 85% e nessuna segnalazione attiva.
- Neutral — 70-85% oppure dati insufficienti.
- Suspicious — 50-70%.
- Angry — < 50% oppure ritardo segnalato negli ultimi 15 minuti.
- Sleeping — fuori orario di servizio o weekend.
- Celebrate — uno studente ha appena sbloccato un achievement.
6. Anti-abuso
Oltre al geofence, applichiamo un rate-limit di 30 check-in all'ora
per utente, penalizziamo i pattern di segnalazione anomali tramite
il punteggio di reputazione, e pesiamo meno i check-in di account molto
recenti. Il dettaglio tecnico vive in CheckinsController e
ReputationService.
7. Dati che usiamo, dati che non usiamo
- ✔ Orari teorici da GTFS statico ufficiale.
- ✔ Snapshot meteo concomitanti (provider: Open-Meteo) per analisi correlate.
- ✔ Check-in pseudonimi degli studenti.
- ✘ Posizione continuativa: mai.
- ✘ Identità reale dello studente.
- ✘ Dati di terze parti (social, pubblicità).