# Redaktion Wie die sichtbaren Inhalte der Website gepflegt werden. Der Inhalt liegt in **PocketBase** — einem kleinen Server mit eigenem Admin-Login — und wird dort über die Weboberfläche bearbeitet. Keine Dateien, kein Commit, kein Rebuild: eine Änderung im Admin ist sofort live. > **Stand.** Die Blazor-App liest ihren gesamten Inhalt aus PocketBase (Issue #8); > die alte Datei-Schicht unter `Content/` gibt es nicht mehr. PocketBase ist damit > die einzige Quelle und dieser Abschnitt der einzige Pflegeweg. > **Sprachkonvention.** Feldnamen und Slugs sind **englisch** (`title`, `slug`, > `board`, `posts`). Der Text, den ein Besucher liest, bleibt **deutsch** — also > der Wert eines Feldes (`title: Vorstandsteam`) und der Fließtext. Englische > Schlüssel, deutsche Werte. --- ## Anmelden Das Admin heißt „Redaktion Elternbeirat" und ist unter der PocketBase-Adresse erreichbar: - **Lokal:** (Dev-Stack, siehe `entwicklung.md`). - **Auf dem Server:** über die NPM-Subdomain (Login von außen — noch offen, #9). Redakteure sind **Superuser**: jede vertraute Person aus dem Vorstand bekommt einen eigenen Superuser-Zugang (unter *Collections → System → `_superusers`*). Es gibt bewusst keinen eigenen Login und keinen Editor in der Website selbst — gepflegt wird nur im Admin. --- ## Die Inhaltsarten (Collections) Jede Inhaltsart ist eine **Collection**. Ein neuer Eintrag = ein neuer Record in der passenden Collection (Button *New record*). | Collection | Was | Öffentlich sichtbar über | |---|---|---| | `pages` | Feste Seiten (Vorstand, Impressum, Kontakt …) | Slug, z. B. `/board` | | `posts` | Neuigkeiten / Beiträge | `/posts`, neueste zuerst | | `events` | Termine (Kalender) | `/events` und der `.ics`-Feed | | `faq_topics` | Themen der häufigen Fragen (z. B. „Mensa und Mittagessen") | Als aufklappbare Gruppen auf `/faqs` | | `faqs` | Häufige Fragen | Auf `/faqs`, in der Gruppe ihres Themas | Jede Collection hat als **letztes Feld `public`** (ja/nein). Nur Records mit `public = true` erscheinen auf der Website — so lässt sich ein Entwurf anlegen, ohne dass er schon sichtbar ist. ### Was redaktionell geht — und was Code braucht Redaktion arbeitet mit **Daten**, nicht mit Struktur. Konkret: | Was du willst | Geht redaktionell? | Wie | |---|---|---| | Beitrag / Termin / Frage hinzufügen | **Ja** | Neuer Record in `posts` / `events` / `faqs` — erscheint sofort in der jeweiligen Liste | | Neues FAQ-Thema (neue Gruppe auf `/faqs`) | **Ja** | Neuer Record in `faq_topics` (siehe *Häufige Fragen*) | | Neue Textseite | **Ja** | Neuer Record in `pages` (siehe unten) | | Eine Seite mit einer Liste anteasern | **Ja** | Feld `embed` der Seite (`posts`/`events`) | | **Neue Art von Liste** (eigene Seite mit eigener Sortierung/Gruppierung und eigener Adresse, z. B. „Protokolle") | **Nein** | Braucht Entwicklung: neue Collection **plus** Code | Das heißt: **Bestehende Listen lassen sich beliebig erweitern**, aber eine *neue* Listenart entsteht nicht durch Anlegen einer Collection allein. Die drei Listen (`posts`, `events`, `faqs`) sind fest verdrahtet, weil jede eine eigene Darstellung hat — Datum und Sortierung, Kalender/`.ics`, Themen-Gruppierung. Eine weitere solche Ansicht anzulegen ist ein **Entwickler-Task**: eine neue Collection in PocketBase, eine Lesemethode im `PocketBaseClient` und eine eigene Komponente mit ihrer Route (siehe `docs/entwicklung.md`). Das ist Absicht: Inhalte sind Daten, Struktur und Darstellung sind Code. --- ## Seiten (`pages`) Eine Seite hat `title` (Überschrift für Menschen, Umlaute erlaubt), `slug` (die URL, klein und **ohne Umlaute**: `board`, nicht `über-uns`) und `body` (der Text, als **Markdown**). **Eine neue Seite anlegen** — Record in `pages`, dann ist die Adresse `/` sofort live, ohne Code und ohne Rebuild: 1. `title` setzen (Pflicht). 2. `slug` setzen (Pflicht), englisch und ohne Umlaute — z. B. `slug = schulweg` ergibt `/schulweg`. 3. `body` als Markdown schreiben (optional; darf leer bleiben). 4. **`public` anhaken.** Ohne Haken ist die Seite ein Entwurf und erscheint auf der Website als „nicht gefunden" (404) — das ist der häufigste Stolperstein. 5. Optional `location` (`header`/`footer`) **und** `order` setzen, damit die Seite ins Menü kommt; optional `embed` für eingebettete Blöcke (siehe unten). - **Slug bleibt englisch und ohne Umlaute** — `imprint`, `privacy`, `contact`, `board`, `patrons`; erzwungen per Pattern (siehe *Slug-Regel wird erzwungen* unten). Der `title` darf deutsch mit Umlauten sein (`Förderverein`). - **Reservierte Slugs.** `posts`, `events`, `faqs` und `/` (die Startseite `home`) gehören den festen Listen-/Sonderansichten. Eine `pages`-Seite mit einem dieser Slugs wird von der jeweiligen Ansicht verdeckt und **nicht** angezeigt; in der Produktion dienen solche Records nur als Menü-Platzhalter. - **Menü:** Ob eine Seite ins Menü kommt, steht an der Seite selbst — die Felder `location` (`header` oder `footer`) und `order` (Reihenfolge, ab 1). Die App baut Kopf- und Fußnavigation daraus; nichts wird im Markup angefasst. - **Eingebettete Blöcke:** Das Feld `embed` (Mehrfachauswahl aus `posts`/`events`) hängt unter den Text der Seite dynamische Blöcke. So ist die Startseite (`home`) eine normale Seite mit `embed = [posts, events]`. Leeres `embed` = reine Textseite. Die FAQ-Liste ist kein `embed`: `/faqs` ist eine feste Ansicht (siehe *Häufige Fragen*). ### Die Startseite (`home`) Der `body` der Startseite füllt den farbigen Kopfbereich. Die App zerlegt ihn so: - Die **erste `#`-Überschrift** wird die große Überschrift im Kopfbereich. Fehlt sie, steht dort „Elternbeirat der IGMH". - Besteht der **letzte Absatz nur aus Links** (je Link eine Zeile), werden daraus Knöpfe — der erste hervorgehoben, die übrigen umrandet. Steht in dem Absatz noch anderer Text, bleibt er normaler Text. - Alles andere ist der Einleitungstext daneben. ```markdown # Willkommen beim Elternbeirat der IGMH Hier finden Sie aktuelle Informationen rund um die Elternarbeit. [Kommende Termine](/events) [Kontakt aufnehmen](/contact) ``` Darunter erscheinen automatisch: - **Nächster Termin** — der früheste kommende Termin aus `events`; gibt es keinen, entfällt die Karte. - **Kacheln** — eine pro öffentlicher Seite mit `location = header` (außer der Startseite), in Menü-Reihenfolge. Der Kacheltext ist der **erste Satz** des `body` (ohne Überschrift, ein Doppelpunkt am Ende fällt weg; ein langer Satz wird nach drei Zeilen mit „…“ abgeschnitten); beginnt der Text mit einer Liste oder einem Baustein, zeigt die Kachel nur den Titel. Auf dem Handy zeigen die Kacheln immer nur Symbol und Titel (zwei Spalten), ab Tablet-Breite auch den Text (drei Spalten). Das Symbol hängt am Slug und ist im Code festgelegt; eine neue Seite bekommt ein Standardsymbol. Eigene Felder für Kacheltext und Symbol gibt es (noch) nicht. > **Impressum und Datenschutz** hängen an ihren Slugs (`imprint`, `privacy`). > Diese Slugs nicht ändern — sonst laufen die rechtlich verlinkten Adressen ins > Leere (404). ### Slug-Regel wird erzwungen Ein Slug muss ein sauberes URL-Segment sein: **Kleinbuchstaben, Ziffern und einzelne Bindestriche als Trenner, keine Umlaute** (`ueber-uns`, nicht `Über uns`). Das ist keine Bitte, sondern eine Feldregel: PocketBase weist einen Slug ab, der sie verletzt, und zeigt beim Speichern einen Fehler. Gibst du `Overview` ein, kommst du erst weiter, wenn du `overview` daraus machst. Die Website verlässt sich darauf — sie repariert einen Slug nicht mehr nachträglich. Die Regel steckt als **Pattern** am Feld `slug`. So ist sie gesetzt (einmalig, pro Collection mit einem Slug — `pages` **und** `posts`): 1. Collection öffnen → *Edit collection* (oben rechts) → Feld `slug`. 2. Am Feld auf das **Zahnrad** (Feldoptionen) → **Pattern**. 3. Als Pattern eintragen: `^[a-z0-9]+(-[a-z0-9]+)*$` 4. **Save** (Feld) und **Save** (Collection). Zum Prüfen: `board`, `ueber-uns`, `faq-lunch` werden angenommen; `Overview`, `über-uns`, `my page`, `-x` und `a--b` werden abgewiesen. --- ## Beiträge (`posts`) Ein Beitrag hat `date`, `title`, `body`, `slug` und `public`. Er erscheint unter `/posts` (neueste zuerst) und unter `/posts/`; die neuesten werden auch auf der Startseite als Vorschau angeteasert. - `date` steuert Sortierung und angezeigtes Datum. Anders als bei Terminen zählt hier nur der **Tag** — eine Uhrzeit wird nie angezeigt, und die UTC-Verschiebung aus dem Termine-Hinweis spielt keine Rolle. Trage einfach das Datum ein. - `slug` ist englisch, klein, ohne Umlaute (z. B. `new-sports-hall-opened`) — dieselbe erzwungene Feldregel wie bei Seiten (siehe *Seiten → Slug-Regel wird erzwungen*). - **Vorschautext auf der Karte:** Die Karte zeigt die ersten rund 160 Zeichen des `body` als reinen Text (Überschriften und Formatierung fallen weg, gekürzt am Wortende mit „…“). Ein eigenes Feld dafür gibt es nicht — beginne den Text deshalb am besten mit einem Satz, der sagt, worum es geht. Auf `/posts` erscheint der neueste Beitrag als große Karte über die volle Breite. --- ## Termine (`events`) Ein Termin hat `start` (Pflicht), `end` (optional, für mehrstündige oder mehrtägige), `title`, `location` (optional), `note` (optional) und `public`. Kein Slug. Die Übersicht `/events` trennt automatisch in kommende und vergangene Termine; die Reihenfolge der Records spielt keine Rolle. Vergangene Termine stehen zugeklappt unter „Vergangene Termine anzeigen“. Besucher können `/events.ics` in ihrer Kalender-App abonnieren (Knopf „Kalender abonnieren“) — der Feed entsteht aus denselben Records. Jeder kommende Termin hat außerdem einen Link „In Kalender übernehmen“, der nur diesen einen Termin als Kalenderdatei liefert. So erscheint ein Termin auf seiner Karte: - Links ein **Kalenderblatt** mit Monat, Tag und Wochentag des `start`. - Daneben die **Uhrzeit**: nur der Beginn, mit `end` am selben Tag die Spanne (`19:30–21:00 Uhr`), bei mehrtägigen Terminen „bis …“ mit dem letzten Tag. Ein ganztägiger Termin (Uhrzeit `00:00`) ohne `end` zeigt keine Uhrzeit. - Darunter `location` und `note`. Auf der Startseite wird `note` nach zwei Zeilen abgeschnitten, auf `/events` steht sie ganz. Einen Einleitungstext über der Liste schreibst du in den `body` der Seite mit dem Slug `events` (unter `pages`); die Website fügt keinen eigenen hinzu. > **Trage einfach die Ortszeit ein.** Gib die Uhrzeit ein, die auf der Seite > stehen soll (Europe/Berlin) — z. B. `08:00`. PocketBase speichert intern in UTC > und zeigt dir nach dem Speichern deshalb einen um 1–2 Stunden früheren Wert an > (aus `08:00` wird im Sommer `06:00`). Das ist **kein** Fehler: Die Website > rechnet beim Anzeigen automatisch nach Ortszeit zurück und zeigt wieder `08:00`, > Sommer- und Winterzeit inklusive. Du musst dich um UTC nicht kümmern. --- ## Häufige Fragen (`faq_topics` und `faqs`) Die FAQ-Seite `/faqs` besteht aus zwei Collections: **Themen** (`faq_topics`) und **Fragen** (`faqs`). Jedes Thema erscheint als aufklappbare Gruppe, darin seine Fragen. Eine Frage gehört zu genau einem Thema, das du aus einer Liste **auswählst** — du tippst es nicht als Text ein. ### Themen (`faq_topics`) Ein Thema hat `title`, `slug`, `intro` (optional), `order` und `public`. - `title` ist die Überschrift der Gruppe (z. B. `Mensa und Mittagessen`). - `intro` ist ein kurzer Einleitungstext (Markdown), der beim Aufklappen über den Fragen steht. - `order` legt die Reihenfolge der Gruppen fest (kleinere Zahl zuerst). - `slug` ist englisch, klein, ohne Umlaute (z. B. `lunch`) — dieselbe Regel wie bei Seiten. Er wird derzeit nicht angezeigt, ist aber Pflicht. - **Eine neue Gruppe** = ein neuer Record in `faq_topics`. Danach steht das Thema bei den Fragen zur Auswahl. ### Fragen (`faqs`) Eine Frage hat `question`, `answer` (Markdown), `topic`, `order` und `public`. - `topic`: das Thema aus `faq_topics` auswählen. - `order` legt die Reihenfolge innerhalb des Themas fest (kleinere Zahl zuerst). > **Stolpersteine.** Eine Frage **ohne** `topic` erscheint nirgends auf der > Website. Ist ein Thema nicht `public`, verschwinden auch alle seine Fragen — > egal, ob diese selbst `public` sind. Überschrift und Rahmentext oben auf `/faqs` sind eine eigene Seite in `pages` (Slug `faqs`). --- ## Gestaltungsbausteine Alle Texte (`body` von Seiten und Beiträgen, `intro` und `answer` bei den FAQs) sind **Markdown**. Die Website gestaltet sie automatisch: Zwischenüberschriften (`## …`) bekommen einen grünen Strich, Listen grüne Punkte, Zitate (`> …`) einen farbigen Balken. Darüber hinaus gibt es ein paar **Bausteine**, mit denen du eine Seite selbst gestaltest — ohne Code und ohne HTML. > **Kein HTML.** HTML im Text (`
`, `
`, `