Files
OPENBUREAU/cms/README.md
T

4.5 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 (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 (ö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/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