Tachographendaten: Parsing, Speicherung und Zugriff¶
1. Zweck und Geltungsbereich¶
Dieses Dokument beschreibt den technischen Datenweg von Fahrerkarte-C-Dateien und Massenspeicher-M-Dateien: vom unveränderten DDD-Original über Klassifizierung, Parsing und Signaturprüfung bis zur Speicherung, archivübergreifenden Deduplizierung und Abfrage durch UI, Reporting und Compliance. Es richtet sich an Entwickler und Administratoren.
Die wichtigsten Garantien sind:
- Das komprimierte DDD-Original bleibt die revisionssichere Beweisquelle.
- Archiv-, Signatur-, Abschnitts- und Rohdatensatznachweise bleiben archivbezogen.
- Erneutes Parsen ersetzt nur abgeleitete Daten des betreffenden Archivs.
- Fahrer- und Fahrzeuggesamtsichten deduplizieren über alle zugeordneten Archive.
- Eine Einzelarchivansicht zeigt weiterhin ausschließlich Beobachtungen dieser Datei.
- Parser- und Signaturstatus werden nicht durch die Deduplizierung verändert.
flowchart LR
A["DDD-Eingang"] --> B["Lokales GZIP-Original"]
B --> C["Archivmetadaten und SHA-256"]
B --> D{"Binäre Klassifizierung"}
D -->|"C-Datei"| E["DriverCardFullParser"]
D -->|"M-Datei"| F["VehicleUnitParser"]
E --> G["Signaturprüfung C"]
F --> H["Signaturprüfung M"]
G --> I["Archivbezogene C-Tabellen"]
H --> J["Archivbezogene M-Tabellen"]
I --> K["Kanonische Gesamtsicht"]
J --> K
K --> L["Repository"]
L --> M["UI / Reporting / Compliance"]
I --> N["Einzelarchivansicht"]
J --> N
2. Archivierung und gemeinsame Importpipeline¶
ddd_archive ist der Einstiegspunkt für jede archivierte Datei. Die Tabelle enthält unter anderem Archiv-ID, Dateiname, Original- und Speicherhash, Ablagepfad, Größen, Quelle, Zeitstempel, DDD-Art, Generation, Parserstatus, Signaturstatus, Identitätsfelder und fachlichen Datenzeitraum.
Der normale Import läuft über TachographImportService.import_archive_id():
- Archivzeile laden und logischen Löschstatus prüfen.
- GZIP-Datei aus
stored_pathlesen. - Binärinhalt klassifizieren; Dateiname oder Präfix allein entscheidet nicht.
- Klassifizierung und Audit mit einer neuen Korrelations-ID speichern.
- C- oder M-Parser ausführen.
- Signaturen gegen den Trust Store prüfen.
- Abgeleitete Archivdaten ersetzen und Archivstatus aktualisieren.
- Fahrzeug-/Personenverknüpfungen, Downloadfristen und Auswertungscaches nachführen.
Die beiden Hashes in ddd_archive haben unterschiedliche Aufgaben:
| Feld | Inhalt | Verwendung |
|---|---|---|
file_hash_sha256 |
SHA-256 der unkomprimierten DDD-Bytes | Beweist den unveränderten fachlichen Dateiinhalt |
stored_hash_sha256 |
SHA-256 der tatsächlich abgelegten GZIP-Datei | Erkennt Änderungen oder Beschädigungen der Archivdatei |
Die Wartungsmigration prüft bei jedem aktiven C-/M-Archiv beide Ebenen: erst die gespeicherte Datei, dann den dekomprimierten Originalinhalt.
sequenceDiagram
participant Import as TachographImportService
participant Archive as ddd_archive
participant File as GZIP-Original
participant Parser as C-/M-Parser
participant Verify as Signaturdienst
participant DB as Fachtabellen
Import->>Archive: Archiv-ID und Metadaten laden
Import->>File: GZIP öffnen und DDD-Bytes lesen
Import->>Import: Inhalt klassifizieren
Import->>Parser: Exakte Bytes parsen
Parser-->>Import: Struktur, Identität, Beobachtungen, Rohbezüge
Import->>Verify: Signierte Blöcke/Sektionen prüfen
Verify-->>Import: VALID / INVALID / UNVERIFIABLE / MISSING
Import->>DB: Archivbezogene Daten ersetzen
Import->>Archive: Generation, Zeitraum und Status aktualisieren
Import->>Archive: Audit mit Korrelations-ID schreiben
3. Parsing von C-Dateien¶
3.1 Segmentierung¶
DriverCardFullParser liest die Datei vollständig in Bytes und zerlegt sie ohne Verlust der EF- und Signaturgrenzen. Jedes Segment besitzt einen 5-Byte-Kopf:
- zwei Byte
file_id; - ein Byte
kind(0G1-Daten,1G1-Signatur,2G2-Daten,3G2-Signatur); - zwei Byte Payloadlänge in Big-Endian;
- exakt
lengthPayloadbytes.
Eine Payload, die über das Dateiende hinausläuft, oder Restbytes nach dem letzten Segment führen zum Parsefehler. Für jedes Segment werden Offset, Länge und SHA-256 der Payload ermittelt. Der Parser hält zusätzlich die exakten Segmentbytes für die spätere kryptografische Prüfung vor.
3.2 EF-Zuordnung und Generation¶
Bekannte EFs werden über ihre Datei-ID einem Decoder zugeordnet. Wesentliche EFs sind:
| EF | Inhalt |
|---|---|
0501, 0525 |
Anwendungsidentifikation, Generation und Recordanzahlen |
0520, 0521 |
Karteninhaber- und Führerscheinidentität |
0504 |
tägliche Fahreraktivitätsdaten |
0502, 0503 |
Ereignisse und Störungen |
0505 |
verwendete Fahrzeuge und Kilometerstände |
0506, 0524 |
Orte und GNSS-Positionen |
0507, 050E |
aktuelle Nutzung und letzter Download |
0526–0530 |
G2V2-Authentifizierung, Grenzen und Be-/Entladung |
C100, C101, C108, C109 |
Karten-, CA-, CardSign- und Linkzertifikate |
Die Generation wird aus vorhandenen Anwendungs- und G2V2-EFs abgeleitet und intern als G1, G2 oder G2V2 geführt. In ddd_archive wird daraus G1, G2_V1 oder G2_V2.
3.3 Fachliche Dekodierung¶
- Identitäts- und Kartendaten werden aus den vorgesehenen EFs zusammengesetzt; es werden keine Werte aus benachbarten Bytebereichen geschätzt.
EF.Driver_Activity_Datawird anhand der Ringpufferzeiger gelesen. Header und Nutzdaten eines Tagesrecords werden zyklisch gelesen: Ein Record darf in den letzten Bytes des EF beginnen und bei Offset null fortgesetzt werden. Der Durchlauf endet erst nach dem durchactivityPointerNewestRecordbezeichneten Record. Falls die Zeiger nicht verwendbar sind, erfolgt ein längengeführter linearer Durchlauf. Tagesrecords werden über Datum und Presence Counter dedupliziert.- Aktivitätswechsel werden nach Minute, Slot, Crew und Aktivitätscode dekodiert und zu Intervallen
BREAK_REST,AVAILABILITY,WORKoderDRIVINGaufgebaut. - Ereignis- und Störungsrecords werden anhand der in der Anwendungsidentifikation angegebenen Gruppengrößen geschnitten. Leere Records werden verworfen.
- Fahrzeugeinsätze enthalten Nutzungsbeginn/-ende, Kilometerstände, Kennzeichen, Land, optional FIN und VU-Blockzähler.
- Orte und GNSS-Records liefern UTC-Zeit, Länder-/Regionscodes, Kilometerstand, Koordinaten, Genauigkeit und gegebenenfalls Authentifizierungsstatus.
- Texte werden codepagebewusst dekodiert, von Steuerzeichen bereinigt und mit stabiler Leerzeichennormalisierung gespeichert.
flowchart TD
A["C-Datei als Bytes"] --> B["5-Byte-Köpfe und Payloadgrenzen prüfen"]
B --> C["EF-Segmente mit Offset und SHA-256 bilden"]
C --> D["Anwendungsidentifikation lesen"]
D --> E["Generation und Recordanzahlen bestimmen"]
E --> F["Identität und Kartenmetadaten"]
E --> G["Ringpuffer der Aktivitäten"]
E --> H["Ereignisse / Störungen"]
E --> I["Fahrzeuge / Orte / GNSS"]
F --> J["Normalisierte C-Beobachtungen"]
G --> J
H --> J
I --> J
J --> K["Signierte EF-Blöcke prüfen"]
K --> L["Archivbezogene Tabellen ersetzen"]
4. Parsing von M-Dateien¶
4.1 TREP-Klassifizierung¶
Jede Sektion beginnt mit 0x76 und einem TREP-Code. Unterstützt werden:
| Generation | TREP-Codes | Bereiche |
|---|---|---|
| G1 | 01–05 |
Übersicht, Aktivitäten, Ereignisse/Störungen, Geschwindigkeit, Technik |
| G2 v1 | 21–25 |
dieselben fünf logischen Bereiche als RecordArrays |
| G2 v2 | 31–35 |
G2-v2-Struktur einschließlich zusätzlicher GNSS-/Grenz-/Ladedaten |
Gemischte Generationen, ungültige Längen, Daten hinter einer Signatur oder unvollständige Pflichtstrukturen führen zum Parsefehler. Eine fehlende detaillierte Geschwindigkeitssektion ist als optionaler Downloadumfang eine Warnung, kein Signaturfehler.
4.2 G1¶
G1-Sektionen haben feste beziehungsweise zählergesteuerte Strukturen und am Ende eine 128-Byte-Signatur. In der Übersicht werden zwei 194-Byte-Zertifikate gelesen. Diese Zertifikate gehören gemäß Annex IB nicht zum VU-signierten Bereich; die signierten Daten beginnen deshalb erst nach den 388 Zertifikatsbytes.
Wichtige G1-Regeln:
- FIN: exakt 17 Zeichen aus der Übersicht.
- Kennzeichen: Staat und Codepage werden übersprungen; gespeichert werden die 13 Zeichen der Registration Number.
- Datenzeitraum:
VuDownloadablePeriod, nichtCurrentDateTime. - Kartensitzungen: Namen, Kartennummer, Generation, Ablauf, Einstecken, Entnehmen und Slot.
- Aktivitätswechsel: 2-Byte-Wort mit Minute, Slot, Crew, Kartenzustand und Aktivität.
- Ereignisse, Störungen und Überschreitungen: zählergesteuerte Records mit UTC-Zeiten.
- Geschwindigkeit: Startzeit plus exakt 60 Geschwindigkeitsbytes.
- Technik und Kalibrierung: VU-Identität, Werkstatt, FIN, Kennzeichen und Kalibrierzeiten.
4.3 G2 v1 und G2 v2¶
G2-Sektionen bestehen nach dem TREP-Kopf aus RecordArrays. Jedes Array enthält Recordtyp, Recordgröße und Recordanzahl. Der Parser prüft record_size × record_count vor dem Lesen. Zertifikate (0x04, 0x0F) und Signatur (0x08) werden separat gehalten; pro Sektion ist genau ein Signaturrecord zulässig.
Jeder Fachrecord erhält section_index, section_code, record_index und einen SHA-256 des exakten Recordinhalts. Dekodiert werden unter anderem Identität, Zeitraum, Tages-/Kilometerdaten, Aktivitäten, Kartensitzungen, Ereignisse, Störungen, Überschreitungen, Geschwindigkeit, technische Daten, Kalibrierungen, Positionen, Grenzübertritte und Be-/Entladungen. Unbekannte begrenzte Recordtypen werden als Rohbezug und Warnung erhalten.
4.4 Geschwindigkeitsblöcke¶
G1, G2 v1 und G2 v2 werden identisch gespeichert:
start_epoch: Unix-Zeit der ersten Sekunde;speeds_blob: exakt 60 Bytes, ein Byte pro Sekunde;0xFF: fehlender Messwert, bleibt im Block erhalten;raw_sha256: einmalig als 32-Byte-BLOB über den Rohblock;- Primärschlüssel: Archiv, Startzeit, Sektion und Recordindex.
Die sekundengenaue Ansicht expandiert nur passende Blöcke. 0xFF wird nicht ausgegeben; Datumsfilter, Offset und Limit werden auf die expandierten gültigen Sekundenwerte angewendet.
flowchart TD
A["M-Datei als Bytes"] --> B{"TREP-Generation"}
B -->|"G1 01-05"| C["Feste/zählergesteuerte Sektionen"]
B -->|"G2 v1 21-25"| D["RecordArrays"]
B -->|"G2 v2 31-35"| D
C --> E["Signierten Bereich und 128-Byte-Signatur trennen"]
D --> F["Recordgröße und Anzahl validieren"]
F --> G["Zertifikate, Fachrecords und Signatur trennen"]
E --> H["Fachrecords normalisieren"]
G --> H
H --> I["SHA-256 je Rohrecord"]
H --> J["60-Sekunden-Geschwindigkeitsblöcke"]
I --> K["Sektionen einzeln verifizieren"]
J --> K
K --> L["M-Tabellen archivbezogen ersetzen"]
5. Signaturen und Trust Store¶
Der Trust Store liegt in tachograph_trust_anchor. Er speichert Generation, Schlüssel-ID, SHA-256-Fingerprint, Originalmaterial, Gültigkeitszeitraum, Widerruf, Quelle und Aktivstatus. Offizielle Trustanker werden ausschließlich beim zentralen Datenbank-Bootstrap beziehungsweise bei einer administrativen Aktualisierung eingespielt.
C-Dateien¶
- G1 verwendet Karten- und CA-Zertifikate sowie RSA PKCS#1 mit SHA-1 über die exakten Datenblockbytes.
- G2/G2V2 verwendet CardSign-/MSCA- und gegebenenfalls Linkzertifikate sowie ECDSA über die exakten signierten EFs.
- Das Ergebnis jedes Blocks wird in
ddd_drivercard_signaturegespeichert.
M-Dateien¶
- Jede Sektion wird getrennt über die ERCA/MSCA/VU-Kette geprüft.
- G1 verwendet RSA PKCS#1/SHA-1; G2 verwendet die im Zertifikat beschriebene ECC-/Hashkombination.
- Das Ergebnis jeder Sektion wird in
ddd_vu_signaturegespeichert.
Als Zertifikatsreferenzzeit wird der jüngste plausible signierte Fachzeitpunkt verwendet. Fehlt dieser, wird mit Warnung auf den Archivzeitpunkt zurückgefallen. Gesamtpriorität: INVALID, dann UNVERIFIABLE, dann MISSING, dann VALID. Ein fehlender Trustanker oder eine technisch nicht mögliche Prüfung wird niemals als VALID behandelt.
| Parserstatus | Bedeutung |
|---|---|
PARSED_VERIFIED |
Struktur und alle erforderlichen Signaturen gültig |
PARSED_VERIFIED_WITH_WARNINGS |
gültig, aber nichtfatale Parser-/Zeitwarnung |
QUARANTINED_INVALID_SIGNATURE |
kryptografisch ungültig |
QUARANTINED_UNVERIFIABLE |
Prüfung nicht vollständig möglich |
PARSE_ERROR |
Struktur oder Verarbeitung fehlgeschlagen |
6. Physisches Datenmodell¶
6.1 Archiv- und Nachweistabellen¶
| Tabelle | Zweck |
|---|---|
ddd_archive |
unveränderliche Archivmetadaten, Hashes und Gesamtstatus |
ddd_audit_log, fleet_audit_log |
Import-, Prüf-, Verknüpfungs- und Administrationsaudit |
tachograph_trust_anchor |
aktive und historische Trustanker |
app_schema_migration |
komponentenbezogene Schemaversionen |
6.2 C-Tabellen¶
| Tabelle | Wesentliche Inhalte |
|---|---|
ddd_drivercard_import |
Parser, Kartenidentität, Generation, Gültigkeit und Signaturgesamtstatus |
ddd_drivercard_activity |
Intervalle, Aktivität, Slot, Crew, Karte |
ddd_drivercard_event |
Ereignisart, UTC-Intervall, Fahrzeugbezug |
ddd_drivercard_fault |
Störungsart, UTC-Intervall, Fahrzeugbezug |
ddd_drivercard_vehicle_used |
Nutzung, Kilometer, Kennzeichen, FIN |
ddd_drivercard_position |
Ort/GNSS, Zeit, Kilometer, Koordinate und Authentifizierung |
ddd_drivercard_signature |
Blockergebnisse, Algorithmen und Zertifikatsfingerprints |
Die historisch vorhandenen Spalten raw_json und source_json bleiben aus Kompatibilitätsgründen im Schema, neue Imports schreiben dort jedoch NULL. Die Werte sind aus Original-DDD und regulären Fachspalten reproduzierbar und werden nicht als Cache dupliziert.
6.3 M-Tabellen¶
| Tabelle | Wesentliche Inhalte |
|---|---|
ddd_vehicle_unit_import |
Generation, Gesamtstatus, FIN, Kennzeichen, Seriennummer, Zeitraum und Warnungen |
ddd_vu_section |
Sektionscode, Generation, Byteoffsets und SHA-256 des signierten Bereichs |
ddd_vu_signature |
Signaturstatus je Sektion |
ddd_vu_raw_record |
Rohrecordposition, Größe, SHA-256 und optional Payload |
ddd_vu_activity, ddd_vu_card_session |
Aktivitätswechsel und Kartensitzungen |
ddd_vu_event, ddd_vu_fault, ddd_vu_overspeed |
Ereignisse, Störungen und Überschreitungen |
ddd_vu_speed_block |
kompakte 60-Sekunden-Blöcke als WITHOUT ROWID |
ddd_vu_technical |
technische Werte; details_json enthält die vollständige strukturierte VU-Identifikation für die Feldbaumdarstellung |
ddd_vu_calibration |
Kalibrierzeit, Zweck, Werkstatt, FIN, Kennzeichen und nächste Kalibrierung |
ddd_vu_position, ddd_vu_border_crossing, ddd_vu_load_operation |
GNSS-, Grenz- und Ladevorgänge |
ddd_vu_odometer_midnight |
Tageskilometerstand am folgenden UTC-Mitternachtspunkt |
fleet_vehicle_vu_link |
Zuordnung aller passenden M-Archive zu einem Fahrzeugstammsatz |
erDiagram
DDD_ARCHIVE ||--o| DDD_DRIVERCARD_IMPORT : "klassifiziert als C"
DDD_ARCHIVE ||--o| DDD_VEHICLE_UNIT_IMPORT : "klassifiziert als M"
DDD_DRIVERCARD_IMPORT ||--o{ DDD_DRIVERCARD_ACTIVITY : enthält
DDD_DRIVERCARD_IMPORT ||--o{ DDD_DRIVERCARD_SIGNATURE : belegt
DDD_VEHICLE_UNIT_IMPORT ||--o{ DDD_VU_SECTION : enthält
DDD_VEHICLE_UNIT_IMPORT ||--o{ DDD_VU_ACTIVITY : enthält
DDD_VEHICLE_UNIT_IMPORT ||--o{ DDD_VU_SPEED_BLOCK : enthält
DDD_VEHICLE_UNIT_IMPORT ||--o{ DDD_VU_CALIBRATION : enthält
DDD_ARCHIVE ||--o{ DDD_FACT_PROVENANCE : liefert
DDD_CANONICAL_FACT ||--o{ DDD_FACT_PROVENANCE : wird_belegt_durch
DDD_FACT_KIND ||--o{ DDD_CANONICAL_FACT : typisiert
FLEET_VEHICLE ||--o{ FLEET_VEHICLE_VU_LINK : besitzt
DDD_ARCHIVE ||--o| FLEET_VEHICLE_VU_LINK : zugeordnet
7. Indizes und SQLite-Konfiguration¶
Zentrale Indizes sind:
| Index | Abfragepfad |
|---|---|
idx_ddd_archive_name, idx_ddd_archive_archived_at |
Archivsuche und Chronologie |
idx_ddd_archive_type |
DDD-Art und Archivdatum |
idx_ddd_archive_parse_status |
Parser-/Signaturfilter |
idx_ddd_drivercard_import_normalized |
Kartennummer + Generation + Archiv |
idx_ddd_drivercard_activity_archive_time |
C-Aktivitäten eines Archivs im Zeitraum |
idx_ddd_drivercard_*_card |
globale Kartenabfragen nach Fachzeit |
ix_ddd_vu_activity_normalized_time |
C-/M-Abgleich nach normalisierter Kartennummer |
ix_ddd_vu_activity_archive_time |
M-Aktivitäten eines Archivs |
ix_ddd_vu_session_archive_time |
Kartensitzungen eines Archivs |
ix_fleet_vehicle_vu_vehicle |
alle M-Archive eines Fahrzeugs |
ix_ddd_fact_time, ix_ddd_fact_cluster |
materialisierte Fakten nach Typ/Zeit beziehungsweise Konfliktcluster |
ix_ddd_provenance_fact |
Quellen eines materialisierten Fakts |
ddd_vu_speed_block benötigt keinen zusätzlichen Zeitindex: Der zusammengesetzte Primärschlüssel beginnt mit archive_id,start_epoch und ist als WITHOUT ROWID bereits die physische Suchstruktur.
Alle Runtime-Verbindungen verwenden foreign_keys=ON, busy_timeout=30000, synchronous=NORMAL und einen begrenzten WAL-Autocheckpoint von 1.000 Seiten. Beim exklusiven Start wird journal_mode=WAL gesetzt. Schemaänderungen laufen vor dem Hauptfenster genau einmal über app_schema_migration; Runtime-Repositories werden mit ensure_schema=False geöffnet.
8. Archivübergreifende Deduplizierung¶
8.1 Zwei Zugriffspfade¶
Die archivbezogenen C-/M-Tabellen bleiben der genaue Herkunftsnachweis. Für Gesamtsichten existieren zwei kompatible Deduplizierungspfade:
- Materialisierte Fakten:
ddd_canonical_factplusddd_fact_provenancespeichert einen normalisierten Fakt einmal und verbindet ihn mit beliebig vielen Archiven. - Kompakter SQL-Fallback: Ist für eine Datenart keine materialisierte Quellenzuordnung vorhanden, dedupliziert das Repository direkt über die typisierten Archivtabellen mittels
ROW_NUMBER(),COUNT()undGROUP_CONCAT().
Die kompakte Produktivmigration verwendet den zweiten Pfad, weil eine zusätzliche vollständige Payloadmaterialisierung die Datenbank vergrößern würde. Die Schnittstellen und Ergebnisse sind gleich: source_count, source_archive_ids, preferred_source_archive_id und has_conflict.
8.2 Normalisierung und Hashes¶
Für materialisierte Fakten gilt:
- Text: Unicode NFC, trimmen und mehrfache Zwischenräume reduzieren.
- FIN, Kennzeichen und Kartennummer: Großschreibung; Leerzeichen, Bindestriche, Doppelpunkte und sonstige Nicht-Alphanumerik entfernen.
- reine Platzhalter aus
?,0,F, Trennzeichen oder leeren Werten: fehlende Information. - Zeit: UTC auf Sekundengenauigkeit.
- Zahlen, Koordinaten und Binärdaten: exakt, ohne Toleranz.
fact_hash: binärer SHA-256 aus Datenart und vollständig normalisiertem Fachinhalt; bei Geschwindigkeit einschließlichspeeds_blob.cluster_hash: binärer SHA-256 aus den identitätsbildenden Clusterfeldern, etwa Kalibrierzeit und Zweck.source_sha256: binärer 32-Byte-Hash des Quellrecords.
Bei Kartenbeobachtungen ist ausschließlich die vollständig normalisierte Kartennummer die
archiv- und quellenübergreifende Identität. card_generation bleibt als
Herkunftsmerkmal im Rohdatensatz und in der Quellenzuordnung erhalten, ist aber weder Bestandteil des
Faktenhashes noch ein Filter für den C-/M-Abgleich. Damit werden G1-Karte/G1-Fahrzeug,
G1-Karte/G2-Fahrzeug, G2-Karte/G1-Fahrzeug und G2-Karte/G2-Fahrzeug gleich behandelt.
ddd_canonical_fact besitzt UNIQUE(kind_id,fact_hash). ddd_fact_provenance ist WITHOUT ROWID und verwendet (archive_ref,fact_id,source_ordinal) als Primärschlüssel. Varianten mit gleichem cluster_hash, aber verschiedenem fact_hash, bleiben getrennt und werden bei materialisiertem Zugriff als Konflikt markiert.
8.3 Deduplizierung im SQL-Fallback¶
Der Fallback partitioniert nach allen fachlichen Feldern der jeweiligen Datenart. Innerhalb einer Partition wird genau eine Navigationsquelle gewählt:
PARSED_VERIFIEDundVALID;- höhere Generation: G2 v2, G2 v1, G1;
- jüngstes Archivdatum.
Diese Reihenfolge entscheidet nur, welches Archiv beim Öffnen angeboten wird. Sie verändert keine fachlichen Werte. COUNT(*) OVER (...) liefert die Quellenanzahl, GROUP_CONCAT(...) alle Archiv-IDs. Die C-Views ddd_drivercard_*_dedup verwenden dasselbe Prinzip für globale Kartenabfragen.
Exakte Geschwindigkeitsduplikate werden nach start_epoch und dem vollständigen 60-Byte-Blob gruppiert. Erst danach werden die Blöcke zu Sekundenwerten expandiert.
Technische Fahrzeugdaten werden anhand von record_type, Wert und der vollständig normalisierten Detailstruktur dedupliziert. Ältere Bestandszeilen ohne details_json werden im Hintergrund aus dem unveränderten, komprimierten M-Original rekonstruiert. Die Fahrzeugakte zeigt jede identische Variante einmal und nennt die Anzahl ihrer Quellarchive; Archiv-ID und Dateiname bleiben ausschließlich als Navigationsmetadaten erhalten. Neue Imports schreiben details_json direkt und beziehen es in den technischen Faktenhash ein.
flowchart TD
A["Fahrzeug oder Person"] --> B["Zugeordnete aktive Archive ermitteln"]
B --> C{"Materialisierte Quellenzuordnung vorhanden?"}
C -->|"Ja"| D["fact_hash auswählen und Quellen gruppieren"]
C -->|"Nein"| E["Archivtabellen per Window Function partitionieren"]
D --> F["Konfliktvarianten über cluster_hash bestimmen"]
E --> G["Exakte Dubletten und Quellenanzahl bestimmen"]
F --> H["Datumsfilter auf kanonische Fakten"]
G --> H
H --> I["Sortierung"]
I --> J["Limit und Offset"]
J --> K["DTOs an UI/Reporting"]
9. Datenzugriff¶
9.1 Repository-Schnittstellen¶
| Schnittstelle | Semantik |
|---|---|
list_vehicle_facts(kind, vehicle_id, ...) |
deduplizierte Gesamtsicht aller verknüpften M-Archive |
count_vehicle_facts(...) |
Anzahl nach Deduplizierung und Datumsfilter |
list_vehicle_speed_seconds(...) |
deduplizierte Blöcke, danach sekundengenaue Expansion |
list_person_facts(kind, person_id, ...) |
deduplizierte C-Gesamtsicht über verknüpfte Kartennummern |
list_archive_observations(kind, archive_id, ...) |
genaue Beobachtungen eines einzelnen Archivs |
list_rows(table, archive_id, ...) |
kompatibler M-Einzelarchivzugriff |
replace_archive_facts(...) |
materialisierte Fakten und Quellenzuordnungen eines Archivs ersetzen |
Fahrzeugarchive werden ausschließlich über fleet_vehicle_vu_link ermittelt. Personenarchive sowie passende M-Beobachtungen werden über fleet_drivercard_link und die normalisierte Kartennummer bestimmt. Die Kartengeneration dient nur der Anzeige und dem Herkunftsnachweis. Logisch gelöschte Archive sind aus Gesamtsichten ausgeschlossen.
9.2 Filter und Pagination¶
Gesamtsichten führen die Operationen in dieser Reihenfolge aus:
- Entität und aktive Quellarchive bestimmen.
- Fachlich deduplizieren.
- Datumsbereich auf dem Faktzeitfeld anwenden.
- Chronologisch sortieren.
LIMITundOFFSETanwenden.
Dadurch kann ein Duplikat nicht auf zwei Seiten erscheinen und die Gesamtzahl entspricht der sichtbaren Ergebnismenge. Die Einzelarchivansicht filtert dagegen direkt mit archive_id und bewahrt Recordreihenfolge beziehungsweise Sektionsbezug.
9.3 Zugriff aus der UI¶
Repository-Abfragen erfolgen in UiJobController-Workern. Der Worker öffnet seine eigene SQLite-Verbindung und liefert nur Listen, Dictionaries oder DTOs zurück. Qt-Widgets und Modelle werden ausschließlich im UI-Callback verändert. Detailtabs werden erst bei ihrer ersten Aktivierung erzeugt; Geschwindigkeit, Aktivitäten und andere große Tabellen laden seitenweise.
10. Idempotenz, Migration und Wiederherstellung¶
- Ein M-Reimport löscht und ersetzt Import-, Abschnitts-, Signatur-, Rohrecord- und Fachtabellen des Archivs innerhalb der Repository-Transaktion.
- C-Fachbereiche werden archivbezogen gelöscht und neu geschrieben; Signatur- und Archivstatus werden anschließend aktualisiert.
- Nicht mehr referenzierte materialisierte Fakten werden entfernt.
- Ein Parserfehler überschreibt einen zuvor verifizierten Archivstatus nicht mit unvollständigen Detaildaten.
raw_json-/source_json-Caches werden nicht neu aufgebaut.- Wartungsmigrationen arbeiten auf einer SQLite-Kopie, prüfen Originalhashes, Zählungen und
PRAGMA quick_check, erzeugen mitVACUUM INTOeine kompakte Kandidatin und tauschen sie nur nach erfolgreicher Abnahme aus. - Ist die Anwendung geöffnet, wird die Kandidatin über einen Hash- und Integritäts-geprüften Restore-Marker für den nächsten Start vorgemerkt. Vor dem Austausch entsteht eine zusätzliche Pre-Restore-Sicherung.
11. Diagnose für Administratoren¶
Empfohlene Nur-Lese-Prüfungen:
PRAGMA quick_check;
PRAGMA journal_mode;
SELECT component, version, applied_at, duration_ms
FROM app_schema_migration
ORDER BY component;
SELECT ddd_type, generation, parse_status, signature_status, COUNT(*)
FROM ddd_archive
WHERE is_deleted = 0
GROUP BY ddd_type, generation, parse_status, signature_status;
SELECT COUNT(*) AS speed_blocks,
SUM(60) AS stored_seconds
FROM ddd_vu_speed_block;
Direkte Schreibzugriffe auf die Datenbank sind im Betrieb nicht zulässig. Reparse, Migration, Restore und Linkkorrekturen müssen über die vorgesehenen Services erfolgen, damit Audit, Hashprüfung, Cacheinvalidierung und Status konsistent bleiben.