From f526ac99e31505741259c07bf5b6fe375c4fa6be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Thu, 26 Mar 2026 21:03:12 +0100 Subject: [PATCH 01/26] Add gitignore for terraform --- deploy/.gitignore | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 deploy/.gitignore diff --git a/deploy/.gitignore b/deploy/.gitignore new file mode 100644 index 00000000..fef646a4 --- /dev/null +++ b/deploy/.gitignore @@ -0,0 +1,4 @@ +.azure +.terraform.lock.hcl +.terraform +terraform.tfstate* From 54d3d8e26befe272680caa787c13ac650498d326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Thu, 26 Mar 2026 21:04:37 +0100 Subject: [PATCH 02/26] README updates --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 43cea2e3..ad607929 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ **turnierplan.NET** is mostly written in C# using [.NET](https://dotnet.microsoft.com/). This includes the core logic, the backend API and database connection as well as all publicly visible web pages. In addition, it serves the *turnierplan.NET portal*, the client application for authenticated users, based on the [Angular](https://angular.dev/) framework. -Visit the **turnierplan.NET** documentation using the following link: [docs.turnierplan.net](https://docs.turnierplan.net). If you want to install **turnierplan.NET** on your server, please visit the [Installation guide](https://docs.turnierplan.net/installation). +Visit the **turnierplan.NET** documentation using the following link: [docs.turnierplan.net](https://docs.turnierplan.net). If you want to set up your own instance of **turnierplan.NET**, visit the [Installation guide](https://docs.turnierplan.net/installation) for detailed information on a local or cloud deployment. > [!NOTE] > The user interface and documentation are currently only available in German 🇩🇪 From 13d7bb95f65a8d120ce61a8d23339d3ef056bad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Sat, 28 Mar 2026 19:37:53 +0100 Subject: [PATCH 03/26] Update zensical --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 32b234e8..d91c01a0 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1 @@ -zensical==0.0.24 +zensical==0.0.29 From b1f248070d551e17036e8c9a2ec7c01257963987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Sat, 28 Mar 2026 19:38:02 +0100 Subject: [PATCH 04/26] Revert previous commit --- deploy/.gitignore | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 deploy/.gitignore diff --git a/deploy/.gitignore b/deploy/.gitignore deleted file mode 100644 index fef646a4..00000000 --- a/deploy/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.azure -.terraform.lock.hcl -.terraform -terraform.tfstate* From 0390aff99333a8a24863c75ca7a2aafee3497e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Sat, 28 Mar 2026 19:38:24 +0100 Subject: [PATCH 05/26] Separate docker compose docs --- docs/pages/installation/azure-terraform.md | 1 + docs/pages/installation/docker-compose.md | 88 ++++++++++++++++++++ docs/pages/installation/index.md | 93 +--------------------- 3 files changed, 92 insertions(+), 90 deletions(-) create mode 100644 docs/pages/installation/azure-terraform.md create mode 100644 docs/pages/installation/docker-compose.md diff --git a/docs/pages/installation/azure-terraform.md b/docs/pages/installation/azure-terraform.md new file mode 100644 index 00000000..4f81d4dd --- /dev/null +++ b/docs/pages/installation/azure-terraform.md @@ -0,0 +1 @@ +# Microsoft Azure (Terraform) diff --git a/docs/pages/installation/docker-compose.md b/docs/pages/installation/docker-compose.md new file mode 100644 index 00000000..792b56d6 --- /dev/null +++ b/docs/pages/installation/docker-compose.md @@ -0,0 +1,88 @@ +# Docker Compose + +Die einfachste Möglichkeit, turnierplan.NET auf einem lokalen Rechner, einer VM oder einem dedizierten Server zu installieren, ist mithilfe von Docker Compose. Die nachfolgende YAML-Definition beinhaltet die notwendigen Container für Datenbank sowie den Anwendungsserver: + +```yaml +services: + turnierplan.database: + image: postgres:latest + environment: + - POSTGRES_PASSWORD=P@ssw0rd + - POSTGRES_DB=turnierplan + volumes: + - turnierplan-database-data:/var/lib/postgresql + networks: + - turnierplan + restart: unless-stopped + + turnierplan.application: + image: ghcr.io/turnierplan-net/turnierplan:latest + depends_on: + - turnierplan.database + environment: + - Turnierplan__ApplicationUrl=http://localhost + - Database__ConnectionString=Host=turnierplan.database;Database=turnierplan;Username=postgres;Password=P@ssw0rd + volumes: + - turnierplan-application-data:/var/turnierplan + networks: + - turnierplan + restart: unless-stopped + ports: + - '80:8080' + +volumes: + turnierplan-application-data: + turnierplan-database-data: + +networks: + turnierplan: +``` + +Statt dem `latest`-Tag sollte immer eine spezifische Version für die Images der Datenbank und von turnierplan.NET verwendet werden. Dies ermöglicht eine bessere Kontrolle, welche Updates wann eingespielt werden. Die neuste Version ist auf der [Release-Seite](https://github.com/turnierplan-NET/turnierplan.NET/releases) der Repository auffindbar. + +Die URL, welche letztendlich für den Zugriff auf turnierplan.NET verwendet wird, sollte in der Umgebungsvariable `Turnierplan__ApplicationUrl` spezifiziert werden. Falls bspw. eine Domain `example.com` verwendet wird, sollte der Wert der Umgebungsvariable `https://example.com` sein. Falls turnierplan.NET im lokalen Netzwerk gehostet wird, könnte der Wert bspw. `http://192.168.0.187` sein. Es muss natürlich das korrekte Protokoll (HTTP vs. HTTPS) verwendet werden. + +Die Volume-Mounts sind im [nachfolgenden Abschnitt](#volume-mounts) näher beschrieben. Je nach Konfiguration kann das Volume-Mount vom turnierlpan.NET-Container auch überflüssig sein. + +Beim ersten Starten der Anwendung werden alle Datenbankmigrationen durchgeführt und es wird ein initialer Administrator-Benutzer angelegt. Die Zugangsdaten werden in den Container-Logs angezeigt. Mit diesen Zugangsdaten kann sich in der Weboberfläche unter [localhost:80](http://localhost:80) (bzw. je nach Konfiguration mit entsprechender Domain) eingeloggt werden. + +!!! danger + **Wichtige Sicherheitshinweise**: + + - Das Datenbankpasswort `POSTGRES_PASSWORD` in der Compose-Datei sollte durch ein zufällig generiertes Passwort ersetzt werden. Dementsprechend muss dann auch der Connection-String der Anwendung angepasst werden. + - Der turnierplan.NET-Server sollte niemals ohne Reverse Proxy mit SSL-Terminierung im Internet erreichbar sein. Hierfür kann z.B. [nginx](https://nginx.org/) verwendet werden. + +## Volume Mounts + +Die turnierplan.NET-Anwendung speichert diverse Dateien in folgendem Verzeichnis innerhalb vom Container: `/var/turnierplan`. Bei einer Standardkonfiguration sollte dieses Verzeichnis in einem Docker Volume oder vergleichbar persistiert werden. Die folgenden Daten werden innerhalb vom o.g. Verzeichnis gespeichert: + +- **Bild-Uploads**: Sofern keine anderweitige Speicherung von Bildern (wie z.B. S3) konfiguriert ist. +- **JWT Signatur-Schlüssel**: Sofern kein Schlüssel via Umgebungsvariable spezifiziert wird, wird ein zufällig generierter Schlüssel hier gespeichert. Siehe auch [Konfiguration der Authentifizierung](../configuration/index.md#authentifizierung). + +## Konfiguration + +turnierplan.NET bietet zahlreiche Konfigurationsmöglichkeiten zur Anbindung von Externen System sowie zur Individualisierung. Alle Optionen können mit Umgebungsvariablen gesetzt werden und sind in der [Konfigurationsanleitung](./configuration) aufgelistet und beschrieben. + +## Erste Schritte + +Die Anmeldung als Administrator erfolgt mit den Zugangsdaten, welche beim ersten Programmstart generiert und in den Container-Logs ausgegeben werden. Weitere Schritte sind auf der entsprechenden Seite [Erste Schritte](../getting-started/index.md) der Dokumentation beschrieben. + +!!! tip + Zum Abrufen der Container-Logs kann der Befehl `docker compose logs turnierplan.application` verwendet werden. + +## Aktualisierung + +Die verwendete Version von turnierplan.NET kann jederzeit auf eine neuere aktualisiert werden. Etwaige Datenbankmigrationen werden beim ersten Start sequenziell angewandt - auch wenn Versionen übersprungen werden. Allerdings sollten vor jeder Aktualisierung *immer* die [Release-Notes](https://github.com/turnierplan-NET/turnierplan.NET/releases) gelesen werden! Es kann jederzeit nicht-rückwärtskompatible Änderungen geben. + +Zudem wird empfohlen, vor jeder Aktualisierung der turnierplan.NET-Anwendung *oder* der verwendeten PostgreSQL-Version ein Datenbankupdate zu erstellen. Dies kann z.B. mit dem [pg_dump](https://www.postgresql.org/docs/current/app-pgdump.html)-Tool gemacht werden. + +## Fehlerbehebung + +Nachfolgend beschrieben sind Fehler, welche bei einer Neuinstallation auftreten können. + +### Verbindung per HTTP + +Beim Zugriff auf einen nicht-lokalen turnierplan.NET-Server via HTTP sollte standardmäßig ein Fehler *401 Unauthorized* erscheinen. Dies liegt daran, dass turnierplan.NET für die Authentifizierung nach dem Login Cookies verwendet, welche standardmäßig als *secure* ausgestellt werden. Dies hat zur Folge, dass Browser den Cookie nur bei lokalen Verbindungen oder über HTTPS mitschicken. Um turnierplan.NET dennoch verwenden zu können, muss die `Identity__UseInsecureCookies` auf `true` gesetzt werden. Siehe auch [Konfiguration der Authentifizierung](configuration.md#authentifizierung). + +!!! warning + Die Verwendung von HTTP-Verbindungen über das Internet ist **absolut nicht empfohlen**, da persönliche Daten und Passwörter somit unverschlüsselt übertragen werden würden. Zudem ist nicht ausgeschlossen, dass Teile der Webanwendung nicht korrekt funktionieren, falls diese HTTPS-exklusive Browser-APIs verwenden (bspw. Zwischenablage oder *crypto*). diff --git a/docs/pages/installation/index.md b/docs/pages/installation/index.md index 8922ea5c..66653243 100644 --- a/docs/pages/installation/index.md +++ b/docs/pages/installation/index.md @@ -4,11 +4,7 @@ icon: lucide/server # Installation -Dieser Artikel beschreibt verschiedene Möglichkeiten, **turnierplan.NET** mithilfe des offiziellen Container-Images bereitzustellen. - -## Container-Image - -Innerhalb der GitHub-Organisation wird für jedes [Release](https://github.com/turnierplan-NET/turnierplan.NET/releases) das offizielle Container-Image veröffentlicht: [ghcr.io/turnierplan-net/turnierplan](https://github.com/turnierplan-NET/turnierplan.NET/pkgs/container/turnierplan) +Dieser Artikel beschreibt verschiedene Möglichkeiten, **turnierplan.NET** mithilfe des offiziellen Container-Images bereitzustellen. Innerhalb der GitHub-Organisation wird für jedes [Release](https://github.com/turnierplan-NET/turnierplan.NET/releases) das offizielle Container-Image veröffentlicht: [ghcr.io/turnierplan-net/turnierplan](https://github.com/turnierplan-NET/turnierplan.NET/pkgs/container/turnierplan) Um turnierplan.NET lokal zu testen, kann der folgende Befehl verwendet werden: @@ -22,88 +18,5 @@ Die Weboberfläche kann über [localhost:80](http://localhost:80) erreicht werde Für ein produktives Deployment gibt es nachfolgende Möglichkeiten basierend auf dem Container-Image. Weitere Methoden werden in der Zukunft ergänzt. -### Docker Compose - -Für die Installation auf einem lokalen Rechner oder einer VM kann im einfachsten Fall Docker Compose verwendet werden. Nachfolgend ein Minimalbeispiel für eine `docker-compose.yaml`: - -```yaml -services: - turnierplan.database: - image: postgres:latest - environment: - - POSTGRES_PASSWORD=P@ssw0rd - - POSTGRES_DB=turnierplan - volumes: - - turnierplan-database-data:/var/lib/postgresql - networks: - - turnierplan - restart: unless-stopped - - turnierplan.application: - image: ghcr.io/turnierplan-net/turnierplan:latest - depends_on: - - turnierplan.database - environment: - - Turnierplan__ApplicationUrl=http://localhost - - Database__ConnectionString=Host=turnierplan.database;Database=turnierplan;Username=postgres;Password=P@ssw0rd - volumes: - - turnierplan-application-data:/var/turnierplan - networks: - - turnierplan - restart: unless-stopped - ports: - - '80:8080' - -volumes: - turnierplan-application-data: - turnierplan-database-data: - -networks: - turnierplan: -``` - -Statt dem `latest`-Tag sollte immer eine spezifische Version für die Images der Datenbank und von turnierplan.NET verwendet werden. Dies ermöglicht eine bessere Kontrolle, welche Updates wann eingespielt werden. Die neuste Version ist auf der [Release-Seite](https://github.com/turnierplan-NET/turnierplan.NET/releases) der Repository auffindbar. - -Die URL, welche letztendlich für den Zugriff auf turnierplan.NET verwendet wird, sollte in der Umgebungsvariable `Turnierplan__ApplicationUrl` spezifiziert werden. Falls bspw. eine Domain `example.com` verwendet wird, sollte der Wert der Umgebungsvariable `https://example.com` sein. Falls turnierplan.NET im lokalen Netzwerk gehostet wird, könnte der Wert bspw. `http://192.168.0.187` sein. Es muss natürlich das korrekte Protokoll (HTTP vs. HTTPS) verwendet werden. - -Die Volume-Mounts sind im [nachfolgenden Abschnitt](#volume-mounts) näher beschrieben. Je nach Konfiguration kann das Volume-Mount vom turnierlpan.NET-Container auch überflüssig sein. - -Beim ersten Starten der Anwendung werden alle Datenbankmigrationen durchgeführt und es wird ein initialer Administrator-Benutzer angelegt. Die Zugangsdaten werden in den Container-Logs angezeigt. Mit diesen Zugangsdaten kann sich in der Weboberfläche unter [localhost:80](http://localhost:80) (bzw. je nach Konfiguration mit entsprechender Domain) eingeloggt werden. - -!!! danger - **Wichtige Sicherheitshinweise**: - - - Das Datenbankpasswort `POSTGRES_PASSWORD` in der Compose-Datei sollte durch ein zufällig generiertes Passwort ersetzt werden. Dementsprechend muss dann auch der Connection-String der Anwendung angepasst werden. - - Der turnierplan.NET-Server sollte niemals ohne Reverse Proxy mit SSL-Terminierung im Internet erreichbar sein. Hierfür kann z.B. [nginx](https://nginx.org/) verwendet werden. - -## Volume Mounts - -Die turnierplan.NET-Anwendung speichert diverse Dateien in folgendem Verzeichnis innerhalb vom Container: `/var/turnierplan`. Bei einer Standardkonfiguration sollte dieses Verzeichnis in einem Docker Volume oder vergleichbar persistiert werden. Die folgenden Daten werden innerhalb vom o.g. Verzeichnis gespeichert: - -- **Bild-Uploads**: Sofern keine anderweitige Speicherung von Bildern (wie z.B. S3) konfiguriert ist. -- **JWT Signatur-Schlüssel**: Sofern kein Schlüssel via Umgebungsvariable spezifiziert wird, wird ein zufällig generierter Schlüssel hier gespeichert. Siehe auch [Konfiguration der Authentifizierung](../configuration/index.md#authentifizierung). - -## Konfiguration - -turnierplan.NET bietet zahlreiche Konfigurationsmöglichkeiten zur Anbindung von Externen System sowie zur Individualisierung. Alle Optionen können mit Umgebungsvariablen gesetzt werden und sind in der [Konfigurationsanleitung](./configuration) aufgelistet und beschrieben. - -## Erste Schritte - -Die Anmeldung als Administrator erfolgt mit den Zugangsdaten, welche beim ersten Programmstart generiert werden, bzw. in der Konfiguration vorgegeben sind. Weitere Schritte sind auf der entsprechenden Seite [Erste Schritte](../getting-started/index.md) der Dokumentation beschrieben. - -## Aktualisierung - -Die verwendete Version von turnierplan.NET kann jederzeit auf eine neuere aktualisiert werden. Etwaige Datenbankmigrationen werden beim ersten Start sequenziell angewandt - auch wenn Versionen übersprungen werden. Allerdings sollten vor jeder Aktualisierung *immer* die [Release-Notes](https://github.com/turnierplan-NET/turnierplan.NET/releases) gelesen werden! Es kann jederzeit nicht-rückwärtskompatible Änderungen geben. - -Zudem wird empfohlen, vor jeder Aktualisierung der turnierplan.NET-Anwendung *oder* der verwendeten PostgreSQL-Version ein Datenbankupdate zu erstellen. Dies kann z.B. mit dem [pg_dump](https://www.postgresql.org/docs/current/app-pgdump.html)-Tool gemacht werden. - -## Fehlerbehebung - -Nachfolgend beschrieben sind Fehler, welche bei einer Neuinstallation auftreten können. - -### Verbindung per HTTP - -Beim Zugriff auf einen nicht-lokalen turnierplan.NET-Server via HTTP sollte standardmäßig ein Fehler *401 Unauthorized* erscheinen. Dies liegt daran, dass turnierplan.NET für die Authentifizierung nach dem Login Cookies verwendet, welche standardmäßig als *secure* ausgestellt werden. Dies hat zur Folge, dass Browser den Cookie nur bei lokalen Verbindungen oder über HTTPS mitschicken. Um turnierplan.NET dennoch verwenden zu können, muss die `Identity__UseInsecureCookies` auf `true` gesetzt werden. Siehe auch [Konfiguration der Authentifizierung](configuration.md#authentifizierung). - -!!! warning - Die Verwendung von HTTP-Verbindungen über das Internet ist **absolut nicht empfohlen**, da persönliche Daten und Passwörter somit unverschlüsselt übertragen werden würden. Zudem ist nicht ausgeschlossen, dass Teile der Webanwendung nicht korrekt funktionieren, falls diese HTTPS-exklusive Browser-APIs verwenden (bspw. Zwischenablage oder *crypto*). +- [Docker Compose](./docker-compose.md) für die installation auf einem dedizierten Server oder einer VM +- [Azure (Terraform)](./azure-terraform.md) für ein Deployment innerhalb einer Microsoft Azure Subscription From 340af1928d9f163671da3a539d94cdaf3e8c8c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Sat, 28 Mar 2026 19:38:35 +0100 Subject: [PATCH 06/26] Update navigation --- docs/zensical.toml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/zensical.toml b/docs/zensical.toml index 592caf7f..a7031447 100644 --- a/docs/zensical.toml +++ b/docs/zensical.toml @@ -15,11 +15,15 @@ docs_dir = "pages" extra_css = ["assets/turnierplan.css"] nav = [ - { "Startseite" = "index.md" }, - { "Installation" = "installation/index.md" }, - { "Konfiguration" = "configuration/index.md" }, - { "Erste Schritte" = "getting-started/index.md" }, - { "Releases" = "releases/index.md" } + "index.md", + { "Installation" = [ + "installation/index.md", + "installation/docker-compose.md", + { "Azure (Terraform)" = "installation/azure-terraform.md" } + ]}, + "configuration/index.md", + "getting-started/index.md", + "releases/index.md" ] [project.theme] @@ -42,7 +46,6 @@ features = [ "navigation.instant", "navigation.instant.prefetch", "navigation.path", - "navigation.sections", "navigation.top", "navigation.tracking", "search.highlight", From 802beec732f5f8ab2d5103fa3d787d29cf0df0bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Sun, 29 Mar 2026 10:47:29 +0200 Subject: [PATCH 07/26] First rough draft for azure docs --- docs/pages/installation/azure-terraform.md | 60 ++++++++++++++++++ .../images/azure-terraform-resources.png | Bin 0 -> 72412 bytes 2 files changed, 60 insertions(+) create mode 100644 docs/pages/installation/images/azure-terraform-resources.png diff --git a/docs/pages/installation/azure-terraform.md b/docs/pages/installation/azure-terraform.md index 4f81d4dd..4e18dcea 100644 --- a/docs/pages/installation/azure-terraform.md +++ b/docs/pages/installation/azure-terraform.md @@ -1 +1,61 @@ # Microsoft Azure (Terraform) + +Dieser Artikel beschreibt das Deployment von turnierplan.NET auf Microsoft Azure mithilfe des IaC-Tools Terraform. + +## Architektur + +!!! danger + TODO + +## Verwendung + +Um das Modul zu verwenden, muss zunächst Terraform installiert sein. Zudem müssen die Provider `hashicorp/azurerm` und `hashicorp/random` verfügbar sein. Mit dem nachfolgenden Terraform-Skript kann das Terraform-Modul direkt aus der [GitHub-Repository](https://github.com/turnierplan-NET/turnierplan.NET-Terraform-Azure) verwendet werden. + +```terraform +module "turnierplan" { + source = "github.com/turnierplan-NET/turnierplan.NET-Terraform-Azure?ref=1.0.0" + + name = "turnierplan-example" + location = "westeurope" + + # Make sure you use the latest version for a new install + turnierplan_container_version = "2026.1.0" + + # DON'T set a secure admin password here! Run the deployment, then log in using credentials + # specified below and change the admin password to a secure one in the web UI afterwards. + turnierplan_initial_user = "admin" + turnierplan_initial_password = "admin" + + turnierplan_additional_app_settings = { + # Additional settings as defined in the documentation: https://docs.turnierplan.net/configuration + "Turnierplan__InstanceName" = "turnierplan.NET on Azure" + } + + app_service_custom_domain = null + app_service_plan_sku_name = "B1" + app_insights_retention_in_days = 90 + storage_account_replication_type = "GRS" + postgresql_availability_zone = 3 + postgresql_sku_name = "B_Standard_B1ms" + postgresql_storage_size_mb = 32768 + postgresql_storage_tier = "P4" + postgresql_charset = "UTF8" + postgresql_collation = "de_DE.utf8" +} +``` + +!!! info + Der `name` wird als Suffix für die Namen aller erstellten Ressourcen verwendet. Um Konflikte bei global eindeutigen Ressourcennamen zu vermeiden, sollte der verwendete `name` möglichst eindeutig sein. Allerdings sollte der `name` nicht zu lang sein, da bei bestimmten Ressourcen auch Längenbegrenzungen für den Namen gelten. + +!!! danger + TODO (Datenbank nicht high-availability) + +Die folgenden Azure-Ressourcen werden durch das Modul erstellt: + +![Auflistung der Ressourcen in Azure Portal-Darstellung](./images/azure-terraform-resources.png) + +Nachdem das Deployment alle Ressourcen erstellt hat, kann auf die Weboberfläche mit der Domain des Azure App Service zugegriffen werden. Anschließend ist der Login mit den festgelegten Zugangsdaten möglich. Weitere Schritte sind auf der entsprechenden Seite [Erste Schritte](../getting-started/index.md) der Dokumentation beschrieben. + +## Aktualisierung + +Die verwendete Version von turnierplan.NET kann jederzeit auf eine neuere aktualisiert werden. Etwaige Datenbankmigrationen werden beim ersten Start sequenziell angewandt - auch wenn Versionen übersprungen werden. Allerdings sollten vor jeder Aktualisierung *immer* die [Release-Notes](https://github.com/turnierplan-NET/turnierplan.NET/releases) gelesen werden! Es kann jederzeit nicht-rückwärtskompatible Änderungen geben. diff --git a/docs/pages/installation/images/azure-terraform-resources.png b/docs/pages/installation/images/azure-terraform-resources.png new file mode 100644 index 0000000000000000000000000000000000000000..3947befb911c6ea9cff4995b9b2c8a3adf021d80 GIT binary patch literal 72412 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 literal 0 HcmV?d00001 From c2e702ea51b84a5846bc4ac5ce01dd6ec7700602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Sun, 29 Mar 2026 10:52:05 +0200 Subject: [PATCH 08/26] Remove token replace step --- .github/workflows/build.yaml | 6 ------ .../Client/src/environments/environment.prod.ts | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 586b75ad..a247bb71 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -36,12 +36,6 @@ jobs: - extract-version steps: - uses: actions/checkout@v2 - - name: 'Replace environment tokens' - uses: cschleiden/replace-tokens@v1 - with: - files: '["**/environment.prod.ts"]' - env: - TOKEN_APPLICATION_VERSION: "${{ needs.extract-version.outputs.turnierplan_version }}" - name: Login to container registry uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 with: diff --git a/src/Turnierplan.App/Client/src/environments/environment.prod.ts b/src/Turnierplan.App/Client/src/environments/environment.prod.ts index a1820106..b23489f5 100644 --- a/src/Turnierplan.App/Client/src/environments/environment.prod.ts +++ b/src/Turnierplan.App/Client/src/environments/environment.prod.ts @@ -1,7 +1,7 @@ export const environment = { production: true, defaultTitle: 'turnierplan.NET', - version: '#{TOKEN_APPLICATION_VERSION}#', + version: '2026.2.0', originOverwrite: undefined, includeE2EData: false, doUpdatesCheck: true From 26f5072f6cae3fd840b10f00eef4329212e2f48e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Sun, 29 Mar 2026 10:52:23 +0200 Subject: [PATCH 09/26] remove obsolete warning --- docker/README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/docker/README.md b/docker/README.md index 078489c2..34d3174f 100644 --- a/docker/README.md +++ b/docker/README.md @@ -11,6 +11,3 @@ The resulting container image can be run as described in the [main readme](../RE ```shell docker run -p 80:8080 -e Turnierplan__ApplicationUrl="http://localhost" -e Database__InMemory="true" turnierplan:dev ``` - -> [!WARNING] -> Manually built container images should not be used in production! This is because the relevant GitHub workflow performs other important steps before actually building the images. From 2916504273233e6d99ec071d1170e46cec4a7fc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Sat, 11 Apr 2026 20:31:38 +0200 Subject: [PATCH 10/26] Set version in packagejson --- src/Turnierplan.App/Client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Turnierplan.App/Client/package.json b/src/Turnierplan.App/Client/package.json index 2ab1fd9a..909a2ecf 100644 --- a/src/Turnierplan.App/Client/package.json +++ b/src/Turnierplan.App/Client/package.json @@ -1,6 +1,6 @@ { "name": "turnierplan-net", - "version": "0.0.0", + "version": "2026.2.0", "description": "The client application of turnierplan.NET", "private": true, "license": "AGPL-3.0-only", From 746bc7a438811a56c7285a3023dfd1e88c0ff422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Sat, 11 Apr 2026 20:36:02 +0200 Subject: [PATCH 11/26] Add scipt for set version --- misc/bump-version.sh | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 misc/bump-version.sh diff --git a/misc/bump-version.sh b/misc/bump-version.sh new file mode 100644 index 00000000..fc61771e --- /dev/null +++ b/misc/bump-version.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# +# Bumps the turnierplan.NET version in all relevant files for the next release. +# +# Usage: +# ./bump-version.sh +# + +if (( $# != 1 )); then + echo "Usage: $0 " + exit 1 +fi + +# The 'version.xml' file is considered leading +current_version=$(grep -Po '\d+\.\d+\.\d+' ../src/version.xml) + +next_version="$1" +if [[ ! $next_version =~ ^20[2-9][0-9]+\.[1-9][0-9]*\.[0-9]+$ ]]; then + echo "Error: The specified new version '$1' is not a valid version." + exit 1 +fi + +if [[ $current_version == $next_version ]]; then + echo "Error: The current version is already '$1'." + exit 1 +fi + +echo "Bumping version: '$current_version' -> '$next_version'" + +update_file () { + echo "Updating file: $1" + sed -i -e "s/$current_version/$next_version/g" "../$1" +} + +update_file "src/version.xml" +update_file "src/Turnierplan.App/Client/package.json" +update_file "src/Turnierplan.App/Client/src/environments/environment.prod.ts" From ff5731ec7f0986ed9c108d8bf70096f17f4a8fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Sat, 11 Apr 2026 20:39:04 +0200 Subject: [PATCH 12/26] Escape . regex --- misc/bump-version.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/bump-version.sh b/misc/bump-version.sh index fc61771e..60c49d44 100644 --- a/misc/bump-version.sh +++ b/misc/bump-version.sh @@ -30,7 +30,7 @@ echo "Bumping version: '$current_version' -> '$next_version'" update_file () { echo "Updating file: $1" - sed -i -e "s/$current_version/$next_version/g" "../$1" + sed -i -e "s/${current_version//./\\.}/$next_version/g" "../$1" } update_file "src/version.xml" From adb70caf43b2bbb4996b366f849b245953ab64bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Sat, 11 Apr 2026 20:52:19 +0200 Subject: [PATCH 13/26] Add tf files from other repo & add docs to bump-version script --- deploy/azure-terraform/app-insights.tf | 15 +++ deploy/azure-terraform/app-service.tf | 86 +++++++++++++++++ deploy/azure-terraform/database.tf | 39 ++++++++ deploy/azure-terraform/networking.tf | 50 ++++++++++ deploy/azure-terraform/resource-group.tf | 4 + deploy/azure-terraform/storage-account.tf | 21 +++++ deploy/azure-terraform/terraform.tf | 14 +++ deploy/azure-terraform/variables.tf | 110 ++++++++++++++++++++++ misc/bump-version.sh | 1 + 9 files changed, 340 insertions(+) create mode 100644 deploy/azure-terraform/app-insights.tf create mode 100644 deploy/azure-terraform/app-service.tf create mode 100644 deploy/azure-terraform/database.tf create mode 100644 deploy/azure-terraform/networking.tf create mode 100644 deploy/azure-terraform/resource-group.tf create mode 100644 deploy/azure-terraform/storage-account.tf create mode 100644 deploy/azure-terraform/terraform.tf create mode 100644 deploy/azure-terraform/variables.tf diff --git a/deploy/azure-terraform/app-insights.tf b/deploy/azure-terraform/app-insights.tf new file mode 100644 index 00000000..fef1597d --- /dev/null +++ b/deploy/azure-terraform/app-insights.tf @@ -0,0 +1,15 @@ +resource "azurerm_log_analytics_workspace" "default" { + name = "log-${var.name}" + location = var.location + resource_group_name = azurerm_resource_group.default.name + sku = "PerGB2018" +} + +resource "azurerm_application_insights" "default" { + name = "appi-${var.name}" + location = var.location + resource_group_name = azurerm_resource_group.default.name + workspace_id = azurerm_log_analytics_workspace.default.id + application_type = "web" + retention_in_days = var.app_insights_retention_in_days +} diff --git a/deploy/azure-terraform/app-service.tf b/deploy/azure-terraform/app-service.tf new file mode 100644 index 00000000..690e57f4 --- /dev/null +++ b/deploy/azure-terraform/app-service.tf @@ -0,0 +1,86 @@ +locals { + app_service_name = "app-${var.name}" +} + +resource "azurerm_service_plan" "default" { + name = "asp-${var.name}" + location = var.location + resource_group_name = azurerm_resource_group.default.name + + os_type = "Linux" + sku_name = var.app_service_plan_sku_name +} + +resource "random_bytes" "identity_sining_key" { + length = 64 +} + +resource "azurerm_linux_web_app" "default" { + name = local.app_service_name + location = var.location + resource_group_name = azurerm_resource_group.default.name + + service_plan_id = azurerm_service_plan.default.id + virtual_network_subnet_id = azurerm_subnet.app.id + + https_only = true + + identity { + type = "SystemAssigned" + } + + site_config { + always_on = true + + application_stack { + docker_registry_url = "https://${var.turnierplan_container_registry}" + docker_image_name = "${var.turnierplan_container_image}:${var.turnierplan_container_version}" + } + } + + app_settings = merge(var.turnierplan_additional_app_settings, { + "Turnierplan__ApplicationUrl" = var.app_service_custom_domain == null ? "https://${local.app_service_name}.azurewebsites.net" : "https://${var.app_service_custom_domain}" + "Turnierplan__InitialUserName" = var.turnierplan_initial_user + "Turnierplan__InitialUserPassword" = var.turnierplan_initial_password + + "ApplicationInsights__ConnectionString" = azurerm_application_insights.default.connection_string + "Database__ConnectionString" = "Host=${azurerm_postgresql_flexible_server.default.fqdn};Database=${azurerm_postgresql_flexible_server_database.default.name};Username=${azurerm_postgresql_flexible_server.default.administrator_login};Password=${azurerm_postgresql_flexible_server.default.administrator_password}" + "Identity__SigningKey" = random_bytes.identity_sining_key.base64 + + "ImageStorage__Type" = "Azure" + "ImageStorage__StorageAccountName" = azurerm_storage_account.default.name + "ImageStorage__ContainerName" = azurerm_storage_container.images.name + }) +} + +resource "azurerm_role_assignment" "application_blob_storage_contributor" { + role_definition_name = "Storage Blob Data Contributor" + principal_id = azurerm_linux_web_app.default.identity[0].principal_id + scope = azurerm_storage_account.default.id +} + +resource "azurerm_app_service_custom_hostname_binding" "default" { + count = var.app_service_custom_domain == null ? 0 : 1 + + resource_group_name = azurerm_resource_group.default.name + app_service_name = azurerm_linux_web_app.default.name + hostname = var.app_service_custom_domain + + lifecycle { + ignore_changes = [ssl_state, thumbprint] + } +} + +resource "azurerm_app_service_managed_certificate" "default" { + count = var.app_service_custom_domain == null ? 0 : 1 + + custom_hostname_binding_id = azurerm_app_service_custom_hostname_binding.default[0].id +} + +resource "azurerm_app_service_certificate_binding" "example" { + count = var.app_service_custom_domain == null ? 0 : 1 + + hostname_binding_id = azurerm_app_service_custom_hostname_binding.default[0].id + certificate_id = azurerm_app_service_managed_certificate.default[0].id + ssl_state = "SniEnabled" +} diff --git a/deploy/azure-terraform/database.tf b/deploy/azure-terraform/database.tf new file mode 100644 index 00000000..30a039f8 --- /dev/null +++ b/deploy/azure-terraform/database.tf @@ -0,0 +1,39 @@ +resource "random_password" "psql_admin" { + length = 32 + special = false +} + +resource "azurerm_postgresql_flexible_server" "default" { + name = "psql-${var.name}" + location = var.location + resource_group_name = azurerm_resource_group.default.name + + public_network_access_enabled = false + delegated_subnet_id = azurerm_subnet.database.id + private_dns_zone_id = azurerm_private_dns_zone.database.id + + administrator_login = "tpsqladm" + administrator_password = random_password.psql_admin.result + + authentication { + active_directory_auth_enabled = false + password_auth_enabled = true + } + + version = "18" + sku_name = var.postgresql_sku_name + zone = var.postgresql_availability_zone + storage_mb = var.postgresql_storage_size_mb + storage_tier = var.postgresql_storage_tier +} + +resource "azurerm_postgresql_flexible_server_database" "default" { + name = "turnierplan" + server_id = azurerm_postgresql_flexible_server.default.id + charset = var.postgresql_charset + collation = var.postgresql_collation + + lifecycle { + prevent_destroy = true + } +} diff --git a/deploy/azure-terraform/networking.tf b/deploy/azure-terraform/networking.tf new file mode 100644 index 00000000..80487619 --- /dev/null +++ b/deploy/azure-terraform/networking.tf @@ -0,0 +1,50 @@ +resource "azurerm_virtual_network" "default" { + name = "vnet-${var.name}" + location = var.location + resource_group_name = azurerm_resource_group.default.name + address_space = ["10.0.0.0/16"] +} + +resource "azurerm_subnet" "app" { + name = "subnet-app-${var.name}" + resource_group_name = azurerm_resource_group.default.name + virtual_network_name = azurerm_virtual_network.default.name + address_prefixes = ["10.0.1.0/24"] + + delegation { + name = "app" + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "database" { + name = "subnet-database-${var.name}" + resource_group_name = azurerm_resource_group.default.name + virtual_network_name = azurerm_virtual_network.default.name + address_prefixes = ["10.0.2.0/24"] + service_endpoints = ["Microsoft.Storage"] + + delegation { + name = "psql" + service_delegation { + name = "Microsoft.DBforPostgreSQL/flexibleServers" + actions = ["Microsoft.Network/virtualNetworks/subnets/join/action"] + } + } +} + +resource "azurerm_private_dns_zone" "database" { + name = "dnszone-${var.name}.postgres.database.azure.com" + resource_group_name = azurerm_resource_group.default.name +} + +resource "azurerm_private_dns_zone_virtual_network_link" "database" { + name = "database-vnet-link" + private_dns_zone_name = azurerm_private_dns_zone.database.name + virtual_network_id = azurerm_virtual_network.default.id + resource_group_name = azurerm_resource_group.default.name + depends_on = [azurerm_subnet.database] +} diff --git a/deploy/azure-terraform/resource-group.tf b/deploy/azure-terraform/resource-group.tf new file mode 100644 index 00000000..ac8d5f8f --- /dev/null +++ b/deploy/azure-terraform/resource-group.tf @@ -0,0 +1,4 @@ +resource "azurerm_resource_group" "default" { + name = "rg-${var.name}" + location = var.location +} \ No newline at end of file diff --git a/deploy/azure-terraform/storage-account.tf b/deploy/azure-terraform/storage-account.tf new file mode 100644 index 00000000..751746b3 --- /dev/null +++ b/deploy/azure-terraform/storage-account.tf @@ -0,0 +1,21 @@ +resource "azurerm_storage_account" "default" { + name = "st${replace(var.name, "-", "")}" + location = var.location + resource_group_name = azurerm_resource_group.default.name + + access_tier = "Hot" + account_tier = "Standard" + account_replication_type = var.storage_account_replication_type + + public_network_access_enabled = true + + lifecycle { + prevent_destroy = true + } +} + +resource "azurerm_storage_container" "images" { + name = "${var.name}-images" + storage_account_id = azurerm_storage_account.default.id + container_access_type = "blob" +} diff --git a/deploy/azure-terraform/terraform.tf b/deploy/azure-terraform/terraform.tf new file mode 100644 index 00000000..a063d5c4 --- /dev/null +++ b/deploy/azure-terraform/terraform.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">= 3.0.0" + } + random = { + source = "hashicorp/random" + version = ">= 3.7.2" + } + } +} diff --git a/deploy/azure-terraform/variables.tf b/deploy/azure-terraform/variables.tf new file mode 100644 index 00000000..207caf06 --- /dev/null +++ b/deploy/azure-terraform/variables.tf @@ -0,0 +1,110 @@ +variable "name" { + description = "Name suffix for all resources" + type = string + nullable = false +} + +variable "location" { + description = "Location of the deployed resources" + type = string + nullable = false +} + +variable "turnierplan_container_registry" { + description = "The container registry to pull the image from" + type = string + default = "ghcr.io" + nullable = false +} + +variable "turnierplan_container_image" { + description = "The name of the container image to pull" + type = string + default = "turnierplan-net/turnierplan" + nullable = false +} + +variable "turnierplan_container_version" { + description = "The name and tag of the container image to pull" + type = string + nullable = false +} + +variable "turnierplan_initial_user" { + description = "The user name for the initially created admin user" + type = string + nullable = false +} + +variable "turnierplan_initial_password" { + description = "The password to initially set for the created admin user" + type = string + nullable = false +} + +variable "turnierplan_additional_app_settings" { + description = "Additional configuration values for turnierplan.NET" + type = map(string) + nullable = false +} + +variable "app_service_plan_sku_name" { + description = "The SKU name to use for the app service plan" + type = string + nullable = false +} + +variable "app_service_custom_domain" { + description = "The domain name which should be bound to the app service or null if no custom domain should be used." + type = string + nullable = true + default = null +} + +variable "app_insights_retention_in_days" { + description = "The retention period for application insights logs" + type = number + nullable = false +} + +variable "storage_account_replication_type" { + description = "The replication type to use for the storage account" + type = string + nullable = false +} + +variable "postgresql_availability_zone" { + description = "The availability zone to deploy the PostgreSQL server in" + type = number + nullable = false +} + +variable "postgresql_sku_name" { + description = "The name of the SKU to use for the PostgreSQL server" + type = string + nullable = false +} + +variable "postgresql_storage_size_mb" { + description = "The storage size in MB for the PostgreSQL server" + type = number + nullable = false +} + +variable "postgresql_storage_tier" { + description = "The storage tier for the PostgreSQL server" + type = string + nullable = false +} + +variable "postgresql_charset" { + description = "The charset to use for the PostgreSQL database" + type = string + nullable = false +} + +variable "postgresql_collation" { + description = "The collation to use for the PostgreSQL database" + type = string + nullable = false +} diff --git a/misc/bump-version.sh b/misc/bump-version.sh index 60c49d44..dd1bfacd 100644 --- a/misc/bump-version.sh +++ b/misc/bump-version.sh @@ -36,3 +36,4 @@ update_file () { update_file "src/version.xml" update_file "src/Turnierplan.App/Client/package.json" update_file "src/Turnierplan.App/Client/src/environments/environment.prod.ts" +update_file "docs/pages/installation/azure-terraform.md" From 0fe8ae93e193c5fbd304beea43124c96edf72d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Sat, 11 Apr 2026 20:54:53 +0200 Subject: [PATCH 14/26] Update docs --- docs/pages/installation/index.md | 6 ++---- misc/bump-version.sh | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/pages/installation/index.md b/docs/pages/installation/index.md index 8922ea5c..98950d90 100644 --- a/docs/pages/installation/index.md +++ b/docs/pages/installation/index.md @@ -29,7 +29,7 @@ Für die Installation auf einem lokalen Rechner oder einer VM kann im einfachste ```yaml services: turnierplan.database: - image: postgres:latest + image: postgres:18 environment: - POSTGRES_PASSWORD=P@ssw0rd - POSTGRES_DB=turnierplan @@ -40,7 +40,7 @@ services: restart: unless-stopped turnierplan.application: - image: ghcr.io/turnierplan-net/turnierplan:latest + image: ghcr.io/turnierplan-net/turnierplan:2026.2.0 depends_on: - turnierplan.database environment: @@ -62,8 +62,6 @@ networks: turnierplan: ``` -Statt dem `latest`-Tag sollte immer eine spezifische Version für die Images der Datenbank und von turnierplan.NET verwendet werden. Dies ermöglicht eine bessere Kontrolle, welche Updates wann eingespielt werden. Die neuste Version ist auf der [Release-Seite](https://github.com/turnierplan-NET/turnierplan.NET/releases) der Repository auffindbar. - Die URL, welche letztendlich für den Zugriff auf turnierplan.NET verwendet wird, sollte in der Umgebungsvariable `Turnierplan__ApplicationUrl` spezifiziert werden. Falls bspw. eine Domain `example.com` verwendet wird, sollte der Wert der Umgebungsvariable `https://example.com` sein. Falls turnierplan.NET im lokalen Netzwerk gehostet wird, könnte der Wert bspw. `http://192.168.0.187` sein. Es muss natürlich das korrekte Protokoll (HTTP vs. HTTPS) verwendet werden. Die Volume-Mounts sind im [nachfolgenden Abschnitt](#volume-mounts) näher beschrieben. Je nach Konfiguration kann das Volume-Mount vom turnierlpan.NET-Container auch überflüssig sein. diff --git a/misc/bump-version.sh b/misc/bump-version.sh index 60c49d44..75ef8a77 100644 --- a/misc/bump-version.sh +++ b/misc/bump-version.sh @@ -36,3 +36,4 @@ update_file () { update_file "src/version.xml" update_file "src/Turnierplan.App/Client/package.json" update_file "src/Turnierplan.App/Client/src/environments/environment.prod.ts" +update_file "docs/pages/installation/index.md" From 16799322e2dfae4ac32fd1e3a67746397ba97cf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Sat, 11 Apr 2026 20:58:30 +0200 Subject: [PATCH 15/26] Hardcode version in variables.tf --- deploy/azure-terraform/variables.tf | 1 + misc/bump-version.sh | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/deploy/azure-terraform/variables.tf b/deploy/azure-terraform/variables.tf index 207caf06..b3a7b524 100644 --- a/deploy/azure-terraform/variables.tf +++ b/deploy/azure-terraform/variables.tf @@ -27,6 +27,7 @@ variable "turnierplan_container_image" { variable "turnierplan_container_version" { description = "The name and tag of the container image to pull" type = string + default = "2026.2.0" nullable = false } diff --git a/misc/bump-version.sh b/misc/bump-version.sh index 4cb01820..a3a9299d 100644 --- a/misc/bump-version.sh +++ b/misc/bump-version.sh @@ -33,8 +33,9 @@ update_file () { sed -i -e "s/${current_version//./\\.}/$next_version/g" "../$1" } -update_file "src/version.xml" -update_file "src/Turnierplan.App/Client/package.json" -update_file "src/Turnierplan.App/Client/src/environments/environment.prod.ts" +update_file "deploy/azure-terraform/variables.tf" update_file "docs/pages/installation/azure-terraform.md" update_file "docs/pages/installation/docker-compose.md" +update_file "src/Turnierplan.App/Client/package.json" +update_file "src/Turnierplan.App/Client/src/environments/environment.prod.ts" +update_file "src/version.xml" From 59af0501f0d6054a34f7cda1d967c390af221e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Sun, 12 Apr 2026 20:34:55 +0200 Subject: [PATCH 16/26] Update zensical --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index d91c01a0..8f405362 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1 @@ -zensical==0.0.29 +zensical==0.0.32 From 7e057e0433814622fad8b324ef3642bc0a10c697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Sun, 19 Apr 2026 09:44:02 +0200 Subject: [PATCH 17/26] Zensical => 0.0.33 --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 8f405362..4a51f3fd 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1 @@ -zensical==0.0.32 +zensical==0.0.33 From 62e637c417b50fd15d148dc6fc2dfea830e0d150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Sun, 19 Apr 2026 10:26:39 +0200 Subject: [PATCH 18/26] Documentation updates --- deploy/azure-terraform/variables.tf | 2 +- docs/pages/installation/azure-terraform.md | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/deploy/azure-terraform/variables.tf b/deploy/azure-terraform/variables.tf index b3a7b524..e1f42a73 100644 --- a/deploy/azure-terraform/variables.tf +++ b/deploy/azure-terraform/variables.tf @@ -56,7 +56,7 @@ variable "app_service_plan_sku_name" { } variable "app_service_custom_domain" { - description = "The domain name which should be bound to the app service or null if no custom domain should be used." + description = "The domain name which should be bound to the app service (e.g. 'turnierplan.example.com') or null if no custom domain should be used." type = string nullable = true default = null diff --git a/docs/pages/installation/azure-terraform.md b/docs/pages/installation/azure-terraform.md index fc51a3ec..5b850d83 100644 --- a/docs/pages/installation/azure-terraform.md +++ b/docs/pages/installation/azure-terraform.md @@ -15,6 +15,7 @@ Um das Modul zu verwenden, muss zunächst Terraform installiert sein. Zudem müs module "turnierplan" { source = "github.com/turnierplan-NET/turnierplan.NET-Terraform-Azure?ref=2026.2.0" + # Use a name with a unique suffix to prevent naming collisions name = "turnierplan-example" location = "westeurope" @@ -42,10 +43,10 @@ module "turnierplan" { ``` !!! info - Der `name` wird als Suffix für die Namen aller erstellten Ressourcen verwendet. Um Konflikte bei global eindeutigen Ressourcennamen zu vermeiden, sollte der verwendete `name` möglichst eindeutig sein. Allerdings sollte der `name` nicht zu lang sein, da bei bestimmten Ressourcen auch Längenbegrenzungen für den Namen gelten. + Der Wert der Variable `name` wird als Suffix für die Namen aller erstellten Ressourcen verwendet. Um Konflikte bei global eindeutigen Ressourcennamen zu vermeiden, sollte der verwendete `name` möglichst eindeutig sein. Allerdings sollte der `name` nicht zu lang sein, da bei bestimmten Ressourcen auch Längenbegrenzungen für den Namen gelten. !!! danger - TODO (Datenbank nicht high-availability) + Die PostgreSQL-Datenbank ist *ohne* Hochverfügbarkeit konfiguriert. Es wird nur ein Replika in der spezifizierten Availability Zone (`postgresql_availability_zone`) deployt - vgl. [Terraform-Doku](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_flexible_server) und [Microsoft-Doku](https://learn.microsoft.com/en-us/azure/postgresql/high-availability/concepts-high-availability) Die folgenden Azure-Ressourcen werden durch das Modul erstellt: From 3c799a420e7ca467137101fddca1cf2d2f782724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Tue, 21 Apr 2026 18:50:39 +0200 Subject: [PATCH 19/26] Documentation complete --- docs/pages/installation/azure-terraform.md | 7 ++++--- .../azure-terraform-architecture.drawio.png | Bin 0 -> 53254 bytes 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 docs/pages/installation/images/azure-terraform-architecture.drawio.png diff --git a/docs/pages/installation/azure-terraform.md b/docs/pages/installation/azure-terraform.md index 5b850d83..39e14a89 100644 --- a/docs/pages/installation/azure-terraform.md +++ b/docs/pages/installation/azure-terraform.md @@ -4,8 +4,9 @@ Dieser Artikel beschreibt das Deployment von turnierplan.NET auf Microsoft Azure ## Architektur -!!! danger - TODO +Die Cloud-Architektur umfasst im Wesentlichen einen Azure App Service sowie eine verwaltete Azure PostgreSQL-Datenbank. Ergänzt werden diese Services von Azure Application Insights zur Erfassung von Telemetriedaten sowie von einem Azure Blob Storage Account, worin die hochgeladenen Bilddateien gespeichert werden. Für die Authentifizierung beim Storage Account verwendet der App Service eine System-Assigned Managed Identity. Um die Datenbank vor Zugriffen aus dem Internet zu schützen, wird für App Service und Datenbank ein virtuelles Netzwerk inklusive Subnetzen verwendet. Der Endnutzer greift direkt per HTTPS auf den Azure App Service zu. Hierbei wird entweder der Standard-Domainname verwendet - oder, optional, ein eigens definierter Domainname. + +![Architektur des Terraform-Moduls](./images/azure-terraform-architecture.drawio.png) ## Verwendung @@ -46,7 +47,7 @@ module "turnierplan" { Der Wert der Variable `name` wird als Suffix für die Namen aller erstellten Ressourcen verwendet. Um Konflikte bei global eindeutigen Ressourcennamen zu vermeiden, sollte der verwendete `name` möglichst eindeutig sein. Allerdings sollte der `name` nicht zu lang sein, da bei bestimmten Ressourcen auch Längenbegrenzungen für den Namen gelten. !!! danger - Die PostgreSQL-Datenbank ist *ohne* Hochverfügbarkeit konfiguriert. Es wird nur ein Replika in der spezifizierten Availability Zone (`postgresql_availability_zone`) deployt - vgl. [Terraform-Doku](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_flexible_server) und [Microsoft-Doku](https://learn.microsoft.com/en-us/azure/postgresql/high-availability/concepts-high-availability) + Die PostgreSQL-Datenbank ist *ohne* Hochverfügbarkeit konfiguriert. Es wird nur ein Replika in der spezifizierten Availability Zone (`postgresql_availability_zone`) erstellt - vgl. [Terraform-Doku](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_flexible_server) und [Microsoft-Doku](https://learn.microsoft.com/en-us/azure/postgresql/high-availability/concepts-high-availability) Die folgenden Azure-Ressourcen werden durch das Modul erstellt: diff --git a/docs/pages/installation/images/azure-terraform-architecture.drawio.png b/docs/pages/installation/images/azure-terraform-architecture.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..be3c7aa3c6db45eb72c58e22fd0436d17795dfdd GIT binary patch literal 53254 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%0De z4I5}IVwHO3DY65Ueu=4J2j)VYuzg8u;JW4pp0GK_v1t2|T4flen8bBa+P*E~5wT6?PFpSpHFtklYv|N_ zZ*UUL1z-@VXTd4go3&{Dq-NtOLB46{ygPZPF@iru4;$XM$Vls7fQ2$ZT>Xk5srWmbrzS?^f}|uXrqLEfzrN ziHqB7)R6fX6AAp$M)k1F!n?7|!5N|%12Xqe?Bg^c7=xuxi37!Ga#r=)nUoaVsHT>4 zY3}`c1P6jn7oPA2K1Bat(N@xFW|(J~guH?5pb+^Wy67>ue+(&q#2A|bm^WLmvs0jI z2X!;9`X5s+lV?SfyQx4_91Q<|UTe@q*UOZp`3G~82tsE~K$jMVP72~rth4??GZJgS zB1mz;xq|V3kc$K&0eCMbp-c)mS3}4XfNVGsSIMlax~0ngdkg=c7=*u25{KZ=XNrLN z6G4D916^+NQw!11IDQrumQdY_0y$9xeZx`T&*s%^ZJx zQ5fi8iH;qYMsI zi6*zBShe@Es~-}StsQ6kSrHpsUgJPVBKCkBNlqQA5?3ZJgq!#!P}T&Bf7$@)*OZgi zdvmxW1dEe6QV>20ip>1|%PUYNUXX$alo>=-Q}w!{t@Of0oUx`l0%*GS3#uIYJ)-3g~N#Tb~gF*>MPA65J`k^DX zGPvv24<(Ig10Q&Ct*|@sk+$Nso4f@W7!iVZIQ<8ug2)v@&mM<&4hi`cr&tFCu zEkFXmqhG+DsV69OV`+Zc3qt0XK(Bl<;@>=gv4)AbVXV`T=i07xdw%0AT zao`ApUpRd$htSXsz{kwtV&XlPNA9=km-lBB<1cGJCc zQ7m4q-A}L!XHVAtSjI3i0a}or?oJM0&#QnUUa$dO)xH8^g~qQ>?hXgVPOooP$;|Cu zAinmIxwx->%@FSnu2|d1^t;$C1hDL@OzIe1#yQX}k#&4|zrd4xh!9XzBq_;xUpa`9 z9ub1+iUCYVB_}bhwSLA{kN*E4i(se}D}qJw5Q6FY*d~ougoNLyd6GA_1)@&I6v z6##?SzSyJq#c+1Y;lMdM#CC8vK>6#(^v^sJ0uwMiJ8#fqwTLr=rR@V_zsQ1d#J{HY;qT-H<2)A3@{O6W z8gm>}TsCDAQVGy6By@Aoj0|9A1f%&?k%k%%B6~8)>da?ywoE5J)`qd79j}tXy z?>omQCkC7M$$#Z3f2lzDT{C61Q%iGYF(sK#QBnxBTxf_u^eJe$R7IprjwWJ@&I_Q* z8|;5aW{wElZ>FJuI@?e{bzjT6&{L)F^o&dtL(iYbze%^%!%WYoY@Ky5@8BDB-Gi6J z80lgFXQMd`);}i60N^#W70@liy@!7g6d-)};J3&#^c)nF))=(pPH5$NMI(G`$W9=hm zWR0*3zST!r|8tb|-L+@cm-0^qNgrYgG@3IvGsIw2MBkp4;CwxQES?o_=fqLPkSJi~ zPK4_H*_tiXPZ-5Z*-x-|VTXd2pFSj1BOhL3ypX7foDMDeFI1IRL@Z@~C{vOsOmp^m!xWFBSkC#P$=bNf8649x@m5yqCCiofBDbJV9)}I#Z~zPl;Yd zGY{;D?qIJSEAFvVa3XYl&|y0(p6`A%EZOWPM{n-;JaTEC-)VQKBLuo%0!%q?3f}`g=l@M$|}>>K<$Oa zZ`^yi+Rf9GpW5(>vE$jj1~ctX1m-lJOhLx-v3S_;`D0d}8CDJ#NpvlXW8|NS7LLA_ z221F!t@}JfEBYNm>qg8D$(#=j9G0K`hPZf0Yn`Z_J<)#7GSGav%+J-xcttf;Y)9Dm zOa96B(A&|zhS)C&Bag5IxEM>Q54_Gt+#2vQaNKNX-ewQH*>H|-bB?!_)_qIh#lA)M z|8`t=Us`lhdz;^NR@`qx-53tWe&xmnq}b0noQ)K)9zl5=@drp=Sy=&#$~K_{g&$0( zc|Y!mGN8nsx6W3+vi0*O^u$q=^i)Kv&f=`sth1OC=NL^1N_%|x?VG#_mNJ_u4WGS? zn;cM3ef~T&jh5JCDop0=^u5W|FBry_w@ze|v*Hu@!djZy*><(lhPOee0}DtPdZQ7W ziJ`5??2DkCoO6=~KYtj{y?y7Yid3H6@_0?r_q~hA;_=*`a0wE`E1wd=cx_RUIY%PL zX#PQ6G@zQ?-Z*J?b~=wZct(d8b#woTRYcHdankkQ-y%Yj)w)8cRPpSq7RayBYS3hhbr*a{i%S~73xqYcQNx~iS zo@D|1w9lob3_!Bw^Eb!o^WRGT=j&YQwXc0#wP@)<@H(xfk5^(hUzbB}qacT%J^hPK zpPF!lK0+cK?2RGhMUnGQbM$*xBxBez6%?stUcUSow8k*breiM&zA1P;Rb^duE2m}z zq5sYgj9!?4$Q@iG8gWn>F@MMw-s@L&KXL6uuWOxm_ad^ly4W-lkRYs2oS5Gq3*m|s zGe%z(k3BeSiY1_yQdifG>}Y-#&a0leO3YQ1%ZgHB)?qhQ>pC8*MIrm^OA^r;r*GyXt;hJ` zJ#hBpr)(2Dday1#V`F2ZPnAbx#OfSRIxoH)V0d*GL&Q{DkxL-XLd9-h$gD#eG(+Vhc7&zj|Jet6d9%P#WjdnN}N1eF|F zFMc54CB?^*WE*?xVV6iLbL66!%+cQL@gsd=b8|BdEo$sO*O;w!iQ%-CT`(~>;u{b* zkP838P;>SJ#p-7D0vXioF-FANW<8;@z)iIAL1J=JhCO>*C>5`!xlIl7v9;RUV%b}PON*(usWuC;2&c@Q(qqaLP^W2G-^ zB#-*VJ$ya$Y`{so()c2L3qJ7p6=vSpov69ff!lVE+nc2ihvP2nCEDXN%=IyIkRhss z4;XKgDXC-A84^vnAB9e@?g|)olk@ve@#u^w#8{QlwNk^UlisIx4CoBqUmqA~xB#d3;eHLh!ZEZvj>G{<2Q($4kxnB1mZ8&dllawrF{f$|-5M$vTw5vC9NHJ8cMd;WST2BEyhT)PB~UNcK(&Ep_eKD;Ei4pypII6aElW$i5!*c&yL;M)k!9HuGZ5HRx!A zOa5WW#4Am;Oxk*?fifuh?#^cP!)Ky+(G_LU($R4t@F>KHSjnM9*)_c?`^KmB|7%Gb z*#(0}9y&5h8`ntCqiTtBQ_WYUmhkV_-^Jm0l*|F|I}PU3R}__C15ie*7FVVSKqL!q`FT zRH@6>A4C4I^#h46{hD3pQNJe&!vQ&q3)tSxOga8Q5gOu9cs>3N%M!C?{7Gp6xMnz+n1M3#pn z{Ti`)i2J^bF$@DUrnRjLh-qQyUrsp;)d(hUzK=yTg>0LJYV|i6sO8+6EL(}=VQsm zPOSkYL?RfF9FMX5VW;;(ce-nA5tmdxuFiu~lwn1dPZ z-(Scd<7*$oG<2xzhf%l0H2$G{d3kzZ%5?Gqu}1MEH{|o4PeH5!Tbn;NZGW^&Ony=Z z(1r<#xn#$Rq_{^Wh0Gdm+3iI0n{m{8YCxbt_kwX0cM|ZF@M)0;RW!Y+pXSlZl;WTk zXvAy}>TAXLip0KT=LwA9YIRcd%dPq}ieu^j)bw*r;^-)Y+<@YnT~r^-d1av@Q|CmA zCzj)>B0GgP3Hv-x%il_r>KQ(&FMqFEZ0nogFoQbvjZ;5CknTRa`g^dmQc8lIm3|_z za1>bxX@bNiAY`;h(^i_O%*I28=_}t<#UsYj9nYU79*YmTc41vMHY+YKwqcKS2o$ie z)C|lO1oboXQF;vR_dN$aE2GvXDH%({lcs6L znrP?v2P~gY*K1I@&rA5#MDgnzj))V4>wrP1=4HLsYFwDPOv943NYO-_8nKAS!}Zm5 z<7SB0wiSE-lM3Iyhr8&$(1Vg2qi9&^Ao^oht7LLuL91!rD5SMP_Fjh2c6vM8=KC9~ z794Ea%%o7?vN5&W$VA35WY#Ix$c2OUSs&Qtu-8i6J6DHKcDJQiBG;g-@F2G7< zlHz}E6}i|`vPp%}wPs|bGg-GRjHGK@PpWI{pcijTrjzOl}0EBsb0W(ar0LgKb&nDfN96B}V&Rc`+ zpal9DB%0}2SPBg$!A!{gD%8ZUUu0$mWLB-z-fIlOHOq#oN%=$VW*^W97w!kzr&*mA zSFjO+HOU$imw$2;B*|_1@}5R9r=+K2W^*?>)Hb$QH+~{!L43o6zvveC^^@9xl7!Lj zSiY~CEUeD`#6;J|+?@I16dnd?set10Cm=Uu=Wa*4$=qI)^^ttCv!UM(uw=r1Tg7z> z*pN-=H`uu~JFZAHJC4vL==xPD_)iap6ENc2*@Gl@w8jU29SB5(fk#asj*@F7QHqPY z6~|5^LxDm8{-dv>LkX&~;q{f1A?lIe+B^8WwJYmpTJzmOxl`ENF)mht*m>8X#`W?q zb#;epxjvOI>IGcb#Ei$g_D+*3S)QRm-!2GYI9uvHTLB;;y`VF|+Hbx0>qBZuCjlkB zX6!E3_mk5r@7v^#0~?|(oa}5WUHAui*2&F%b|oo{oeOJ#X%Ph+17rtF+;mbE2_beF z)|)puaUdV1i_@(hv3B;bWw&iHnIeHQ<HsU@TZomwvbXcCuU%Hh+H-dr3!mqi9-a3ltlw+%i)mI= z6wBp4{&RYI3@yrT!)xW;Ktx0uK#e-}_Fp1Q7c_P4G`3A$sf{YcC}tW>iA~ z%D;pg9ByOX&v(jw>zB8NV9N*^o#l5&>#Sv=G$Vk#!X=0St{BykFc#0;eQ2~2N?rCH zNMY$4DkIph7}kjt z=pyCed{m^~zKH0tPH-BYB6{Berk`{Uvo9KG8R}tbMQ9%UOf+;hC9FX+psrydYH7huSyt5L}QR>O5l;aoXOdrSC!_ z;&vDfApDSbN%xDy1GHOP_WZi~=^-?36mq>68J3#SB^V+}OiEe>4hg8;b9~<(5e+HD zXwTnEWC#_bzdv=FgkSg)jpAS2qWeWPkgGu2Z-kdaGQSX}d7BF~z&l`>_dEGw{QhDA z_8q|(0$E3>`k!7!oc`!s%;vWt1?5SRbuT%Pr-I_!%Q~&lLYi= z|LI~J=A39HX|SkANQ5<|Yv0Ab0wNr%Um4@1!*FRJt!F?c=v)H_3P}%-&o29f2cXoc zCzi%$z4-E}fcC)Cw1XgD6PV1Yy9TsVeuYhLSS>czil>v-vb`ucYf_o7 zwFv_W*!Fq5Jr$0)f6+l{3NUI}Md`D)CI+ZVf&u^=#cG~u*A?b8aAFOlDqLH} zoziva29o-(elNx)CK5XmBL0qwjEql7kvn28_qqI4r<=6tNn?>}|5h7ek}!M{UNVRD z{7;Uf3mtqvxv<*F%pmAd8jzzUb6xV-z8?m8Qw1(&6Kk?$dp|gASjPqF)B=U{A%S^p zP}y9K14w+oo64AClTU}Op2r}0#Hy3c8$>&~GKvXE?3$vw%50Gal)!zQ_cFuW9ygPy=D;x-b z&QbJulg|K)mxFuBkTgw4!_Vl`9jQNvfIJxDS#5dz!kpxpo8)B&SX1S2z^>v^nAhPYpgK95_QKLR8TmfCe>S#=2tYVC9| z#a+uT7&ku>1zdoLNluO$hHPoP<}Otq2q-?C+zm8^CbLO^AK4Wttkb;kn%M17EQG}3 z!b$Qg$n@JMR8o0|(YUs)v{)X=$HmFn{dqep3ea-{PJk{|&^w7vX2?GW zl27Bco#BD|UY*FH4nXV?R%mcOhFQA;+2uIZ$a@qz6$aiXG9#FtkX8+BUm05%i0Z6H z+UqEKJbTSwn<5#(=XUgY`|bkJwScIjFrWYtv>0jVb4tQ0$*h#F{(?Zj{$Q^5Y`^-O zMAa*#N3?pBTY#t91A5rLS2FAMn7nqS5yDwqo;W-EfX;eqY;}Z3bhI6QTG`_oOplMHI<=VljlOFUET!=$Jt#l$sD(zvmtqu496ypqvLvgN zi~+m7yBt(AC~zT?w6RPgBbXHc5<&2a} zLgWw@rntU1t(JU4@JuE5Df_+Oec7a9Zg!HO{s}xnh_yc>VmMistnUf3VWk2F1PmkO zh%R4REO&D)VVRf#UHKY_C|JE1&#!)hX{W5THpXEu$yMLMrP}+EHQOOQ=M1*~Mb|Bw zvdn!ybR#&yG*-AL0~wHKYS(w01NO^5q`pdZBg6`!N1^SNelQHT95T@oD>Kiml*sK` zew_AYz-)7)O6>OPhkYUq+V*2y zH+_k^nAqJfhdVk`bkQO30l(w#;SzyR_PLU%yptrrkzi$}1}d=Vf6hkj)*Wy_OkERN zbs4XpwInd|sfSBcCxUz!19bt_IrBr?Crf^lM=V^9vMkrN!m$qP_d*5-pZSd$eDMr8 ztvAtx3Qj(T|Rqr2e_%MK(5O{h0-->LBca zl&`NCpgn+dO+4sz?5r9irLA!k6yUOz-}i{N^b;b1LYHxoimxDN*?oIK z3N-m2Uo!3WOzWwehn~#ha29g)o`Rybz-qOi$tUoqQlF98D?WDaIr*qPb;N0ItAi0D zgmeP-yY+Hs`nz{_y+DW$$u(w7K^CFMWm@Pk(zM(X2a_Z0G80>(NAD&ufkd0d!ubK$ zh(~Xc%ictvvP6yyHxEt765zU<_xh`8!`2YL30BA%1nmnf`d%Ki!>@o21m+-a!KVLB zFRdT7-f|o%C+^xdZ3ZYqT@w~@buB}q_E#N^9;JFcq3|}?E#NC7Q&hqeI^Gab zq)rW~3{b(BK(NtPZX78RTkE`D3#bEtM*wy@mlnw}otrxlr7B0;IYjL#ra;KX)>fWw zy?u|?tvGJrRvfmolY}5A=1;jGn?YFBH4%%lv}v%8elQ_C;=_8WyqjuEJq@vSX08Wd z=U;+|K715L$~69*_4<4}J0~f;nq`qo%Jq#hkY|y+G za?@!#8GTpRIwct3e+O*`i`Epu2$7q}g>Qn8Ckc@FLAv;`T`D~9!dLnDFO$hlZuAO9lyTIw;sRtUuLYW0KK~y*WpEPr?y7b zz^?v>zbo&Zb!^@Ue;hj-tD+pTuItC?mNDhe=9YRg?h{4H9w=5;^h0KEKvmboS6g^P zZ~gm;^NV3a^$q)VTob#MwYPVs$x6MnWxeU|BX*QzA2x?$`t&t16{h(7)@;|fwob`c zia(Dca`6Do2cNf;*2STYz7higF^OrE7JtnB>gv4uM9kjFVJ}z$JvvGvc&;I9 zI&xHCXc-wP3jT&DGHMGbGUAjx;pZrLI*7x|#B&9rse^BiUQRL}hNd!zXx|GLAdPCQ zZ(?$6pu%{}E52qKPG@*uno97V8goUW$i)O1?-UtVDM2a8*4GD&MP6dr^@|i_Z&*$^ zjafA<^&iE0g+F76B0)jYq{4VzwqS~547+!OoLx`z&KLjX(Q>PUH*c}2-kj){1@GIN zFG@*t63uh`hFrYtXEl8xJtjN8_B^KIVq)dYsGqxUz=j$`JuikE**!u_p;uhD(1u4V zwjf8G=8XO<3*6iW?a4XD1y&|i;mw8l^)42pJ-!Z}H+B1TvE&x3a0zcW zx?EfmDEKg3`s{yMeS0ceck}obel)#xJ$LlmYIon+i3gcs0`&(gmj#_>ISn=S!%~Ur z+0yHSXE5thb$&#X!e3>MjEB@%7gICDnG@vC(xUgc7GiYq-=i9or_Ww zyRhqXo+Js^e`9K}X`(+iG0R5UEK=mvb@p|OOH2V@_;=A{xW+fl*1(1XcH|5@lJfPr z3RieT9j%zRrJunrI5OFpsC)G8>D1BVBSNncCj8u~eBL!5O`gLBmlsA~-b_ahe2R4E zKdf)84^A`nc#r<@QeRDW=Ch_I+jLX6$22^1S-S>P#i)kYQFyPF6i@w&*}SiA*KK!n=%(M5k?eOxGd(3Ige z?O8x;McLI6VL_zz>lCh4IGudB&;a|KzVI5%a#s{u_=j~3CP^!jw9IAHfM&z_oKyix zBSG-cTsvKSO0-lv84%A?&8tH$KZQ!56R4TVH@Uzy8K0g5d?_a9_LBidYzl6h-yY&x zSzW2Xg{~$~gi_hwJ14v74>=t1I!Qot#c!1pZ5 zLf6G%I7|W^%=Ufm0QB03M_#0ql3RJZ+M}%eGOe+x+*6+-*{UCme)sbz`;b_4@hL}f zF_$~wIB-wD8ZohHM68OXXj!Zz<=IiGkzN)l624DYmg$;mBqo=}lXJaN4#!e^ zxr5jzFa1QFJkUSUTjSkfvzXt_LV0j4rY7?lrDE;-ma)gl)x(d#T0U2qw<~p*BVdJA z+*jRaq?^z1w=a$-B849MK0?4VSUTwcf^$8-5*h-0S_}SCcTvQjy>YZS19P#BqBa7O zyVx?Wt`c-d)3`YWefTqkpc^;?p7C8i@jrb7e`^+fnV|T4C`0g)_q^=e103++KxdUQ z;^)@Ijyx>~0u8Sww;OlS-*Qiz)gQhSbxSX2|Kw%2{EO-PrtkIjrCVo+4%a%H^UTyG zznN^B?w_s>1Z$6>s?sEW!+k^o1uYq0@r$9$TH0^I)zmED=V4;?(IUu_bjXrMSI7^7 z@U<1`B<(o!VCqkKj)k(uwdK-&+mxzst>XsZlZ%4SSBbX|pXJvbn{GzVd~8hofkkM# z#e(Wh0+O5yRh5n$iM zRxMJ>bT1(L^NBy}3Kf{p^Z4q;A%7YgohT7XgUHB?pDVBymXiC=s0BChECc*zO}2x% zpfVzb%fDY(10K2#_BlGVF8uRaC76j-rCMr!koVtP_~eg4+eXDZo`J5WLoSe`&S?p>94z3SJMuEh(&dsyf&U-MEB568 literal 0 HcmV?d00001 From a4d171027383e5fb7c6f14f97413b64391f52712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Tue, 21 Apr 2026 19:01:21 +0200 Subject: [PATCH 20/26] Readme for deploy folder --- deploy/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 deploy/README.md diff --git a/deploy/README.md b/deploy/README.md new file mode 100644 index 00000000..8c154d67 --- /dev/null +++ b/deploy/README.md @@ -0,0 +1,3 @@ +# turnierplan.NET · Deployment Scripts + +This directory contains scripts for various deployment methods. Refer to the [documentation](https://docs.turnierplan.net/installation/) for details on how to use the scripts. From f53ed09e5762c75b9b9a7f4806f9bd149df6847e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Tue, 21 Apr 2026 19:04:32 +0200 Subject: [PATCH 21/26] Reset structure of nav --- docs/zensical.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/zensical.toml b/docs/zensical.toml index a7031447..5b19614b 100644 --- a/docs/zensical.toml +++ b/docs/zensical.toml @@ -18,12 +18,12 @@ nav = [ "index.md", { "Installation" = [ "installation/index.md", - "installation/docker-compose.md", + { "Docker Compose" = "installation/docker-compose.md" }, { "Azure (Terraform)" = "installation/azure-terraform.md" } ]}, - "configuration/index.md", - "getting-started/index.md", - "releases/index.md" + { "Konfiguration" = "configuration/index.md" }, + { "Erste Schritte" = "getting-started/index.md" }, + { "Releases" = "releases/index.md" } ] [project.theme] From 3aa6c34e05766c8c9ea0f8cc3917613078aeb01a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Tue, 21 Apr 2026 19:05:34 +0200 Subject: [PATCH 22/26] Start --- docs/zensical.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zensical.toml b/docs/zensical.toml index 5b19614b..38478182 100644 --- a/docs/zensical.toml +++ b/docs/zensical.toml @@ -15,7 +15,7 @@ docs_dir = "pages" extra_css = ["assets/turnierplan.css"] nav = [ - "index.md", + { "Startseite" = "index.md" }, { "Installation" = [ "installation/index.md", { "Docker Compose" = "installation/docker-compose.md" }, From f05cecb0aef8b7eeef794abd6c37c4da56ab46e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Tue, 21 Apr 2026 19:12:55 +0200 Subject: [PATCH 23/26] Update tf source --- docs/pages/installation/azure-terraform.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/installation/azure-terraform.md b/docs/pages/installation/azure-terraform.md index 39e14a89..3a24b1f0 100644 --- a/docs/pages/installation/azure-terraform.md +++ b/docs/pages/installation/azure-terraform.md @@ -14,7 +14,7 @@ Um das Modul zu verwenden, muss zunächst Terraform installiert sein. Zudem müs ```terraform module "turnierplan" { - source = "github.com/turnierplan-NET/turnierplan.NET-Terraform-Azure?ref=2026.2.0" + source = "github.com/turnierplan-NET/turnierplan.NET//deploy/azure-terraform?ref=2026.2.0" # Use a name with a unique suffix to prevent naming collisions name = "turnierplan-example" From 3d6abfc7275f939556c366372a8fca2b24bb4c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Tue, 21 Apr 2026 19:14:13 +0200 Subject: [PATCH 24/26] newline --- deploy/azure-terraform/resource-group.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/azure-terraform/resource-group.tf b/deploy/azure-terraform/resource-group.tf index ac8d5f8f..05d7aa2f 100644 --- a/deploy/azure-terraform/resource-group.tf +++ b/deploy/azure-terraform/resource-group.tf @@ -1,4 +1,4 @@ resource "azurerm_resource_group" "default" { name = "rg-${var.name}" location = var.location -} \ No newline at end of file +} From 6771b86384ff0c6efc81f3dce8cf523e39cce653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Tue, 21 Apr 2026 19:18:27 +0200 Subject: [PATCH 25/26] Add tf outpout --- deploy/azure-terraform/app-service.tf | 3 ++- deploy/azure-terraform/outputs.tf | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 deploy/azure-terraform/outputs.tf diff --git a/deploy/azure-terraform/app-service.tf b/deploy/azure-terraform/app-service.tf index 690e57f4..2e43e15c 100644 --- a/deploy/azure-terraform/app-service.tf +++ b/deploy/azure-terraform/app-service.tf @@ -1,5 +1,6 @@ locals { app_service_name = "app-${var.name}" + application_url = var.app_service_custom_domain == null ? "https://${local.app_service_name}.azurewebsites.net" : "https://${var.app_service_custom_domain}" } resource "azurerm_service_plan" "default" { @@ -39,7 +40,7 @@ resource "azurerm_linux_web_app" "default" { } app_settings = merge(var.turnierplan_additional_app_settings, { - "Turnierplan__ApplicationUrl" = var.app_service_custom_domain == null ? "https://${local.app_service_name}.azurewebsites.net" : "https://${var.app_service_custom_domain}" + "Turnierplan__ApplicationUrl" = local.application_url "Turnierplan__InitialUserName" = var.turnierplan_initial_user "Turnierplan__InitialUserPassword" = var.turnierplan_initial_password diff --git a/deploy/azure-terraform/outputs.tf b/deploy/azure-terraform/outputs.tf new file mode 100644 index 00000000..3662abcc --- /dev/null +++ b/deploy/azure-terraform/outputs.tf @@ -0,0 +1,4 @@ +output "turnierplan_application_url" { + description = "The application URL of the turnierplan.NET App Service without a trailing slash." + value = local.application_url +} From 45adb02d90f284b735d82fe0a25f040cce6fd9b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20H=C3=B6rner?= Date: Tue, 21 Apr 2026 19:33:10 +0200 Subject: [PATCH 26/26] Docu update --- docs/pages/installation/azure-terraform.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/pages/installation/azure-terraform.md b/docs/pages/installation/azure-terraform.md index 3a24b1f0..7ade0718 100644 --- a/docs/pages/installation/azure-terraform.md +++ b/docs/pages/installation/azure-terraform.md @@ -43,16 +43,19 @@ module "turnierplan" { } ``` -!!! info - Der Wert der Variable `name` wird als Suffix für die Namen aller erstellten Ressourcen verwendet. Um Konflikte bei global eindeutigen Ressourcennamen zu vermeiden, sollte der verwendete `name` möglichst eindeutig sein. Allerdings sollte der `name` nicht zu lang sein, da bei bestimmten Ressourcen auch Längenbegrenzungen für den Namen gelten. +Der Wert der Variable `name` wird als Suffix für die Namen aller erstellten Ressourcen verwendet. Um Konflikte bei global eindeutigen Ressourcennamen zu vermeiden, sollte der verwendete `name` möglichst eindeutig sein. Allerdings sollte der `name` nicht zu lang sein, da bei bestimmten Ressourcen auch Längenbegrenzungen für den Namen gelten. -!!! danger - Die PostgreSQL-Datenbank ist *ohne* Hochverfügbarkeit konfiguriert. Es wird nur ein Replika in der spezifizierten Availability Zone (`postgresql_availability_zone`) erstellt - vgl. [Terraform-Doku](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_flexible_server) und [Microsoft-Doku](https://learn.microsoft.com/en-us/azure/postgresql/high-availability/concepts-high-availability) +Standardmäßig ist die turnierplan.NET-Instanz über die App Service-Domain `.azurewebsites.net` erreichbar. Um eine eigene Domain zu verwenden, kann die Variable `app_service_custom_domain` entsprechend konfiguriert werden. Hierdurch wird ein Hostname-Binding mit einem durch Azure verwalteten SSL-Zertifikat konfiguriert. Hierfür muss entsprechend der [Microsoft-Doku](https://learn.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-custom-domain) ein entsprechender `CNAME`-Record (und ggf. auch ein `TXT`-Record) für die Domain angelegt werden. + +Unabhängig davon, ob eine eigene Domain konfiguriert wird, stellt das Modul den Output `turnierplan_application_url` bereit, welcher die vollständige URL der turnierplan.NET-Instanz beinhaltet. Die folgenden Azure-Ressourcen werden durch das Modul erstellt: ![Auflistung der Ressourcen in Azure Portal-Darstellung](./images/azure-terraform-resources.png) +!!! danger + Die PostgreSQL-Datenbank ist *ohne* Hochverfügbarkeit konfiguriert. Es wird nur ein Replika in der spezifizierten Availability Zone (`postgresql_availability_zone`) erstellt - vgl. [Terraform-Doku](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_flexible_server) und [Microsoft-Doku](https://learn.microsoft.com/en-us/azure/postgresql/high-availability/concepts-high-availability) + Nachdem das Deployment alle Ressourcen erstellt hat, kann auf die Weboberfläche mit der Domain des Azure App Service zugegriffen werden. Anschließend ist der Login mit den festgelegten Zugangsdaten möglich. Weitere Schritte sind auf der entsprechenden Seite [Erste Schritte](../getting-started/index.md) der Dokumentation beschrieben. ## Aktualisierung