--- title: 'Veröffentlichen' description: 'Vom lokalen Stack zu Staging und Live: URLs, Skripte, Reload, Token-Trennung.' --- import { Aside, Tabs, TabItem, Steps } from '@astrojs/starlight/components'; Lokal entwickeln, auf Staging prüfen, per Branch auf Live heben. Der Weg: `.env`-URLs verstehen, CI-Skripte laufen lassen, Config neu laden, Köpfe sauber trennen. Suchbegriffe: Deploy, Staging, Live, Produktion, Reload, Freischaltung. ## URL-Bild ```bash title=".env — die drei Bühnen (Platzhalter im Starter ersetzen)" # TODO: echte Domain eintragen LIVE_URL=https://example.com # Produktion (im echten Projekt: echte Domain) STAGING_URL=https://dev-.staging.testversion.online CODING_URL=https://.code.testversion.online ``` | Bühne | Branch | Was liegt dort | |---|---|---| | Coding | dein Arbeits-Branch | Deine Sandbox mit Basic-Auth | | Staging | `dev` | Prüfbühne, per `ci-staging.sh` gebaut | | Live | `master` | Produktion, per `ci-deploy.sh` via rsync | ```text title="Branch zu Bühne: dev wird Staging, master wird Live" push auf dev ──▶ CI: validate, build, build:server ──▶ ci-staging.sh ──▶ STAGING_URL push auf master ─▶ CI: validate, build, build:server ──▶ ci-deploy.sh ──▶ LIVE_URL ``` Lokal startest du mit `docker-compose-local.yml` (`tibi`-Profil: fertiges Image, Projekt als `/data` gemountet). Staging nutzt `docker-compose-staging.yml` (frisch gebauter Stack im CI-Verzeichnis). ## Deploy-Ablauf 1. Checkout, Starter-Defaults auflösen, `yarn install`. 2. `yarn validate` (Svelte-Check plus TypeScript) — rot heißt Stopp. 3. `ci-modify-config.sh` passt die Config für die Zielbühne an. 4. `yarn build` (Frontend) und `yarn build:server` (SSR-Bundle nach `api/hooks/lib/app.server.js`). 5. Sourcemaps zu Sentry hochladen. 6. Branch `dev` → `ci-staging.sh`; Branch `master` → `ci-deploy.sh`. ```bash title="Kurzfassung: kopieren, starten, neu laden" rsync -av api frontend/dist frontend/assets "${API_BASEDIR}/" docker compose -f docker-compose-staging.yml up -d --build curl -X POST "${STAGING_URL}/api/_/admin/reload" \ -H "Authorization: Bearer ${ADMIN_TOKEN}" -d '{}' curl -X POST "${STAGING_URL}/api/ssr?clear=1" \ -H "Content-Type: application/json" -d '{}' ``` ```bash title="Kurzfassung: rsync, Rechte, neu laden" rsync ... frontend/ "${RSYNC_HOST}":./frontend/ # master: ohne src und *.map rsync ... api/ "${RSYNC_HOST}":./api/ rsync ... media "${RSYNC_HOST}":./ curl -X POST "${LIVE_URL}/api/_/admin/reload" -H "Authorization: Bearer ${ADMIN_TOKEN}" -d '{}' curl -X POST "${LIVE_URL}/api/ssr?clear=1" -H "Content-Type: application/json" -d '{}' ``` Zugang per `RSYNC_USER`, `RSYNC_PASS`, `RSYNC_HOST`, `RSYNC_PORT` aus `.env`. Auf `master` fliegen im Frontend-Sync Quellen und Karten raus (`--exclude=src --exclude=*.map`); der `api/`-Sync läuft ohne Excludes. ## CI-Umgebung und Variablen Beide Skripte liegen in `scripts/` und lesen per `allexport` erst `.env`, dann `api/config.yml.env` ein. `ci-deploy.sh` bricht ohne `RSYNC_USER`, `RSYNC_PASS`, `RSYNC_HOST`, `RSYNC_PORT` ab; `ci-staging.sh` verlangt `API_BASEDIR` und `COMPOSE_PROJECT_NAME` (Schrägstriche werden zu Bindestrichen). Erkennt `ci-deploy.sh` die Starter-Vorlage (`PROJECT_NAME=__PROJECT_NAME__`, `_CUSTOMER_ID_` in `PRODUCTION_PATH` oder `LIVE_URL=https://www`), steigt es mit Exit 0 aus — kein Deploy, kein Fehler. | Variable | Woher | Wofür | |---|---|---| | `RSYNC_USER`, `RSYNC_PASS`, `RSYNC_HOST`, `RSYNC_PORT` | CI-Umgebung | SSH-Zugang und Ziel für den Live-rsync | | `BRANCH` | CI-Umgebung | `master` schaltet `--exclude=src --exclude=*.map` (nur Frontend-Sync) | | `ADMIN_TOKEN` | `api/config.yml.env` | `Bearer`-Kopf für den Proxy-Reload | | `LIVE_URL`, `STAGING_URL` | `.env` | Ziele für Reload und SSR-Clear | | `API_BASEDIR`, `COMPOSE_PROJECT_NAME` | CI-Umgebung | Staging-Zielverzeichnis und Compose-Projektname | | `PREVIEW_URL` | wird geschrieben | `ci-modify-config.sh` setzt `LIVE_URL/preview`, `ci-staging.sh` überschreibt mit `STAGING_URL/preview` | | `PROJECT_NAME`, `PRODUCTION_PATH` | `.env` | Nur Template-Schutz (siehe oben) | Was das Skript tut: Live per rsync (`frontend/`, `api/`, `media/`) auf `RSYNC_HOST`, danach Reload plus SSR-Clear; Staging per rsync nach `API_BASEDIR` (`api`, `frontend/dist`, `frontend/assets`), danach `docker compose up -d --build` mit Wartezeit, Reload plus SSR-Clear. Nicht als Deploy-Variablen listen: `ADMIN_ASSET_VERSION` steht zwar in `api/config.yml.env`, wird aber von keinem CI-Skript gelesen. `CODING_URL` und `CODING_TIBIADMIN_URL` sind Test-Basis-URLs (siehe [Tests](/projekt/tests/)), keine Deploy-Ziele. `.basic-auth-code` und `.basic-auth-web` liegen im Repo, sind in `docker-compose-local.yml` aber derzeit auskommentiert; Playwright umgeht Basic-Auth per User-Agent-Marker. ## Reload-Endpunkte Nach jedem Deploy: Config neu laden **und** SSR-Cache wischen — sonst siehst du alte Seiten auf neuer Config. | Endpunkt | Kopf | Wirkung | |---|---|---| | `POST /api/_/admin/reload` (Live/Staging-URL) | `Authorization: Bearer ` | Projekt-Config über den Reverse-Proxy neu laden | | `POST /api/ssr?clear=1` (Starter-URL über Proxy/Webserver, kein tibi-server-Pfad — siehe `scripts/ci-staging.sh` und `scripts/ci-deploy.sh`) | keiner nötig (`public.post: true` in `api/collections/ssr.yml`) | Ganzen SSR-Cache löschen (Hook `hooks/ssr/post_bind.js` reagiert auf `?clear`) | | `POST /api/v1/_/:project/_/admin/reload` | `X-Admin-Token` (Server-Ebene) | Gleicher Reload direkt am Server | | `POST /api/v1/_/:project/_/admin/regenerate-search` | `X-Admin-Token` | Suchindex neu aufbauen ([Suche](/projekt/suche/)) | ## Token-Trennung Vier Köpfe, vier Zwecke — aus [Rechte und Tokens](/projekt/rechte-tokens/): | Kopf | Wert | Wofür hier | |---|---|---| | `Token` | `ADMIN_TOKEN` | Sammlungs-CRUD in Skripten | | `X-Auth-Token` | JWT nach Login | Deine Nutzer-Aktionen beim Testen | | `X-Admin-Token` | Server-Admin-Token | Server-Ebene (Projekte, Reload direkt, Backups) — **nicht** ins Deploy-Skript | | `Authorization: Bearer …` | `ADMIN_TOKEN` | Proxy-Reload auf Live/Staging — das ist der Deploy-Kopf | ## Checkliste und Abnahme 1. Platzhalter in `.env` ersetzt (`PROJECT_NAME`, `PRODUCTION_PATH`, `LIVE_URL`)? 2. `yarn validate`, `yarn build`, `yarn build:server` lokal grün? 3. Auf `dev` gepusht, Staging-URL geprüft (anonym, nicht nur mit Token)? 4. Auf `master` gepusht, Reload plus `?clear=1` in den CI-Logs gesehen? 5. Live-URL anonym geöffnet: Navigation da, Bilder da, kein alter Stand? | Fehlerbild | Ursache | Lösung | |---|---|---| | Deploy steigt mit „starter template detected" aus | Guard greift (Exit 0, kein Deploy, kein Fehler) | `.env` und `PRODUCTION_PATH` vervollständigen | | Neue Config wirkt nicht | Reload vergessen | Reload-Endpunkt pro Bühne aufrufen | | Alte Seite trotz neuer Daten | SSR-Cache alt | `?clear=1`, Köpfe `X-SSR-Cache`/`X-SSR-Cleared` prüfen | | `project not found` | Namespace falsch | [Neues Projekt](/einstieg/neues-projekt/) Schritt 5 | | 401/403 beim Reload | Falscher Kopf (z. B. `Token:` statt `Bearer`) | Tabelle oben: Deploy nimmt `Bearer`, Server-API nimmt `X-Admin-Token` | Verifiziert am e3f92eb 2026-10-17 (tibi-svelte-starter, .env, ci-deploy.sh, ci-staging.sh, deploy.yml)