SpedySpedy Docs

Preview-Konfiguration (BYOC)

Mach jedes Repository preview-fähig mit einer .spedy/preview.yml — deklariere Service und Port, die Spedy nach außen routet, oder verlass dich auf Auto-Detection.

BYOC = Bring Your Own Compose. Die Preview bootet das eigene docker-compose.yml deines Projekts — kein Shopware/Magento-Template. Du sagst Spedy nur, welcher Service die Preview ausliefert.

Damit ein Repository als Live-Preview pro Ticket genutzt werden kann, braucht es zwei Dinge im Repo:

  1. ein eigenes Compose-File (das deinen Stack startet), und
  2. eine .spedy/preview.yml, die den Service + Port deklariert, den Spedy nach außen routet.

Diese Seite beschreibt diese Konfigurationsdatei. Die UI-Seite — Repo verbinden, Datenbank-Snapshots hochladen und die Preview im Ticket nutzen — findest du unter Preview-Umgebungen.

Minimal-Setup

dein-repo/
├── docker-compose.yml          # dein Stack (BYOC)
├── .spedy/
│   └── preview.yml             # welcher Service/Port ist die Preview?
└── …                            # dein App-Code

.spedy/preview.yml:

# Sagt dem Spedy-Supervisor, wie diese Preview exponiert wird.
service: app     # Name des compose-Service, auf den Traefik routet
port: 3000       # Container-Port, der HTTP ausliefert

Das war's. Beim Klick auf „Preview starten" im Ticket:

  1. klont der Runner das Repo (auf dem Feature-Branch des Tickets),
  2. liest .spedy/preview.yml,
  3. bootet dein docker-compose.yml und routet service/port unter <orgSlug>--<ticket>.preview.spedy.test.

Felder in .spedy/preview.yml

FeldPflichtBedeutung
serviceempfohlenName des compose-Service (Schlüssel unter services:), den Traefik anspricht. Ohne Angabe → Auto-Detection (siehe unten).
portempfohlenContainer-interner Port, auf dem dein Service HTTP ausliefert (z. B. 3000, 8080, 80).
domainoptionalZusätzliche Host()-Regel neben <slug>.preview.spedy.test — z. B. eine feste Prod-Preview-Domain.

.spedy/preview.yaml (mit a) wird ebenfalls akzeptiert.

Wichtig: port ist der Port im Container, nicht ein Host-Mapping. Dein Service muss innerhalb des Containers auf diesem Port lauschen. Host-Port-Mappings (ports:) im Compose werden von Spedy entfernt (mehrere Previews parallel würden sonst kollidieren) — du brauchst sie für die Preview nicht.

Ohne .spedy/preview.yml: Auto-Detection

Fehlt die Datei, versucht der Supervisor den primären Service selbst zu finden (pickPrimary):

  1. Label gewinnt: der Service mit labels: { spedy.primary: "true" }.
  2. Sonst: der erste Service (alphabetisch) mit einem ports:- oder expose:-Eintrag.

Port-Auflösung (in dieser Reihenfolge): port aus preview.yml → erster ports:/expose:-Port des Service → Fallback 80.

Findet er gar keinen Service mit Port und du hast nichts deklariert, bricht der Start ab mit:

could not identify a primary HTTP service — declare it in .spedy/preview.yml (service + port), or add a ports:/expose: / spedy.primary label

Empfehlung: Verlass dich nicht auf die Heuristik — deklariere service + port explizit in .spedy/preview.yml. Das ist eindeutig und überlebt Umbenennungen/zusätzliche Services.

Vollständiges Beispiel (Node-App)

docker-compose.yml:

services:
  app:
    build: .
    ports:
      - "3000:3000"      # Host-Mapping nur fürs lokale Dev — Spedy strippt es
    restart: unless-stopped

.spedy/preview.yml:

service: app
port: 3000

Mehrere Services (App + DB)? Deklariere nur den, der HTTP ausliefert:

# docker-compose.yml hat services: web, db, redis
# .spedy/preview.yml:
service: web
port: 8080

db/redis laufen mit, werden aber nicht nach außen geroutet.

Was Spedy mit deinem Compose macht

Der Supervisor rendert beim Boot ein abgeleitetes docker-compose.spedy.yml neben deinem Original (build: . bleibt damit relativ zum Repo). Dabei:

  • strippt er bei allen Services ports: (Host-Mappings) und container_name (Kollision bei parallelen Previews),
  • hängt den primären Service ans externe Docker-Netz spedy-preview,
  • injiziert Traefik-Labels (Routing auf <slug>.preview.spedy.test, loadbalancer.server.port = dein port),
  • mountet den geklonten Workspace nach /opt/spedy-workspace im primären Container (dort arbeitet der Coding-Agent, siehe unten).

Das generierte docker-compose.spedy.yml wird lokal über .git/info/exclude ignoriert — es landet nie in deinem Repo/PR.

Hot-Reload (damit Agent-Änderungen live erscheinen)

Der Coding-Agent editiert den Workspace unter /opt/spedy-workspace. Damit seine Änderungen sofort in der Preview sichtbar werden, sollte dein Preview-Stack im Dev-Modus mit Watch aus dem gemounteten Source laufen, z. B.:

services:
  app:
    build: .
    working_dir: /opt/spedy-workspace
    command: npm run dev        # next dev / node --watch / vite …
    # der Port wird in .spedy/preview.yml gesetzt, nicht hier

Ohne Hot-Reload baut Spedy die Preview nach jedem Agent-Lauf neu (--build), damit die Änderung greift — das funktioniert auch, dauert aber länger.

Optional: Snapshots & Branch-Hooks

.spedy/ kann mehr als preview.yml — DB-Snapshots und Lifecycle-Hooks pro Branch. Das ist unabhängig von BYOC. Die Auflösungsreihenfolge der Snapshots steht unter Preview-Umgebungen → Datenbank pro Ticket überschreiben.

.spedy/
├── preview.yml                 # diese Datei (BYOC service/port)
├── snapshots/
│   ├── default.sql.gz          # DB-Default
│   └── <branch>.sql.gz         # Branch-spezifischer DB-Stand
└── hooks/
    ├── post-clone.sh
    └── post-checkout.sh

Fehlerbehebung

SymptomUrsache / Fix
Start bricht ab: „could not identify a primary HTTP service"Kein Service mit Port + keine .spedy/preview.ymlservice + port deklarieren.
Preview lädt, aber 502/leerDein Service lauscht nicht auf dem in port angegebenen Container-Port. Prüfe, worauf die App im Container bindet (0.0.0.0:<port>, nicht 127.0.0.1).
Falscher Service wird geroutetAuto-Detection hat den falschen erwischt → explizit service setzen oder labels: { spedy.primary: "true" } am richtigen Service.
Agent-Änderung nicht sichtbarKein Hot-Reload im Stack → Abschnitt „Hot-Reload", oder die Preview wird nach dem Lauf neu gebaut (etwas Geduld).
docker-compose.spedy.yml taucht im git status aufSollte über .git/info/exclude ignoriert sein; falls nicht, einmal die Preview neu starten (der Supervisor trägt den Eintrag beim Boot nach).