Align the FAQ docs with the faq_topics collection

This commit is contained in:
tleininger committed 2026-10-01 11:37:04 +02:00
1 parent 5f28237ef0
commit 8fb5044062
4 files changed
+44 -19

No files matched your search

+1 -1
View File
@@ -85,7 +85,7 @@ public record FaqTopic
/// <remarks> /// <remarks>
/// Convenience over <see cref="Expand"/>: questions name their topic, so /// Convenience over <see cref="Expand"/>: questions name their topic, so
/// PocketBase returns them under the back-relation key when the query expands it /// PocketBase returns them under the back-relation key when the query expands it
/// (<c>faqs_via_topic</c>). The topic detail page reads them from here. They /// (<c>faqs_via_topic</c>). The FAQ page reads them from here. They
/// arrive unsorted, so this orders them by <see cref="Faq.Order"/> for a stable /// arrive unsorted, so this orders them by <see cref="Faq.Order"/> for a stable
/// render. Drafts are dropped: PocketBase does not apply the topic query's /// render. Drafts are dropped: PocketBase does not apply the topic query's
/// <c>public</c> filter to the expanded children, so this keeps /// <c>public</c> filter to the expanded children, so this keeps
+2 -2
View File
@@ -28,8 +28,8 @@ architecture. Never global.
## AE-2: Content in PocketBase, read per request (revised) ## AE-2: Content in PocketBase, read per request (revised)
**Decision:** All visible content lives in **PocketBase** (collections `pages`, **Decision:** All visible content lives in **PocketBase** (collections `pages`,
`posts`, `events`, `faqs`); the app reads it over the REST API per request via a `posts`, `events`, `faq_topics`, `faqs`); the app reads it over the REST API per
typed `PocketBaseClient`. Documents remain PDFs under `wwwroot`. request via a typed `PocketBaseClient`. Documents remain PDFs under `wwwroot`.
**Original decision (stage 1):** Content as files in the repo — Markdown with YAML **Original decision (stage 1):** Content as files in the repo — Markdown with YAML
frontmatter, events as `Content/events.yml`. The rationale then was: no DB backup, frontmatter, events as `Content/events.yml`. The rationale then was: no DB backup,
+1 -1
View File
@@ -108,7 +108,7 @@ and the dev overlay mounts that folder into PocketBase (`./pb/pb_migrations:/pb_
| File | Role | | File | Role |
|---|---| |---|---|
| `collections_schema.json` | The four content collections (`pages`, `posts`, `events`, `faqs`) as PocketBase exports them. **The single source of truth for the schema** — the test fixture imports this same file. | | `collections_schema.json` | The five content collections (`pages`, `posts`, `events`, `faq_topics`, `faqs`) as PocketBase exports them. **The single source of truth for the schema** — the test fixture imports this same file. |
| `<timestamp>_dev_seed.js` | The PocketBase migration. Reads the schema file, creates any missing collection, then inserts the example records. | | `<timestamp>_dev_seed.js` | The PocketBase migration. Reads the schema file, creates any missing collection, then inserts the example records. |
Both steps are **idempotent**: a collection is created only if it is missing, and Both steps are **idempotent**: a collection is created only if it is missing, and
+40 -15
View File
@@ -41,7 +41,8 @@ der passenden Collection (Button *New record*).
| `pages` | Feste Seiten (Vorstand, Impressum, Kontakt …) | Slug, z. B. `/board` | | `pages` | Feste Seiten (Vorstand, Impressum, Kontakt …) | Slug, z. B. `/board` |
| `posts` | Neuigkeiten / Beiträge | `/posts`, neueste zuerst | | `posts` | Neuigkeiten / Beiträge | `/posts`, neueste zuerst |
| `events` | Termine (Kalender) | `/events` und der `.ics`-Feed | | `events` | Termine (Kalender) | `/events` und der `.ics`-Feed |
| `faqs` | Häufige Fragen | Werden auf der FAQ-Seite gruppiert angezeigt | | `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 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, `public = true` erscheinen auf der Website — so lässt sich ein Entwurf anlegen,
@@ -54,8 +55,9 @@ Redaktion arbeitet mit **Daten**, nicht mit Struktur. Konkret:
| Was du willst | Geht redaktionell? | Wie | | Was du willst | Geht redaktionell? | Wie |
|---|---|---| |---|---|---|
| Beitrag / Termin / Frage hinzufügen | **Ja** | Neuer Record in `posts` / `events` / `faqs` — erscheint sofort in der jeweiligen Liste | | 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) | | Neue Textseite | **Ja** | Neuer Record in `pages` (siehe unten) |
| Eine Seite mit einer Liste anteasern | **Ja** | Feld `embed` der Seite (`posts`/`events`/`faqs`) | | 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 | | **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* Das heißt: **Bestehende Listen lassen sich beliebig erweitern**, aber eine *neue*
@@ -98,9 +100,10 @@ sofort live, ohne Code und ohne Rebuild:
`location` (`header` oder `footer`) und `order` (Reihenfolge, ab 1). Die App `location` (`header` oder `footer`) und `order` (Reihenfolge, ab 1). Die App
baut Kopf- und Fußnavigation daraus; nichts wird im Markup angefasst. baut Kopf- und Fußnavigation daraus; nichts wird im Markup angefasst.
- **Eingebettete Blöcke:** Das Feld `embed` (Mehrfachauswahl aus - **Eingebettete Blöcke:** Das Feld `embed` (Mehrfachauswahl aus
`faqs`/`posts`/`events`) hängt unter den Text der Seite dynamische Blöcke. So `posts`/`events`) hängt unter den Text der Seite dynamische Blöcke. So ist die
ist die Startseite (`home`) eine normale Seite mit `embed = [posts, events]`, Startseite (`home`) eine normale Seite mit `embed = [posts, events]`. Leeres
und `/faqs` eine Seite mit `embed = [faqs]`. Leeres `embed` = reine Textseite. `embed` = reine Textseite. Die FAQ-Liste ist kein `embed`: `/faqs` ist eine
feste Ansicht (siehe *Häufige Fragen*).
> **Impressum und Datenschutz** hängen an ihren Slugs (`imprint`, `privacy`). > **Impressum und Datenschutz** hängen an ihren Slugs (`imprint`, `privacy`).
> Diese Slugs nicht ändern — sonst laufen die rechtlich verlinkten Adressen ins > Diese Slugs nicht ändern — sonst laufen die rechtlich verlinkten Adressen ins
@@ -162,16 +165,38 @@ ihrer Kalender-App abonnieren — der Feed entsteht aus denselben Records.
--- ---
## Häufige Fragen (`faqs`) ## Häufige Fragen (`faq_topics` und `faqs`)
Eine Frage hat `question`, `answer` (Markdown), `topic` und `public`. Die App Die FAQ-Seite `/faqs` besteht aus zwei Collections: **Themen** (`faq_topics`) und
baut die FAQ-Seite generiert: sie gruppiert die Fragen nach `topic` und zeigt den **Fragen** (`faqs`). Jedes Thema erscheint als aufklappbare Gruppe, darin seine
`topic`-Text unverändert als Gruppen-Überschrift. `topic` ist also **keine feste Fragen. Eine Frage gehört zu genau einem Thema, das du aus einer Liste
Auswahl**, sondern der Überschriftentext selbst (z. B. `Mensa und Mittagessen`) — **auswählst** — du tippst es nicht als Text ein.
eine neue Gruppe entsteht einfach, indem eine Frage einen neuen `topic`-Text
bekommt; Fragen mit gleichem `topic` landen in derselben Gruppe. Auf Groß-/ ### Themen (`faq_topics`)
Kleinschreibung und Leerzeichen achten, sonst entstehen versehentlich zwei
Gruppen. Der Rahmentext oben auf `/faqs` ist eine eigene Seite in `pages` 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`). (Slug `faqs`).
--- ---
@@ -180,7 +205,7 @@ Gruppen. Der Rahmentext oben auf `/faqs` ist eine eigene Seite in `pages`
- **Nach dem Ändern einer Zugriffsregel** immer den Haupt-*Save* der Collection - **Nach dem Ändern einer Zugriffsregel** immer den Haupt-*Save* der Collection
drücken, sonst greift die Änderung nicht. drücken, sonst greift die Änderung nicht.
- Die vier Collections sind öffentlich **lesbar** (List/View offen), aber nur - Die fünf Collections sind öffentlich **lesbar** (List/View offen), aber nur
eingeloggt **schreibbar** — ein Schreibversuch ohne Login wird abgewiesen. Das eingeloggt **schreibbar** — ein Schreibversuch ohne Login wird abgewiesen. Das
ist Absicht; nicht „vereinfachen". ist Absicht; nicht „vereinfachen".
- **Backup:** Der gesamte Inhalt liegt in `pb_data`. Ein Backup dieses - **Backup:** Der gesamte Inhalt liegt in `pb_data`. Ein Backup dieses