Files
OPENBUREAU/cms/README.md
T
karim bd4b470877 cms: Rollen + Kollaboration (Admin sieht alles, Autoren nur eigene/geteilte)
- ADMIN_EMAILS (.env) = Admins, sehen/bearbeiten alles
- Autor:innen sehen nur Einträge mit ihrer Mail unter `authors:`; Ersteller wird
  beim Anlegen automatisch Autor
- Kollaboration: Feld „Autor:innen" im Editor → mehrere Mails = gemeinsamer Zugriff
- API erzwingt Zugriff bei list/read/save (403 ohne Recht)
- ADMIN_EMAILS in compose + LXC-Script (fragt Admin-Mail ab)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 12:22:06 +02:00

5.4 KiB

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