Zusammenfassung
Diese Dokumentation beschreibt interne technische Prozesse, die das Verständnis und den Umgang mit den Daten erleichtern, wenn mit diesen außerhalb der Receipts App umgegangen werden soll. Die Architektur ist im Geiste von “Local First” und “File Over App” entworfen.
Dateiformat - Sync
Log
Änderungen an Daten werden in ein spezielles fortlaufendes “Log” geschrieben. Dabei schreibt jede Installation ihren eigenen Log. Installationen werden durch eine unikale clientId
unterschieden. Die Einträge in jedem Log werden fortlaufend mit ganzen Zahlen nummeriert, beginnend mit der 0
. Im Dateisystem wird aus technischen Gründen (Vermeidung von Konflikten, Integritätsprüfung, Vereinfachung für fremde Datei-Sync-Services) für jeden Eintrag eine eigene Datei erzeugt, die nach einem Verteilungs-Algorithmus zu je 1000 Dateien in einzelne Verzeichnisse geschrieben werden.
Änderungen
Die Änderungen der lokalen Datenbank werden als Liste gesammelt und in einer Transaktion (transactions
) zusammengefasst. Durch den Wert von _id
wird jedes einzelne Datenbank-Objekt eindeutig identifiziert. Der ganzzahlige Wert von _v
wird für die Last-Write-Wins (LWW) Methode verwendet (Lamport-Clock), um bei der Wiederherstellung einen letztendlich konsistenten Datenbestand sicherzustellen. Dabei werden nur die neuen Werte beim Sync gesetzt, deren _v
Eintrag größer als der vorgefundene Wert ist. Sollte es dort zum Konflikt kommen, gewinnt der Eintrag mit dem höheren Zeitstempel. Durch diese Methode ist die Reihenfolge der Anwendung der Änderungseinträge unerheblich (CRDT).
Dateiformat
Die Ablage erfolgt in der einfachsten Form als JSONL Datei. Die erste Zeile ist der Header und alle nach dem Zeilenwechsel folgenden Daten, in ihrer tatsächlichen binären Representation, sind der Content.
Der Header enthält die Prüfelemente s
mit der Größe an Bytes des Contents. c
die SHA256 Checksumme des Contents als Base64 mit URL konformer Kodierung (-
statt +
und _
statt /
) ohne Padding. t
ist die Uhrzeit der Erstellung als Timestamp in Sekunden. v
enthält die Versionsnummer des Formates, die aktuell 1
ist, aber so für Anpassungen vorbereitet ist. Beispiel:
{"s":1473,"v":1,"c":"QHqyEU4WJOFsnxitlmsXFmpCXV2kZCCctzvO50_3IgM","t":1732311704}
Es folgen die einzelnen Änderung pro Zeile als JSON Objekt, wie in JSONL definiert. Siehe oben. Beispiel:
{"_id":"47855a70de36449f821d40b45f8c170a","_type":"category","_v":1,"title":"Telekommunikation"}
Dateianhänge
Dateien werden außerhalb der Datenbank gespeichert als Assets (assets
). Diese werden ebenfalls pro Client mit einem fortlaufenden Index gespeichert, analog zu den Transaktionen. Datenbankeinträge verweisen auf Assets mit einer speziellen URL, die folgende Daten enthält:
cid
: Die Client-ID.idx
: Der Index innerhalb der Assets Ablage.
Metadaten werden nicht mit abgelegt, sondern sind Teil des Verweises, wodurch wiederum auch die Konsistenz der Daten geprüft werden kann. Weitere Informationen sind:
checksum
: SHA-256 als Base64 kodiert.size
: Größe in Bytes.type
: MIME Type.name
: Dateiname.
Der Verweis zum Asset wird als URL kodiert:
asset:///
cid
/idx
/name
?t=type
&s=size
&d=checksum
Beispiel:
asset:///1EH7BEtuL9xOz5aTpEyI4K/466/unnamed?s=6284&t=application%2Fpdf&d=JAd0HmXcSIVVdYMmDBjfVZeTvAyXQ94GmjA6CwSwOYU
Spezielle Datentypen
- Der Verweis zu einem anderen Datensatz wird durch die
_id
des Eintrages realisiert. Der Name der Eigenschaft entspricht in der Regel dem Typ des Zielobjektes:_type
. - Datum ohne Uhrzeit wird durch einen Integer Wert mit dem Format
YYYYMMDD
realisiert. Der 1. Dezember 2024 wird also als20241201
dargestellt. - Der Betrag wird als Fließkommazahl dargestellt z. B.
1.23
. - Timestamps sind in der Regel Sekundengenau.
Beispiel
node.js Projekt das die Receipts Sync Datei ausliest, die Datenbank herstellt und alle Daten (JSON) und Assets in den Ordner export
schreibt: