# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Build & Test Commands ```bash # Build everything gradle build # Run all tests gradle test # Run tests for a specific module gradle :parser:test gradle :layout:test gradle :renderer-pdf:test gradle :app:test # Run a single test class gradle :parser:test --tests ChordProParserTest # Run a single test method gradle :parser:test --tests "ChordProParserTest.parse complete song" # Build and run CLI gradle :cli:run --args="build -d /path/to/project" gradle :cli:run --args="validate -d /path/to/project" # Launch GUI gradle :gui:run ``` Requires Java 21 (configured in `gradle.properties`). Kotlin 2.1.10, Gradle 9.3.1. ## Architecture **Pipeline:** Parse → Measure → Paginate → Render `SongbookPipeline` (in `app`) orchestrates the full flow: 1. `ConfigParser` reads `songbook.yaml` → `BookConfig` 2. `ChordProParser` reads `.chopro` files → `Song` objects 3. `Validator` checks config and songs 4. `MeasurementEngine` calculates each song's height in mm using `FontMetrics` 5. `TocGenerator` estimates TOC page count and creates entries 6. `PaginationEngine` arranges songs into pages (greedy spread packing) 7. `PdfBookRenderer` generates the PDF via OpenPDF **Module dependency graph:** ``` model ← parser model ← layout model ← renderer-pdf parser, layout, renderer-pdf ← app app ← cli (Clikt) app, parser ← gui (Compose Desktop) ``` `model` is the foundation with no dependencies — all data classes, the `FontMetrics` interface, and the `BookRenderer` interface live here. The `FontMetrics` abstraction decouples layout from rendering: `PdfFontMetrics` is the real implementation (in renderer-pdf), `StubFontMetrics` is used in layout tests. **Pagination constraint:** Songs spanning 2 pages must start on a left (even) page. The `PaginationEngine` inserts filler images or blank pages to enforce this. ## Key Types - `Song` → sections → `SongLine` → `LineSegment(chord?, text)` — chord is placed above the text segment - `PageContent` — sealed class: `SongPage`, `FillerImage`, `BlankPage` - `SectionType` — enum: `VERSE`, `CHORUS`, `BRIDGE`, `REPEAT` - `BuildResult` — returned by `SongbookPipeline.build()` with success/errors/counts ## Song Format ChordPro-compatible `.chopro` files: directives in `{braces}`, chords in `[brackets]` inline with lyrics, comments with `#`. See `songs/` for examples. ## Test Patterns Tests use `kotlin.test` annotations with Kotest assertions (`shouldBe`, `shouldHaveSize`, etc.) on JUnit 5. Layout tests use `StubFontMetrics` to avoid PDF font dependencies. App integration tests create temp directories with song files and config. ## Package All code under `de.pfadfinder.songbook.*` — subpackages match module names (`.model`, `.parser`, `.layout`, `.renderer.pdf`, `.app`, `.cli`, `.gui`).