# ADR-002: Sparse-Checkout für Git Submodules

**Status**: Proposed
**Datum**: 2025-10-31
**Entscheider**: Development Team
**Kontext**: Optimierung des Dokumentations-Builds bei Multi-Purpose Repositories

## Kontext und Problem

Die als Git Submodules eingebundenen Repositories (`authentication`, `data`) können neben den Python-Packages auch Microservices und andere Komponenten enthalten. Beim Dokumentations-Build im Docker Container wird aktuell das gesamte Repository ausgecheckt, obwohl nur die Python-Package-Verzeichnisse benötigt werden.

### Ist-Zustand

```dockerfile
# Aktuelle Implementierung
RUN git submodule update --init --recursive || true
```

Dies checkt vollständig aus:
- `authentication/` - komplettes Repository
- `data/` - komplettes Repository (inkl. unbenötigter Microservices)

### Anforderungen

- Reduzierung der Build-Zeit durch kleinere Checkout-Größe
- Reduzierung des Disk-Space im Docker Image
- Nur relevante Verzeichnisse für Dokumentations-Build
- Wartbarkeit und Nachvollziehbarkeit

## Betrachtete Optionen

1. **Full Checkout** (Status Quo) - Gesamtes Repository auschecken
2. **Sparse-Checkout** - Nur spezifische Unterverzeichnisse auschecken
3. **Separate Documentation Repositories** - Docs in eigene Repos auslagern

---

## Option 1: Full Checkout (Status Quo)

### Beschreibung

Git Submodules checken komplette Repositories aus, unabhängig von der tatsächlich benötigten Struktur.

### Implementierung

```dockerfile
RUN git submodule update --init --recursive || true
```

### PRO

✅ **Einfachste Implementierung**
Keine zusätzliche Konfiguration nötig

✅ **Keine Pfad-Dependencies**
Repository-Struktur kann sich ändern ohne Build-Anpassung

✅ **Vollständiger Kontext**
Alle Dateien verfügbar bei Debugging

✅ **Standard Git Workflow**
Team kennt den Workflow bereits

### CONTRA

❌ **Unnötiger Overhead**
Microservices, Tests, CI-Configs werden ausgecheckt aber nicht genutzt

❌ **Längere Build-Zeit**
Mehr Daten müssen übertragen und gespeichert werden

❌ **Größeres Docker Image**
Builder-Stage enthält unnötige Dateien (werden zwar nicht ins finale Image kopiert, aber Builder ist größer)

❌ **Netzwerk-Overhead**
Mehr Daten müssen von Git-Remote geladen werden

### Metriken (Beispiel)

```
Repository-Größe: 150 MB
Benötigt für Docs: 15 MB (10%)
Overhead: 135 MB (90%)
Build-Zeit: ~2 Minuten
```

---

## Option 2: Sparse-Checkout

### Beschreibung

Git Sparse-Checkout ermöglicht das Auschecken nur spezifischer Verzeichnisse aus einem Repository. Kombiniert mit Submodules können gezielt nur die benötigten Package-Verzeichnisse ausgecheckt werden.

### Implementierung

#### Variante A: Manuell im Dockerfile

```dockerfile
# Git Submodules mit Sparse-Checkout
RUN git config submodule.authentication.update none && \
    git config submodule.data.update none && \
    git submodule init && \
    \
    # Authentication sparse checkout
    cd authentication && \
    git sparse-checkout init --cone && \
    git sparse-checkout set src tests examples docs && \
    git fetch origin && \
    git checkout main && \
    cd .. && \
    \
    # Data sparse checkout
    cd data && \
    git sparse-checkout init --cone && \
    git sparse-checkout set python-package && \
    git fetch origin && \
    git checkout main && \
    cd ..
```

#### Variante B: Mit .gitmodules Konfiguration

```gitmodules
[submodule "authentication"]
    path = authentication
    url = https://...
    sparse-checkout = src\ntests\nexamples\ndocs

[submodule "data"]
    path = data
    url = https://...
    sparse-checkout = python-package
```

Dann im Dockerfile:
```dockerfile
RUN git -c submodule.authentication.update=sparse-checkout \
    -c submodule.data.update=sparse-checkout \
    submodule update --init --recursive
```

### PRO

✅ **Reduzierte Build-Zeit**
Nur 10-20% des Repository-Inhalts wird übertragen

✅ **Kleinerer Builder-Stage**
Weniger Disk-I/O während des Builds

✅ **Netzwerk-Effizienz**
Signifikant weniger Daten von Git-Remote

✅ **Explizite Dependencies**
Dokumentiert klar, welche Verzeichnisse benötigt werden

✅ **Production-Ready**
Sparse-Checkout ist seit Git 2.25+ stabil (2020)

### CONTRA

❌ **Höhere Konfigurationskomplexität**
Pfade müssen explizit definiert werden

❌ **Pfad-Dependencies**
Bei Umstrukturierung im Source-Repo muss Dockerfile angepasst werden

❌ **Debugging eingeschränkt**
Nicht alle Dateien verfügbar bei Problemen

❌ **Team-Wissen erforderlich**
Sparse-Checkout ist weniger bekannt als Standard-Checkout

❌ **Wartungsaufwand**
Bei neuen Verzeichnissen muss Sparse-Config aktualisiert werden

### Metriken (Beispiel)

```
Ausgecheckter Inhalt: 20 MB (statt 150 MB)
Reduktion: 87%
Build-Zeit: ~1 Minute (statt 2 Minuten)
Verbesserung: 50%
```

---

## Option 3: Separate Documentation Repositories

### Beschreibung

Dokumentation wird aus den Multi-Purpose Repositories in dedizierte Docs-Only Repositories ausgelagert.

### Struktur

```
questra-authentication-docs/
  docs/
  mkdocs.yml

questra-data-docs/
  docs/
  mkdocs.yml
```

### Implementierung

```bash
git submodule add https://.../questra-authentication-docs.git authentication
git submodule add https://.../questra-data-docs.git data
```

### PRO

✅ **Minimaler Checkout**
Nur Dokumentation, keine andere Struktur

✅ **Klare Separation**
Docs unabhängig von Code-Repositories

✅ **Einfacher Dockerfile**
Standard Submodule-Checkout ohne Sparse-Config

✅ **Unabhängige Versionierung**
Docs können unabhängig von Code versioniert werden

### CONTRA

❌ **Kein Single Source of Truth**
Dokumentation ist vom Code getrennt

❌ **Synchronisations-Overhead**
Docs müssen zwischen Repos synchronisiert werden

❌ **Mehr Repositories**
2x mehr Repos zu managen

❌ **Developer Experience leidet**
Developer sehen Docs nicht bei Code-Änderungen

❌ **Inkonsistenz-Risiko**
Docs können out-of-sync mit Code geraten

❌ **Gegen ADR-001**
Widerspricht der Single-Source-of-Truth Entscheidung

### Aufwand

- **Initial**: 8-12 Stunden (Repos erstellen, Migration, Sync-Automation)
- **Wartung**: 30-60 Minuten/Monat (Synchronisation)
- **Neues Projekt**: 2-3 Stunden

---

## Entscheidungsmatrix

| Kriterium | Full Checkout | Sparse-Checkout | Separate Repos |
|-----------|---------------|-----------------|----------------|
| **Build-Performance** | ❌ Langsam | ✅ Schnell | ✅ Schnell |
| **Netzwerk-Effizienz** | ❌ Hoch | ✅ Niedrig | ✅ Niedrig |
| **Konfigurationskomplexität** | ✅ Minimal | ⚠️ Mittel | ❌ Hoch |
| **Wartbarkeit** | ✅ Einfach | ⚠️ Mittel | ❌ Komplex |
| **Single Source of Truth** | ✅ Ja | ✅ Ja | ❌ Nein |
| **Developer Experience** | ✅ Gut | ✅ Gut | ❌ Schlecht |
| **Robustheit bei Änderungen** | ✅ Hoch | ⚠️ Mittel | ⚠️ Mittel |
| **Team-Wissen erforderlich** | ✅ Vorhanden | ⚠️ Zu lernen | ❌ Komplex |

**Legende**: ✅ Gut | ⚠️ Akzeptabel | ❌ Problematisch

---

## Empfehlung

### **Situationsabhängige Entscheidung**

#### Wenn Repository-Größe < 50 MB: **Option 1 (Full Checkout)** ✅

**Begründung**:
- Overhead von 1-2 MB und 10-20 Sekunden ist vernachlässigbar
- Einfachste Wartung
- Kein zusätzlicher Lernaufwand
- YAGNI-Prinzip: "You Aren't Gonna Need It"

#### Wenn Repository-Größe > 100 MB: **Option 2 (Sparse-Checkout)** ✅

**Begründung**:
- Signifikante Build-Zeit-Verbesserung (30-50%)
- Reduzierte Netzwerk-Last in CI/CD
- Explicit ist besser als Implicit (Python Zen)
- Einmalige Konfiguration, langfristiger Nutzen

#### Option 3 (Separate Repos): ❌ Nicht empfohlen

**Begründung**:
- Widerspricht ADR-001 (Single Source of Truth)
- Hoher Wartungsaufwand ohne echten Nutzen
- Sparse-Checkout löst das Problem besser

---

## Implementierungsstrategie für Sparse-Checkout

### Phase 1: Analyse (30 Minuten)

```bash
# Repository-Größe prüfen
cd authentication && du -sh . && cd ..
cd data && du -sh . && cd ..

# Verzeichnisstruktur analysieren
tree -d -L 2 authentication/
tree -d -L 2 data/
```

### Phase 2: Sparse-Checkout konfigurieren (1-2 Stunden)

```dockerfile
FROM python:3.11-slim AS builder

WORKDIR /build

# System Dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
    git \
    && rm -rf /var/lib/apt/lists/*

# Python Dependencies
RUN pip install --no-cache-dir \
    mkdocs>=1.6.1 \
    mkdocs-material>=9.6.22 \
    mkdocstrings[python]>=0.30.1 \
    mkdocs-git-revision-date-localized-plugin>=1.4.7 \
    mkdocs-minify-plugin>=0.8.0

# Projekt kopieren
COPY . .

# Git Submodules mit Sparse-Checkout
RUN git config submodule.authentication.update none && \
    git config submodule.data.update none && \
    git submodule init && \
    \
    # Authentication: nur Docs-relevante Verzeichnisse
    cd authentication && \
    git sparse-checkout init --cone && \
    git sparse-checkout set src tests examples docs scripts && \
    git fetch origin && \
    git checkout main && \
    cd .. && \
    \
    # Data: nur Python-Package (angenommen in Unterverzeichnis)
    cd data && \
    git sparse-checkout init --cone && \
    git sparse-checkout set python-package docs scripts && \
    git fetch origin && \
    git checkout main && \
    cd ..

# PYTHONPATH für mkdocstrings
ENV PYTHONPATH="/build/authentication/src:/build/data/python-package/src"

# Dokumentation bauen
RUN mkdocs build

# Production stage
FROM nginx:stable-alpine3.21-slim

COPY --from=builder /build/site /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf

RUN touch /var/run/nginx.pid && \
    chown -R nginx:nginx /var/run/nginx.pid /usr/share/nginx /var/cache/nginx /var/log/nginx /etc/nginx/conf.d

USER nginx
EXPOSE 3000
CMD ["nginx", "-g", "daemon off;"]
```

### Phase 3: Testing (30 Minuten)

```bash
# Lokal testen
docker build -t questra-docs:test .

# Build-Zeit messen
time docker build --no-cache -t questra-docs:test .

# Image-Größe vergleichen
docker images | grep questra-docs
```

### Phase 4: Dokumentation (30 Minuten)

README.md erweitern:

```markdown
## Sparse-Checkout Konfiguration

Die Submodules nutzen Sparse-Checkout für effiziente Builds:

**Authentication**: `src`, `tests`, `examples`, `docs`, `scripts`
**Data**: `python-package`, `docs`, `scripts`

Bei Änderungen der Repository-Struktur muss `Dockerfile` angepasst werden.
```

---

## Konsequenzen

### Positiv (bei Sparse-Checkout)

- ✅ 30-50% schnellere Builds bei großen Repositories
- ✅ Reduzierte Netzwerk-Last in CI/CD Pipeline
- ✅ Explizite Dokumentation der Abhängigkeiten
- ✅ Single Source of Truth bleibt erhalten

### Negativ (bei Sparse-Checkout)

- ⚠️ Höhere Konfigurationskomplexität
- ⚠️ Wartungsaufwand bei Repository-Umstrukturierung
- ⚠️ Team muss Sparse-Checkout verstehen

### Neutral

- Bei kleinen Repositories (<50 MB): kein signifikanter Unterschied
- Entscheidung kann jederzeit revidiert werden

---

## Risiken & Mitigation

**Risiko**: Falsche Pfade konfiguriert → Build schlägt fehl
**Mitigation**:
- Pfade testen vor Commit
- CI/CD Pipeline fängt Fehler ab
- Dokumentation mit korrekten Pfaden

**Risiko**: Repository-Struktur ändert sich
**Mitigation**:
- Dokumentation im Source-Repo über Sparse-Checkout-Requirement
- Versionierte Submodule-Commits verhindern Breaking Changes

**Risiko**: Team-Wissen fehlt
**Mitigation**:
- Dokumentation im README
- Sparse-Checkout ist gut dokumentiert (Git Docs)

---

## Offene Fragen

- [ ] Wie groß sind die aktuellen Submodule-Repositories?
- [ ] Wie ist die genaue Verzeichnisstruktur im `data` Submodule?
- [ ] Gibt es Performance-Metriken der aktuellen Builds?
- [ ] Wie häufig ändert sich die Repository-Struktur?

---

## Nächste Schritte

1. [ ] Repository-Größen messen
2. [ ] Entscheidung: Full vs. Sparse-Checkout
3. [ ] Falls Sparse: Dockerfile anpassen
4. [ ] Testing in Feature-Branch
5. [ ] Dokumentation ergänzen
6. [ ] Team-Review
7. [ ] Production-Deployment

---

## Referenzen

- [Git Sparse-Checkout Documentation](https://git-scm.com/docs/git-sparse-checkout)
- [Git 2.25 Release Notes](https://github.blog/2020-01-17-bring-your-monorepo-down-to-size-with-sparse-checkout/)
- ADR-001: Multi-Projekt Dokumentations-Architektur
- [Dockerfile](../../Dockerfile)

---

## Lessons Learned (nach Implementierung)

_Wird nach Implementierung ausgefüllt_

- Performance-Verbesserung: TBD
- Unerwartete Probleme: TBD
- Team-Feedback: TBD

---

**Änderungshistorie**:

- 2025-10-31: Initial Draft
