Redaktionssystem: Inhalte pflegen ohne Entwickler #6

Open
opened 2026-09-22 13:17:12 +02:00 by Tom · 3 comments
Owner

Heute liegen alle Inhalte als Markdown im Repo und werden ins Image gebacken. Ein neuer Beitrag heisst: auschecken, Markdown anlegen, committen, Image bauen, deployen. Das kann ein Entwickler – aber kein normales Elternbeirats-Mitglied.

Anforderungen

  1. Mehrere Redakteure, regelmaessig, ohne Entwickler.
  2. Sofort live – kein Rebuild/Deploy-Schritt.
  3. Login / Zugriffsschutz.
  4. Persistenz ueber Container-Neustart und Deploy hinaus (kritischste Anforderung) – Inhalte liegen ausserhalb des Images.
  5. Backup und Wiederherstellung durch den Betreiber selbst, ohne Entwickler.

Recherche-Ergebnis (Kurzfassung)

Zentraler Konflikt: "sofort live" (3) und "Inhalte ausserhalb des Images" (4) ziehen gegeneinander. Untersucht:

  • A – Eigenbau Mini-CMS in Blazor: ausgeschlossen (selbstgebaute Auth = groesste Angriffsflaeche).
  • B – Git-basiertes UI auf Gitea (Sveltia/Decap): Backup konkurrenzlos (Git-Historie, Restore = git clone), Datenschutz perfekt, keine zweite DB. Haken: "live erst nach Auto-Rebuild", ausser man baut Volume + Webhook.
  • C – Directus + SQLite: echtes komfortables UI, sofort live, Backup = SQLite-Datei kopieren. Haken: zweiter Container mit eigenem Update-Zyklus, source-available Lizenz.

Empfehlung: maximale Einfachheit + bombensicheres Backup -> B; "in Sekunden live" harte Bedingung -> C.

Sub-Issues (Reihenfolge)

Herkunft: tasks/001-redaktion-ohne-entwickler.md

Heute liegen alle Inhalte als Markdown im Repo und werden ins Image gebacken. Ein neuer Beitrag heisst: auschecken, Markdown anlegen, committen, Image bauen, deployen. Das kann ein Entwickler – aber kein normales Elternbeirats-Mitglied. ## Anforderungen 1. Mehrere Redakteure, regelmaessig, ohne Entwickler. 2. Sofort live – kein Rebuild/Deploy-Schritt. 3. Login / Zugriffsschutz. 4. **Persistenz ueber Container-Neustart und Deploy hinaus (kritischste Anforderung)** – Inhalte liegen ausserhalb des Images. 5. Backup und Wiederherstellung durch den Betreiber selbst, ohne Entwickler. ## Recherche-Ergebnis (Kurzfassung) Zentraler Konflikt: "sofort live" (3) und "Inhalte ausserhalb des Images" (4) ziehen gegeneinander. Untersucht: - **A – Eigenbau Mini-CMS in Blazor:** ausgeschlossen (selbstgebaute Auth = groesste Angriffsflaeche). - **B – Git-basiertes UI auf Gitea (Sveltia/Decap):** Backup konkurrenzlos (Git-Historie, Restore = git clone), Datenschutz perfekt, keine zweite DB. Haken: "live erst nach Auto-Rebuild", ausser man baut Volume + Webhook. - **C – Directus + SQLite:** echtes komfortables UI, sofort live, Backup = SQLite-Datei kopieren. Haken: zweiter Container mit eigenem Update-Zyklus, source-available Lizenz. Empfehlung: maximale Einfachheit + bombensicheres Backup -> **B**; "in Sekunden live" harte Bedingung -> **C**. ## Sub-Issues (Reihenfolge) - [ ] #7 - [ ] #8 - [ ] #9 - [ ] #29 - [x] #38 _Herkunft: tasks/001-redaktion-ohne-entwickler.md_
Tom added this to the Elternbeirat-Website milestone 2026-09-22 13:17:12 +02:00
Tom added a new dependency 2026-09-22 13:18:07 +02:00
Tom removed a dependency 2026-09-22 13:20:36 +02:00
Author
Owner

Fortschritt 2026-09-22 — PocketBase steht (Option C, aber schlank):

Entscheidung gefallen: sofort live ist Pflicht -> kein Git-CMS (B), sondern eine schreibbare Datenschicht. Directus verworfen (Overkill). Genommen: PocketBase (eine Binary, SQLite eingebaut, Admin-UI + Login dabei).

  • Container auf Unraid: ghcr.io/muchobien/pocketbase:0.40.4 (fester Tag, nicht latest), Daten im Volume /mnt/user/appdata/pocketbase/pb_data, Host-Port 8090.
  • Superuser angelegt. Dashboard: http://<unraid>:8090/_/.
  • Collection posts (Base): title, slug, body (Editor/HTML), published (bool), date; Unique-Index auf slug.
  • API rules getestet: List/View published = true (oeffentlich lesbar), Create/Update/Delete @request.auth.id != "" (nur eingeloggt). Schreiben ohne Login gibt 403.
  • 2 Beispiel-Beitraege eingespielt (aus Content/posts/*.md, noch mit TODO-Platzhaltern).

Naechster Schritt (Sub-Issue #8): In der Blazor-App einen getippten HttpClient-Service bauen, der posts per REST von PocketBase liest, plus Ausfallverhalten (PocketBase down). Danach: NPM-Subdomain fuer den Admin-Login, Backup-Cron auf /pb_data + Restore einmal echt testen (#9), Doku/AE-2/AE-3 nachziehen.

Offene Risiken: PocketBase ist pre-1.0 ("nicht fuer Produktion empfohlen") -> Updates bewusst machen, Changelog lesen. Backup der einen SQLite-Datei ist daher kritisch.

**Fortschritt 2026-09-22 — PocketBase steht (Option C, aber schlank):** Entscheidung gefallen: **sofort live** ist Pflicht -> kein Git-CMS (B), sondern eine schreibbare Datenschicht. Directus verworfen (Overkill). Genommen: **PocketBase** (eine Binary, SQLite eingebaut, Admin-UI + Login dabei). - Container auf Unraid: `ghcr.io/muchobien/pocketbase:0.40.4` (fester Tag, nicht latest), Daten im Volume `/mnt/user/appdata/pocketbase/pb_data`, Host-Port 8090. - Superuser angelegt. Dashboard: `http://<unraid>:8090/_/`. - Collection `posts` (Base): title, slug, body (Editor/HTML), published (bool), date; Unique-Index auf slug. - API rules getestet: List/View `published = true` (oeffentlich lesbar), Create/Update/Delete `@request.auth.id != ""` (nur eingeloggt). Schreiben ohne Login gibt 403. - 2 Beispiel-Beitraege eingespielt (aus Content/posts/*.md, noch mit TODO-Platzhaltern). **Naechster Schritt (Sub-Issue #8):** In der Blazor-App einen getippten HttpClient-Service bauen, der `posts` per REST von PocketBase liest, plus Ausfallverhalten (PocketBase down). Danach: NPM-Subdomain fuer den Admin-Login, Backup-Cron auf /pb_data + Restore einmal echt testen (#9), Doku/AE-2/AE-3 nachziehen. **Offene Risiken:** PocketBase ist pre-1.0 ("nicht fuer Produktion empfohlen") -> Updates bewusst machen, Changelog lesen. Backup der einen SQLite-Datei ist daher kritisch.
Author
Owner

Update 2026-09-22 — zweite Collection events steht:

  • Collection events (Base): title (Text, req), start (Date, req), end (Date, opt), location (Text, opt), note (Text, opt). Kein slug/published (Termine sind Liste, keine Einzel-URL).
  • API rules: List/View offen (leer = öffentlich), Create/Update/Delete @request.auth.id != "". Getestet: Lesen 200 / Schreiben ohne Login 403.
  • 4 Termine aus events.yml eingespielt (Sitzung, Herbstbasar, Weihnachtsferien, Elternsprechtag).

Datum-Fallstrick (wichtig für den Blazor-Service): PocketBase Date-Feld erwartet/liefert das Format YYYY-MM-DD HH:mm:ss.SSSZ. Kurzformen wie 2026-10-08 19:30 werden als leer/ungültig verworfen (400). Ganztägige Termine haben Uhrzeit 00:00:00 — daran erkennt der Service später „ganztägig".

Beide Inhaltstypen (posts, events) sind damit in PocketBase modelliert, befüllt und abgesichert. Nächstes: Blazor-Leseservice (#8).

**Update 2026-09-22 — zweite Collection `events` steht:** - Collection `events` (Base): `title` (Text, req), `start` (Date, req), `end` (Date, opt), `location` (Text, opt), `note` (Text, opt). Kein slug/published (Termine sind Liste, keine Einzel-URL). - API rules: List/View offen (leer = öffentlich), Create/Update/Delete `@request.auth.id != ""`. Getestet: Lesen 200 / Schreiben ohne Login 403. - 4 Termine aus events.yml eingespielt (Sitzung, Herbstbasar, Weihnachtsferien, Elternsprechtag). **Datum-Fallstrick (wichtig für den Blazor-Service):** PocketBase Date-Feld erwartet/liefert das Format `YYYY-MM-DD HH:mm:ss.SSSZ`. Kurzformen wie `2026-10-08 19:30` werden als leer/ungültig verworfen (400). Ganztägige Termine haben Uhrzeit `00:00:00` — daran erkennt der Service später „ganztägig". Beide Inhaltstypen (posts, events) sind damit in PocketBase modelliert, befüllt und abgesichert. Nächstes: Blazor-Leseservice (#8).
Author
Owner

Update 2026-09-22 — dritte Collection pages, Migration komplett:

  • Collection pages (Base): slug (Text, req, Unique-Index), title (Text, req), body (Editor, req). List/View offen, Create/Update/Delete @request.auth.id != "".
  • Alle 11 Seiten aus Content/pages/*.md migriert (impressum, datenschutz, kontakt, faq, faq-mensa, faq-schliessfach, faq-elterneuro, faq-elternarbeit, foerderverein, vorstandsteam, downloads). Body als Markdown, doppelte H1 entfernt, TODO-Platzhalter + interne Links (/kontakt usw.) erhalten.
  • Getestet: Lesen 200 (11 Seiten), Schreiben ohne Login blockiert.

Damit ist der gesamte Content (posts, events, pages) in PocketBase — alle Markdowns + events.yml migriert.

Neuer Arbeitsmodus: .env hat jetzt PB_URL/PB_ADMIN_EMAIL/PB_ADMIN_PASSWORD (gitignored). Damit Login als Superuser -> Collections anlegen + Records schreiben per API, OHNE die API rules zu öffnen (Superuser bypasst sie). Kein „Create kurz offen" mehr nötig. .env.example entsprechend erweitert.

Nächstes (#8): Blazor-Leseservices (posts/events/pages) statt Content/-Dateien; danach die alten Markdowns/events.yml + die dateibasierten Reader entfernen. Dann NPM-Subdomain für Admin-Login + Backup/Restore (#9).

**Update 2026-09-22 — dritte Collection `pages`, Migration komplett:** - Collection `pages` (Base): `slug` (Text, req, Unique-Index), `title` (Text, req), `body` (Editor, req). List/View offen, Create/Update/Delete `@request.auth.id != ""`. - Alle **11 Seiten** aus Content/pages/*.md migriert (impressum, datenschutz, kontakt, faq, faq-mensa, faq-schliessfach, faq-elterneuro, faq-elternarbeit, foerderverein, vorstandsteam, downloads). Body als Markdown, doppelte H1 entfernt, TODO-Platzhalter + interne Links (/kontakt usw.) erhalten. - Getestet: Lesen 200 (11 Seiten), Schreiben ohne Login blockiert. **Damit ist der gesamte Content (posts, events, pages) in PocketBase — alle Markdowns + events.yml migriert.** **Neuer Arbeitsmodus:** `.env` hat jetzt PB_URL/PB_ADMIN_EMAIL/PB_ADMIN_PASSWORD (gitignored). Damit Login als Superuser -> Collections anlegen + Records schreiben per API, OHNE die API rules zu öffnen (Superuser bypasst sie). Kein „Create kurz offen" mehr nötig. `.env.example` entsprechend erweitert. **Nächstes (#8):** Blazor-Leseservices (posts/events/pages) statt Content/-Dateien; danach die alten Markdowns/events.yml + die dateibasierten Reader entfernen. Dann NPM-Subdomain für Admin-Login + Backup/Restore (#9).
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Tom/Elternbeirat#6