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:

Kernaussage

Ein GitCover-Tagebucheintrag ist ein JSON-Artifact mit:

  1. JSON-Schema-First - das Schema existiert vor dem Eintrag; der Eintrag wird gegen das Schema validiert (Pre-Commit-Hook)
  2. V7GUID (Class Identifier) - klassifiziert das Dokument/die Action anhand der .gitcover Registry (was/welcher Typ); dient der Ablage-Organisation und DB-Query (z. B. EF Core in Vertical App)
  3. 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
  4. Composite Key V7GUID:uuidV7 - der GCPN Sidecar Composite Key, dient Ablage-Organisation und Query; die Erfassungszeit steckt in der uuidV7 (48-Bit-Zeitstempel), kein separates datetime/date-Feld
  5. Sidecar-Pflicht - jeder Beleg erhält einen .v7g.md-Sidecar mit eigener uuidV7 (Klassifizierungsakt) und der uuidV7 des Dokuments
  6. Retrograde/progressive Nachverfolgbarkeit - vom Buchungssatz → Beleg → Tagebucheintrag → uuidV7 und 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 der uuidV7 selbst 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)

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#FBFAF7','primaryTextColor':'#0F1B33','primaryBorderColor':'#6B7280','lineColor':'#6B7280'}}}%% flowchart LR S["JSON-Schema
(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 der uuidV7 (48-Bit-Zeitstempel, RFC 9562 §5.7). Eine separate String-Darstellung ist redundant und wird nicht in den Fakten geführt. Die uuidV7 allein ist die eindeutige DocID; der Composite Key V7GUID:uuidV7 dient der Ablage-Organisation und DB-Query.

V7GUID - Aufbau und 48-Bit-Zeitstempel

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#FBFAF7','primaryTextColor':'#0F1B33','primaryBorderColor':'#6B7280','lineColor':'#6B7280'}}}%% flowchart LR subgraph V7["V7GUID (128 Bit, RFC 9562 §5.7)"] direction LR T["timestamp_ms
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 uuidV7 selbst verankert und kann nicht nachträglich geändert werden, ohne die GUID ungültig zu machen. Ein separates datetime-Feld existiert nicht - die Zeit steckt in der uuidV7. 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

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#FBFAF7','primaryTextColor':'#0F1B33','primaryBorderColor':'#6B7280','lineColor':'#6B7280'}}}%% flowchart LR F["Fremd-Key
(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():

  1. Fremd-Key parsen - 260815_09002026-08-15T09:00:00Z
  2. 48-Bit-Zeitstempel berechnen - Unix-Millisekunden seit Epoch
  3. uuidV7 generieren - Guid.CreateVersion7() mit explizitem Zeitstempel, Rest mit Zufall
  4. Composite Key - V7GUID (Class aus Registry) : uuidV7 (Object mit Zeitmarke)
  5. 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 uuidV7 kryptographisch 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:

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#FBFAF7','primaryTextColor':'#0F1B33','primaryBorderColor':'#6B7280','lineColor':'#6B7280'}}}%% flowchart TD D["Dokument
(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 .gitcover Registry: was/welcher Typ)
  • uuidV7 (Feld 2) - Object ID des Sidecars selbst, generiert mit vorgegebener Zeitmarke (wann wurde klassifiziert?), 48-Bit-Zeitstempel in der GUID verankert
  • v7g_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 separates datetime-Feld - die Zeit steckt in den uuidV7-Werten.

Retrograde und progressive Nachverfolgbarkeit

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#FBFAF7','primaryTextColor':'#0F1B33','primaryBorderColor':'#6B7280','lineColor':'#6B7280'}}}%% flowchart LR subgraph RET["Retrograd (vom Buchungssatz rückwärts)"] direction LR B["Buchungssatz
(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-Leiter vs. GF) und die tags (["fzul", "forschung"] vs. ["verwaltung"]).

Was im Git-Repo landet - und was nicht

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#FBFAF7','primaryTextColor':'#0F1B33','primaryBorderColor':'#6B7280','lineColor':'#6B7280'}}}%% flowchart TD IN["Ins Git-Repo"] IN --> J["JSON-Artefakte
(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

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.