ED03 - Tagebuch-Format: JSON-Artifacts, temporale Signatur, V7GUID, Sidecars
Problem
Ein Unternehmer will sein Tagebuch in Git führen - aber wie genau sieht ein Eintrag technisch aus? Die heutige Praxis kennt keine verbindliche Antwort:
- Freitext-Notizen in Markdown, Word oder Papier - nicht maschinenlesbar, nicht schemavalidiert, nicht nachvollziehbar
- Excel-Zeilen mit Datum, Tätigkeit, Stunden - nicht versioniert, nicht kryptographisch verankert, nicht revisionssicher
- Lohnsoftware-Exporte als PDF - nicht maschinell auswertbar (§ 147 Abs. 6 AO), nicht retrograd/progressiv nachverfolgbar
- Keine eindeutige Identität - jeder Eintrag hat einen Dateinamen, aber der Dateiname kann sich ändern; die Identität des Eintrags ist nicht stabil
- Keine temporale Verankerung - das Datum steht als String im Dokument, aber wer hat wann wirklich erfasst? Die Erfassungszeit ist nicht kryptographisch mit der Identität verknüpft
Kernaussage
Ein GitCover-Tagebucheintrag ist ein JSON-Artifact mit:
- JSON-Schema-First - das Schema existiert vor dem Eintrag; der Eintrag wird gegen das Schema validiert (Pre-Commit-Hook)
- V7GUID (Class Identifier) - klassifiziert das Dokument/die Action
anhand der
.gitcoverRegistry (was/welcher Typ); dient der Ablage-Organisation und DB-Query (z. B. EF Core in Vertical App) - uuidV7 (Object ID) - ist bereits allein die eindeutige Identität
(DocID) des Eintrags, RFC 9562 §5.7, generiert aus einer
vorgegebenen Zeitmarke (nicht
now()) via GitCover Helper (UuidV7Gen), Rest mit Zufall aufgefüllt - Composite Key
V7GUID:uuidV7- der GCPN Sidecar Composite Key, dient Ablage-Organisation und Query; die Erfassungszeit steckt in deruuidV7(48-Bit-Zeitstempel), kein separatesdatetime/date-Feld - Sidecar-Pflicht - jeder Beleg erhält einen
.v7g.md-Sidecar mit eigeneruuidV7(Klassifizierungsakt) und deruuidV7des Dokuments - Retrograde/progressive Nachverfolgbarkeit - vom Buchungssatz →
Beleg → Tagebucheintrag →
uuidV7und zurück auflösbar
Compliance by Design: Das Format ist nicht nachträglich - es ist strukturell. Schema, V7GUID (Class), uuidV7 (Object) und Sidecar sind Pflichtfelder, ohne die ein Eintrag nicht ins Repo aufgenommen wird.
Kein redundantes
datetime/date: Die Erfassungszeit ist in deruuidV7selbst verankert (48-Bit-Zeitstempel, RFC 9562 §5.7). Eine separate String-Darstellung in JSON-Schemata oder JSON-Daten ist redundant und wird nicht in den Fakten geführt. String-Darstellung für DTO/HTMX-Transfer ist Harness-Verantwortung, nicht Fakten-Ebene.
Das JSON-Schema (Schema-First)
(vor Eintrag)"] S --> V["Schema-Validierung
(Pre-Commit-Hook)"] E["Tagebucheintrag
(JSON)"] E --> V V -->|gültig| C["Commit akzeptiert
+ uuidV7 generiert"] V -->|ungültig| R["Commit abgelehnt
Schema-Verstoß"] style S fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style V fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style E fill:#0F1B33,stroke:#0F1B33,color:#FBFAF7 style C fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style R fill:#FDBA74,stroke:#C2410C,color:#0F1B33
Das Schema existiert vor dem Eintrag - es wird im
.gitcover/schemas/diary-entry-1.0.schema.json abgelegt und ist
versioniert. Ein Eintrag ohne Schema-Referenz ($schema) wird vom
Pre-Commit-Hook abgelehnt.
Schema diary-entry-1.0.schema.json (vereinfacht)
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://gitcover.org/schemas/diary-entry-1.0.schema.json",
"title": "GitCover Diary Entry v1.0",
"type": "object",
"required": [
"$schema", "V7GUID", "uuidV7",
"author", "role", "tenant", "sphere", "source"
],
"properties": {
"$schema": {
"type": "string",
"format": "uri",
"const": "https://gitcover.org/schemas/diary-entry-1.0.schema.json"
},
"V7GUID": {
"type": "string",
"description": "Class Identifier - klassifiziert das Dokument/die Action aus .gitcover Registry (was/welcher Typ)"
},
"uuidV7": {
"type": "string",
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
"description": "Object ID - RFC 9562 §5.7 UUIDv7, generiert aus vorgegebener Zeitmarke (nicht now()), 48-Bit-Zeitstempel in der GUID verankert"
},
"author": { "type": "string", "description": "Akteur-Platzhalter, z. B. E1" },
"role": {
"type": "string",
"enum": ["GF", "Buchhalter", "Lohnverantwortlicher", "F&E-Leiter", "Administrator"]
},
"tenant": { "type": "string", "description": "Tenant-Platzhalter, z. B. ORG-1" },
"sphere": {
"type": "string",
"enum": ["ideell", "vermögensverwaltend", "zweckbetrieblich", "wirtschaftlich", "n/a"]
},
"source": {
"type": "string",
"enum": ["E1", "StB", "Notar", "Bank", "DRV", "FA", "BA", "VBG", "KK", "auto"]
},
"source_sha256": {
"type": "string",
"pattern": "^[0-9a-f]{64}$",
"description": "SHA-256 des referenzierten Belegs (eindeutige Beleg-ID)"
},
"tags": { "type": "array", "items": { "type": "string" } }
}
}
Wichtig - kein
datetime/date-Feld: Die Erfassungszeit steckt in deruuidV7(48-Bit-Zeitstempel, RFC 9562 §5.7). Eine separate String-Darstellung ist redundant und wird nicht in den Fakten geführt. DieuuidV7allein ist die eindeutige DocID; der Composite KeyV7GUID:uuidV7dient der Ablage-Organisation und DB-Query.
V7GUID - Aufbau und 48-Bit-Zeitstempel
Bits 0–47
48 Bit Unix-ms"] V["version
Bits 48–51
0111 (UUIDv7)"] R["rand_a
Bits 52–63
12 Bit"] VA["variant
Bits 64–65
10"] RB["rand_b
Bits 66–127
62 Bit"] end T --> DT["48-Bit-Zeitstempel
in uuidV7 verankert
(kein separates datetime-Feld)"] V7 --> ID["uuidV7-Feld
Object ID
(vorgegebene Zeitmarke)"] style T fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style V fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style R fill:#E5E7EB,stroke:#6B7280,color:#0F1B33 style VA fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style RB fill:#E5E7EB,stroke:#6B7280,color:#0F1B33 style DT fill:#0F1B33,stroke:#0F1B33,color:#FBFAF7 style ID fill:#0F1B33,stroke:#0F1B33,color:#FBFAF7
| Bit-Bereich | Breite | Inhalt | RFC-fix |
|---|---|---|---|
| 0–47 | 48 Bit | Unix-Millisekunden seit Epoch (1970-01-01T00:00:00Z) | Ja (RFC 9562 §5.7) |
| 48–51 | 4 Bit | Version = 0111 (UUIDv7) |
Ja |
| 52–63 | 12 Bit | rand_a (Zufall) | Nein |
| 64–65 | 2 Bit | Variant = 10 |
Ja |
| 66–127 | 62 Bit | rand_b (Zufall) | Nein |
Kernprinzip: Die 48-Bit-Zeitstempel-Komponente (Bits 0–47) ist autoritativ für die Erfassungszeit. Sie ist in der
uuidV7selbst verankert und kann nicht nachträglich geändert werden, ohne die GUID ungültig zu machen. Ein separatesdatetime-Feld existiert nicht - die Zeit steckt in deruuidV7. String-Darstellung für DTO/HTMX ist Harness-Verantwortung.
GitCover-Erweiterung: Hierarchie und Prozess-IDs in Bits 66–127
Die GitCover-V7GUID-Spezifikation (work/OSS/TOP/.gitcover/specs/v7guid/)
erweitert die 62-Bit-Zufallskomponente (Bits 66–127) um eine
6-Level-Hierarchie und Prozess-IDs - das ist die patentgeschützte
Erweiterung (DPMA Az. 10 2025 003 091.6):
| Bit-Bereich | Breite | Inhalt |
|---|---|---|
| 66–89 | 6×4 Bit | 6-Level-Hierarchie (L1–L6, je 4 Bit) |
| 90–97 | 8 Bit | ProcessTypeId (Prozesstyp) |
| 98–105 | 8 Bit | GatewayId (Kontrollpunkt) |
| 106–113 | 8 Bit | Status (Lebenszyklus-Bitmask) |
| 114–121 | 8 Bit | Kind (Art der Tätigkeit) |
| 122–127 | 6 Bit | VariantId (Ausprägungsklasse) |
Hinweis: Diese Erweiterung ist für die Tagebuch-Serie nicht zwingend erforderlich - sie wird in ED02 (Tenant/Sphäre/Rolle) und späteren Artikeln (Harness) relevant. Hier genügt die RFC-9562-Basis mit 48-Bit-Zeitstempel.
Helper-Routinen: V7GUID aus Fremd-Keys erstellen
(Zeitmarke in Daten
oder Dateiname)"] F --> H["Helper-Routine
UuidV7Gen"] H --> TS["48-Bit-Zeitstempel
extrahiert/konvertiert"] TS --> G["uuidV7 generiert
(Guid.CreateVersion7)"] G --> A["JSON-Artefakt
V7GUID + uuidV7"] A --> D["GoBD-Dokumentation
zeitnahe Erfassung
nachvollziehbar"] style F fill:#FDBA74,stroke:#C2410C,color:#0F1B33 style H fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style TS fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style G fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style A fill:#0F1B33,stroke:#0F1B33,color:#FBFAF7 style D fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33
Das GitCover OSS Tool UuidV7Gen (work/OSS/TOP/tools/UuidV7Gen/)
stellt zwei zentrale Operationen bereit:
gen - uuidV7 (guid) erzeugen
# Erzeugt eine neue uuidV7 mit vorgegebener Zeitmarke (nicht now())
# Zeitmarke z. B. aus Dateiname "260815_0900" → ISO 2026-08-15T09:00:00Z
uuidv7gen gen "2026-08-15T09:00:00Z" "Tagebucheintrag-260815"
# Ausgabe: Label;UUID;ISO-Zeitstempel
# Tagebucheintrag-260815;019f2c6f-0900-7000-8000-000000000000;2026-08-15T09:00:00.000Z
decode - Zeitstempel aus uuidV7 extrahieren
# Extrahiert den 48-Bit-Zeitstempel aus einer uuidV7
uuidv7gen decode 019f2c6f-0900-7000-8000-000000000000
# Ausgabe: ISO-8601-Zeitstempel
# 2026-08-15T09:00:00.000Z
Fremd-Key → uuidV7
Die Helper-Routinen erlauben, aus einem Fremd-Key (z. B. eine Zeitmarke
im Dateinamen wie 260815_0900_Lohnabrechnung.pdf) einen gültigen
uuidV7-Schlüssel zu erstellen - mit vorgegebener Zeitmarke, nicht
now():
- Fremd-Key parsen -
260815_0900→2026-08-15T09:00:00Z - 48-Bit-Zeitstempel berechnen - Unix-Millisekunden seit Epoch
uuidV7generieren -Guid.CreateVersion7()mit explizitem Zeitstempel, Rest mit Zufall- Composite Key -
V7GUID(Class aus Registry) :uuidV7(Object mit Zeitmarke) - GoBD-Dokumentation - zeitnahe Erfassung nachvollziehbar verankert (kein separates datetime-Feld)
GoBD-Bezug: Die zeitnahe Erfassung (GoBD Rz. 146) wird durch den 48-Bit-Zeitstempel in der
uuidV7kryptographisch dokumentiert - nicht nur behauptet. Der Zeitstempel ist Teil der Identität, nicht nachträglich änderbar.
Sidecar-Struktur (.v7g.md)
Jeder Beleg erhält einen Sidecar mit zwei uuidV7 Bezügen:
(PDF, XML, EML)"] D --> S["Sidecar .v7g.md"] S --> U1["uuidV7 (eigen)
Identität des Sidecars
+ 48-Bit-Erfassungszeit"] S --> U2["uuidV7 (fremd)
Identität des Dokuments
in v7g_taxonomy"] S --> SH["sha256
Eindeutige Beleg-ID"] S --> T["v7g_taxonomy
Klassifizierung
(Tenant, Sphäre, Kategorie)"] S --> O["obsolescence
status: active/superseded/obsolete"] style D fill:#0F1B33,stroke:#0F1B33,color:#FBFAF7 style S fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style U1 fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style U2 fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style SH fill:#FDBA74,stroke:#C2410C,color:#0F1B33 style T fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style O fill:#E5E7EB,stroke:#6B7280,color:#0F1B33
Sidecar-Beispiel
{
"$schema": "https://gitcover.org/schemas/v7g-sidecar-1.0.schema.json",
"V7GUID": "<V7GUID-Class-aus-Registry>",
"uuidV7": "019f2c6f-0900-7001-8000-000000000001",
"sha256": "ab94670c0dd8499c27ef2feddd1d9c5925977d55a52150a6fca0f6567d2e5e79",
"title": "260815_Lohnabrechnung.pdf",
"original_filename": "260815_Lohnabrechnung.pdf",
"locations": [
{
"unc_path": "./ORG-1/sources/lohn/260815_Lohnabrechnung.pdf",
"from": "260815",
"to": null,
"note": "Primärspeicherort"
}
],
"v7g_taxonomy": [
{
"v7guid": "019f2c6f-0900-7000-8000-000000000000",
"taxonomy": "ORG-1/Lohn",
"valid_from": "260815",
"valid_to": null,
"note": "Tenant: ORG-1, Category: Lohn, Sphäre: ideell"
}
],
"gcpn": {
"prima_nota_ref": null,
"journal_entry_ref": null
},
"obsolescence": {
"status": "active",
"superseded_by": null,
"superseded_at": null
}
}
Composite Key
V7GUID:uuidV7:
V7GUID(Feld 1) - Class Identifier des Sidecars (Klassifizierung aus.gitcoverRegistry: was/welcher Typ)uuidV7(Feld 2) - Object ID des Sidecars selbst, generiert mit vorgegebener Zeitmarke (wann wurde klassifiziert?), 48-Bit-Zeitstempel in der GUID verankertv7g_taxonomy[].v7guid- Object ID des klassifizierten Dokuments (welches Dokument wird klassifiziert?)So ist nicht nur das Dokument eindeutig identifiziert, sondern auch der Klassifizierungsakt selbst - inklusive Zeitpunkt (in
uuidV7), wer klassifiziert hat und in welcher Rolle. Kein separatesdatetime-Feld - die Zeit steckt in denuuidV7-Werten.
Retrograde und progressive Nachverfolgbarkeit
(SKR04)"] B --> BE["Beleg
(SHA-256)"] BE --> DE["Tagebucheintrag
(uuidV7)"] DE --> V7["uuidV7
(48-Bit-Zeitstempel)"] end subgraph PRO["Progressiv (vom Beleg vorwärts)"] direction LR BE2["Beleg
(SHA-256)"] BE2 --> BS["Buchungssatz
(SKR04)"] BS --> GB["Grundbuch
(JSON)"] GB --> EB["Eröffnungsbilanz"] end style B fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style BE fill:#FDBA74,stroke:#C2410C,color:#0F1B33 style DE fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style V7 fill:#0F1B33,stroke:#0F1B33,color:#FBFAF7 style BE2 fill:#FDBA74,stroke:#C2410C,color:#0F1B33 style BS fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style GB fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style EB fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33
| Richtung | Start | Auflösung über | Ziel |
|---|---|---|---|
| Retrograd | Buchungssatz (SKR04) | source_sha256 → Beleg → uuidV7 |
Tagebucheintrag mit 48-Bit-Zeitstempel |
| Progressiv | Beleg (SHA-256) | uuidV7 → Tagebucheintrag → source_sha256 |
Buchungssatz → Grundbuch → Eröffnungsbilanz |
GoBD-Bezug: Die retrograde Nachverfolgbarkeit entspricht GoBD Rz. 146 (Nachvollziehbarkeit). Die progressive Nachverfolgbarkeit entspricht GoBD Rz. 147 (Prüfbarkeit). Beide sind by Design durch
uuidV7+ SHA-256 gewährleistet - nicht durch manuelle Querverweise.
Zeit-Erfassung im Tagebuch
Jeder Tagebucheintrag enthält eine Zeit-Erfassungstabelle:
| Start | Ende | Stunden | Aktivität | Tenant | Sphäre | Quelle |
|---|---|---|---|---|---|---|
| 0900 | 1200 | 3,0 | Lohnkonto-Stammdaten | ORG-1 | ideell | E1 |
| 1200 | 1400 | 2,0 | F&E: V7GUID-Spezifikation | ORG-1 | ideell | E1 |
FZul-Bezug: Die Zeit-Erfassung ist die Grundlage für FZul-Stundennachweise (ED18). Die Trennung F&E vs. Verwaltung erfolgt über das
role-Feld (F&E-Leitervs.GF) und dietags(["fzul", "forschung"]vs.["verwaltung"]).
Was im Git-Repo landet - und was nicht
(Tagebucheinträge, Grundbuch)"] IN --> S["Sidecars .v7g.md"] IN --> B["Belege
(PDF, XML, EML)"] IN --> SC["Schemata"] IN --> D["Dictionaries"] OUT["Nicht im Git-Repo"] OUT --> P["Private Dokumente
(sofern nicht ausdrücklich eingeführt)"] OUT --> T["Temporäre Dateien"] OUT --> C["Credentials/Secrets"] style IN fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style J fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style S fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style B fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style SC fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style D fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style OUT fill:#FDBA74,stroke:#C2410C,color:#0F1B33 style P fill:#FDBA74,stroke:#C2410C,color:#0F1B33 style T fill:#FDBA74,stroke:#C2410C,color:#0F1B33 style C fill:#FDBA74,stroke:#C2410C,color:#0F1B33
Wichtig: Nur strukturierte Artefakte (JSON, Sidecars, Belege, Schemata, Dictionaries) werden ins Git-Repo aufgenommen. Private Dokumente werden nie ins Repo aufgenommen, sofern sie nicht ausdrücklich als Artefakt eingeführt und klassifiziert wurden. Das ist eine Datenschutz- und Compliance-Anforderung (DSGVO, GoBD).
Risiko-Leverage
| Heute (cheap) | Morgen (revisionssicher) | Risiko gemindert |
|---|---|---|
JSON-Artefakt mit V7GUID (Class) + uuidV7 (Object) |
Erfassungszeit kryptographisch in uuidV7 verankert | Bestreitung der Erfassungszeit |
| Schema-Validierung (Pre-Commit) | Nur gültige Einträge ins Repo | Schema-Verstoß, unvollständige Pflichtfelder |
Sidecar mit Composite Key V7GUID:uuidV7 |
Klassifizierungsakt nachvollziehbar | Bestreitung der Klassifizierung |
source_sha256 pro Eintrag |
Retrograde Nachverfolgbarkeit | Bestreitung der Beleg-Zuordnung |
Helper UuidV7Gen für Fremd-Keys |
Zeitnahe Erfassung dokumentiert (Zeitmarke in uuidV7) | GoBD-Verstoß "nicht zeitnah" |
Harness-Anforderung (Vorschau)
Aus ED03 ableitbar:
| ID | Anforderung | Priorität |
|---|---|---|
| FA-1.1 | Tagebuch-Einträge als JSON-Artifacts (Schema-First) | MUST |
| FA-1.2 | Composite Key V7GUID (Class) : uuidV7 (Object) - kein separates datetime/date-Feld; Zeit in uuidV7 (RFC 9562 §5.7) |
MUST |
| FA-1.3 | uuidV7 generiert aus vorgegebener Zeitmarke (nicht now()) via Helper |
MUST |
| FA-2.1 | SHA-256 als Beleg-ID | MUST |
| FA-2.2 | .v7g.md Sidecar-Pflicht |
MUST |
| FA-2.3 | Sidecar mit Composite Key V7GUID:uuidV7 (Class + Object) |
MUST |
| FA-2.12 | Retrograde Nachverfolgbarkeit (Buchung → Beleg → uuidV7) |
MUST |
| FA-2.13 | Progressive Nachverfolgbarkeit (Beleg → Buchung → Grundbuch) | MUST |
| TA-1.5 | Helper-Routinen für V7GUID-Erstellung aus Fremd-Keys (UuidV7Gen) |
MUST |
| TA-1.6 | Temporal-Anforderungen GoBD dokumentiert (48-Bit-Zeitstempel in uuidV7) |
MUST |
| TA-2.1 | Pre-Commit: JSON-Schema-Validierung | MUST |
Die vollständige Anforderungsliste in Harness-Anforderungen.md.
Quellen
- RFC 9562 §5.7 (UUIDv7) - 48-Bit Unix-ms-Zeitstempel
- V7GUID-Spezifikation -
work/OSS/TOP/.gitcover/specs/v7guid/(normativ) - DPMA Az. 10 2025 003 091.6 - V7GUID-Patent (Hauptanspruch 2, Ansprüche 5–8)
- GitCover OSS Tool
UuidV7Gen-work/OSS/TOP/tools/UuidV7Gen/(Helpergen/decode) - GoBD (BMF-Schreiben, Rz. 146 - Nachvollziehbarkeit, Rz. 147 - Prüfbarkeit)
- AO (§ 147 Abs. 2 - "maschinell auswertbar", § 147 Abs. 6 - Datenzugriff)
AFJD/agents/(anonymisiert) - SSoT-Konzept mit JSON-Artifacts, Sidecars
Quellen-Topologie und CDN-Referenz-Links
| Rolle | Ort | Zweck |
|---|---|---|
| Primary / SSoT | git.gitcover.org/GCC | Kanonische Ablage (GPG-signiert, versioniert) |
| Public OSS Mirror / CDN | codeberg.org/gitcover-commons | Read-only-Spiegel; FLOSS-Discovery |
| Community Hub | github.com/gitcover-commons | Issues & Discussions; Quell-Code-Referenz auf Codeberg |
Hinweis: Diese Zuordnung von Quellen, Mirror und Community-Hub spiegelt den aktuellen Stand wider und kann sich ändern. Bitte prüfen Sie die jeweilige kanonische Quelle auf gitcover.org für den aktuellen Zustand.