refactor(terraform): move shelly to projects/shelly_taupunktluefter and flatten core infra

This commit is contained in:
Moritz Graf
2026-10-20 09:39:26 +02:00
parent a34fa7ee08
commit 28eedea372
38 changed files with 118 additions and 33 deletions
+14 -12
View File
@@ -19,16 +19,12 @@ This repository is divided into distinct domains, each with its own `AGENTS.md`
* **OpenClaw**: For OpenClaw AI agent deployment and troubleshooting, see [k8s/openclaw/AGENTS.md](./k8s/openclaw/AGENTS.md) and [k8s/openclaw/TROUBLESHOOTING.md](./k8s/openclaw/TROUBLESHOOTING.md). * **OpenClaw**: For OpenClaw AI agent deployment and troubleshooting, see [k8s/openclaw/AGENTS.md](./k8s/openclaw/AGENTS.md) and [k8s/openclaw/TROUBLESHOOTING.md](./k8s/openclaw/TROUBLESHOOTING.md).
* **Read**: [k8s/AGENTS.md](./k8s/AGENTS.md) * **Read**: [k8s/AGENTS.md](./k8s/AGENTS.md)
### 3. Terraform (`terraform/`) ### 3. [Terraform](./terraform/AGENTS.md) (`terraform/`)
* **Purpose**: Infrastructure as Code divided into two symmetrical modules: * **Purpose**: Declarative core cloud infrastructure as code.
* **Cloud & DNS (`terraform/infrastructure/`)**: * **DNS Zones**: `haumdaucher.de`, `moritzgraf.de`, `ameliegraf.de`, and others via OVH (`ovh/ovh`).
* **DNS Zones**: `haumdaucher.de`, `moritzgraf.de`, `ameliegraf.de`, and others via OVH (`ovh/ovh`). * **Cloud Services**: Authentik SSO (`authentik.tf`), GCP APIs, Velero backup SA (`gcp_backups.tf`), OpenClaw calendar SA (`gcp_calendar.tf`), and Google Workspace MX/SPF/DKIM (`google_workspace.tf`).
* **Cloud Services**: Authentik SSO (`authentik.tf`), GCP APIs, backups, and Google Workspace MX/SPF/DKIM. * **Usage**: `cd terraform && terraform apply`
* **Usage**: `cd terraform/infrastructure && terraform apply` * **Read**: [terraform/AGENTS.md](./terraform/AGENTS.md)
* **Smart Home Shelly Automation (`terraform/shelly/`)**:
* **Taupi Cellar Mold Ventilation**: Automates Shelly Plug S with psychrometric dew point calculations (`Taupi-4.0.js`) and BTHome Bluetooth sensor telemetry.
* **Usage**: `cd terraform/shelly && terraform apply`
* **Read**: [terraform/shelly/AGENTS.md](./terraform/shelly/AGENTS.md)
### 4. Monitoring (`monitoring/`) ### 4. Monitoring (`monitoring/`)
* **Purpose**: Physical ambient BLE sensor fleet monitoring across living areas. * **Purpose**: Physical ambient BLE sensor fleet monitoring across living areas.
@@ -112,12 +108,18 @@ This repository is divided into distinct domains, each with its own `AGENTS.md`
* **Key Rules**: Vue 3, Vite, TypeScript, and Tailwind CSS; net calorie balance hero, Garmin health breakdown, and quick meal logger. * **Key Rules**: Vue 3, Vite, TypeScript, and Tailwind CSS; net calorie balance hero, Garmin health breakdown, and quick meal logger.
* **Read**: [projects/moritz/AGENTS.md](./projects/moritz/AGENTS.md) * **Read**: [projects/moritz/AGENTS.md](./projects/moritz/AGENTS.md)
### 15. Utility Scripts (`scripts/`) ### 15. [Shelly Taupunktlüfter](./projects/shelly_taupunktluefter/AGENTS.md) (`projects/shelly_taupunktluefter/`)
* **Purpose**: Automated cellar ventilation controller ("Taupi") on Shelly Plug S Gen 3 to prevent mold growth using psychrometric calculations and BTHome BLE sensors.
* **Usage**: `cd projects/shelly_taupunktluefter && terraform apply`
* **Key Rules**: Sedlbauer LIM I decoupled mold danger evaluation, summer overheating and winter cold guards, optimal night drying window (03:00–07:00), and Prometheus metrics export.
* **Read**: [projects/shelly_taupunktluefter/AGENTS.md](./projects/shelly_taupunktluefter/AGENTS.md)
### 16. Utility Scripts (`scripts/`)
* **Purpose**: Cross-cutting operational and administration CLI scripts that do not belong inside Kubernetes namespace directories. * **Purpose**: Cross-cutting operational and administration CLI scripts that do not belong inside Kubernetes namespace directories.
* **Key Tools**: * **Key Tools**:
* `scripts/htpasswd.py`: Generates bcrypt-hashed htpasswd credentials for ingress basic auth secrets. * `scripts/htpasswd.py`: Generates bcrypt-hashed htpasswd credentials for ingress basic auth secrets.
### 16. Network & Router Integration (`fritzbox/`) ### 17. Network & Router Integration (`fritzbox/`)
* **Purpose**: Site-to-Site WireGuard LAN coupling and DynDNS OVH synchronization for the home FritzBox router. * **Purpose**: Site-to-Site WireGuard LAN coupling and DynDNS OVH synchronization for the home FritzBox router.
* **Cluster Endpoint**: `k8s/wireguard/` (`vpn.haumdaucher.de`). * **Cluster Endpoint**: `k8s/wireguard/` (`vpn.haumdaucher.de`).
* **Read**: [fritzbox/README.md](./fritzbox/README.md) * **Read**: [fritzbox/README.md](./fritzbox/README.md)
+5 -3
View File
@@ -6,15 +6,17 @@ Infrapuzzle is the monorepo for personal infrastructure, Kubernetes cluster oper
- **[`bootstrap/`](bootstrap/)**: Provisioning the single-node Kubernetes cluster (`haumdaucher`) using Kubespray. - **[`bootstrap/`](bootstrap/)**: Provisioning the single-node Kubernetes cluster (`haumdaucher`) using Kubespray.
- **[`k8s/`](k8s/)**: Kubernetes workloads. **Every subdirectory represents a Kubernetes namespace.** - **[`k8s/`](k8s/)**: Kubernetes workloads. **Every subdirectory represents a Kubernetes namespace.**
- **[`terraform/`](terraform/)**: Declarative Infrastructure as Code: - **[`terraform/`](terraform/)**: Declarative Infrastructure as Code for core cloud infrastructure (OVH DNS zones, Authentik SSO, Google Workspace, and GCP APIs).
- `terraform/infrastructure/`: Cloud infrastructure, OVH DNS zones, Authentik SSO, and Google Workspace.
- `terraform/shelly/`: Smart home Shelly Plug S ventilation controller ("Taupi") for cellar mold prevention.
- **[`projects/`](projects/)**: Self-contained hosted applications and projects: - **[`projects/`](projects/)**: Self-contained hosted applications and projects:
- `projects/shelly_taupunktluefter/`: Smart home Shelly Plug S ventilation controller ("Taupi") for cellar mold prevention.
- `projects/sasch40/`: Retro birthday adventure game (`sasch40.haumdaucher.de`). - `projects/sasch40/`: Retro birthday adventure game (`sasch40.haumdaucher.de`).
- `projects/moritzgrafde/`: Personal homepage and executive portfolio (`moritzgraf.de`). - `projects/moritzgrafde/`: Personal homepage and executive portfolio (`moritzgraf.de`).
- `projects/haumdaucherde/`: Official community website & portal (`haumdaucher.de`). - `projects/haumdaucherde/`: Official community website & portal (`haumdaucher.de`).
- `projects/grabengasse/`: Climate & weather dashboard (`grabengasse7.de`). - `projects/grabengasse/`: Climate & weather dashboard (`grabengasse7.de`).
- `projects/esphome_display_kitchen/`: ESP32 e-Paper kitchen status display & flashing wizard. - `projects/esphome_display_kitchen/`: ESP32 e-Paper kitchen status display & flashing wizard.
- `projects/duckdb-backend/`: In-memory analytics and tracking query API.
- `projects/mila/`: Baby tracking PWA (`family.haumdaucher.de/tracking/mila`).
- `projects/moritz/`: Health and nutrition dashboard (`family.haumdaucher.de/tracking/moritz`).
- **[`monitoring/`](monitoring/)**: ESPHome fleet for BLE ambient room temperature & humidity sensors. - **[`monitoring/`](monitoring/)**: ESPHome fleet for BLE ambient room temperature & humidity sensors.
- **[`fritzbox/`](fritzbox/)**: Home router Site-to-Site WireGuard VPN coupling and DynDNS synchronization. - **[`fritzbox/`](fritzbox/)**: Home router Site-to-Site WireGuard VPN coupling and DynDNS synchronization.
- **[`scripts/`](scripts/)**: Operational utility scripts (e.g. `htpasswd.py`). - **[`scripts/`](scripts/)**: Operational utility scripts (e.g. `htpasswd.py`).
@@ -99,7 +99,7 @@ Chosen Option: **Option 3: Comprehensive Everything-as-Code with Pragmatic State
- Cluster IP mapping to the bare-metal ingress endpoint. - Cluster IP mapping to the bare-metal ingress endpoint.
* **Execution**: Fully automated via `terraform plan` / `terraform apply` directly from version-controlled state. * **Execution**: Fully automated via `terraform plan` / `terraform apply` directly from version-controlled state.
#### Tier 4: Smart Home & IoT Edge Hardware (`terraform_shelly/`, `esphome/`, `monitoring/`) #### Tier 4: Smart Home & IoT Edge Hardware (`projects/shelly_taupunktluefter/`, `esphome/`, `monitoring/`)
* **Tooling**: ESPHome, Shelly Terraform Provider, YAML configs. * **Tooling**: ESPHome, Shelly Terraform Provider, YAML configs.
* **Scope**: * **Scope**:
- Shelly relays and smart switches provisioned declaratively via Terraform. - Shelly relays and smart switches provisioned declaratively via Terraform.
+1 -1
View File
@@ -678,7 +678,7 @@ kubectl create ns migrate
# backup on moritzgraf.de # backup on moritzgraf.de
ssh moritzgraf.de "sudo su - docker -c 'cd /home/docker/mailu && docker-compose stop' && sudo su - root -c 'cd /home/docker && tar czvf mailu.tar.gz ./mailu && mv mailu.tar.gz /home/moritz/ && chown moritz. /home/moritz/mailu.tar.gz' && scp mailu.tar.gz haumdaucher.de:/home/moritz/" ssh moritzgraf.de "sudo su - docker -c 'cd /home/docker/mailu && docker-compose stop' && sudo su - root -c 'cd /home/docker && tar czvf mailu.tar.gz ./mailu && mv mailu.tar.gz /home/moritz/ && chown moritz. /home/moritz/mailu.tar.gz' && scp mailu.tar.gz haumdaucher.de:/home/moritz/"
# terraform change # terraform change
cd ../terraform/infrastructure && terraform apply cd ../terraform && terraform apply
# helm apply # helm apply
cd ../k8s cd ../k8s
helm upgrade --create-namespace --install mailu mailu/mailu -n mailu -f mailu/mailu.secret.yml helm upgrade --create-namespace --install mailu mailu/mailu -n mailu -f mailu/mailu.secret.yml
+2 -2
View File
@@ -170,10 +170,10 @@ The Authentik login screen is customized with a **Haumdaucher** glassmorphism th
* **Branded Footer**: "HAUMDAUCHER Wurst und Spezialitäten n.e.V." subtle watermark. * **Branded Footer**: "HAUMDAUCHER Wurst und Spezialitäten n.e.V." subtle watermark.
### Managing Theme via Terraform ### Managing Theme via Terraform
Branding is provisioned via the `authentik_brand` resource in `terraform/infrastructure/authentik.tf` using the stylesheet `terraform/infrastructure/haumdaucher-theme.css`: Branding is provisioned via the `authentik_brand` resource in `terraform/authentik.tf` using the stylesheet `terraform/haumdaucher-theme.css`:
```bash ```bash
cd terraform/infrastructure cd terraform
terraform apply -target=authentik_brand.haumdaucher terraform apply -target=authentik_brand.haumdaucher
``` ```
+5 -5
View File
@@ -22,7 +22,7 @@ This guide covers everything you need to know about managing users in Authentik
| Question | Answer & Key Mechanism | | Question | Answer & Key Mechanism |
| :--- | :--- | | :--- | :--- |
| **How to add new users?** | **4 Ways**: (1) Admin Web UI (`Directory > Users`), (2) **Invitations flow** (`Directory > Invitations` - recommended for self-service), (3) **Terraform** (`authentik_user` resource), or (4) **REST API / Python script** for bulk imports. | | **How to add new users?** | **4 Ways**: (1) Admin Web UI (`Directory > Users`), (2) **Invitations flow** (`Directory > Invitations` - recommended for self-service), (3) **Terraform** (`authentik_user` resource), or (4) **REST API / Python script** for bulk imports. |
| **Can this be done in Terraform?** | **Yes.** Use `resource "authentik_user"` in `terraform/infrastructure/authentik.tf`. Supports custom attributes via `jsonencode()`, group assignments, and active status. | | **Can this be done in Terraform?** | **Yes.** Use `resource "authentik_user"` in `terraform/authentik.tf`. Supports custom attributes via `jsonencode()`, group assignments, and active status. |
| **Can I change the email sent to the user?** | **Yes.** Configured in **Flows & Stages > Stages > Email Stage**. You can customize the subject line, token expiration, and HTML template (written in Django template syntax with access to user fields and custom attributes). | | **Can I change the email sent to the user?** | **Yes.** Configured in **Flows & Stages > Stages > Email Stage**. You can customize the subject line, token expiration, and HTML template (written in Django template syntax with access to user fields and custom attributes). |
| **Can I limit what a user has access to?** | **Yes.** Through **Policy Bindings** attached to Applications: Group Membership Policies (e.g., `infra-admins` vs `users`), IP/Geo Policies, or Python Expression Policies checking custom attributes (e.g., only active club members). | | **Can I limit what a user has access to?** | **Yes.** Through **Policy Bindings** attached to Applications: Group Membership Policies (e.g., `infra-admins` vs `users`), IP/Geo Policies, or Python Expression Policies checking custom attributes (e.g., only active club members). |
| **How to handle Excel tables with custom attributes?** | Authentik stores arbitrary key-value pairs in `user.attributes` (JSON). You can import an Excel/CSV file with a Python script or Terraform `csvdecode()`, map fields like `haumdaucher_mitgliedsnummer` or `second_email`, and expose them to downstream apps (Nextcloud, Grafana, Gitea) via OIDC Scope Mappings. | | **How to handle Excel tables with custom attributes?** | Authentik stores arbitrary key-value pairs in `user.attributes` (JSON). You can import an Excel/CSV file with a Python script or Terraform `csvdecode()`, map fields like `haumdaucher_mitgliedsnummer` or `second_email`, and expose them to downstream apps (Nextcloud, Grafana, Gitea) via OIDC Scope Mappings. |
@@ -75,7 +75,7 @@ If you encounter this screen when opening an invite link:
### Solution: The Haumdaucher Custom Invitation Flow (`haumdaucher-invitation-flow`) ### Solution: The Haumdaucher Custom Invitation Flow (`haumdaucher-invitation-flow`)
We provision a dedicated, streamlined flow in `terraform/infrastructure/authentik.tf`: We provision a dedicated, streamlined flow in `terraform/authentik.tf`:
```mermaid ```mermaid
graph LR graph LR
@@ -122,7 +122,7 @@ graph LR
## 🏗️ Method 2: User Provisioning via Terraform ## 🏗️ Method 2: User Provisioning via Terraform
You can manage users, groups, and permissions directly in `terraform/infrastructure/authentik.tf`. You can manage users, groups, and permissions directly in `terraform/authentik.tf`.
### 1. Single User Definition ### 1. Single User Definition
```hcl ```hcl
@@ -161,7 +161,7 @@ max.mustermann,Max Mustermann,max@example.com,max.privat@gmail.com,HM-2024-042,f
anna.schmidt,Anna Schmidt,anna@example.com,anna.work@company.de,HM-2024-043,true anna.schmidt,Anna Schmidt,anna@example.com,anna.work@company.de,HM-2024-043,true
``` ```
In `terraform/infrastructure/authentik.tf`: In `terraform/authentik.tf`:
```hcl ```hcl
locals { locals {
csv_users = csvdecode(file("${path.module}/users.csv")) csv_users = csvdecode(file("${path.module}/users.csv"))
@@ -479,7 +479,7 @@ graph TD
| **haumdaucher.de** | `haumdaucher.de` | ForwardAuth / OIDC | **`Admin`** ✅ | **`Member Access`** ✅ | ❌ *Denied* | | **haumdaucher.de** | `haumdaucher.de` | ForwardAuth / OIDC | **`Admin`** ✅ | **`Member Access`** ✅ | ❌ *Denied* |
### Policy Bindings in Terraform ### Policy Bindings in Terraform
All policy bindings are enforced directly in `terraform/infrastructure/authentik.tf`: All policy bindings are enforced directly in `terraform/authentik.tf`:
```hcl ```hcl
# 1. Admin-Only Tools (Restricted strictly to infra-admins) # 1. Admin-Only Tools (Restricted strictly to infra-admins)
@@ -4,11 +4,11 @@ This directory manages the configuration, code templating, and deployment for th
## Domain Structure & Key Files ## Domain Structure & Key Files
* **[main.tf](file:///Users/moritz/src/infrapuzzle/terraform/shelly/main.tf)**: Coordinates rendering the JavaScript template and executing the Python upload script. * **[main.tf](file:///Users/moritz/src/infrapuzzle/projects/shelly_taupunktluefter/main.tf)**: Coordinates rendering the JavaScript template and executing the Python upload script.
* **[variables.tf](file:///Users/moritz/src/infrapuzzle/terraform/shelly/variables.tf)**: Defines MAC addresses for the Bluetooth sensors, safety parameters, and the mold calculation coefficients. * **[variables.tf](file:///Users/moritz/src/infrapuzzle/projects/shelly_taupunktluefter/variables.tf)**: Defines MAC addresses for the Bluetooth sensors, safety parameters, and the mold calculation coefficients.
* **[scripts/Taupi-4.0.js](file:///Users/moritz/src/infrapuzzle/terraform/shelly/scripts/Taupi-4.0.js)**: The source Shelly control script containing the logic for parsing Bluetooth BTHome events, calculating dew points, evaluating mold danger, and switching the relay. * **[scripts/Taupi-4.0.js](file:///Users/moritz/src/infrapuzzle/projects/shelly_taupunktluefter/scripts/Taupi-4.0.js)**: The source Shelly control script containing the logic for parsing Bluetooth BTHome events, calculating dew points, evaluating mold danger, and switching the relay.
* **[scripts/Taupi-4.0.templated.js](file:///Users/moritz/src/infrapuzzle/terraform/shelly/scripts/Taupi-4.0.templated.js)**: The locally generated script rendering the variables passed from Terraform. Do not edit directly. * **[scripts/Taupi-4.0.templated.js](file:///Users/moritz/src/infrapuzzle/projects/shelly_taupunktluefter/scripts/Taupi-4.0.templated.js)**: The locally generated script rendering the variables passed from Terraform. Do not edit directly.
* **[scripts/upload.py](file:///Users/moritz/src/infrapuzzle/terraform/shelly/scripts/upload.py)**: Helper script executing during `terraform apply` to upload the templated script to the Shelly device over local HTTP RPC commands. * **[scripts/upload.py](file:///Users/moritz/src/infrapuzzle/projects/shelly_taupunktluefter/scripts/upload.py)**: Helper script executing during `terraform apply` to upload the templated script to the Shelly device over local HTTP RPC commands.
## Architecture Decisions & Logic Gates ## Architecture Decisions & Logic Gates
+26
View File
@@ -0,0 +1,26 @@
# Shelly Taupunktlüfter ("Taupi") 💨
Automated psychrometric cellar ventilation controller for mold prevention, running on a Shelly Plug S (Gen 3) paired with outdoor and indoor Shelly BLU H&T Bluetooth low-energy sensors.
## Features
- **Dew Point Ventilation**: Dynamically switches the ventilation fan based on indoor and outdoor psychrometric dew point calculations.
- **Sedlbauer LIM I Mold Alert**: Decoupled mold danger warning curve evaluated against Fraunhofer IBP Lowest Isopleth for Mould specifications.
- **Thermal Governors**: Summer cellar overheating protection (blocks warm moist air ingestion) and winter frost/overcooling protection.
- **Prometheus Metrics Pipeline**: Generates standard Prometheus exposition text scraped by cluster monitoring.
- **Automated Deployment**: Templated JavaScript upload via local Shelly RPC API orchestrated by Terraform.
## Usage
```bash
# Initialize Terraform providers
terraform init
# Plan and preview changes
terraform plan
# Deploy templated Taupi script to the Shelly device
terraform apply
```
For in-depth architectural decisions, state-machine logic gates, and sensor parameters, see [AGENTS.md](AGENTS.md).
+3 -2
View File
@@ -1,2 +1,3 @@
.terraform .terraform/
crash.log
crash.*.log
+31
View File
@@ -0,0 +1,31 @@
# Core Terraform Infrastructure Agent Documentation
This directory manages the core external cloud infrastructure, DNS zones, Authentik SSO, Google Cloud platform integrations, and Google Workspace configurations for Infrapuzzle.
## Key Files & Resources
* **[authentik.tf](file:///Users/moritz/src/infrapuzzle/terraform/authentik.tf)**: Provisions Authentik SSO flows, applications, groups, proxy outposts, OIDC providers, and custom styling with `haumdaucher-theme.css`.
* **[authentik.secret.auto.tfvars](file:///Users/moritz/src/infrapuzzle/terraform/authentik.secret.auto.tfvars)**: Git-crypt encrypted token variables for authenticating with the cluster Authentik API.
* **[haumdaucher-theme.css](file:///Users/moritz/src/infrapuzzle/terraform/haumdaucher-theme.css)**: Custom branded stylesheet injected into Authentik login and flow pages.
* **[ovh.tf](file:///Users/moritz/src/infrapuzzle/terraform/ovh.tf)**: DNS zone and record definitions for `haumdaucher.de`, `moritzgraf.de`, and other domains.
* **[gcp_apis.tf](file:///Users/moritz/src/infrapuzzle/terraform/gcp_apis.tf)**: Enables foundational Google Cloud APIs.
* **[gcp_backups.tf](file:///Users/moritz/src/infrapuzzle/terraform/gcp_backups.tf)**: Provisions GCP service account and credentials for Velero Google Drive cluster backups (`k8s/velero/gdrive_sa.json.secret`).
* **[gcp_calendar.tf](file:///Users/moritz/src/infrapuzzle/terraform/gcp_calendar.tf)**: Provisions GCP service account and credentials for OpenClaw Google Calendar integration (`k8s/openclaw/calendar_sa.json.secret`).
* **[google_workspace.tf](file:///Users/moritz/src/infrapuzzle/terraform/google_workspace.tf)**: DNS records for Google Workspace (MX, SPF, DKIM, TXT verification).
* **[versions.tf](file:///Users/moritz/src/infrapuzzle/terraform/versions.tf)**: Terraform provider versions and requirements.
## Usage & Execution
```bash
# Initialize providers (OVH, Authentik, Google, Local, Random)
terraform init
# Review execution plan
terraform plan
# Apply infrastructure changes
terraform apply
```
> [!IMPORTANT]
> Secrets in this directory (such as `authentik.secret.auto.tfvars`) and generated service account keys are encrypted using `git-crypt`. Ensure the repository is unlocked before planning or applying.
+25
View File
@@ -0,0 +1,25 @@
# Core Infrastructure (Terraform) ☁️
Declarative Infrastructure as Code managing external cloud services, DNS zones, and cluster identity.
## Managed Resources
- **OVH DNS**: Authoritative DNS zones and records (`haumdaucher.de`, `moritzgraf.de`, etc.).
- **Authentik SSO**: Central IdP configuration, applications, proxy outposts, OIDC clients, and custom theme CSS.
- **Google Cloud Platform**: Service accounts for Velero backups and OpenClaw calendar integration.
- **Google Workspace**: Domain verification, MX, SPF, and DKIM DNS records.
## Usage
```bash
# Initialize Terraform
terraform init
# Plan changes
terraform plan
# Apply changes
terraform apply
```
For agent documentation and architecture guidelines, see [AGENTS.md](AGENTS.md).
-2
View File
@@ -1,2 +0,0 @@
.terraform