Files
OPENBUREAU/cms
karim 6d20be036a dialog: Position/Rolle + Breadcrumb-Nav + nüchterne Wortmeldungen, Footer voll-breit
- comments: author_role (Position bei OPENBUREAU) aus authors.json gespeichert/ausgeliefert
- schema: comments.author_role hinzugefügt
- dialog.js: Breadcrumb (Dialoge › Forum), volles Datum/Uhrzeit, Box→Trennlinien-Layout
- css: Footer voll-breit (Flex statt Grid), Balken zwischen Header/main/Footer entfernt

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 19:37:50 +02:00
..

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 cms Supabase intern über http://kong:8000 (Service-Key); die Admin-SPA nutzt browser-seitig API_EXTERNAL_URL + ANON_KEY.
  • Abweichung von RAPPORT: realtime + storage weggelassen (nutzt das CMS nicht — Bild-Uploads gehen auf Platte nach static/images/). Nachrüstbar durch Kopieren der Service-Blöcke aus RAPPORT-SERVER.

Quelle der Wahrheit: die .md-Dateien

Dateibasiert. Die echten content/**/*.md sind kanonisch — das CMS liest und schreibt sie direkt (Frontmatter via gray-matter). Damit erscheinen alle bestehenden Inhalte im Editor: Beiträge (library/<rubrik>/…), Seiten (manifest.md, colophon.md) und Rubriken (_index.md).

Supabase wird nur noch für den Login (GoTrue) gebraucht — keine Posts in der DB. Drafts liegen als draft: true in der Datei; der Live-Build lässt sie aus, der Preview-Build (--buildDrafts) zeigt sie.

Rechte & Kollaboration

  • Admin (E-Mails in ADMIN_EMAILS) sieht und bearbeitet alle Einträge.
  • Autor:innen sehen nur Einträge, in denen ihre Mail unter authors: steht. Beim Anlegen wird der Ersteller automatisch eingetragen.
  • Kollaboration: im Editor weitere E-Mails ins Feld „Autor:innen" → beide haben Zugriff auf denselben Beitrag.
  • Bestehende Beiträge/Seiten/Rubriken ohne authors: sind nur für Admins sichtbar; ein Admin kann Autor:innen zuweisen, um sie freizugeben.
  • Hinweis: authors: landet im Frontmatter (öffentliches Repo) — also E-Mails, die du dort einträgst, sind im Repo sichtbar.

Setup

Schnellweg: Proxmox-LXC

proxmox/create-openbureau-lxc.sh auf dem Proxmox-Host ausführen — legt den LXC an, installiert Docker, zieht das (öffentliche) Repo, generiert alle Secrets und startet den Stack. Als Einzeiler:

bash <(curl -fsSL https://git.kgva.ch/karim/OPENBUREAU/raw/branch/main/cms/proxmox/create-openbureau-lxc.sh)

Fragt interaktiv nur Storage/Bridge/IP ab (Enter = Default). Kein Token nötig. GIT_TOKEN nur setzen, wenn das CMS per GIT_PUBLISH nach Gitea zurückschreiben soll.

Manuell (oder im Container)

  1. cp .env.example .env
  2. POSTGRES_PASSWORD + JWT_SECRET setzen: je openssl rand -hex 32
  3. Keys ableiten: node scripts/generate-keys.mjsANON_KEY + SERVICE_ROLE_KEY in .env
  4. SITE_URL + API_EXTERNAL_URL auf die LAN-/Domain-Adresse setzen
  5. docker compose up -d --build (Erststart: DB bootet + Schema/Migrations)
  6. 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/content Alle Einträge listen (Beiträge/Seiten/Rubriken)
GET /api/content/entry?path=… Einen Eintrag lesen (Frontmatter + Body)
PUT /api/content/entry Eintrag anlegen/speichern ({path, frontmatter, body})
POST /api/preview Preview-Build (--buildDrafts), liefert /_preview/…
POST /api/publish Public-Build → live + (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