Files
Elternbeirat/CLAUDE.md
T

6.8 KiB

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

# 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.