Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
OPENBUREAU CMS
Headless CMS vor der Hugo-Engine. Hugo bleibt die Render-Engine; dieser Stack
schreibt Content aus Supabase in content/*.md, baut die Site und serviert sie.
Architektur
Ein docker-compose-Stack / ein LXC (Muster gespiegelt von RAPPORT-SERVER):
docker compose
├── db supabase/postgres ← posts-Tabelle (schema.sql)
├── auth gotrue ← Login
├── rest postgrest ← supabase-js liest/schreibt posts
├── kong :8000 ← API-Gateway (/auth/v1, /rest/v1)
└── cms :8080 Node + Hugo-Binary + Admin-SPA
├─ / live (public/)
├─ /_preview Vorschau (preview/, --buildDrafts)
├─ /admin React-Editor
└─ /api Backend (mountet Repo unter /site)
- cms hält das Hugo-Binary (0.161.1 extended, = lokal), mountet das Repo-Root
unter
/site, serviert die Site selbst (kein separater nginx). - Server-seitig spricht
cmsSupabase intern überhttp://kong:8000(Service-Key); die Admin-SPA nutzt browser-seitigAPI_EXTERNAL_URL+ANON_KEY. - Abweichung von RAPPORT:
realtime+storageweggelassen (nutzt das CMS nicht — Bild-Uploads gehen auf Platte nachstatic/images/). Nachrüstbar durch Kopieren der Service-Blöcke aus RAPPORT-SERVER.
Quelle der Wahrheit (DB-backed)
Die posts-Tabelle in Supabase ist kanonisch. content/*.md ist ein
generiertes Artefakt — nicht von Hand editieren, wird beim Publish
überschrieben. Drafts liegen als draft: true in content/ und werden vom
Live-Build automatisch ausgelassen; nur der Preview-Build (--buildDrafts)
zeigt sie.
Setup
Schnellweg: Proxmox-LXC
proxmox/create-openbureau-lxc.sh auf dem Proxmox-Host ausführen — legt den LXC
an, installiert Docker, zieht das Repo, generiert alle Secrets und startet den
Stack. Details im Script-Kopf (Storage, Bridge, GIT_TOKEN für das private Repo).
Manuell (oder im Container)
cp .env.example .envPOSTGRES_PASSWORD+JWT_SECRETsetzen: jeopenssl rand -hex 32- Keys ableiten:
node scripts/generate-keys.mjs→ANON_KEY+SERVICE_ROLE_KEYin.env SITE_URL+API_EXTERNAL_URLauf die LAN-/Domain-Adresse setzendocker compose up -d --build(Erststart: DB bootet + Schema/Migrations)- Login-User anlegen (Self-Signup ist aus):
source .env curl -X POST "$API_EXTERNAL_URL/auth/v1/admin/users" \ -H "apikey: $SERVICE_ROLE_KEY" -H "Authorization: Bearer $SERVICE_ROLE_KEY" \ -H "Content-Type: application/json" \ -d '{"email":"du@example.ch","password":"…","email_confirm":true}'
Dann: Admin …:8080/admin/ · Live …:8080/ · Preview …:8080/_preview/
Lokale Entwicklung am Admin
cd admin && npm install && npm run dev (Vite-Devserver, proxyt /api +
/_preview an den laufenden Container auf :8080).
API
Alle /api/* (ausser /health) verlangen Authorization: Bearer <supabase-token>.
| Methode | Pfad | Zweck |
|---|---|---|
| GET | /api/health |
Healthcheck (offen) |
| GET | /api/posts |
Alle Posts listen |
| GET | /api/posts/:id |
Einen Post |
| POST | /api/posts |
Post anlegen (Draft) |
| PUT | /api/posts/:id |
Post aktualisieren |
| POST | /api/preview/:id |
Draft als draft:true schreiben + Preview-Build |
| POST | /api/publish/:id |
Live schreiben + Public-Build + (opt.) git commit |
| POST | /api/upload |
Bild → static/images/, liefert /images/<name> |
Stand
- api + Hugo-Binary, Ein-Container-Setup
- Publish-Flow (DB → MD →
hugo→ live) - Echte Hugo-Vorschau (
--buildDrafts→/_preview) - React-Admin (
admin/) — Login, Editor, Frontmatter-Formular, iframe-Preview - Supabase-Auth-Middleware auf der API
- Bild-Upload für
cover_image
Noch denkbar
- nginx davor für Caching/TLS (oder über deinen bestehenden Reverse-Proxy)
- Post löschen / Slug-Umbenennung (alte MD-Datei entfernen)
- Mehrbenutzer + Rollen, wenn ein zweiter Autor dazukommt