From: Kai Moritz Date: Sun, 14 Jun 2026 12:21:47 +0000 (+0000) Subject: CLAUDE.md: Komplett überarbeitet — IST-Zustand des Astro-Projekts dokumentiert X-Git-Url: https://juplo.de/gitweb/?a=commitdiff_plain;h=80c0ca316b72d12c2530d381582a16a8f5617f69;p=website CLAUDE.md: Komplett überarbeitet — IST-Zustand des Astro-Projekts dokumentiert Alle Hugo-spezifischen Inhalte entfernt. Alle Abschnitte beschreiben jetzt den aktuellen Stand des Astro-Projekts ohne historischen Kontext. Neu oder wesentlich erweitert: - Projektstruktur als Astro-Verzeichnisbaum - HTML-Seitenstruktur via BaseLayout.astro-Slots - Sitemap-Menü: vollständige Erklärung von Zweck, CSS-Klassen-Logik und Implementierung als explizite State-Machine in BlogNav.astro - Blog-Sonderregeln: Canonical-URL-Logik, Archiv-Sichtbarkeit, Taxonomy-Verhalten - About-Seitenstruktur inkl. isNode-Logik - Projects-Sonderregeln: sichtbar/nicht-sichtbar, SNAPSHOT-Nav-Substitution, generierte Inhalte ohne Layout in public/projects/ Co-Authored-By: Claude Sonnet 4.6 --- diff --git a/CLAUDE.md b/CLAUDE.md index 04149550..eb5fe92d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,10 +1,9 @@ # CLAUDE.md -Diese Datei enthält Anweisungen für Claude Code (claude.ai/code) beim Arbeiten mit diesem Verzeichnis. +Diese Datei enthält Anweisungen für Claude Code (claude.ai/code) beim Arbeiten mit diesem Repository. ## Arbeitsregeln -- Wenn du nicht explizit anders angewiesen wirst, arbeitest du nur innerhalb dieses Repositories und des Theme-Submodules. - Du arbeitest immer auf dem bereits ausgecheckten Branch `content--via-astro`. - Ab und zu bin ich ungenau oder bringe Details durcheinander. Wenn du den Eindruck hast, dass etwas nicht passt oder Details fehlen, frage immer direkt nach. - Für alle Aufgaben gilt: du kannst und sollst Nachfragen stellen, bevor du mit der Umsetzung beginnst, wenn das sinnvoll ist. @@ -13,269 +12,142 @@ Diese Datei enthält Anweisungen für Claude Code (claude.ai/code) beim Arbeiten - Erstelle nach dem Abschluss einer Aufgabe jeweils einen Commit — direkt, ohne vorher nachzufragen. - Fasse in der Commit-Nachricht zusammen, was und warum geändert wurde. -- Wenn du zugehörige Änderungen im Theme-Repository gemacht hast, erstelle auch dort einen separaten Commit mit einer ebenfalls sinnvollen Beschreibung. -- Wenn du meinst, dass ein Theme-Commit besonders wichtig oder unabhängig verständlich ist, weise mich darauf hin. - -### Submodule-Pointer-Updates - -Der Zeiger auf den Theme-Commit (`themes/hugo-juplo`) darf **nicht automatisch** mit in Commits des Haupt-Repos einfließen. Er soll nur aktualisiert werden, wenn eine inhaltlich zusammengehörige Änderung im Haupt-Repo dies erfordert — und selbst dann nur nach Rückfrage. Begründung: Ein Submodule-Pointer-Update koppelt implizit einen bestimmten Theme-Stand an den Content und sollte eine bewusste, begründete Entscheidung sein, kein Nebenprodukt. ## Projektstruktur -Das Projekt besteht aus zwei Git-Repositories: +Das Projekt ist eine statisch generierte Website, gebaut mit **Astro 6.4.4**. Wichtigste Verzeichnisse: ``` -content--via-hugo (dieses Repo) -├── content/ ← Blog-Artikel, Projects-Doku -│ ├── _index.md ← Startseite -│ ├── blog/ ← Blog-Artikel, nach Jahr organisiert unter archive/ -│ └── projects/ ← Maven-Plugin-Dokumentation (generiert, versioniert) -├── hugo.yaml ← Hugo-Konfiguration -├── data/ ← YAML-Datendateien (comments, library) -├── static/ ← Statische Assets (Maven-Site-Outputs etc.) -└── themes/hugo-juplo/ ← Git-Submodule (Branch: frontend) - ├── layouts/ ← Hugo-Templates - ├── assets/scss/ ← SCSS-Quellen (5 Breakpoints + Print) - ├── content/ ← Struktureller Site-Content (About, Impressum, Taxonomien) - └── exampleSite/ ← Standalone-Testsite für Theme-Entwicklung (hugo.dev/hugo-themes best practice) +src/ + pages/ ← Dateibasiertes Routing (alle Seiten und API-Routen) + content/ + blog/ ← Blog-Artikel als Markdown (Content Collection, glob-Loader) + projects/ ← Projektdokumentation als HTML + YAML-Frontmatter (Custom Loader) + components/ ← Wiederverwendbare Astro-Komponenten (BlogNav.astro, ProjectPage.astro, …) + lib/ ← Shared TypeScript-Helpers (posts.ts, projects.ts) + styles/ ← SCSS-Quellen +public/ + css/ ← Compiliertes CSS (aus SCSS, im Git eingecheckt) + img/ ← Bilder und statische Assets + projects/ ← Generierter Maven-Site-Output (apidocs, xref etc.) — ohne Astro-Layout +data/ ← YAML-Datendateien (Kommentare, Bibliothek) ``` -Das Theme ist als Git-Submodule unter `themes/hugo-juplo` eingebunden (Branch `frontend` im selben Git-Server-Repo unter einem anderen Branch). Änderungen am Theme werden im Submodule-Verzeichnis committet, Änderungen am Content im Hauptrepo – immer getrennt. - -Zur CLAUDE.md im Theme-Submodule: `themes/hugo-juplo/CLAUDE.md` - -## Template-Struktur +## HTML-Seitenstruktur -`baseof.html` definiert das HTML-Gerüst aller Seiten: +`BaseLayout.astro` definiert das HTML-Gerüst aller Seiten über benannte Slots: ``` body └── #page ├── header#header Logo + Slogan - ├── #breadcrumb (block: breadcrumb – überschreibbar) + ├── #breadcrumb (slot: breadcrumb) └── main.content - ├── article#content (block: article → block: title + block: content) + ├── article#content (slot: article) └── .marginal - ├── nav#nav (block: menu – Menü/Sitemap) - └── asides (block: marginalcontent – Taxonomien, Custom-Content) + ├── nav#nav (slot: menu — Sitemap-Menü, s.u.) + └── asides (slot: marginalcontent — Taxonomien, Custom-Content) └── footer#footer Copyright + Footer-Links ``` -Spezialisierte Layouts nach Seitentyp (alle als `{{ define "block" }}` Overrides): - -| Layout | Verwendung | Besonderheit | -|---|---|---| -| `index.html` | Startseite | überschreibt `article` | -| `section.html` | Generic-Section | überschreibt `content` | -| `article.html` | Generic-Artikel | überschreibt `article` | -| `page.html` | Standalone-Seite | überschreibt `content` + `marginalcontent` (zeigt Taxonomie-Terms) | -| `blog/section.html` | `/blog/` | überschreibt `menu` + `article` | -| `blog/archive/section.html` | `/blog/archive/` | überschreibt `menu` + `content` + `title` | -| `blog/archive/year.html` | `/blog/archive/YYYY/` | überschreibt `menu` + `content` + `title` | -| `blog/archive/page.html` | Blog-Artikel | überschreibt `menu` + `content` | -| `categories/taxonomy.html` | `/categories/` | überschreibt `breadcrumb` + `menu` + `content` | -| `categories/term.html` | `/categories/X/` | überschreibt `breadcrumb` + `menu` + `content` | -| `tags/taxonomy.html` | `/tags/` | überschreibt `breadcrumb` + `menu` + `content` | -| `tags/term.html` | `/tags/X/` | überschreibt `breadcrumb` + `menu` + `content` | - -## Menü-Konzept (SEO-Sitemap) - -Das Menü unter `nav#nav` ist bewusst am **Ende des HTML** platziert (im `.marginal`-Bereich) und dient gleichzeitig als SEO-Sitemap. Es hat zwei Ebenen: - -**Ebene 1 – Section-Menu (`#menu`):** Horizontale Hauptnavigation aus `MainSections` (Blog, Projects, About). - -**Ebene 2 – Sub-Menu (`#submenu`):** Baumstruktur der gesamten Site ab Home. Zeigt immer den vollständigen Baum, wobei: -- Items mit Kindern erhalten Klasse `sub` -- Items außerhalb des aktuellen Pfads erhalten Klasse `off` -- Der aktive Link und seine Vorfahren erhalten `class="selected"` am ``-Element - -Das rekursive Partial `menu/tree.html` handhabt die Projects-Sektion mit spezieller Sichtbarkeitslogik: Von Projektversionen werden im Menü nur Seiten angezeigt, die sich im aktuellen URL-Pfad befinden oder im Frontmatter `current: true` gesetzt haben. - -Für den Blog-Ast (Archive, Categories, Tags) gibt es separate Template-Logik in den jeweiligen Layout-Dateien, da Taxonomy-Seiten nicht im normalen Hugo-Seitenbaum liegen. - -## Content-Architektur (Zielzustand) - -- **Theme** (`themes/hugo-juplo`): ausschließlich Layouts, SCSS, Partials, Archetypes, `exampleSite` -- **Dieses Repo**: ausschließlich Content (alle `.md`/`.html` Seiten inkl. About, Impressum) - -Der `exampleSite`-Ansatz im Theme dient zum isolierten Testen des Themes unabhängig vom Content-Branch. - -## Stand der Umsetzung - -Das Theme ist funktional (Menü, Breadcrumb, Taxonomien, Blog-Archiv, Syntax-Highlighting, responsive Layout). Die Template-Implementierung enthält noch Copy-paste-Duplikate, die schrittweise konsolidiert werden sollen. Größte offene Aufgabe: Den `menu`-Block aus den 7+ Einzel-Templates in ein parametrisiertes Partial konsolidieren. - -Bekannte Baustellen und ihre Priorität sind in der Analyse vom 2026-06-03 dokumentiert. +Seiten befüllen die Slots mit ``. Den `menu`-Slot übernimmt immer `BlogNav.astro`. --- -## Astro-Implementierung: Design- und Architektur-Entscheidungen - -Dieser Abschnitt dokumentiert die technischen Entscheidungen des Astro-Branches (`content--via-astro`). Er unterscheidet zwischen Entscheidungen, die Astro-Standard folgen, und solchen, bei denen bewusste Abweichungen getroffen wurden. - -### Standard-Entscheidungen (Astro Best Practices) - -**Statische Site-Generierung (SSG)** -Astro erzeugt beim Build statische HTML-Dateien. Der `output`-Mode ist nicht explizit konfiguriert, da `'static'` Astros Default ist. -Quelle: https://docs.astro.build/en/basics/rendering-modes/ - -**Content Collections mit glob-Loader** -Blog-Artikel in `src/content/blog/` werden über Astros Content Collections API eingebunden. Die Konfiguration in `src/content.config.ts` nutzt den `glob()`-Loader, der alle `.md`-Dateien im Verzeichnis einliest und Schema-Validierung (Zod) für Frontmatter-Felder ermöglicht. -Quelle: https://docs.astro.build/en/guides/content-collections/ - -**Dateibasiertes Routing** -Jede Datei in `src/pages/` ergibt eine Route. Dynamische Routen (`[year].astro`, `[term].astro`) implementieren `getStaticPaths()`, um alle Pfade zur Build-Zeit zu erzeugen. -Quelle: https://docs.astro.build/en/guides/routing/ +## Sitemap-Menü -**Named Slots in Layouts** -`BaseLayout.astro` definiert benannte Slots (`breadcrumb`, `article`, `menu`, `marginalcontent`, `footerlinks`), die von Seiten mit `` befüllt werden. Dies spiegelt direkt Hugo's `{{ define "block" }}`-Pattern. -Quelle: https://docs.astro.build/en/basics/layouts/ +Das Menü unter `nav#nav` ist bewusst am **Ende des HTML** platziert und dient primär als **SEO-Sitemap**: Es enthält den vollständigen Seitenbaum als verlinkten Baum, damit Suchmaschinen-Robots alle Seiten entdecken und crawlen können. Im Browser dient es gleichzeitig als sekundäre Navigation. -**TypeScript im Frontmatter** -Alle `.astro`-Dateien nutzen TypeScript im `---`-Frontmatter. Astro kompiliert das automatisch, ohne separate Build-Konfiguration. -Quelle: https://docs.astro.build/en/guides/typescript/ +### Aufbau -**`public/` als Verzeichnis für statische Assets** -Statische Dateien (CSS, JS, Bilder, Fonts) liegen in `public/` und werden 1:1 ins Build-Verzeichnis kopiert. Hugo nannte dieses Verzeichnis `static/` — in Astro ist `public/` der Standard. Die Dateien wurden bei der Migration entsprechend verschoben. -Quelle: https://docs.astro.build/en/basics/project-structure/#public +**Ebene 1 — Section-Menu (`#menu`):** Horizontale Hauptnavigation mit drei Hauptbereichen: Blog, Projects, About. -**RSS-Feeds via `@astrojs/rss`** -RSS-Feeds werden mit dem offiziellen Astro-Integration-Paket `@astrojs/rss` erzeugt. Jede Feed-Datei ist eine TypeScript-API-Route (`.ts`-Endung statt `.astro`), die eine `GET`-Funktion exportiert. -Quelle: https://docs.astro.build/en/guides/rss/ +**Ebene 2 — Sub-Menu (`#submenu`):** Der vollständige Seitenbaum als verschachtelte Listenstruktur. Alle Items sind **immer im HTML enthalten** — CSS blendet nicht relevante Äste aus: ---- - -### Eigene Entscheidungen (nicht Astro-vorgegeben) +- Items mit Kindern erhalten Klasse `sub` +- Items außerhalb des relevanten Pfads erhalten Klasse `off` → `display: none` (Classic-Layout: `#submenu li.s.off { display: none }`) +- Der aktive Link und seine Vorfahren erhalten `class="selected"` am ``-Element +- Aktive `
    `-Ebenen erhalten Klasse `active` -#### CSS: Separater SCSS-Build statt Astro-Integration +Ein `ul.s` ohne `active` blendet sich **nicht selbst** aus — nur `li.s.off` ist hidden. -**Was:** SCSS wird über einen separaten `sass`-CLI-Aufruf kompiliert (`npm run build:css`), nicht über Astros eingebaute SCSS/Vite-Integration. Das kompilierte CSS landet in `public/css/` und ist im Git eingecheckt. +### Implementierung: `BlogNav.astro` -**Warum:** Das SCSS stammt ursprünglich aus dem Hugo-Theme-Repository (`themes/hugo-juplo`), das mit der Astro-Migration entfernt wurde. Die SCSS-Quellen liegen jetzt in `src/styles/` und sind authoritative Kopie im Website-Repo. Eine Integration in Astros Asset-Pipeline (Vite/PostCSS) war möglich, wurde aber nicht gewählt, um das bewährte SCSS-Build-Setup unverändert zu übernehmen. Der separate Build-Schritt (`sass src/styles/screen.scss public/css/screen.css` etc.) ist einfacher als eine Vite-Plugin-Konfiguration. Der `prebuild`/`predev`-Hook in `package.json` stellt sicher, dass CSS immer aktuell ist. +`BlogNav.astro` empfängt `currentUrl` als Parameter und berechnet daraus vollständig in TypeScript alle Navigationszustände (`onBlog`, `onArchive`, `onCategoriesIndex`, `onProjectsSection` etc.). Alle CSS-Klassen werden direkt aus diesen Variablen abgeleitet. Nie werden Items per `{condition &&
  • }` weggelassen — nur die `off`-Klasse steuert die Sichtbarkeit via CSS. -**Konsequenz:** SCSS-Änderungen erfordern `npm run build:css` oder einen Dev-Server-Neustart. HMR funktioniert für SCSS nicht automatisch. +### Section-`off`-Logik ---- +Welche der drei Hauptsections sichtbar ist, hängt vom aktiven Bereich ab: -#### Taxonomy-URL-Struktur: Split zwischen Index und Term +- `blogSectionOff = onAboutSection || onProjectsSection` +- `projectsSectionOff = blogSelected || onAboutSection` +- `aboutOff = blogSelected || onProjectsSection` +- Auf der Homepage und Root-Standalone-Seiten (keiner Section zugehörig) sind alle drei Sections sichtbar -**Was:** Die Taxonomie-Seiten sind auf zwei URL-Ebenen verteilt: -- Index-Seiten: `/blog/categories/` und `/blog/tags/` (unter dem Blog-Pfad) -- Term-Seiten: `/categories/TERM/` und `/tags/TERM/` (direkt unter Root) +### Item-`off`-Logik innerhalb einer Section -**Warum:** Diese Struktur ist identisch mit dem Hugo-Output. Hugo legt Taxonomie-Listenseiten (`/blog/categories/`) unter dem konfigurierten `taxonomyTerms`-Pfad ab, während Term-Seiten (`/categories/kafka/`) direkt unter dem Taxonomie-Namen generiert werden. Die Beibehaltung dieser Struktur ist notwendig für URL-Kompatibilität mit bestehenden Links und SEO. +Innerhalb einer Section gilt: +``` +off = !(isCurrent || isAncestor || isSibling || isChild) +``` +Dabei ist `isSibling` nur aktiv, wenn die aktuelle Seite kein Section-Index-Node ist (`!isNode`). Section-Index-Seiten unterdrücken also die Geschwister-Sichtbarkeit und zeigen nur ihre eigenen Kinder. --- -#### BlogNav: Explizite State-Machine statt Template-Rekursion - -**Was:** `BlogNav.astro` berechnet den Navigationszustand vollständig in TypeScript-Variablen (`onBlog`, `onArchive`, `onCategoriesIndex`, `onCategoryTerm`, etc.) und rendert das HTML anhand dieser Flags. +### Blog-Bereich: Sonderregeln -**Warum:** Hugo's `menu/tree.html` ist ein rekursives Partial, das den Baum traversiert und dabei Hugo-interne Konzepte wie `.IsDescendant`, `.Ancestors`, `.Eq` nutzt. Diese existieren in Astro nicht. Statt einer allgemeinen Lösung wurde eine explizite State-Machine gewählt, die die konkreten Seitentypen kennt und die CSS-Klassen (`off`, `sub`, `selected`, `active`) direkt ableitet. +**Situation:** Blog-Artikel haben kanonische SEO-URLs, die nicht immer dem Dateibaum entsprechen, und tauchen in mehreren Kontexten auf: chronologisch im Archiv, und unter jeder ihrer Categories bzw. Tags. -**Wichtige Regel:** `#submenu li.s.off { display: none }` (Classic-Layout). Ein `ul.s` ohne `active` blendet sich nicht selbst aus — nur `li.s.nav-leaf` und `li.s.off` sind hidden. +**Anforderung:** Jeder Artikel soll im Sitemap-Menü **genau einmal** erscheinen — unter seiner kanonischen URL im Blog-Archiv. Die Taxonomy-Bereiche (Categories, Tags) zeigen nur die Term-Übersichten, keine doppelten Artikel-Verlinkungen. -**`off`-Klassen-Logik** (aus Hugo-Template-Quellen im `frontend`-Branch hergeleitet): +**Umsetzung im Nav:** +- Die Jahresstruktur (`/blog/archive/YYYY/`) mit Posts darunter ist immer im HTML; die `off`-Klasse steuert die Sichtbarkeit: + - Jahreszahlen: `off` wenn weder der Archive-Bereich noch das jeweilige Jahr aktiv ist + - Post-Items: immer gerendert; sichtbar sobald das Eltern-Jahr sichtbar ist +- Auf Taxonomy-Seiten (Categories-Index, Tags-Index, Term-Seiten) ist der Blog-Archiv-Ast im Nav hidden, aber die Blog-Section bleibt als Hauptbereich sichtbar -Hugo verwendet zwei verschiedene Menü-Templates: -- `layouts/_partials/menu/blog.html` — für Blog-Seiten: Blog immer sichtbar, alle anderen Sections immer `off` -- `layouts/_partials/menu/default.html` + `tree.html` — für alle anderen Seiten: Section-Index-Seiten (`IsNode=true`) blenden alle anderen Sections aus; auf der Homepage und regulären Root-Seiten (Impressum, Datenschutz) sind alle Sections sichtbar (Kind- bzw. Geschwister-Logik in `tree.html`) +### About-Bereich: Seitenstruktur -Daraus ergibt sich für `BlogNav.astro`: -- `blogSectionOff = onAboutSection` — Blog hidden auf allen About-Section-Seiten (inkl. Impressum, Datenschutz etc.) -- `aboutOff = blogSelected` — About hidden nur auf Blog-Seiten -- Auf Homepage und regulären Root-Seiten sind Blog und About beide sichtbar +Der About-Seitenbaum ist statisch in `BlogNav.astro` als TypeScript-Konstante (`NavPage[]`) definiert. Sortiert nach weight: -**About-Subtree:** Der About-Seitenbaum ist statisch in `BlogNav.astro` definiert (Typ `NavPage`), da About-Seiten keine Content Collection nutzen. Die `off`-Logik für Einträge innerhalb der Subtree spiegelt `tree.html` direkt: `aboutPageOff(page, parentUrl)` prüft `isCurrent || isAncestor || isSibling(!isNode) || isChild`. Section-Index-Seiten (About, Impressum) unterdrücken die Geschwister-Logik (`!currentAboutIsNode`). - -About-Seitenstruktur (aus `content/about/` im Hugo-Branch, sortiert nach weight): ``` /about.html - /contact.html (weight 10) - /impressum.html (weight 10, section-index) + /contact.html (weight 10) + /impressum.html (weight 10, section-index/isNode) /urheberrechte.html (weight 10) /datenschutz.html (weight 20) /haftung-inhalte.html (weight 30) /haftung-links.html (weight 40) /google-analytics.html - /agb.html (weight 30) + /agb.html (weight 30) ``` -Wenn Projects implementiert wird: `blogSectionOff |= onProjectsSection`, `aboutOff |= onProjectsSection`. - ---- - -#### URL-Kompatibilität via `url`-Frontmatter-Feld - -**Was:** Blog-Artikel können ein `url`-Feld im Frontmatter setzen (z.B. `url: /mein-alter-slug/`). Astro verwendet dieses, um die kanonische URL zu erzeugen, statt des Dateinamens. +Section-Index-Seiten (`isNode=true`: About, Impressum) unterdrücken die Geschwister-Logik — auf `/impressum.html` sieht man nur die Impressum-Kinder, nicht die Geschwister von Impressum. -**Warum:** Hugo generierte Blog-Post-URLs aus dem `url`-Frontmatter-Feld oder aus dem Slug, teilweise flach unter `/` (nicht unter `/blog/`). Um keine URLs zu brechen, wird `post.data.url ?? '/${post.id}/'` als Postlink verwendet. Die `getStaticPaths()`-Funktion in `[slug].astro` leitet die Route ebenfalls aus diesem Feld ab. - ---- +### Projects-Bereich: Sonderregeln -#### Word Count und Reading Time: Manuelle Berechnung aus Markdown-Body +Der Projects-Bereich unterscheidet zwischen **sichtbaren** und **nicht sichtbaren** Projektversionen. -**Was:** Wortanzahl und Lesezeit werden in Hilfsfunktionen `wordCount()` und aus `Math.ceil(wc / 200)` berechnet, indem Code-Blöcke aus dem Markdown-Body entfernt und der Rest auf Whitespace gesplittet wird. - -**Warum:** Astro stellt keine eingebaute Word-Count-API bereit. Alternativen wären Remark-Plugins, die beim Build laufen. Die Inline-Berechnung ist einfacher und ausreichend genau. Code-Blöcke werden herausgefiltert, weil sie die Lesezeit verzerren würden. Die 200-wpm-Rate entspricht Hugo's Standard (`reading_time_minutes = words / 200` gerundet aufwärts). - ---- +**Sichtbare Versionen** (`params.current: true`): Die aktuell veröffentlichte Version eines Projekts. Hat eine kanonische URL direkt unter Root (z.B. `/hibernate-maven-plugin/`). Erscheint immer im Sitemap-Menü. -#### Summary-Extraktion: Erste Nicht-Code-Paragraph bis 350 Zeichen +**Nicht sichtbare Versionen** (`params.current: false`): Ältere oder zukünftige (SNAPSHOT-)Versionen. Haben URLs unter `/projects/PROJEKT_NAME/VERSION/`. `params.canonical` verweist auf die entsprechende Seite der sichtbaren Version. -**Was:** `getSummary(body)` extrahiert eine Vorschau aus dem Markdown-Body, indem Code-Blöcke, HTML-Tags, Shortcodes, Links, Markdown-Formatierung und Überschriften entfernt werden und dann der erste Paragraph mit mindestens 20 Zeichen und maximal 350 Zeichen zurückgegeben wird. - -**Warum:** Hugo nutzt automatisch den ersten Paragraph als Summary. In Astro gibt es dafür keine eingebaute Funktion — bei Content Collections ist `post.body` der rohe Markdown-String. Statt eines Remark-Plugins wurde eine String-Manipulation gewählt, die für den vorhandenen Content ausreichend ist. - ---- - -#### `.html`-Endungen für Standalone-Seiten - -**Was:** Seiten wie About, Impressum und Datenschutz haben `.html`-Endungen in der URL (`/about.html`). In Astro wird das durch Benennung der Datei als `about.html.astro` erreicht. - -**Warum:** Diese URLs sind historisch aus dem WordPress-Import gewachsen und wurden in Hugo explizit mit `url: /about.html` beibehalten. Änderungen würden externe Links und Suchmaschinen-Indizes brechen. - ---- - -#### Standalone-Seiten: Navigation über BlogNav - -**Was:** Alle About-Section-Seiten (`about.html`, `impressum.html`, `datenschutz.html` sowie zukünftige wie `contact.html`, `agb.html` etc.) nutzen `BlogNav.astro` im `menu`-Slot. Die vollständige About-Subtree ist immer im HTML vorhanden; CSS blendet nicht relevante Einträge via `.off` aus. - -**Offener Punkt — Projects-Baum:** Hugo zeigt auf allen Seiten auch den Projects-Baum im Submenu (mit spezieller `current`-Flag-Logik für Projektversionen, aus `menu/tree.html`). Dieser fehlt noch. Sobald Projects implementiert wird, muss `BlogNav.astro` um den Projects-Ast erweitert werden. - ---- +**Nav-Verhalten nicht sichtbarer Versionen:** Sie erscheinen nur dann im Sitemap-Menü, wenn man gerade auf einer Seite dieser Version ist — und zwar **an der Position der sichtbaren Version** (ersetzen diese im Nav). Alle Nav-Links zeigen auf die SNAPSHOT-URLs. -#### RSS-Feed-Routing: Verzeichnisstruktur für korrekte URLs +**Zweck:** Suchmaschinen-Robots entdecken über das Sitemap-Menü alle Versionen und werden via `` auf die aktuelle Version verwiesen. Menschliche Besucher, die eine ältere Version aufrufen, sehen die originalen Inhalte mit einem Hinweis auf die aktuelle Version. -**Was:** RSS-Feed-Routen für Taxonomie-Terms und Jahres-Archive liegen in Unterverzeichnissen: `src/pages/categories/[term]/index.xml.ts` statt `src/pages/categories/[term].xml.ts`. +**Generierte Inhalte (apidocs, xref etc.):** Maven-Site-Outputs liegen fertig generiert in `public/projects/PROJEKT_NAME/VERSION/` und werden als statische Dateien ausgeliefert — ohne Astro-Layout, ohne HTML-Anpassungen, ohne Routing-Dateien in `src/pages/`. `src/lib/projects.ts` (`generatedDocNodes()`) erkennt diese Verzeichnisse zur Build-Zeit automatisch und fügt sie als Nav-Blatteinträge hinzu: -**Warum:** Astro generiert aus `[term].xml.ts` die URL `/categories/TERM.xml`, aber die erwartete URL ist `/categories/TERM/index.xml` (analog zur HTML-Route `/categories/TERM/`). Die Verzeichnisstruktur `[term]/index.xml.ts` erzeugt korrekt `/categories/TERM/index.xml`. Dasselbe gilt für `tags/[term]/index.xml.ts` und `blog/archive/[year]/index.xml.ts`. - -**Generierte Feed-Routen:** -- `/blog/index.xml` — alle Posts -- `/blog/archive/index.xml` — alle Posts (identisch) -- `/blog/archive/YYYY/index.xml` — Posts eines Jahres -- `/categories/TERM/index.xml` — Posts einer Kategorie -- `/tags/TERM/index.xml` — Posts eines Tags - ---- - -#### Shared Helpers: `src/lib/posts.ts` - -**Was:** Gemeinsam genutzte Hilfsfunktionen (`getAllPosts`, `postUrl`, `getSummary`, `wordCount`) sind in `src/lib/posts.ts` zentralisiert und werden von allen Seiten und API-Routen importiert. - -**Warum:** Ohne dieses Modul wäre `getCollection('blog')`, die Sortierlogik, `wordCount` und `getSummary` in allen Seiten-Dateien dupliziert worden (Blog-Index, Jahres-Archiv, Kategorie-Term, Tag-Term, Blog-Post, alle RSS-Feeds). Der Refactoring-Schritt wurde nach dem ersten Implementierungs-Durchlauf gemacht, als die Duplikation offensichtlich wurde. - ---- - -#### SEO: Description-Prop und OG-Tags in BaseLayout - -**Was:** `BaseLayout.astro` akzeptiert eine optionale `description`-Prop, die zu `` und `` wird. Zusätzlich werden `og:title`, `og:type` und `og:url` immer gerendert. - -**Warum:** Hugo rendert diese Meta-Tags automatisch aus dem Frontmatter. In Astro gibt es kein eingebautes SEO-System — es wurde bewusst darauf verzichtet, ein SEO-Integrations-Paket (z.B. `astro-seo`) einzuführen. Die wenigen benötigten Tags wurden direkt in `BaseLayout.astro` implementiert, da das einfacher und transparenter ist. Seiten ohne explizite `description`-Prop (z.B. Archiv-Seiten) rendern keine Description-Tags. +| Verzeichnis | Nav-Bezeichnung | +|---|---| +| `apidocs/` | API-Docs | +| `testapidocs/` | Test-API-Docs | +| `xref/` | Quelltext | +| `xref-test/` | Test-Quelltext | --- -#### Projects: Content-Architektur und Anforderungen ans Tooling +## Projects: Content-Architektur und Tooling-Anforderungen Projektdokumentation liegt in `src/content/projects/PROJEKT_NAME/VERSION/` als HTML-Dateien mit YAML-Frontmatter. Ein Custom Loader in `src/content.config.ts` (mit `js-yaml`) liest diese ein; Routing und Nav-Logik werden in `src/lib/projects.ts` und `BlogNav.astro` verwaltet. @@ -344,35 +216,64 @@ import ProjectPage from '/components/ProjectPage.astro'; ``` -Die `entryId` ist der relative Pfad innerhalb von `src/content/projects/` (ohne dieses Präfix), also z.B. `"hibernate-maven-plugin/2.1.1/project-reports/_index.html"`. +Die `entryId` ist der relative Pfad innerhalb von `src/content/projects/` ohne dieses Präfix, z.B. `"hibernate-maven-plugin/2.1.1/project-reports/_index.html"`. -**`.html`-URL-Quirk:** `configuration.html.astro` erzeugt im Build `configuration.html/index.html` (Astro verwendet immer Directory-Style). Nginx serviert das korrekt via Directory-Index — identisches Verhalten wie bei den About-Seiten (`/contact.html` etc.). +**`.html`-URL-Quirk:** `configuration.html.astro` erzeugt im Build `configuration.html/index.html` (Astro verwendet immer Directory-Style). Nginx serviert das korrekt via Directory-Index — identisches Verhalten wie bei den About-Seiten. -**Generierte Inhalte** (apidocs, xref etc.): Der statische Maven-Site-Output wird direkt in `public/projects/PROJEKT_NAME/VERSION/` abgelegt — kein `src/content/`-Eintrag, keine Routing-Datei. `src/lib/projects.ts` (`generatedDocNodes()`) erkennt diese Verzeichnisse automatisch zur Build-Zeit und erzeugt Nav-Einträge. +**Generierte Inhalte** werden direkt in `public/projects/PROJEKT_NAME/VERSION/` abgelegt — kein `src/content/`-Eintrag, keine Routing-Datei nötig (s.o. Nav-Erkennung via `generatedDocNodes()`). -Erkannte Unterverzeichnisse in `public/projects/X/Y/`: +--- -| Verzeichnis | Nav-Bezeichnung | -|---|---| -| `apidocs/` | API-Docs | -| `testapidocs/` | Test-API-Docs | -| `xref/` | Quelltext | -| `xref-test/` | Test-Quelltext | +## Architektur-Entscheidungen ---- +### CSS: Separater SCSS-Build + +SCSS-Quellen liegen in `src/styles/`. Sie werden über einen separaten `sass`-CLI-Aufruf kompiliert (`npm run build:css`); das kompilierte CSS landet in `public/css/` und ist im Git eingecheckt. Der `prebuild`/`predev`-Hook in `package.json` stellt sicher, dass CSS beim Build immer aktuell ist. + +SCSS-Änderungen erfordern `npm run build:css` oder einen Dev-Server-Neustart; HMR für SCSS funktioniert nicht automatisch. + +### Taxonomy-URL-Struktur + +Taxonomy-Seiten sind auf zwei URL-Ebenen verteilt: +- Index-Seiten: `/blog/categories/` und `/blog/tags/` (unter dem Blog-Pfad) +- Term-Seiten: `/categories/TERM/` und `/tags/TERM/` (direkt unter Root) + +### `.html`-Endungen für Standalone-Seiten + +Seiten wie About, Impressum und Projekt-Unterseiten haben `.html`-Endungen in der URL. In Astro wird das durch Benennung der Datei als `page.html.astro` erreicht. Astro erzeugt dabei `page.html/index.html` im Build-Output (Directory-Style). Nginx serviert das korrekt via Directory-Index. + +### URL via `url`-Frontmatter-Feld + +Blog-Artikel und Projekt-Seiten können ein `url`-Feld im Frontmatter setzen. Astro verwendet dieses für die kanonische URL statt des Dateinamens (`post.data.url ?? '/${post.id}/'`). Die `getStaticPaths()`-Funktion in `[slug].astro` leitet die Route daraus ab. + +### Shared Helpers + +- `src/lib/posts.ts` — `getAllPosts`, `postUrl`, `getSummary`, `wordCount` für Blog-Seiten und RSS-Feeds +- `src/lib/projects.ts` — `getActiveProject`, `getVisibleProjectNavTrees`, `buildNavTree`, `generatedDocNodes` für die Projects-Nav-Logik in `BlogNav.astro` + +### Content Collections + +- **Blog:** `src/content/blog/` — Markdown-Dateien, `glob()`-Loader, Zod-Schema-Validierung +- **Projects:** `src/content/projects/` — HTML-Dateien mit YAML-Frontmatter, Custom Loader in `src/content.config.ts` (nutzt `js-yaml` für Frontmatter-Parsing) + +### SEO-Meta-Tags + +`BaseLayout.astro` rendert ``, `og:title`, `og:type`, `og:url`, `og:description` (optional über `description`-Prop). Eine optionale `canonical`-Prop erzeugt `` — wird für nicht sichtbare Projektversionen genutzt, die auf die sichtbare Version verweisen. + +### RSS-Feed-Routing + +Feed-Routen liegen in Unterverzeichnissen (`src/pages/categories/[term]/index.xml.ts` statt `src/pages/categories/[term].xml.ts`), weil Astro sonst `/categories/TERM.xml` statt `/categories/TERM/index.xml` erzeugen würde. + +Generierte Feeds: +- `/blog/index.xml` und `/blog/archive/index.xml` — alle Posts +- `/blog/archive/YYYY/index.xml` — Posts eines Jahres +- `/categories/TERM/index.xml` — Posts einer Kategorie +- `/tags/TERM/index.xml` — Posts eines Tags + +### Word Count und Reading Time + +`wordCount()` entfernt Code-Blöcke aus dem Markdown-Body und splittet auf Whitespace. Lesezeit = `Math.ceil(wc / 200)` (200 wpm, aufgerundet). + +### Summary-Extraktion -#### Hugo-Dateien entfernt nach Migration - -**Was:** Nach Abschluss der Astro-Migration wurden folgende Hugo-spezifische Dateien und Verzeichnisse aus dem Repo entfernt: -- `content/` (1288 Blog-Artikel und Seiten — nun in `src/content/blog/`) -- `themes/PaperMod/` (Hugo-Theme-Submodul) -- `themes/hugo-juplo/` (das eigene Hugo-Theme-Submodul) -- `hugo.yaml` (Hugo-Konfiguration) -- `archetypes/` (Hugo-Vorlagen für neue Inhalte) -- `inventory.md` (Hilfsdatei zur Analyse während der Migration) -- `.gitmodules` (Submodul-Konfiguration, da keine Submodule mehr vorhanden) - -**Behalten:** -- `data/` (enthält echte Nutzer-Kommentardaten, kein Hugo-spezifischer Content) -- `docker-compose.yml` und `nginx.conf` (Deployment-Konfiguration, unabhängig vom SSG) -- `public/` (statische Assets, bereits im Astro-Format) +`getSummary(body)` gibt den ersten Nicht-Code-Paragraph mit 20–350 Zeichen zurück. Code-Blöcke, HTML-Tags, Shortcodes, Links, Markdown-Formatierung und Überschriften werden vor der Extraktion entfernt.