No description
  • JavaScript 95.8%
  • PHP 2.4%
  • Twig 1%
  • CSS 0.7%
Find a file
Owen Kieffer-Jones 138cf2c455 feat: Deployment mit Coolify
- Dockerfile (PHP >= 8.5.12, Apache, APP_ENV=stage) und compose.coolify.yaml mit PostgreSQL 18
- Volumes: var/storage/ (Mediendateien) und Datenbank
- Jeder Start: `sulu:build prod`, Konto „admin“ anlegen, falls es fehlt (Passwort aus SULU_ADMIN_PASSWORD)
- APP_SECRET und Datenbank-Zugang erzeugt Coolify

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 17:48:53 +02:00
assets/admin feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
bin feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
config feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
docker feat: Deployment mit Coolify 2026-10-22 17:48:53 +02:00
migrations feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
public feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
src feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
templates feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
tests feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
translations feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
.dockerignore feat: Deployment mit Coolify 2026-10-22 17:48:53 +02:00
.editorconfig feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
.env feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
.env.dev feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
.env.stage feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
.env.test feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
.gitignore feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
.php-cs-fixer.dist.php feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
.twig-cs-fixer.dist.php feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
compose.coolify.yaml feat: Deployment mit Coolify 2026-10-22 17:48:53 +02:00
compose.yaml feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
composer.json feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
composer.lock feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
Dockerfile feat: Deployment mit Coolify 2026-10-22 17:48:53 +02:00
phpstan.dist.neon feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
phpunit.dist.xml feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
README.md feat: Deployment mit Coolify 2026-10-22 17:48:53 +02:00
rector.php feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00
symfony.lock feat: Sulu-Prototyp der Website 2026-10-22 15:34:38 +02:00

Website Musikwerk Stuttgart (Sulu-Prototyp)

Prototyp für die öffentliche Website des Musikwerk Stuttgart e. V. auf Basis von Sulu 3. Nachbau von musikwerk-stuttgart.de mit Startseite, Events, den Seiten unter „Mitmachen“ und „Verein“ sowie einigen Bildergalerien im Rückblick. Die Inhalte sind Beispieldaten aus der bisherigen WordPress-Seite, kein vollständiger Import.

Nicht Teil dieser Website: Webshop, Mitgliederbereich („Interner Bereich“), Ticketverkauf. Dorthin wird nur verlinkt.

Starten

Voraussetzung: PHP ab 8.2 mit gd, intl, curl, dom und pdo_pgsql, Docker für die Datenbank (PostgreSQL auf Port 5433).

composer install
docker compose up -d
bin/adminconsole sulu:build dev    # Datenbank, Rollen, Benutzer admin/admin
composer seed                      # Beispielinhalte
composer serve

Website: http://127.0.0.1:8002/, Administration: http://127.0.0.1:8002/admin (Benutzer admin, Passwort admin).

Bildgrößen werden beim ersten Aufruf erzeugt. Mit dem eingebauten PHP-Server dauert der erste Seitenaufruf mit vielen Bildern daher einige Sekunden.

sulu:build dev --destroy setzt die Datenbank vollständig zurück.

Deployment (Coolify)

Ressource aus dem Git-Repository, Build Pack „Docker Compose“, Compose-Datei /compose.coolify.yaml. Domain beim Dienst web eintragen. Image: Dockerfile (PHP ≥ 8.5.12, Apache), Umgebung stage.

  • Dienste: web und db (PostgreSQL 18). Volumes: storage (Mediendateien, var/storage/) und database.
  • Coolify erzeugt APP_SECRET, Datenbank-Zugang und das Passwort des Kontos admin (SERVICE_PASSWORD_SULUADMIN, unter Environment Variables).
  • Jeder Start führt sulu:build prod aus (Schema aktualisieren, Grunddaten) und legt admin an, falls es fehlt.
  • Beispielinhalte im Terminal des Containers web: runuser -u www-data -- bin/adminconsole app:seed

Beispielinhalte

composer seed                                  # anlegen/aktualisieren
bin/adminconsole app:seed --refresh            # Texte neu von der alten Seite laden
bin/adminconsole app:seed --alle-bilder        # Galerien vollständig statt 16 Bilder

Der Befehl liest die WordPress-REST-API und die Event-Seiten der alten Website und legt einen Cache unter var/seed-cache/ an. Er ist wiederholbar: Seiten, Events und Personen bekommen eine aus ihrer Adresse abgeleitete UUID und werden beim nächsten Lauf aktualisiert, Medien werden über Sammlung und Dateinamen wiedererkannt und nicht erneut hochgeladen. Texte werden bei jedem Lauf überschrieben.

Angelegt wird über dieselben Nachrichten, die auch die Administration verschickt (CreatePageMessage, ApplyWorkflowTransitionPageMessage …), nicht über Doctrine-Fixtures – die würden die Datenbank samt Benutzer leeren.

Was es in WordPress nicht strukturiert gibt, steht von Hand in src/Command/SeedCommand.php und ist dort markiert: Probenzeiten und -orte, Leitung und Farbe der Chorgruppen, Zuordnung von Events zu Chorgruppen, die Einzeltermine des Familiensingens, die Videos im Rückblick, die Kurzbeschreibungen.

Aufbau

Pfad Inhalt
config/webspaces/musikwerk.xml Webspace: Sprache de, Navigationskontexte Haupt- und Fußmenü
config/templates/pages/ Seitenvorlagen (Inhaltsmodell der Seiten)
config/templates/fragments/ gemeinsame Felder, per XInclude eingebunden (Kopf, Inhalt, Farbe)
config/templates/articles/event.xml Events als Artikel
config/templates/snippets/ Personen und Website-Einstellungen
config/image-formats.xml Bildgrößen für srcset
templates/ Twig: Seitengerüst (base.html.twig), Bausteine (macros.html.twig), je Vorlage eine Datei
src/Twig/MusikwerkExtension.php Events nach Terminen, Unterseiten, Rückwärtsbeziehungen, deutsche Datumsangaben
src/Command/SeedCommand.php, src/Seed/ Import der Beispielinhalte aus WordPress
public/assets/ CSS, JavaScript, Schriften, Logo – alles lokal

Code, installierte Pakete, Inhalte

Was Wo Git
Eigener Code src/, config/, templates/, translations/, migrations/, public/ (ohne die Zeilen unten) ja
Abhängigkeiten vendor/ (Versionen in composer.lock), public/bundles/ (assets:install) nein
Inhalte Datenbank, var/storage/ (Mediendateien) nein, Backup
Erzeugt, entbehrlich var/cache/, var/log/, var/share/, public/uploads/ (Bildgrößen) nein
Geheimnisse .env.local bzw. .env.$APP_ENV.local oder Umgebungsvariablen nein

APP_SECRET steht nur in .env.dev (lokal). Jede andere Umgebung muss ihn selbst setzen, z. B. in .env.stage.local.

Inhaltsmodell

/                                   homepage     Startseite
├── events/                         events
│   └── <event>                     Artikel „event“, ein oder mehrere Termine
├── mitmachen/                      abschnitt
│   ├── chorgruppen/                chorgruppen
│   │   └── <chorgruppe>/           chorgruppe   kinderchor, pop-chor, familiensingen, offener-chor
│   ├── foerdermoeglichkeiten/      seite
│   └── mitgliedsantrag             Verknüpfung → verein/dokumente
├── rueckblick/                     rueckblick   nach Jahren gruppiert
│   ├── fotos                       Verknüpfung → rueckblick
│   ├── videos                      externer Link → YouTube
│   └── <projekt>/                  projekt      Galerie und Videos
├── verein/                         abschnitt
│   ├── kuenstlerische-leitung/     leitung      wählt Personen (Snippets) aus
│   ├── impressum/                  seite        auch im Fußmenü
│   ├── foerdermoeglichkeiten       Verknüpfung → mitmachen/foerdermoeglichkeiten
│   └── dokumente/                  dokumente    PDFs als Blöcke
├── shop                            externer Link (bleibt vorerst in WordPress)
└── datenschutz/                    seite        nur im Fußmenü

Snippets:  person          Name, Rolle, Porträt, Kontakt, Kurzbiografie
           einstellungen   Beschreibung, Social-Media-Links (Snippet-Bereich „einstellungen“)
Mediathek: Sammlungen je Chorgruppe und je Rückblick-Projekt, dazu Seiten,
           Events, Personen, Dokumente

Grundsätze:

  • Listen erzeugt die Vorlage. Die Übersicht der Chorgruppen, die Termine, der Rückblick nach Jahren und die Kacheln der Abschnitte entstehen aus den Unterseiten bzw. Artikeln. Niemand pflegt dieselbe Liste zweimal.
  • Beziehungen statt Fließtext. Events und Projekte wählen Chorgruppen aus, Chorgruppen ihre Leitung (Personen-Snippets). Daraus entstehen auf der Chorgruppenseite „Nächste Termine“ und „Zuletzt dabei“ und auf der Leitungsseite die Zuordnung der Personen. Die Rückwärtsrichtung berechnet MusikwerkExtension.
  • Events sind Artikel mit Terminen, nicht mit einem Datum. Der Block termine erlaubt Reihen (Familiensingen) und abgesagte Einzeltermine. Sortiert und angezeigt wird nach dem nächsten Termin, der stattfindet. Vergangene Events verschwinden von selbst aus der Übersicht; die des letzten Jahres stehen darunter.
  • Galerie = Medienauswahl. Jede Galerie hat ihre eigene Sammlung in der Mediathek; die Reihenfolge der Auswahl ist die der Galerie. Beschreibung wird Bildunterschrift und Alternativtext, das Feld „Copyright“ der Fotonachweis.
  • Fließtext als Blöcke mit bewusst wenigen Typen (Text, Bild, Video). Links auf andere Seiten und Dateien sind Sulu-Links und bleiben beim Verschieben gültig.

Navigation

Haupt- und Fußmenü entstehen aus dem Seitenbaum: Jede Seite gibt unter Einstellungen → Navigationskontexte an, ob sie im Haupt- oder Fußmenü steht. Dass dieselbe Seite unter zwei Punkten erscheint (Fördermöglichkeiten unter Mitmachen und Verein) oder ein Punkt nach außen zeigt (Videos, Shop), erledigen Verknüpfungsseiten (interner bzw. externer Link). Die Farbe eines Hauptpunkts ist das Feld „Farbe“ der Abschnittsseite; externe Links haben keine Felder und bekommen die Akzentfarbe.

Frontend

Gleiches Markup, CSS und JavaScript wie der Kirby-Prototyp.

  • Keine Ressourcen von fremden Servern: Schriften (Montserrat, AntiqueOlive), Logo und Skripte liegen unter public/assets/. YouTube-Videos laden erst nach einem Klick über youtube-nocookie.com. Deshalb kein Cookie-Banner.
  • Eigenes, schlankes CSS statt Bootstrap. Bis 991 px Breite Burger-Menü.
  • Bilder als WebP in mehreren Größen (srcset), Lightbox ohne Bibliothek.

Einschränkungen des Prototyps

  • Suche: Der Suchindex liegt nur im Speicher (SEAL_DSN=memory://), weil das Standard-Backend Loupe pdo_sqlite braucht. Für den Betrieb Meilisearch o. Ä. einrichten.
  • HTTP-Cache: Die eigenen Listen (Events, Unterseiten) melden ihre Inhalte dem Reference Store, sind aber nicht unter Last getestet.
  • Die Administration erscheint für den Benutzer admin auf Englisch; die Feldbezeichnungen gibt es auch auf Deutsch (Benutzersprache umstellen).
  • Neues Event: Die Adresse (page_tree_route) braucht als Elternseite „Events“, die sich nicht vorbelegen lässt. Im Test blieb „Bestätigen“ in der Seitenauswahl ausgegraut; über die API (POST /admin/api/articles) angelegte Events erscheinen korrekt. Vor einer Entscheidung für Sulu klären, ob das ein Fehler in Sulu 3.0 ist.