# Domain & Deployment Concept

> Status: ratifiziert am 2026-06-04 per Operator-Direktive. Dies ist **die einzige maschinen- und agentenlesbare Quelle der Wahrheit**, die für **jeden** Agenten eine Frage beantwortet: **"Ich habe einen neuen Service / ein neues Tool / eine neue Seite — WO lege ich das an?"**

Zwei Dinge waren vorher unklar und werden hier festgezurrt:

1. Die alte Server-Regel vermischte die **generische Entscheidungslogik** mit unserer **konkreten Host-Liste**. Beides ist jetzt strikt getrennt: Die Logik ist universell (sie funktioniert für jeden, sogar mit einem einzigen Server); unsere Host-Liste ist nur **Config** — eine Instanziierung der Logik.
2. Eine zweite Achse fehlte: **welche DOMAIN (TLD)** ein Service gehört.

Eine Platzierungs-Entscheidung hat **DREI unabhängige Dimensionen**. Entscheide jede einzeln:

| # | Dimension | Frage | Antwort-Raum |
|---|---|---|---|
| 1 | **Domain (TLD)** | Wer erreicht es? | `.cloud` (öffentlich / Dritte) vs. `.eu` (intern / Doku / Kollektionen) |
| 2 | **Additivität** | Bedient `.eu` das schon? | `.cloud` wird **hinzugefügt**; `.eu` wird im selben Schritt **nie** gelöscht |
| 3 | **Server / Umgebung** | Welche Umgebung betreibt es? | STAGING → LIVE → (Single-Server-Kollaps) + immer BACKUP |

Die Dimensionen sind orthogonal: Ein Service hat eine TLD **und** eine Umgebung. Maschinenlesbarer Spiegel aller drei: `/etc/bbe/policy.yaml` (`domain_placement`, `deployment_targets.decision_order`, `server_map`).

## Dimension 1 — Domain-Platzierung (welche TLD)

**Eine Frage entscheidet:**

> **Greift ein Dritter darauf zu?**
> **JA → `.cloud` (zabazingo.cloud).**
> **NEIN — nur intern / Dokumentation / Marken-Kollektion → `.eu` (zabazingo.eu).**

### `.cloud` = zabazingo.cloud — ÖFFENTLICH / DRITTE

Alles, in das Nutzer, Kunden oder Dritte sich **einloggen oder das sie verwenden**. Produkte und Services, die nach außen exponiert sind.

Beispiele (nicht abschließend): `mail`, `secrets`, `cloud`, `storage`, `vault`, `keychain`, `login`, `app`.
→ `mail.zabazingo.cloud`, `secrets.zabazingo.cloud`, `cloud.zabazingo.cloud`, `storage.zabazingo.cloud`, `vault.zabazingo.cloud`, `keychain.zabazingo.cloud`, `login.zabazingo.cloud`, `app.zabazingo.cloud`.

### `.eu` = zabazingo.eu — INTERN + DOKUMENTATION + MARKE / KOLLEKTIONEN

Nur-interne Tools, die Dokumentationsseite und die Marken- / Kollektions-Seiten. Nicht für Login / Nutzung durch Dritte gedacht.

- **Dokumentation** (gebaut im Stil von `claude.adam---eve.com`, aber in **ZABAZINGO CI**) lebt hier: `docs.zabazingo.eu`.
- **Marke / Kollektionen**: `collection.zabazingo.eu`, `collections.zabazingo.eu`.
- **Interne Tools**: jede Admin- / Ops- / agenten-interne Oberfläche.

Beispiele (nicht abschließend): `docs`, `collection`, `collections`, plus alle internen / Admin- / Ops-Werkzeuge → `.eu`.

### Entscheidungsbaum (Dimension 1)

```
neuer Service
  └─ Loggt sich ein Dritter (Nutzer/Kunde/extern) ein oder nutzt es?
        ├─ JA → .cloud   (mail, secrets, cloud, storage, vault, keychain, login, app …)
        └─ NEIN → ist es Doku / Marken-Kollektion / nur-intern?
                    └─ JA → .eu   (docs, collection(s), interne/Admin-Tools)
```

## Dimension 2 — Additivität (`.cloud` kommt hinzu, `.eu` bleibt)

Einen Service auf `.cloud` zu bringen ist **ADDITIV**, niemals ein Verschieben-mit-Löschen.

- **TU:** Stelle die `.cloud`-Instanz **zusätzlich** auf. Verifiziere sie. Betreibe sie.
- **Die `.eu`-Instanz bleibt vollständig unangetastet und läuft weiter.**
- **NIEMALS** die `.eu`-Instanz löschen, deaktivieren oder umbiegen, um `.cloud` bereitzustellen. Zu keinem Moment verliert das Estate die `.eu`-Oberfläche.
- **`.eu`-Stilllegung ist eine SEPARATE Entscheidung** — explizit, pro Service und **Operator-gated**. Sie wird nie in den `.cloud`-Rollout gebündelt, nie autonom.

> **Invariante:** *`.cloud` hinzufügen darf `.eu` nicht entfernen.* Wenn eine Aufgabe sagt "verschiebe X auf `.cloud`", lies das als "**stelle** X **auch** auf `.cloud` bereit; lass `.eu` laufen".

## Dimension 3 — Server- / Umgebungs-Platzierung (GENERISCH)

Dies ist die **universelle** Logik. Sie verwendet nur abstrakte Rollen — **STAGING, LIVE (Produktion), BACKUP** — und funktioniert für jeden mit 1..N Servern. Sie macht **keine** Annahme, dass zwei getrennte Hosts existieren. (Unsere konkreten Hosts stehen im Config-Abschnitt weiter unten — das ist **nicht** Teil dieser Regel.)

### Generische Entscheidungs-Reihenfolge (von oben nach unten, erster Treffer gewinnt)

```
1. STAGING existiert? (dedizierter Host ODER Staging-Zone)
      → BAUE + VERIFIZIERE dort ZUERST. Immer. Nie überspringen.

2. SEPARATE LIVE/Produktions-Umgebung existiert? (und Staging verifiziert)
      → PROMOTE staging → live. owner/operator-gated.

3. NUR EIN Server (kein separates staging/live)?
      → läuft auf diesem EINEN Server. Staging und Live KOLLABIEREN darauf:
        nutze eine Staging-Subdomain / Pfad / Pre-Prod-Vhost auf demselben Host,
        verifiziere, DANN flippe auf den Prod-Vhost auf demselben Host.

4. BACKUP-Ziel existiert?  [IMMER — nicht erster-Treffer]
      → IMMER off-site restic-Backup einrichten UND Stateful-Daten auf eine
        DEDIZIERTE Daten-Partition/Volume legen, getrennt vom OS-Volume.
```

### Invariante (Dimension 3)

> **Kein Stateful-Service ohne Backup + dedizierte Daten-Partition**, wo immer ein Backup-Ziel existiert. Daten dürfen nie auf genau einer Maschine leben (`no_single_copy`). Stateful-Daten sitzen nie auf dem OS-Root-Volume.

## CONFIG (nicht die Regel) — UNSERE konkrete SERVER-MAP

Diese Tabelle ist **unsere Instanziierung** von Dimension 3. Sie ist **Konfiguration**, nicht die Logik. Ein anderes Estate füllt sie anders; die Regel oben bleibt unverändert. Maschinenlesbarer Spiegel: `/etc/bbe/policy.yaml` → `server_map`.

| Rolle | Host | IP |
|---|---|---|
| **STAGING** | bbe-demo (Hetzner, host_id 4) | 178.105.187.135 |
| **LIVE** (Produktion) | bbe-live (Hetzner, host_id 5) | 91.99.99.252 |
| **BACKUP** | Hetzner Storage Box (restic) | box `u587136` |
| **Nur-intern — KEIN neues öffentliches Web** | 159 / bbe-primary (Netcup) | 159.195.30.60 |
| **Legacy-Quelle / Rollback** | 73er / alt-server (Netcup) | 45.84.199.73 |

Wendet man die generische Logik mit dieser Map an: Neues öffentliches Web wird **zuerst auf bbe-demo (178) gebaut**, **auf bbe-live (91.99.99.252) promotet** unter einem Operator-Gate, **auf die Storage Box gesichert**, während **159 kein neues öffentliches Web trägt** und **der 73er nur Rollback/Legacy ist** (migrieren-weg, nie neues Main).

## Zusammengesetzt — vollständige Platzierung in 3 Fragen

Für jeden neuen Service, der Reihe nach beantworten:

1. **TLD:** Zugriff durch Dritte? → `.cloud`. intern/Doku/Kollektion? → `.eu`.
2. **Additiv:** Wenn `.eu` das schon bedient, `.cloud` **hinzufügen**, `.eu` oben lassen. (`.eu`-Stilllegung = später, separat, Operator-gated.)
3. **Umgebung:** STAGING zuerst → promote zu LIVE (gated) → (oder Kollaps auf den einzelnen Server) → **immer** Backup + Daten-Partition. Unsere Map: STAGING=bbe-demo/178, LIVE=bbe-live/91.99.99.252, BACKUP=Storage Box.

## Querverweise

- Staging→Live-Promotion-Flow + Hostname-Konventionen: `staging-policy.md`
- Maschinenlesbare Policy: `/etc/bbe/policy.yaml`
- Server-Inventar + Zugang: `inventory.md` und Kapitel **Server- & Infra-Übersicht**
- No-data-loss-Migrationsschritte: `migration-protocol.md`
- Backup-Einrichtung: `backup.md`
- DNS (Infomaniak, beide TLDs): `infomaniak.md`
