# Architektur

GitLab-Pipelines bauen Docker-Images, ein GitOps-Repository hält fest, welche Version wo läuft, und Ansible bringt diesen Stand auf Server, die MainPath mit Traefik, Firewall und HTTPS eingerichtet hat.

> Source: https://www.mainpath.ai/de/docs/architecture/

Jedes Projekt ist eine Gruppe im GitLab von MainPath unter `gitlab.application-platform.com` mit einem Repository pro Komponente, `local-configuration` für die gemeinsame Editor-Konfiguration, `gitops-configuration` für das Deployment und `gitlab-profile` mit der README.

```
orgs/<organisation>/<projekt>/
├── backend/                  # z. B. NestJS-API mit Dockerfile
├── <app>/                    # z. B. Flutter-App, auch mehrere
├── <homepage>/               # z. B. Hugo-Site
├── gitops-configuration/     # Deployment-Konfiguration für Dev und Prod
├── local-configuration/      # .vscode, .idea
└── gitlab-profile/           # README der Gruppe
```

Im geklonten Projektordner zeigen Symlinks auf `local-configuration`, deshalb sehen Editoren für alle Repos dieselben Einstellungen. Regeln für KI-Agenten kommen aus dem Agent-Plugin (`mp agent install`).

## Vom Push zum laufenden Container

```mermaid
flowchart LR
  push["Push auf main"] -->|"Pipeline"| image["Docker-Image<br/>mit Versions-Tag"]
  image -->|"Tag eintragen"| gitops["gitops-configuration<br/>versions.yaml"]
  gitops -->|"Ansible"| dev["Dev-Server"]
  gitops -->|"Ansible, manueller Job"| prod["Prod-Server"]
```

Die Pipeline berechnet aus den Commit-Nachrichten die nächste Version (`feat:` und `fix:` zählen hoch), baut das Docker-Image, lädt es in die Registry und trägt den Tag in die Deployment-Konfiguration für Dev ein; das Deployment-Repository rollt ihn per Ansible auf den Dev-Server aus. Produktion bekommt denselben Tag erst über den manuellen Produktions-Job, den [Git-Workflow und Deployment]({{< relref "git-workflow" >}}) beschreibt.

## Das GitOps-Repository

```
gitops-configuration/
└── configurations/
    ├── dev/
    │   ├── generated.yaml   # Plattform: Hostnamen, Registry, Secrets (SOPS)
    │   ├── custom.yaml      # du: eigene Umgebungsvariablen
    │   └── versions.yaml    # Pipeline: deployte Image-Versionen
    └── prod/                # gleiche Struktur
```

`generated.yaml` schreibt MainPath bei jeder Projektänderung mit Hostnamen, Registry-Zugang und SOPS-verschlüsselten Secrets wie Datenbank-Passwörtern und JWT-Secrets. `custom.yaml` gehört dir und nimmt eigene Umgebungsvariablen unter `additional_env_variables` auf. `versions.yaml` schreibt die Pipeline mit dem deployten Image-Tag. Jeder Commit auf `main`, ob von der Pipeline oder von dir, löst das Ansible-Deployment der betroffenen Umgebung aus. Das Zusammenspiel mit den `env/`-Dateien steht unter [Umgebungsvariablen]({{< relref "environment-setup" >}}).

## Was auf dem Server läuft

Beim ersten Deployment richtet MainPath den Server per Ansible ein: Docker, Traefik als Reverse Proxy, eine Firewall, HTTPS-Zertifikate und einen Deploy-Schlüssel in den `authorized_keys` des angegebenen Benutzers. Traefik verteilt Anfragen anhand der Domain an den richtigen Container, auch an [Docker Apps]({{< relref "hosted-apps" >}}). Let's Encrypt prüft die Domain standardmäßig per TLS-ALPN am Server; bei Cloudflare setzt MainPath die DNS-Einträge deshalb ohne Proxy. Ist der Server von außen nicht erreichbar, kannst du in den Details einer [DNS-Anbindung]({{< relref "connections" >}}) optional DNS-01 anhaken.

Die Daten deines Backends liegen außerhalb der Container auf dem Server: `./backend-mysql` für die Datenbank, `./backend-uploads` für Uploads, die im Container unter `/app/upload` erscheinen, und `./backend-backups` für die Archive von Easy Backup. Ein Release tauscht nur die Container aus.

Reine Homepage-Projekte auf einem [Webspace]({{< relref "webspace-ftp" >}}) lädt die Pipeline per FTP oder SFTP hoch, ohne Docker, GitOps und Ansible. Projekte auf einem [Kubernetes-Cluster]({{< relref "kubernetes-integration" >}}) rollt GitOps per Helm aus; Datenbanken liegen dann als Cloud-Datenbank im Konto unter [Cloud-Accounts]({{< relref "cloud-accounts" >}}). Auf klassischen Servern laufen Anwendungen weiterhin per Docker.

## Generierte Konfiguration und Sentry

MainPath erzeugt `.gitlab-ci.yml`, `env/*.generated.env` und `generated.yaml` und überschreibt sie bei jeder Projektänderung; eigene Werte gehören in `env/*.custom.env` und `custom.yaml`. Aktivierst du Sentry für eine Komponente unter **Funktionen**, legt MainPath das Sentry-Projekt in deinem unter **Anbindungen** verbundenen Konto an und schreibt die DSN in diese Konfiguration, für Apps zum Beispiel in `env/shared.generated.env`. Den Umgang damit beschreibt [Betrieb]({{< relref "operations" >}}).

