MotoRun - Offline-first Verseny Adminisztrációs Rendszer
Áttekintés
A MotoRun egy modern Android alkalmazás Silkolene motoRun motoros navigációs versenyekhez, amely egyszerűsíti a verseny szervezői és résztvevői számára a pontőröknél történő adatnaplózást. Az alkalmazás offline-first megközelítéssel készült, ahol az elsődleges cél a megbízható, másodperc-pontos digitális naplózás volt még internetkapcsolat nélkül is.
A projekt során különös figyelmet fordítottam a Clean Architecture elvekre, MVVM mintára és az offline-first adatkezelésre, biztosítva hogy a kritikus versenyinformációk soha ne vesszenek el kapcsolódási problémák miatt.
A rendszer azóta tovább nőtt:
- 2024-2025: Android alkalmazás Firebase backenddel. Az oldal nagy része ezt a verziót mutatja be.
- 2026 tavasz: saját Spring Boot backend a Firebase helyett, az Önálló laboratórium keretében.
- 2026 ősz: auditálható versenyértékelés és webes adminisztráció a szakdolgozatomban.
Architektúra és tervezési minták
Clean Architecture implementáció
- Presentation Layer:
@HiltViewModelannotált ViewModel-ek unidirectional data flow-val (StateFlow) - Domain Layer: Repository interface-ek és use-case-ek a business logic elkülönítésére
- Data Layer: Room database + Firestore hibrid megoldás offline-first prioritással
- UI Layer: Jetpack Compose-zal felépített stateless Composable-ök
State Management és reaktív programozás
data class CheckpointUiState(
val sorter: Sorter = Sorter.TimeDESC,
val filter: Filter = Filter.Arrived,
val selectedEntry: Entry? = null,
val sortedEntries: List<Entry> = emptyList(),
val isFilterHidingEntries: Boolean = false
)
- Sealed classes típusbiztos state/error modeling-hez (
AuthState,AuthError) - Flow operators (
combine,distinctUntilChanged) reaktív adatáramláshoz
Dependency Injection és modularitás
- Hilt használata teljes DI coverage-dzsel
- Moduláris felépítés:
AuthRepository,EntryRepository,NetworkManager - Interface segregation a tesztelhetőség javítására
Kulcs funkciók és implementációk
NFC-alapú csapat regisztráció
@Singleton
class NFCHandler @Inject constructor(
private val authRepository: AuthRepository,
private val entryRepository: EntryRepository
) {
sealed class NFCState {
object Disabled : NFCState()
data class Enabled(val checkpointId: Int) : NFCState()
}
fun handleNfcIntent(intent: Intent) {
// Role-based authorization and automatic entry creation
}
}
Offline-first adatszinkronizáció
- Room database helyi perzisztenciával
- Firestore cloud backup és multi-device sync
- Conflict resolution version-based update strategiával
- Network state monitoring automatikus reconnection és retry logikával
Role-based hozzáférés-vezérlés
enum class Role {
UNKNOWN, TEAM, CHECKPOINT, ORGANIZER, ADMIN
}
sealed class AuthState {
data object Idle : AuthState()
data object Loading : AuthState()
data class LoggedIn(val role: Role, val isOnline: Boolean) : AuthState()
data class Error(val error: AuthError) : AuthState()
}
Robusztus hálózatkezelés
- NetworkManager lifecycle-aware hálózatkezelés
- Exponential backoff újra csatlakozási stratégia
- Rate limiting Firestore API túlterhelés ellen (free tier :))
- Health checks és automatikus helyreállás
Technikai megvalósítás
Offline képességek
- AndroidKeyStore belépési adatok és kulcsok biztonságos tárolásához
- Room komplex relációs lekérdezésekkel és indexeléssel
- DataStore konfigurációk kezeléséhez
UI/UX tervezés
- Material 3 design system
- Compose UI deklaratív kezelőfelület leírás
- State hoisting clean separation of concerns-ért
- Dialog management centralizált UI state handling-gel
Adatexport és jelentések
- Apache POI Excel export funkcióhoz
- Google Apps Script Google Sheets export funkcióhoz
- FileProvider offline file sharing-hez
- Progress tracking callbacks hosszú műveleteknél
Hardware integráció
- NFC card reading NDEF message parsing-gal
- Device identification unique device tracking-hez
- Hardware sensor access készülék-specifikus adatokhoz
Alkalmazott technológiák
Android fejlesztés:
- Kotlin 2.0 modern nyelvi elemek használata
- Jetpack Compose declarative UI
- Navigation Compose type-safe navigáció
- Hilt dependency injection
- Room + DataStore data persistence
Backend és szinkronizáció (első verzió):
- Firebase Auth role-based authentication
- Firebase Firestore szinkronizációs adatbázis, verziókezeléssel
- Firebase Crashlytics crash reporting
Architektúra és patterns:
- MVVM + Clean Architecture
- Repository pattern adat absztakciós réteg
- Observer pattern reactive programming-hoz
- Singleton pattern system services-hez
Fejlesztői tooling:
- Gradle KTS build configuration
- ProGuard code obfuscation and minifying
- BuildConfig environment-specific settings
Eredmények és teljesítmény
- Offline működés: 100% funkcionalitás internet nélkül
- Adatbiztonság: Zero data loss konfliktus-feloldó szinkronizációval
- NFC response idő: < 200ms card-tól entry creation-ig
- Multi-role support: 4 különböző felhasználói szerepkör
- Excel export: Teljes verseny eredmények batch export-ja
- Network resilience: Automatikus reconnection és retry logika
A projekt demonstrálja a modern Android fejlesztés best practice-eit, különös tekintettel a reliability, scalability és maintainability szempontjaira kritikus alkalmazási környezetben.
2026: saját backend (Önálló laboratórium)
A Firebase induláskor jól szolgált, de az alkalmazás kinőtte: a Firestore árazása miatt kliensoldali rate limitinget kellett bevezetnem, ami perces szinkronizációs késéseket okozott, az üzleti logika kizárólag a klienseken futott, és nem volt szerveroldali source of truth. A 2026-os tavaszi félévben ezért a teljes Firebase backendet saját fejlesztésű, Spring Boot alapú moduláris monolitra cseréltem. A Room alapú offline-first működés érintetlen maradt, csak a távoli szinkronizációs réteg változott.
- Spring Boot 4 + Spring Modulith (Java 25): auth és entry modul, PostgreSQL 18, Liquibase sémakezelés.
- JWT alapú autentikáció és RBAC: access és refresh tokenek,
TEAM,CHECKPOINT,ORGANIZERésADMINszerepkörök Spring Security-vel. - Determinisztikus, szerveroldali konfliktusfeloldás: kombinált push/pull szinkronizáció az órákig offline pontőri eszközökhöz, ahol a szerver dönt autoritatívan.
- Valós idejű adatszórás: STOMP over WebSocket, így a szervező késleltetés nélkül látja az ellenőrzőpontok adatait.
- Android kliens: a Firebase SDK-k helyett OkHttp és Retrofit alapú távoli szinkronizációs réteg.
- Infrastruktúra: Docker Compose, GitHub Actions CI/CD, Cloudflare, Prometheus és Grafana monitoring.
A backendet OpenRouter + OpenCode alapú agentic fejlesztéssel építettem. A tervet és az ütemezést az Önálló laboratórium tervben írtam le.
Szakdolgozat: auditálható versenyértékelés (2026 ősz, folyamatban)
A verseny végeredménye ma még egy manuális bizalmi határon halad át: a szervezők Google Sheetsből egy több munkalapos Excel fájlba másolják az adatokat, ahol egy elcsúszott hivatkozás vagy hibás copy-paste úgy módosíthatja az eredményt, hogy azt csak hosszú kézi ellenőrzéssel lehet megtalálni. A szakdolgozatomban ezt a folyamatot váltom ki:
- Determinisztikus pontszámítás verziózott szabályok alapján, részletes számítási naplóval: minden összesített érték visszakövethető a nyers pontőri bejegyzésekig.
- Compose Multiplatform Web adminisztrációs felület: versenykonfiguráció, csapat-szakasz hőtérkép, hibapont-főkönyv, javítások és egyedi elbírálások.
- Megváltoztathatatlan, verziózott publikáció: a csapatok egy hozzájuk kötött linken (QR kóddal) látják a saját eredményük teljes levezetését.
- Bizonyítható működés: visszaellenőrzés a 2026-os verseny teljes adathalmazán, Playwright E2E tesztek, automatizált mentés és helyreállítás.
- AI mint másodvélemény: az LLM a determinisztikusan megjelölt gyanús értékekhez ad második véleményt, a résztvevőknek pedig a saját publikált eredményük alapján magyaráz, de a pontszámításba nem szól bele.
A részletes terv és ütemezés a Szakdolgozat tervben olvasható.
Vissza a projektekhez