Skip to content

datenmodell

Actionbot edited this page Oct 6, 2026 · 9 revisions

Daten: Überblick

Zweck

Erklärt, wie Daten im Netzwerk modelliert und lokal gespeichert sind.

Wichtige Dateien

  • app/src/main/kotlin/de/traewelling/app/data/model/Models.kt
  • app/src/main/kotlin/de/traewelling/app/data/model/SevModels.kt
  • app/src/main/kotlin/de/traewelling/app/data/model/RoadRouteModels.kt
  • app/src/main/kotlin/de/traewelling/app/data/model/TransitRouteModels.kt
  • app/src/main/kotlin/de/traewelling/app/data/local/StatusEntity.kt
  • app/src/main/kotlin/de/traewelling/app/service/GpsJourneyTimeEstimator.kt
  • app/src/main/kotlin/de/traewelling/app/service/JourneyTimeResolver.kt

Modelle (Retrofit / Gson)

Die Modelle verwenden Gson. @SerializedName legt abweichende JSON-Feldnamen fest; gleich benannte Felder werden direkt zugeordnet.

Auth-Modelle

Modell Beschreibung
OAuthTokenResponse Token-Antwort mit accessToken, refreshToken, tokenType, expiresIn

AuthSession in util/AuthSession.kt ist dagegen ein lokaler atomarer Snapshot aus Server-URL, optionalem nicht leerem Access-Token und Revisionskennung. Er ist kein Retrofit-/OAuth-Antwortmodell. Die Revision trennt auch Abmeldung und erneute Anmeldung mit denselben Zugangsdaten; vergleichende Persistenzoperationen und der Feature-ViewModel-Store verwenden diesen Zustand. Auth beschreibt seinen Lebenszyklus.

User-Modelle

Modell Beschreibung
UserResponse Wrapper für User-Daten
User Nutzerdaten: id, uuid, username, displayName, profilePicture, bio, totalDistance, totalDuration, points, following, muted, blocked

Status-Modelle

Modell Beschreibung
StatusListResponse Wrapper für Liste von Statusen mit PaginationLinks
SingleStatusResponse Wrapper für einzelnen Status
Status Check-in-Status: id, body, createdAt, likes, liked, visibility, business, user, checkin, event, tags
StatusUser User-Kurzform für Status
CheckinInfo Check-in-Details mit origin, destination, operator, numerischem trip, tripUuid, Plan-/Echtzeitdaten und manuellen Zeitkorrekturen
StopOperator Betreiber: id als String (Legacy-Zahl oder UUID), bevorzugte uuid, name, identifiers

Station-Modelle

Modell Beschreibung
StationIdentifier Kennung mit type, identifier sowie optional name und origin
TrainStation Bahnhof: interne id, uuid, name, latitude, longitude, identifiers; ibnr und rilIdentifier werden aus identifiers berechnet
StopStation Konkreter Halt: id, uuid, verschachtelte station, arrivalPlanned/arrivalReal, departurePlanned/departureReal, Gleis- und Ausfallinformationen
StationSearchResponse Liste von TrainStation
DepartureResponse Liste von DepartureTrip

Trip-Modelle

Modell Beschreibung
DepartureTrip Abfahrt: tripId, line, direction, station, plannedWhen, realWhen (JSON when), platform, cancelled; berechnete delayMinutes
HafasLine Linieninfo: name, fahrtNr, product, mode; kein veraltetes line.operator
TripResponse Wrapper für TripDetails
TripDetails Trip: numerische id, uuid, Provider-tripId, lineName, category, operator, stopovers
StopoversResponse Map von tripId zu StopStation-Liste

Check-in-Modelle

Modell Beschreibung
TravelReason Enum für den Reisegrund beim Check-in: PRIVATE=0, BUSINESS=1, COMMUTE=2
CheckInRequest Request für Check-in: tripId, lineName, startStationId, destinationStationId, departure, arrival, body, business, visibility
CheckInResponse Antwort mit Status und Points
CheckInResult Enthält Status und CheckInPoints
CheckInPoints Gesamtpunkte und calculation mit base, reason, distance, factor
CheckInConflictResponse / CheckInConflictData HTTP-409-Envelope mit data.conflicts als Status-Liste
CheckInConflictException Konfliktliste und verständliche Meldung mit Linie, Ziel und Status-ID
UpdateStatusRequest PUT-Request für Status-Updates; Zielwechsel mit destinationId und destinationArrivalPlanned gemeinsam

Statistik-Modelle

Modell Beschreibung
StatisticsResponse Wrapper für StatisticsData
StatisticsData Statistiken: categories, operators, time, purpose
StatEntry Kategorie/Betreiber-Stat: name, count, duration
StatDay Tagesstatistik: date, count, duration

Notification-Modelle

Modell Beschreibung
NotificationListResponse Liste mit Pagination
Notification notification: id, type, lead, notice, link, readAt, createdAt, createdAtForHumans

Pagination

Modell Beschreibung
PaginationLinks first, last, prev, next URLs
PaginationMeta currentPage, lastPage, total, perPage

Wichtige Extensions

Stationsdaten und Haltidentität

StopStation.stationId liest ausschließlich station.id. Stopover-id wird nie für Stationsanfragen oder Check-ins verwendet: Träwelling widmet dieses Feld nach dem 30.11.2026 zur Halt-ID um.

stationName liest station.name; nur für die Anzeige alter gecachter Statusdaten bleibt ein privater Rückfall auf das frühere JSON-Feld name. stationIdentifier(type) liest ausschließlich station.identifiers. TrainStation.ibnr nutzt de_db_ibnr, TrainStation.rilIdentifier nutzt de_db_ril100.

matchesStopover(other) vergleicht bevorzugt die Stopover-UUID. Falls eine UUID fehlt, müssen interne Station-ID und eine geplante Ankunft oder Abfahrt übereinstimmen. ISO-Zeitstempel werden als Zeitpunkte verglichen. Wiederholte Besuche derselben Station auf einer Rundfahrt bleiben dadurch unterscheidbar.

Effektive Zeiten

effectiveArrival ist arrivalReal ?: arrivalPlanned, effectiveDeparture ist departureReal ?: departurePlanned. Diese Modellhelfer wählen vorhandene Felder, prüfen aber deren Parsebarkeit nicht. Die Legacy-Felder arrival und departure werden nicht gelesen. Der Tracking-Service berücksichtigt manuelle Einstieg-/Zielzeiten in seiner internen Route. Das Fahrtdetail behält API-Halte und manuelle Check-in-Zeiten getrennt; die Live-Anzeige verwendet JourneyTimeResolver statt GPS-Prognosen in Echtzeitfelder zu schreiben.

DepartureTrip.delayMinutes berechnet die Differenz zwischen when und plannedWhen in Minuten. Bei fehlender oder ungültiger Zeit ist der Wert null; das Legacy-Feld delay wird nicht verwendet.

Lokale Tracking- und Zeitmodelle

Modell/Feld Bedeutung und Lebensdauer
TrackingStop.plannedDepartureMillis Geplante Abfahrt des konkreten Besuchs, getrennt von effectiveDepartureMillis; optional für alte Cache-Routen.
TrackingLiveState.gpsTimes Optionales prozesslokales Ergebnis der GPS-Zeitauswertung; nur passende eigene aktive Fahrt, nicht serialisiert.
TrackingLiveState.sessionRevision Bindet den RAM-Livezustand an die Zugangsgeneration; gleicher numerischer Status eines anderen Kontos darf ihn nicht übernehmen. Kein Fahrtcache-Feld und keine Zugangsdaten.
TrackingLiveState.gpsGeometrySource Optional TRIP_POLYLINE beziehungsweise ROAD_MODEL aus der aktuellen Zeitauswertung, sonst frischer aktiver Railprojektion der Stationsengine. Kein Prefetchmarker oder ETA-Beleg; nicht persistiert.
RideRecognitionState.authSessionRevision Bindet prozesslokale Fahrtvorschläge an dieselbe aktuelle Zugangsgeneration; das Check-in-ViewModel verwirft fremde oder frühere Revisionen. Nicht persistiert.
GpsStopTime Besuchsschlüssel, Station-ID, Plan-Ankunft/-Abfahrt und optionale lokale Ankunft/-Abfahrt; Flags unterscheiden beobachtet und geschätzt.
GpsJourneyTimes Liste besuchsbezogener GPS-Zeiten, Unterstützungs-Fixzeitpunkt und Gültigkeitsende; spätestens nach 30 Sekunden unbrauchbar. Geeignete Folgefixes ohne neue Prognose dürfen das Ende nicht verlängern.
JourneyTime Aufgelöster Anzeigezeitpunkt mit JourneyTimeSource, Planzeit, Quellenlabel und optionaler positiver/negativer Abweichung in Minuten.

JourneyTimeResolver prüft je Ereignis gültige GPS-Zeit, manuelle Zeit, parsebare API-Echtzeit und Planzeit in dieser Reihenfolge. GPS-Matching bevorzugt UUID und verlangt in beiden Zuordnungswegen das exakt gleiche nullable Planpaar einschließlich Markeranwesenheit. Ohne UUID sind zusätzlich gleiche vorhandene Station-ID, mindestens ein parsebarer Planmarker und ein eindeutiger Treffer erforderlich. Diese strengere GPS-Zuordnung ersetzt nicht den allgemeinen API-Helfer matchesStopover. Die GPS-Erweiterung führt keine neuen Retrofit-, Room- oder Status-PUT-Felder ein. Prognosen und Standortbeobachtungen bleiben RAM-Zustand; Details stehen unter GPS-Zeiten.

Lokale SEV-Quellen und Besuchshinweise

Die Modelle in SevModels.kt ergänzen die öffentliche Bahnhofskarte, ohne den Träwelling-Vertrag zu verändern:

Modell Bedeutung
SevMap Stations-Slug, öffentliche Quellen-URL, Bahnhofkoordinate zur Plausibilitätsprüfung, SEV-Punkte, Weg-/Maßnahmenhinweise und Abrufzeit.
SevPoint Öffentliche sev.*-Kennung, physische Koordinate, optionale Richtungsbezeichnung und Quellen-Bearbeitungsstand.
SevStopInfo Quellenlink, Bezeichnung, Wegbeschreibung und optionales eindeutig zugeordnetes Koordinatenpaar für einen Haltbesuch; bei Rückfall zusätzlich ein Grund.

SevStopInfo.hasCoordinates unterscheidet einen nutzbaren Punkt von einem reinen Hinweis. GeoJSON liefert Längengrad vor Breitengrad; das App-Modell hält beide benannt. Der Bearbeitungsstand eines Punkts ersetzt kein Gültigkeitsintervall. Ein allgemeiner Kartenmittelpunkt wird niemals als SEV-Punkt ausgegeben.

Die Zuordnung bleibt lokal. API-Stations-ID, Stopover-UUID, Plan-/Echtzeit und Check-in-Werte behalten ihre Identität und Bedeutung; es werden keine SEV-Koordinaten per Status-PUT übertragen. Die Auflösungsregeln und Lebensdauer stehen unter SEV-Ersatzhaltestellen.

Lokale Linienzug-Geometrien

RoadRouteModels.kt definiert gemeinsame Geometrieformen; TransitRouteModels.kt ergänzt die native Fahrtbindung. Quellen bleiben ausdrücklich getrennt von Gerätefixes:

Modell Bedeutung und Lebensdauer
RoutePoint Benannter Breitengrad/Längengrad eines öffentlichen Haltpunkts oder Geometrieknotens; kein Gerätefix für Routinganfragen.
RouteGeometry / Alias RoadRouteGeometry Geordnete Endpunkte from/to, Kandidatenlinienzüge in alternatives und fetchedAtMillis; keine Provider-ETA. Road erlaubt bis zu drei, native Abschnitte genau einen Kandidaten.
GpsGeometrySource ROAD_MODEL für approximative SEV-Straßenwege beziehungsweise TRIP_POLYLINE für einen nativen Träwelling-Streckenverlauf.
GpsSegmentGeometry Bindet geometry über fromKey, toKey und source an zwei konkrete geordnete Haltbesuche, auch bei wiederholten Stationsbesuchen. Bestehende Road-Aufrufer behalten ROAD_MODEL als Standard.
TransitRouteVisit Besuchsschlüssel, Stations-ID/-UUID, nullable Planpaar, öffentliche Stationskoordinate und Ausfallstatus; keine Echtzeit, Gleise oder Geräteposition.
TransitRouteRequest Status-ID, Tripidentität und vollständige geordnete Check-in-Besuchsfolge inklusive gestrichener Zwischenbesuche.
TransitRouteGeometry Derselbe Request, eindeutig gebundene verwendbare Abschnitte und Abrufzeit; native Form höchstens 15 Minuten verwendbar.

Die lokale GPS-Zeitauswertung projiziert auf geeignete Formen. Native Abschnitte können zusätzlich gerichtete Trackinghilfen stützen; physische Ankunft und Zielabschluss bleiben Stationsbelege. Das Pkw-Modell ist keine offizielle SEV-Busroute; der native Backend-Linienzug ist ebenfalls keine garantierte aktuelle Gleisführung. Weder eine Routingdauer noch ein Netzabschluss erzeugt eine GPS-Istzeit. Gerätepositionen werden nicht an diese Quellen gesendet. Geometrien bleiben in Service-/Repository-RAM und erweitern weder Room noch trip_tracking_state; ein Neustart übernimmt keine persistierte Geometrie. Ein tatsächlicher Formwechsel verwirft Zukunftsprognose und Bewegungsfenster, erhält aber bestätigte tatsächliche Ereignisse bei unveränderter Besuchs-/Haltbasis.

List.deduplicate()

fun List<StopStation>.deduplicate(): List<StopStation>

Dedupliziert aufeinanderfolgende Halte derselben Station mit gleichen geplanten Zeiten. Unterschiedliche Stationen oder unterschiedliche vorhandene Stopover-UUIDs bleiben auch bei identischen Zeiten erhalten. Bei doppelten Einträgen wird eine vorhandene Gleisinformation beziehungsweise der kürzere Stationsname bevorzugt.

StopoversResponse.allStopovers()

fun StopoversResponse.allStopovers(): List<StopStation>

Flacht die Map von tripId zu StopStation-Liste in eine flache Liste.

Manuelle Zeitedits

Die API unterstützt manuelle Korrekturen von Abfahrts-/Ankunftszeiten:

  • manualDeparture: Manuell korrigierte Abfahrtszeit
  • manualArrival: Manuell korrigierte Ankunftszeit

Diese werden im CheckInInfo-Modell gespeichert und beim Auflösen der Anzeige berücksichtigt. Eine frische eindeutige GPS-Zeit hat in der eigenen aktiven Begleitung Vorrang; außerhalb dieser Beobachtung bleiben manuelle Zeiten vor API-/Planzeit. Das Bearbeitungsformular wird ohne GPS-Werte initialisiert.

Bei einem Zielwechsel über UpdateStatusRequest wird zusätzlich zur neuen internen Station-ID deren geplante Ankunft als destinationArrivalPlanned gesendet. Der Upstream-Request verlangt beide Felder gemeinsam. Für reine Text-, Sichtbarkeits- oder Zeitänderungen werden sie weggelassen.

Reisegrund

Der Reisegrund wird beim Check-in im Feld business übertragen. Das Android-Modell verwendet dafür TravelReason mit den API-Werten 0 (Privat), 1 (Geschäftlich) und 2 (Arbeitsweg). Standard ist TravelReason.PRIVATE.

Verwandte Seiten

Clone this wiki locally