# Update-System

## Wie es funktioniert

Jede Brautpaar-Instanz der App kann über das Backstage-Dashboard auf neue Versionen aktualisiert werden. Die Update-Card im Dashboard prüft beim Öffnen automatisch, ob eine neue Version verfügbar ist. Brautpaar-Daten werden dabei nie angefasst.

---

## Was wird nie überschrieben

```
data/                   ← config.json, design.json, sections.json, guests.json, ...
uploads/                ← alle hochgeladenen Bilder
config/credentials.php  ← SMTP-Zugangsdaten
config/app.php          ← URL-Konstanten
```

Alles andere (`api/`, `assets/`, `backstage/`, `index.php`, `.htaccess`) ist sicher zu überschreiben.

---

## Versionsdatei

`data/version.json` gehört zur Instanz und liegt im geschützten Bereich:

```json
{
    "version": "1.0.0",
    "updated_at": "2026-04-03T14:00:00+02:00",
    "previous_version": null,
    "rollback_available": false,
    "migrations_run": []
}
```

---

## Update-Server einrichten

Statisches Hosting, kein Backend nötig. Struktur auf dem Server (z.B. `updates.27pixel.de/howe/`):

```
latest.json
releases/
  1.1.0/
    manifest.json
    howe-1.1.0.zip
```

**`latest.json`** – Go-Live-Datei, steuert was Instanzen als Update sehen:

```json
{
    "stable": {
        "version": "1.1.0",
        "description": "Kurze Beschreibung der Änderungen",
        "manifest_url": "https://updates.27pixel.de/howe/releases/1.1.0/manifest.json",
        "package_url":  "https://updates.27pixel.de/howe/releases/1.1.0/howe-1.1.0.zip",
        "sha256":       "abc123..."
    }
}
```

> Update-Server-URL anpassen in `api/Updater.php`, Konstante `UPDATE_INDEX_URL`.

---

## Neues Release erstellen

### 1. Migrations-Skript schreiben *(nur wenn neue JSON-Felder eingeführt werden)*

```bash
cp release-tools/migrations/example-1.0.0.php.example \
   release-tools/migrations/1.1.0.php
# Funktion umbenennen auf migrate_1_1_0
```

Regeln für Migrations-Skripte:
- Nur fehlende Schlüssel **hinzufügen** mit sicheren Defaults – nie löschen, nie umbenennen
- `array_key_exists()` statt `isset()` verwenden
- Atomic Write: erst `.tmp`-Datei schreiben, dann `rename()`
- Idempotent – kann mehrfach laufen ohne Schaden

Beispiel:

```php
function migrate_1_1_0(string $dataDir, array &$log): void
{
    $file = $dataDir . '/config.json';
    $data = json_decode(file_get_contents($file), true) ?? [];
    if (!array_key_exists('mein_neues_feld', $data)) {
        $data['mein_neues_feld'] = false;
        $tmp = $file . '.tmp';
        file_put_contents($tmp, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), LOCK_EX);
        rename($tmp, $file);
        $log[] = 'config.json: mein_neues_feld hinzugefügt';
    }
}
```

Funktionsname-Schema: `migrate_` + Version mit `.` → `_`
Beispiel: `1.1.0` → `migrate_1_1_0`

### 2. Release bauen

```bash
cd release-tools/
./build-release.sh 1.1.0 "Kurze Beschreibung"
```

Das Script kopiert alle App-Dateien, generiert `manifest.json` mit Datei-Checksummen, erstellt das Zip und gibt die Upload-Anweisung aus.

Output in `release-tools/dist/releases/1.1.0/`:
- `howe-1.1.0.zip`
- `manifest.json`

### 3. Auf Update-Server hochladen *(FTP/SFTP)*

```
howe-1.1.0.zip  →  updates.27pixel.de/howe/releases/1.1.0/howe-1.1.0.zip
manifest.json   →  updates.27pixel.de/howe/releases/1.1.0/manifest.json
```

### 4. `latest.json` auf dem Server aktualisieren

Das ist der Go-Live-Moment. Alle Instanzen sehen das Update beim nächsten Dashboard-Aufruf.
Die fertige `latest.json` gibt das Build-Script am Ende direkt aus – einfach kopieren.

### 5. Testen

Eine Instanz öffnen → Dashboard → Update-Card → Update installieren → Daten und neue Funktion prüfen.

---

## Update auf alle Instanzen pushen

`release-tools/push-all.sh` konfigurieren (API-Key steht in `data/config.json` der jeweiligen Instanz unter `api_key`):

```bash
INSTANCES=(
    "https://couple1.de|api-key"
    "https://couple2.de|api-key"
)
```

```bash
./push-all.sh
```

Das Script startet das Update auf jeder Instanz per API-Key, ohne dass das Brautpaar etwas tun muss.

---

## Rollback

Nach jedem Update wird automatisch ein Backup des alten App-Codes in `data/backup/` erstellt. Im Dashboard erscheint ein Rollback-Button, der die vorherige Version wiederherstellt. Brautpaar-Daten bleiben dabei immer erhalten.

- Nur ein Schritt zurück möglich
- Max. 2 Backups werden aufbewahrt

---

## Relevante Dateien

| Datei | Beschreibung |
|---|---|
| `api/Updater.php` | Gesamte Update-Logik (Download, Verify, Backup, Extract, Migrate, Rollback) |
| `data/version.json` | Versionsverfolgung der Instanz |
| `data/update.log` | Protokoll aller Update-Vorgänge |
| `release-tools/build-release.sh` | Release bauen (Zip + Manifest + SHA256) |
| `release-tools/build-manifest.php` | Manifest mit Datei-Checksummen generieren |
| `release-tools/push-all.sh` | Update auf alle Instanzen pushen |
| `release-tools/migrations/` | Migrations-Skripte, nach Version benannt |
| `release-tools/latest.json.example` | Vorlage für die Server-Datei |
