docs/ via separate Mittwald-Static-Files-App ausliefern
docs/ wird in eine eigenständige Mittwald-Static-Files-App (Short-ID a-t884dh, Pfad /home/p-nxm58l/html/docs) deployed, parallel zur Drupal-App a-q7fxvm. Push auf main triggert eine zweite Azure-DevOps-Stage DeployDocs (rsync --delete über SSH), unabhängig vom Drupal-Build.
Kontext
Mit ADR-0022 wurde der komplette docs/-Strang (Plans, PRDs, ADRs, Brainstorms, Reports, Context-Snapshots, Design-Mapping, Wiki) auf HTML-First umgestellt. Die Dateien sind self-contained, brauchen keinen Build-Step und lassen sich direkt aus einem statischen HTTP-Server ausliefern.
Bisher war die Doku nur über das Repo erreichbar (lokal per file:// oder im Azure-DevOps-Git-Viewer). Stakeholder ausserhalb des Repos (Product Owner, Designer, externe Reviewer) brauchen aber einen direkten URL-Zugriff — vor allem auf docs/wiki/, docs/adr/ und docs/design/MAPPING.html.
Verfügbare Komponenten:
- Mittwald-Projekt
p-nxm58lmit drei installierten Apps:a-q7fxvm(PHP, Drupal-Staging),a-fxrj9r(PHP, Dev),a-t884dh(Static Files, frisch installiert). - Bestehende Azure-DevOps-Pipeline mit Stages
PR_Validation→Build→DeployTest→DeployProd(siehe ADR-0019). SSH-Auth via Secure Filesolcom_azure_mittwald_deploy_keyist eingerichtet und für das gesamte Projekt gültig. - HTML-First-Konvention (ADR-0022): Keine Markdown-Render-Pipeline nötig, jedes Doc-File ist selbst-tragend.
Entscheidung
Eine zweite Top-Level-Stage DeployDocs in azure-pipelines.yml, die bei jedem main-Push den Ordner docs/ per rsync --delete in die Static-Files-App spiegelt.
- Stage-Position: Top-Level,
dependsOn: [], parallel zuBuild/DeployTest. Doc-Auslieferung hängt nicht am Drupal-Build (kein Composer, kein Theme-Build). - Trigger-Condition:
eq(Build.SourceBranch, refs/heads/main)&ne(Build.Reason, PullRequest)— identisch zur DeployTest-Bedingung, keinpaths-Filter. - Transport:
rsync -az --delete --exclude='.DS_Store' --exclude='.gitkeep'über SSH (gleicher Key wie DeployTest, Host-Key-Pinning aufssh.altgemeinde.project.host). - Mapping: Source
docs/(Trailing-Slash, Prefix wird gestripped) → Dest$MITTWALD_APP_ROOT_DOCS/. Resultierende URL:$MITTWALD_DOCS_URL/index.html. - Variable Group: Eigene Gruppe
solcom-mittwald-secrets-docsmitMITTWALD_APP_ROOT_DOCS,MITTWALD_SSH_USER_DOCS(z.B.ssh-dpwyjd@a-t884dh),MITTWALD_DOCS_URL,MITTWALD_API_TOKEN. SSH-Key bleibt das bestehende Secure-File. - Guard: Stage bricht ab, wenn
$MITTWALD_APP_ROOT_DOCSleer oder/ist — Schutz davor, bei fehlender Variable die Server-Root zu nuken. - Verifikation: Mini-Smoke-Test (
curl --fail $MITTWALD_DOCS_URL/index.html | grep -q SOLCOM); wird übersprungen, fallsMITTWALD_DOCS_URLleer ist (noch keine Domain angehängt). - Audit-Marker: Nach dem rsync wird der kurze Commit-SHA in
$MITTWALD_APP_ROOT_DOCS/last-deploy.txtgeschrieben — analog zumlast-release.txtder Drupal-App.
Rejected alternatives
GitHub Pages aus dem Azure-Devops-Mirror rejected
Der Code lebt primär in Azure DevOps, nicht in GitHub. Pages bräuchte einen separaten Sync-Push, Branch-Switch oder GitHub Actions — zusätzlicher Wartungspfad ausserhalb der bestehenden Pipeline. Ausserdem entstünde ein zweiter "wo ist der aktuelle Stand?"-Knoten.
docs/ als Subroute der Drupal-Site (/docs unter test.solcom.de) rejected
Hätte interne und externe Doku unter einer Domain vereint, aber: koppelt Doku-Sichtbarkeit an Drupal-Health (Wartungsfenster, fehlgeschlagene Deploys), erzwingt Webserver-Rewrite-Regeln in Drupal-Stack, und exponiert WIP-Strands (docs/tasks/, docs/brainstorms/) hinter der Marken-Domain. Static-Files-App entkoppelt sauber.
Confluence/SharePoint-Mirror rejected
Hätte stakeholder-vertraute UI gegeben, aber: bricht HTML-First (ADR-0022) durch Konversionsschritt, verliert die self-contained-Eigenschaft der Docs, und macht das Repo nicht mehr zur Source-of-Truth. Plus: kein automatisches Sync ohne separates ETL.
Mittwald-static-files-app im gleichen App-Slot wie Drupal rejected
Theoretisch hätte ein zusätzlicher /docs-Pfad im Drupal-App-Filesystem gereicht. Praktisch hätte das das Drupal-Rollback-Pattern (Releases-Symlink-Switch) gestört: jedes Drupal-Release hätte den docs/-Stand mitziehen oder explizit ausklammern müssen. Saubere Trennung via eigener App ist robuster.
Atomic-Releases-Pattern wie Drupal (releases/<SHA>/ + Symlink-Switch) rejected
Wäre konsistent mit der DeployTest-Stage gewesen, aber: für statisches HTML überdimensioniert. Mittwald-Static-Files-Apps haben einen fixen Doc-Root (kein nutzer-flippbarer Symlink), und das Risiko inkonsistenter Lese-Zustände während rsync ist bei einer Doku-Seite irrelevant. rsync --delete ist deutlich simpler und genauso wiederherstellbar (nächster Deploy korrigiert).
Consequences
- Zweite Deploy-Lane — die Pipeline hat jetzt zwei unabhängige Deploy-Stages (DeployTest für Drupal, DeployDocs für Static-Files). Ein Fehler in einer Lane blockiert die andere nicht.
- Geringer Operationsaufwand — kein Composer-Install, kein Drush, keine Maintenance-Mode, keine Releases-Verwaltung. Stage-Laufzeit erwartet < 1 Minute (Checkout + rsync + Curl).
- Komplette docs/-Sichtbarkeit — auch WIP-Strands wie
docs/tasks/todo.htmlunddocs/brainstorms/sind öffentlich. Bewusst gewählt (Transparenz > Kuration), kann jederzeit über den rsync-Excludes verschärft werden. - SSH-Schreibrechte pro App — der Mittwald-SSH-User (
ssh-dpwyjd) muss in der Static-Files-App schreibberechtigt sein. Mittwald scoped Filesystem-Access über das@a-t884dh-Suffix; Berechtigung wird beim ersten Push validiert. - Variable-Group-Pflege — neue Group
solcom-mittwald-secrets-docsin der Azure-DevOps-Library und Pipeline-Permission-Grant; ohne diese läuft die Stage in einen leerenMITTWALD_APP_ROOT_DOCSund der Guard bricht ab (kein Daten-Verlust, aber failed deploy). - Domain-Setup als Folgeschritt — solange keine Domain an
a-t884dhhängt, läuft der Smoke-Test mit leererMITTWALD_DOCS_URLin den Skip-Branch. Doku ist dann nur über die Mittwald-Default-URL (oder per SSH) erreichbar. - Refactoring-Pfad zurück bleibt offen — sollte sich später z.B. eine Confluence-Pflicht ergeben, lässt sich der Static-Files-Stage entfernen ohne den Doku-Quell-Strand anzufassen.