Files
Elternbeirat/CLAUDE.md
T

124 lines
6.8 KiB
Markdown

# CLAUDE.md
Website des Elternbeirats der IGMH. Blazor Web App mit statischem
Server-Side-Rendering, .NET 10. Läuft als Container auf Unraid hinter dem Nginx
Proxy Manager. Die Inhalte liegen in **PocketBase** (zweiter Container); die App
liest sie pro Request über einen typisierten `PocketBaseClient`.
Architekturentscheidungen und deren Begründung: `docs/architektur.md`. Dort
nachlesen, bevor eine davon in Frage gestellt wird.
## Wann welches Dokument
| Thema | Datei |
|---|---|
| Warum SSR statt WASM, warum PocketBase als Datenschicht (AE-1 bis AE-4) | `docs/architektur.md` |
| Stack lokal starten, Tests, compose-Overlays | `docs/entwicklung.md` |
| Unraid, compose, NPM-Proxy-Host, Registry, Rollback | `docs/deployment.md` |
| Inhalte anlegen und ändern (PocketBase-Admin) | `docs/redaktion.md` |
| Impressum, Datenschutz, Fotos | `docs/recht.md` |
| Offene Arbeit, Meilensteine, offene Punkte | Gitea-Issues (Milestone „Elternbeirat-Website") |
Offene Aufgaben liegen als **Gitea-Issues**, nicht als Markdown im Repo. So löst
das Anlegen oder Ändern eines Tickets keinen Build aus. Die vier Arbeitsstränge
(Redaktionssystem, Deployment, Inhalte, Infrastruktur) sind Parent-Issues mit
Sub-Issues als Checkliste im Body, alle am Milestone „Elternbeirat-Website".
## Kommandos
```bash
# Lokaler Stack (App + PocketBase) über das Dev-Overlay, siehe docs/entwicklung.md:
docker compose -f compose.yaml -f compose.dev.yaml up --build # App :5000, PocketBase-Admin :8090/_/
dotnet test # Smoke-Tests (starten eigene PocketBase) + Unit-Tests
```
Die App liest ihren Inhalt pro Request aus PocketBase; sie hält selbst keinen
Inhalt und liest nichts beim Start ein. Kein EF Core, keine Migrationen, kein
Seeding im Code. Ein `git clone` ist **nicht** der vollständige Stand — der
Inhalt liegt in PocketBase (`pb_data`), das separat gesichert wird (siehe
`docs/deployment.md`).
## Nicht offensichtlich
- **Inhalte liegen in PocketBase** (`pb_data`-Volume), nicht im Image. Eine
Textänderung ist ein Eintrag im PocketBase-Admin und sofort live — kein Commit,
kein Rebuild (`docs/architektur.md`, AE-2/AE-3). Nur die statischen Assets unter
`wwwroot/` (CSS, Fonts, PDFs) sind ins Image gebacken.
- **Kein `UseHttpsRedirection()`, kein `UseHsts()`.** NPM terminiert TLS; beides
erzeugt hinter dem Proxy eine Redirect-Schleife. `UseForwardedHeaders` mit
geleerten `KnownNetworks`/`KnownProxies` ist korrekt so, weil der Container kein
Port-Mapping hat und nur über NPM erreichbar ist.
- **Das chiseled-Runtime-Image hat keine Shell.** `HEALTHCHECK` mit `curl` oder
`sh` schlägt dort fehl.
- Neue Seite / neuer Beitrag / neuer Termin / neue Frage = **Record in der
passenden PocketBase-Collection** (`pages` / `posts` / `events` / `faqs`), nicht
eine Datei und **kein** `.razor`. `pages` mit `slug` ist sofort unter `/<slug>`
erreichbar; `location`+`order` steuern das Menü, `embed` bettet Listen ein
(`docs/redaktion.md`). Eine **neue Art von Liste** (eigene Route/Logik) ist
dagegen Code: neue Collection + `PocketBaseClient`-Methode + Komponente
(`docs/entwicklung.md`).
- Slugs ohne Umlaute (`ueber-uns`, nicht `über-uns`).
## Regeln
- **Statisches SSR ist der Default.** Kein `@rendermode` ohne konkreten Anlass,
und wenn, dann an genau der einen Komponente — nie global.
- **Keine externen Ressourcen.** Keine CDN-Skripte, keine Google Fonts, keine
Maps- oder Video-Embeds. Schriften werden selbst ausgeliefert. Grund ist
Datenschutz, nicht Geschmack (`docs/recht.md`).
- **Kein EF Core, kein ORM, keine Migrationen.** Inhalte kommen aus PocketBase
über den `PocketBaseClient` (REST), nicht aus einer relationalen DB im Code.
- **Inhalte gehören nach PocketBase**, nicht als Markup in Komponenten und nicht
in Dateien im Repo.
- Kein eigenes CMS, kein Login und keine Benutzerkonten **in der Website** —
gepflegt wird ausschließlich im PocketBase-Admin (Redakteure sind Superuser).
- UI-Texte auf Deutsch, ohne Anglizismen. `Termine`, nicht `Events`.
- Neue NuGet-Abhängigkeiten vorher begründen. Genutzt wird nur `Markdig`
(Markdown → HTML). `YamlDotNet` stammt aus der abgelösten Datei-Schicht, wird
nicht mehr verwendet und soll aus dem `csproj` entfernt werden.
## Stil
- Nullable aktiviert, `ImplicitUsings` an, File-scoped Namespaces.
- Datenzugriff über den typisierten `PocketBaseClient` (registriert via
`AddHttpClient`), der pro Request liest — kein Start-Cache, kein Singleton mit
Inhalten. Komponenten liegen feature-basiert unter `Features/<Bereich>/`.
- **Code durchgängig auf Englisch** — Typen, Member, Variablen, Kommentare,
Skripte und Doku. Das gilt **auch für Domänenbegriffe**: im Code `Event`, nicht
`Termin`; `Post`, nicht `Beitrag`. Deutsch bleibt ausschließlich, was ein
Besucher liest oder ein Redakteur pflegt: UI-Texte sowie die **Werte** der
PocketBase-Records (z. B. `title: Vorstandsteam`, der Markdown-`body`). Die
Feldnamen und Slugs bleiben dagegen englisch (`title`, `slug`, `/board`).
## Coding Convention
- **Ausdruckskörper (`=>`) sind Pflicht, wo syntaktisch möglich** — Methoden,
Properties, Konstruktoren, Operatoren, lokale Funktionen. Ein `if/else`, das
einen Wert liefert, wird zum ternären Ausdruck oder zur `switch`-Expression, kein
Block-Körper mit `return`. Ein Block-Körper nur, wo ein Ausdruck sprachlich nicht
geht (mehrere Anweisungen ohne Rückgabe, `ref`/`out`, `yield`).
- Ternäre und `switch`-Expressions dürfen dafür mehrzeilig umgebrochen werden;
Lesbarkeit entsteht durch Einrückung, nicht durch einen Block.
- Nullable aktiv nutzen: `?`, `??`, `??=` statt Nullprüfungen im Block. Ein
ungültiger `null`-Fall wird als Ausdruck geworfen (`?? throw new …`).
- Argumente/Rückgaben früh und knapp validieren, bevorzugt als Ausdruck.
## Documentation Convention
Vorbild ist `Elternbeirat.PocketBase/LocalDateTimeConverter.cs` — daran
ausrichten.
- **Jeder öffentliche (`public`/`protected`) Typ und Member bekommt XML-Doc** —
nicht nur `PocketBaseClient` und `Contracts`. Interne Helfer, die Teil der
fachlichen Erklärung sind (wie `WallClock`), ebenfalls. Razor-Markup nicht.
- Voller Umfang, wo zutreffend: `<summary>`, dazu `<param>`, `<returns>`,
`<exception>` (jede geworfene Bedingung), `<remarks>` für Kontext/Fallstricke,
`<example>` mit `<code>` für nicht offensichtliche Nutzung, `<seealso>` auf
verwandte Typen. `<inheritdoc/>` bei Interface-/Basis-Implementierungen.
- Code im Text als Markup referenzieren, nicht als Prosa: `<see cref="…"/>`,
`<see langword="null"/>`/`<see langword="false"/>`, `<c>…</c>` für Literale.
- Einrückung: der Textinhalt steht mit vier Leerzeichen unter dem `///`-Tag
(`/// Text`), Tags sauber verschachtelt.
- Englisch, leicht verständlich, erklärt **warum**, nicht was der Code ohnehin
zeigt.