ED03 - Định dạng Nhật ký: JSON Artefact, Chữ ký thời gian, V7GUID, Sidecar
Vấn đề
Một doanh nhân muốn giữ nhật ký trong Git - nhưng chính xác một mục trông như thế nào về kỹ thuật? Thực hành hiện nay không có câu trả lời bắt buộc:
- Ghi chú văn bản tự do trong Markdown, Word hoặc giấy - không đọc được bằng máy, không xác thực schema, không truy vết được
- Hàng Excel với ngày, hoạt động, giờ - không có phiên bản, không neo mật mã, không kiểm toán được
- Xuất phần mềm lương dạng PDF - không đánh giá được bằng máy (§ 147 Abs. 6 AO), không truy vết retrograde/progressive
- Không có danh tính duy nhất - mỗi mục có tên tệp, nhưng tên tệp có thể đổi; danh tính của mục không ổn định
- Không neo thời gian - ngày là chuỗi trong tài liệu, nhưng ai đã ghi nhận gì khi nào? Thời điểm ghi nhận không được liên kết mật mã với danh tính
Tuyên bố cốt lõi
Một mục nhật ký GitCover là một JSON artefact với:
- JSON-Schema-First - schema tồn tại trước mục; mục được xác thực chống schema (Pre-Commit hook)
- V7GUID (Class Identifier) - phân loại tài liệu/hành động dựa
trên registry
.gitcover(cái gì/loại nào); phục vụ tổ chức lưu trữ và truy vấn DB (ví dụ EF Core trong Vertical App) - uuidV7 (Object ID) - đã một mình là danh tính duy nhất
(DocID) của mục, RFC 9562 §5.7, tạo từ timestamp định sẵn
(không phải
now()) qua GitCover helper (UuidV7Gen), phần còn lại điền ngẫu nhiên - Composite Key
V7GUID:uuidV7- GCPN Sidecar Composite Key, phục vụ tổ chức lưu trữ và truy vấn; thời điểm ghi nhận nằm tronguuidV7(timestamp 48-bit), không có trườngdatetime/dateriêng - Nghĩa vụ sidecar - mỗi chứng từ nhận một sidecar
.v7g.mdvớiuuidV7riêng (hành động phân loại) vàuuidV7của tài liệu - Truy vết retrograde/progressive - giải quyết được từ booking →
chứng từ → mục nhật ký →
uuidV7và ngược lại
Compliance by Design: Định dạng không phải sau sự cố - nó mang tính cấu trúc. Schema, V7GUID (Class), uuidV7 (Object) và sidecar là trường bắt buộc, không có chúng một mục không được nhận vào repo.
Không
datetime/datedư thừa: Thời điểm ghi nhận được neo trong chínhuuidV7(timestamp 48-bit, RFC 9562 §5.7). Một biểu diễn chuỗi riêng trong JSON schema hoặc dữ liệu JSON là dư thừa và không được giữ trong facts. Biểu diễn chuỗi cho DTO/HTMX transfer là trách nhiệm của harness, không phải lớp facts.
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
Schema tồn tại trước mục - nó được lưu trong
.gitcover/schemas/diary-entry-1.0.schema.json và có phiên bản. Một
mục không có tham chiếu schema ($schema) bị Pre-Commit hook từ chối.
Schema diary-entry-1.0.schema.json (rút gọn)
{
"$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" } }
}
}
Quan trọng - không có trường
datetime/date: Thời điểm ghi nhận nằm tronguuidV7(timestamp 48-bit, RFC 9562 §5.7). Một biểu diễn chuỗi riêng là dư thừa và không được giữ trong facts.uuidV7một mình là DocID duy nhất; Composite KeyV7GUID:uuidV7phục vụ tổ chức lưu trữ và truy vấn DB.
V7GUID - Cấu trúc và timestamp 48-bit
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
| Khoảng bit | Độ rộng | Nội dung | RFC-cố định |
|---|---|---|---|
| 0-47 | 48 bit | Unix mili-giây từ Epoch (1970-01-01T00:00:00Z) | Có (RFC 9562 §5.7) |
| 48-51 | 4 bit | Version = 0111 (UUIDv7) |
Có |
| 52-63 | 12 bit | rand_a (ngẫu nhiên) | Không |
| 64-65 | 2 bit | Variant = 10 |
Có |
| 66-127 | 62 bit | rand_b (ngẫu nhiên) | Không |
Nguyên lý cốt lõi: Thành phần timestamp 48-bit (bit 0-47) là có thẩm quyền cho thời điểm ghi nhận. Nó được neo trong chính
uuidV7và không thể thay đổi sau đó mà không làm GUID vô hiệu. Trườngdatetimeriêng không tồn tại - thời gian nằm tronguuidV7. Biểu diễn chuỗi cho DTO/HTMX là trách nhiệm của harness.
Mở rộng GitCover: Hierarchy và Process ID trong bit 66-127
GitCover V7GUID specification
(work/OSS/TOP/.gitcover/specs/v7guid/) mở rộng thành phần ngẫu
nhiên 62-bit (bit 66-127) với hierarchy 6 cấp và process ID -
đây là mở rộng được bảo hộ bằng sáng chế (DPMA Az. 10 2025 003 091.6):
| Khoảng bit | Độ rộng | Nội dung |
|---|---|---|
| 66-89 | 6×4 bit | Hierarchy 6 cấp (L1-L6, mỗi cấp 4 bit) |
| 90-97 | 8 bit | ProcessTypeId (loại quy trình) |
| 98-105 | 8 bit | GatewayId (điểm kiểm soát) |
| 106-113 | 8 bit | Status (bitmask vòng đời) |
| 114-121 | 8 bit | Kind (loại hoạt động) |
| 122-127 | 6 bit | VariantId (lớp biến thể) |
Lưu ý: Mở rộng này không bắt buộc cho loạt bài nhật ký - nó trở nên liên quan trong ED02 (Tenant/Sphere/Role) và các bài sau (Harness). Ở đây cơ sở RFC 9562 với timestamp 48-bit là đủ.
Helper Routine: Tạo V7GUID từ Foreign 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
GitCover OSS tool UuidV7Gen
(work/OSS/TOP/tools/UuidV7Gen/) cung cấp hai thao tác trung tâm:
gen - tạo uuidV7 (guid)
# 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 - trích timestamp từ uuidV7
# 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
Foreign Key → uuidV7
Helper routine cho phép tạo một khóa uuidV7 hợp lệ từ một foreign
key (ví dụ timestamp trong tên tệp như
260815_0900_Lohnabrechnung.pdf) - với timestamp định sẵn, không
phải now():
- Parse foreign key -
260815_0900→2026-08-15T09:00:00Z - Tính timestamp 48-bit - Unix mili-giây từ Epoch
- Sinh
uuidV7-Guid.CreateVersion7()với timestamp tường minh, phần còn lại ngẫu nhiên - Composite Key -
V7GUID(Class từ registry) :uuidV7(Object với timestamp) - Tài liệu GoBD - ghi nhận kịp thời được neo truy vết (không có trường datetime riêng)
Tham chiếu GoBD: Ghi nhận kịp thời (GoBD Rz. 146) được tài liệu hóa mật mã bởi timestamp 48-bit trong
uuidV7- không chỉ tuyên bố. Timestamp là một phần của danh tính, không thể thay đổi sau.
Cấu trúc Sidecar (.v7g.md)
Mỗi chứng từ nhận một sidecar với hai tham chiếu uuidV7:
(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
Ví dụ Sidecar
{
"$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(trường 1) - Class Identifier của sidecar (phân loại từ registry.gitcover: cái gì/loại nào)uuidV7(trường 2) - Object ID của chính sidecar, tạo với timestamp định sẵn (khi nào được phân loại?), timestamp 48-bit neo trong GUIDv7g_taxonomy[].v7guid- Object ID của tài liệu được phân loại (tài liệu nào đang được phân loại?)Như vậy không chỉ tài liệu được định danh duy nhất, mà cả hành động phân loại - bao gồm thời điểm (trong
uuidV7), ai phân loại và trong role nào. Không có trườngdatetimeriêng - thời gian nằm trong các giá trịuuidV7.
Truy vết Retrograde và Progressive
(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
| Hướng | Bắt đầu | Giải quyết qua | Đích |
|---|---|---|---|
| Retrograde | Booking (SKR04) | source_sha256 → chứng từ → uuidV7 |
Mục nhật ký với timestamp 48-bit |
| Progressive | Chứng từ (SHA-256) | uuidV7 → mục nhật ký → source_sha256 |
Booking → sổ cái → bảng cân đối đầu kỳ |
Tham chiếu GoBD: Truy vết retrograde tương ứng GoBD Rz. 146 (khả năng truy vết). Truy vết progressive tương ứng GoBD Rz. 147 (khả năng kiểm toán). Cả hai được đảm bảo by Design qua
uuidV7+ SHA-256 - không qua tham chiếu chéo thủ công.
Ghi nhận thời gian trong nhật ký
Mỗi mục nhật ký chứa một bảng ghi nhận thời gian:
| Bắt đầu | Kết thúc | Giờ | Hoạt động | Tenant | Sphere | Nguồn |
|---|---|---|---|---|---|---|
| 0900 | 1200 | 3,0 | Dữ liệu master tài khoản lương | ORG-1 | ideell | E1 |
| 1200 | 1400 | 2,0 | R&D: spec V7GUID | ORG-1 | ideell | E1 |
Tham chiếu FZul: Ghi nhận thời gian là cơ sở cho ghi giờ FZul (ED18). Việc tách R&D vs. hành chính được thực hiện qua trường
role(F&E-Leitervs.GF) vàtags(["fzul", "forschung"]vs.["verwaltung"]).
Cái gì vào Git Repo - và cái gì không
(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
Quan trọng: Chỉ các artefact có cấu trúc (JSON, sidecar, chứng từ, schema, dictionary) mới được nhận vào Git repo. Tài liệu cá nhân không bao giờ được nhận vào repo trừ khi được giới thiệu và phân loại rõ ràng như artefact. Đây là yêu cầu bảo vệ dữ liệu và tuân thủ (GDPR, GoBD).
Đòn bẩy rủi ro
| Hôm nay (rẻ) | Ngày mai (kiểm toán được) | Rủi ro giảm |
|---|---|---|
JSON artefact với V7GUID (Class) + uuidV7 (Object) |
Thời điểm ghi nhận neo mật mã trong uuidV7 | Tranh chấp thời điểm ghi nhận |
| Xác thực schema (Pre-Commit) | Chỉ mục hợp lệ vào repo | Vi phạm schema, trường bắt buộc thiếu |
Sidecar với Composite Key V7GUID:uuidV7 |
Hành động phân loại truy vết được | Tranh chấp phân loại |
source_sha256 mỗi mục |
Truy vết retrograde | Tranh chấp phân công chứng từ |
Helper UuidV7Gen cho foreign key |
Ghi nhận kịp thời được tài liệu hóa (timestamp trong uuidV7) | Vi phạm GoBD "không kịp thời" |
Yêu cầu Harness (Xem trước)
Dẫn xuất từ ED03:
| ID | Yêu cầu | Ưu tiên |
|---|---|---|
| FA-1.1 | Mục nhật ký là JSON artefact (Schema-First) | MUST |
| FA-1.2 | Composite Key V7GUID (Class) : uuidV7 (Object) - không trường datetime/date riêng; thời gian trong uuidV7 (RFC 9562 §5.7) |
MUST |
| FA-1.3 | uuidV7 tạo từ timestamp định sẵn (không now()) qua helper |
MUST |
| FA-2.1 | SHA-256 làm ID chứng từ | MUST |
| FA-2.2 | Nghĩa vụ sidecar .v7g.md |
MUST |
| FA-2.3 | Sidecar với Composite Key V7GUID:uuidV7 (Class + Object) |
MUST |
| FA-2.12 | Truy vết retrograde (booking → chứng từ → uuidV7) |
MUST |
| FA-2.13 | Truy vết progressive (chứng từ → booking → sổ cái) | MUST |
| TA-1.5 | Helper routine cho tạo V7GUID từ foreign key (UuidV7Gen) |
MUST |
| TA-1.6 | Yêu cầu thời gian GoBD được tài liệu hóa (timestamp 48-bit trong uuidV7) |
MUST |
| TA-2.1 | Pre-Commit: xác thực JSON schema | MUST |
Danh sách yêu cầu đầy đủ trong Harness-Anforderungen.md.
Nguồn
- RFC 9562 §5.7 (UUIDv7) - timestamp Unix-ms 48-bit
- V7GUID specification -
work/OSS/TOP/.gitcover/specs/v7guid/(normative) - DPMA Az. 10 2025 003 091.6 - Sáng chế V7GUID (claim chính 2, claim 5-8)
- GitCover OSS tool
UuidV7Gen-work/OSS/TOP/tools/UuidV7Gen/(helpergen/decode) - GoBD (thư BMF, Rz. 146 - truy vết, Rz. 147 - kiểm toán)
- AO (§ 147 Abs. 2 - "đánh giá bằng máy", § 147 Abs. 6 - truy cập dữ liệu)
AFJD/agents/(ẩn danh) - khái niệm SSoT với JSON artefact, sidecar
Topo nguồn và liên kết tham chiếu CDN
| Role | Địa điểm | Mục đích |
|---|---|---|
| Primary / SSoT | git.gitcover.org/GCC | Lưu trữ chính thức (ký GPG, có phiên bản) |
| Public OSS Mirror / CDN | codeberg.org/gitcover-commons | Mirror chỉ đọc; khám phá FLOSS |
| Community Hub | github.com/gitcover-commons | Issues & Discussions; tham chiếu mã nguồn trên Codeberg |
Lưu ý: Phân công nguồn, mirror và community hub này phản ánh trạng thái hiện tại và có thể thay đổi. Vui lòng kiểm tra nguồn chính thức tương ứng trên gitcover.org cho trạng thái hiện tại.