ED02 - The SME Organisational Model: Tenants, Spheres, Roles
Problem
An entrepreneur founds an organisation - and faces the question: How do I structure my organisation so that compliance obligations are cleanly separated, traceable and auditable?
Today's practice in the SME sector knows no clean separation:
- Everything in one pot - private and business documents mix in a single mailbox, a single drive, a single cloud account.
- No tenant separation - a holding with several companies keeps all books in one instance, without it being clear which record belongs to which company.
- No sphere separation - in non-profit organisations, ideal, asset-managing, purpose-operated and commercial activities mix in a single account, a single folder, a single repo.
- No role separation - the entrepreneur does everything themselves (MD, accountant, payroll, R&D), but the repo does not know in which role they are acting at any given moment.
- No clear identity - records have no unique identifier that assigns them to an organisation, a sphere, a role.
Core Statement
Structuring an organisation as a GitCover federation means: Tenant (organisation), Sphere (area of activity for non-profits) and Role (function of the actor) are defined as mandatory fields of every artefact - not as optional metadata. Git hooks check on every commit that the separation is complete. This creates Compliance by Design: the structure of the organisation is anchored in the structure of the repo.
Compliance by Design: Tenant, Sphere and Role are not after-the-fact labels - they are structural mandatory fields, without which an artefact is not admitted to the repo.
The Three-Level Model: Tenant, Sphere, Role
(Beleg, Tagebucheintrag, Grundbuch-Eintrag)"] A --> T["Tenant
Welche Organisation?"] A --> S["Sphäre
Welcher Tätigkeitsbereich?
(nur gemeinnützig)"] A --> R["Rolle
In welcher Funktion handelt der Akteur?"] T --> T1["ORG-1 (KMU)"] T --> T2["ORG-1a (Tochter)"] T --> T3["ORG-1b (Tochter)"] S --> S1["ideell"] S --> S2["vermögensverwaltend"] S --> S3["zweckbetrieblich"] S --> S4["wirtschaftlich"] R --> R1["GF (Geschäftsführer)"] R --> R2["Buchhalter"] R --> R3["Lohnverantwortlicher"] R --> R4["F&E-Leiter"] R --> R5["Administrator"] style A fill:#0F1B33,stroke:#0F1B33,color:#FBFAF7 style T fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style S fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style R fill:#FDBA74,stroke:#C2410C,color:#0F1B33 style T1 fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style T2 fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style T3 fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style S1 fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style S2 fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style S3 fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style S4 fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style R1 fill:#FDBA74,stroke:#C2410C,color:#0F1B33 style R2 fill:#FDBA74,stroke:#C2410C,color:#0F1B33 style R3 fill:#FDBA74,stroke:#C2410C,color:#0F1B33 style R4 fill:#FDBA74,stroke:#C2410C,color:#0F1B33 style R5 fill:#FDBA74,stroke:#C2410C,color:#0F1B33
Level 1 - Tenant (Organisation)
A Tenant is a legally independent organisational unit for which separate record-keeping obligations exist. In the GitCover federation, each tenant is maintained as its own Git repo (or its own branch namespace).
| Tenant Type | Example (placeholder) | Own Obligations |
|---|---|---|
| Sole proprietorship | ORG-1 (SME) |
GoBD, AO, e-invoice |
| Holding with subsidiaries | ORG-1 (holding), ORG-1a/ORG-1b (subsidiaries) |
Per company: own bookkeeping, own annual accounts |
| Non-profit organisation | ORG-1 (non-profit) |
Additionally: sphere separation, § 52 AO, VBG exemption |
| Consortium / federation | ORG-1, ORG-2, ORG-3 |
Per organisation its own tenant, cross-references via V7GUID |
Practical example: An entrepreneur (
E1) runs a holding (ORG-1) with two subsidiaries (ORG-1a,ORG-1b). Each subsidiary is its own tenant with its own repo. The holding has a meta-repo that links the subsidiaries via V7GUID references - but the books of the subsidiaries remain separate.
Level 2 - Sphere (Area of Activity, only for Non-Profits)
The Sphere is only relevant for non-profit organisations - but then mandatory. Tax law (§ 51-68 AO) requires the separation of the four spheres in order not to jeopardise non-profit status.
| Sphere | Meaning | Example |
|---|---|---|
| ideell (ideal) | Purpose-operated activity within the meaning of the statutes, tax-free | Workshop series, educational offer |
| vermögensverwaltend (asset-managing) | Management of foundation assets, tax-free | Interest from investments, rental income |
| zweckbetrieblich (purpose-operated) | Commercial business that fulfils the purpose, tax-free (§ 65 AO) | Membership fees, admission fees |
| wirtschaftlich (commercial) | Commercial business that does not fulfil the purpose, taxable | Merchandising, advertising revenue |
steuerfrei
§ 52 AO"] V --> VV["vermögensverwaltend
steuerfrei"] V --> Z["zweckbetrieblich
steuerfrei
§ 65 AO"] V --> W["wirtschaftlich
steuerpflichtig
§ 64 AO"] I --> F["Freibetrag
§ 3 Nr. 26/26a EStG"] Z --> F W --> ST["USt/KSt
pflichtig"] style V fill:#0F1B33,stroke:#0F1B33,color:#FBFAF7 style I fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style VV fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style Z fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style W fill:#FDBA74,stroke:#C2410C,color:#0F1B33 style F fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style ST fill:#FDBA74,stroke:#C2410C,color:#0F1B33
Risk if sphere separation is missing: Asset mixing (§ 55 Abs. 1 Nr. 5 AO) is a ground for revocation of non-profit status. A non-profit organisation that does not separate commercial and ideal activities risks losing its non-profit status - and consequently re-taxation of reserves (up to 15 years retroactively).
Level 3 - Role (Function of the Actor)
The Role documents in which function an actor has acted. This is important because in many organisations one person often holds several roles (especially in SMEs) - and because the role determines which obligations apply.
| Role | Function | Typical Obligations |
|---|---|---|
| GF (Managing Director) | External representation, overall responsibility | GoBD, AO, deadlines, representation authority |
| Buchhalter (Accountant) | Bookkeeping, document archive | GoBD, e-invoice, retention |
| Lohnverantwortlicher (Payroll Officer) | Payroll accounting, social-security notifications | SGB IV, DEÜV, LStDV |
| F&E-Leiter (R&D Lead) | Research, FZul hour records | FZulG, BSFZ, R&D vs. administration |
| Administrator | Repo administration, hooks, access | Git, GPG, access rights |
Practical example: The entrepreneur
E1is simultaneously MD, accountant, researcher, developer and R&D lead. In the repo, every artefact documents in which role they acted - e.g.role: "GF"for a resolution,role: "F&E-Leiter"for an FZul hour record. This keeps it traceable whether a record originated from the MD perspective (administration) or the R&D perspective (research).
Implementation in the Git Repo
Directory Structure
ORG-1/ # Tenant: KMU
├── .gitcover/ # GitCover-Konfiguration
│ ├── LEGAL_ENTITY.v7g.json # Tenant-Identität (V7GUID)
│ ├── dictionaries/ # Sphären, Rollen, Beleg-Typen
│ └── schemas/ # JSON-Schemata für Artefakte
├── diary/ # Tagebuch (SSoT)
│ ├── entries/ # Tages-Einträge
│ └── tenants/ # Tenant-Sichten (Symlinks)
├── registry/ # Behörden-Identifikatoren
├── sources/ # Belegarchiv (PDF, XML, EML)
├── sidecars/ # .v7g.md Sidecars
└── checks/ # Fristen-Check, Sphären-Check
JSON Artefact with Tenant, Sphere, Role
Every artefact (diary entry, document, ledger entry) contains Tenant,
Sphere and Role as mandatory fields. Central core principle of
temporal traceability: the recording time is not a separate field,
but anchored in the uuidV7 itself - as a 48-bit timestamp according to
RFC 9562 §5.7. The uuidV7 is generated from a predefined timestamp
(not now()) via the GitCover helper (UuidV7Gen), the rest filled
with randomness. This cryptographically links the recording time to the
identity of the artefact and makes it non-modifiable after the fact.
Important - what lands in the Git repo: Only these structured artefacts (JSON entries, sidecars, documents) are admitted to the Git repo. Private documents are never admitted to the repo unless they have been explicitly introduced and classified as artefacts.
{
"$schema": "https://gitcover.org/schemas/diary-entry-1.0.schema.json",
"V7GUID": "<V7GUID-Class-aus-Registry>",
"uuidV7": "<uuidV7-Object-mit-vorgegebener-Zeitmarke>",
"author": "E1",
"role": "GF",
"tenant": "ORG-1",
"sphere": "ideell",
"source": "E1",
"source_sha256": "<SHA-256-...>",
"tags": ["lohnabrechnung", "sv-meldung"]
}
Composite Key explanation:
V7GUID(Class Identifier) classifies the document/action based on the.gitcoverregistry (what/which type).uuidV7(Object ID) is the concrete object identifier with the predefined timestamp (RFC 9562 §5.7, 48-bit Unix-ms). Together they form the GCPN Sidecar Composite KeyV7GUID:uuidV7. A separatedatetimeordatestring representation is redundant and is not kept in the facts - the 48-bit timestamp is already contained in theuuidV7. String representations for DTO/HTMX transfer are the harness's responsibility, not the facts layer.
Git Hooks check the Separation
vorhanden?"} P1 -->|nein| R1["Commit abgelehnt
Tenant fehlt"] P1 -->|ja| P2{"Sphäre
vorhanden?
(nur gemeinnützig)"} P2 -->|nein| R2["Commit abgelehnt
Sphäre fehlt"] P2 -->|ja| P3{"Rolle
vorhanden?"} P3 -->|nein| R3["Commit abgelehnt
Rolle fehlt"] P3 -->|ja| P4{"Sphäre
gültig?"} P4 -->|nein| R4["Commit abgelehnt
ungültige Sphäre"] P4 -->|ja| OK["Commit akzeptiert"] style C fill:#0F1B33,stroke:#0F1B33,color:#FBFAF7 style H1 fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style P1 fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style P2 fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style P3 fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style P4 fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style R1 fill:#FDBA74,stroke:#C2410C,color:#0F1B33 style R2 fill:#FDBA74,stroke:#C2410C,color:#0F1B33 style R3 fill:#FDBA74,stroke:#C2410C,color:#0F1B33 style R4 fill:#FDBA74,stroke:#C2410C,color:#0F1B33 style OK fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33
| Hook | Check | Error on |
|---|---|---|
| Pre-Commit | tenant field present and valid |
Missing or unknown tenant |
| Pre-Commit | sphere field present (non-profit only) |
Missing sphere for non-profit tenant |
| Pre-Commit | sphere value valid (ideell/vermögensverwaltend/zweckbetrieblich/wirtschaftlich) |
Invalid sphere value |
| Pre-Commit | role field present and valid |
Missing or unknown role |
| Post-Commit | Auto-index generation per tenant and sphere | - |
Tenant Federation: Multiple Organisations
Meta-Repo"] H --> R1["ORG-1a (Tochter 1)
eigenes Repo"] H --> R2["ORG-1b (Tochter 2)
eigenes Repo"] H --> R3["ORG-1c (Tochter 3)
eigenes Repo"] R1 --> V1["V7GUID-Referenz
auf ORG-1"] R2 --> V2["V7GUID-Referenz
auf ORG-1"] R3 --> V3["V7GUID-Referenz
auf ORG-1"] H --> M["Meta-Repo
Querverweise über V7GUID
keine Buchungen"] style H fill:#0F1B33,stroke:#0F1B33,color:#FBFAF7 style R1 fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style R2 fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style R3 fill:#DBEAFE,stroke:#1D4ED8,color:#0F1B33 style V1 fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style V2 fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style V3 fill:#D1FAE5,stroke:#0A7F5C,color:#0F1B33 style M fill:#10A987,stroke:#0A7F5C,color:#FBFAF7
A tenant federation (holding with subsidiaries, consortium) is linked via V7GUID references - not via shared repos. Each tenant keeps its own bookkeeping, but the holding's meta-repo can reference documents and entries of the subsidiaries without copying them.
Important: The meta-repo contains no bookings - only cross-references. The bookkeeping stays with each tenant. The meta-repo is an index layer, not an accounting layer.
Risk Leverage
| Today (cheap) | Tomorrow (auditable) | Risk mitigated |
|---|---|---|
tenant field per artefact |
Clear assignment during holding audit | Asset mixing between companies |
sphere field per entry |
Non-profit status defended | Revocation § 55 AO (asset mixing) |
role field per entry |
Traceable in which function was acted | Role conflict, unauthorised representation |
| Pre-Commit hook checks sphere | Sphere separation gapless | Manual sphere errors |
| V7GUID reference instead of copy | Unique assignment without duplicates | Inconsistency in copies |
Harness Requirements (Preview)
Derivable from ED02:
| ID | Requirement | Priority |
|---|---|---|
| FA-1.4 | Tenant assignment (tenant: "ORG-1") per entry |
MUST |
| FA-3.1 | Sphere tags: ideell/vermögensverwaltend/zweckbetrieblich/wirtschaftlich |
MUST (non-profit) |
| FA-3.2 | Sphere tag mandatory per ledger entry and diary entry | MUST (non-profit) |
| FA-3.3 | Pre-Commit hook checks sphere tag completeness | MUST (non-profit) |
| TA-2.3 | Pre-Commit hook: sphere tag check (non-profit only) | MUST (non-profit) |
| FA-1.3 | V7GUID per entry (tenant-crossing uniqueness) | MUST |
The full requirements list in Harness-Anforderungen.md.
Sources
- AO (§§ 51-68 - non-profit status, sphere separation, § 55 Abs. 1 Nr. 5 - asset mixing)
- EStG (§ 3 Nr. 26/26a - lump sums, sphere reference)
- GoBD (BMF letter, procedural documentation, tenant separation)
AFJD/agents/(anonymised) - SSoT concept with Tenant, Sphere, Role
Source Topology and CDN Reference Links
| Role | Location | Purpose |
|---|---|---|
| Primary / SSoT | git.gitcover.org/GCC | Canonical storage (GPG-signed, versioned) |
| Public OSS Mirror / CDN | codeberg.org/gitcover-commons | Read-only mirror; FLOSS discovery |
| Community Hub | github.com/gitcover-commons | Issues & Discussions; source-code reference on Codeberg |
Note: This assignment of sources, mirror and community hub reflects the current state and may change. Please check the respective canonical source on gitcover.org for the current state.