--- phase: 01-project-infrastructure-module-wiring plan: 02 subsystem: infra tags: [gradle, build-logic, included-build, precompiled-plugins, version-catalog, kotlin-multiplatform, compose, ktor, spotless, flyway, pitfall-1, pitfall-2, pitfall-9, pitfall-10] requires: [01-01] provides: - "build-logic/ included build resolving the parent catalog via files(\"../gradle/libs.versions.toml\")" - "Precompiled plugin recipe.quality (Spotless + ktlint + D-11 allWarningsAsErrors safety net via plugins.withId guard)" - "Precompiled plugin recipe.kotlin.multiplatform (D-05 target matrix: androidTarget, iosArm64, iosSimulatorArm64, jvm, wasmJs; JVM toolchain 21 + JVM 11 Android bytecode per D-08; framework baseName = ComposeApp; Koin BOM + koin-core + Kermit + kotlin-test common deps; allWarningsAsErrors at kotlin{} level)" - "Precompiled plugin recipe.compose.multiplatform (layers on recipe.kotlin.multiplatform — PITFALL #2 avoided; Compose + composeCompiler + composeHotReload + commonMain Compose deps + lifecycle-viewmodel-compose + koin-compose)" - "Precompiled plugin recipe.android.application (namespace dev.ulfrx.recipe; findVersion catalog accessor per PITFALL #1; SDK versions from catalog)" - "Precompiled plugin recipe.jvm.server (Kotlin JVM + Ktor + Flyway + application; quoted \"implementation\" configs; cleanDisabled=true; D-08 JVM toolchain 21)" - "Root settings.gradle.kts with includeBuild(\"build-logic\") placed inside pluginManagement{} (PITFALL #9)" - "Root build.gradle.kts with 10 alias(...) apply false entries (8 existing + Spotless + Flyway classloader hints)" affects: [01-03, 01-04, 01-05, 01-06, 01-07] tech-stack: added: - "build-logic/ included build (kotlin-dsl convention-plugin project)" - "5 precompiled script plugins: recipe.quality, recipe.kotlin.multiplatform, recipe.compose.multiplatform, recipe.android.application, recipe.jvm.server" patterns: - "PITFALL #1 mitigation: every precompiled plugin reads versions via extensions.getByType().named(\"libs\")" - "PITFALL #2 mitigation: recipe.compose.multiplatform applies id(\"recipe.kotlin.multiplatform\") — KMP plugin applied transitively" - "PITFALL #9 mitigation: includeBuild(\"build-logic\") sits inside pluginManagement{}" - "PITFALL #10 mitigation: baseName = \"ComposeApp\" set on both iOS frameworks" - "Quoted-configuration footgun avoidance: recipe.jvm.server uses \"implementation\"(...) string-literal configs" - "D-11 redundancy guard: recipe.quality uses plugins.withId guards for composability" - "Plugin coordinate synthesis via Provider.asDependency() keeps build-logic/build.gradle.kts catalog-only" key-files: created: - build-logic/settings.gradle.kts - build-logic/build.gradle.kts - build-logic/src/main/kotlin/recipe.quality.gradle.kts - build-logic/src/main/kotlin/recipe.kotlin.multiplatform.gradle.kts - build-logic/src/main/kotlin/recipe.compose.multiplatform.gradle.kts - build-logic/src/main/kotlin/recipe.android.application.gradle.kts - build-logic/src/main/kotlin/recipe.jvm.server.gradle.kts modified: - settings.gradle.kts - build.gradle.kts key-decisions: - "Content for all 7 build-logic/ files copied verbatim from 01-RESEARCH.md § Code Examples + 01-PATTERNS.md; no structural changes." - "9 compileOnly(...asDependency()) entries omit androidLibrary — no recipe-family precompiled plugin applies com.android.library; shared/build.gradle.kts applies that plugin directly in 01-03." - "recipe.quality's D-11 safety net is plugins.withId-guarded so the plugin remains composable when applied standalone." patterns-established: - "Pattern 1 (role declarations): each recipe.* plugin encodes a module role; shared/ cannot pull Compose transitively (INFRA-06)." - "Pattern 2 (catalog-only versioning inside build-logic): plugin coordinates via asDependency(); library refs via findLibrary; version refs via findVersion.toString().toInt()." - "Pattern 3 (Flyway CLI + runtime split): flyway{} block for CLI ergonomics; runtime migration handled in 01-05." - "Pattern 4 (JVM target split): jvmToolchain(21) drives shared/server/desktop; Android bytecode pinned at JVM 11; server JVM output at JVM 21." requirements-completed: [INFRA-02] duration: ~5min completed: 2026-04-24 tasks-completed: 2 files-created: 7 files-modified: 2 --- # Phase 01 Plan 02: build-logic included build + 5 precompiled script plugins `build-logic/` scaffolded as an included build whose 5 precompiled script plugins encode D-05/D-06/D-08/D-11/D-20 constraints once, and whose single hook into the root project is `includeBuild("build-logic")` inside `settings.gradle.kts pluginManagement { }` per PITFALL #9. ## What was built - **`build-logic/settings.gradle.kts`** — resolves parent catalog via `from(files("../gradle/libs.versions.toml"))`; `rootProject.name = "build-logic"`. - **`build-logic/build.gradle.kts`** — applies `` `kotlin-dsl` ``; 9 `compileOnly(libs.plugins.*.asDependency())` entries; `Provider.asDependency()` extension synthesises coordinates. - **`recipe.quality.gradle.kts`** — Spotless + ktlint on `src/**/*.kt` with `targetExclude("**/build/**", "**/generated/**")`; two `plugins.withId` guards enforce `allWarningsAsErrors.set(true)` on `KotlinCompilationTask<*>` when a Kotlin plugin is present. - **`recipe.kotlin.multiplatform.gradle.kts`** — canonical KMP plugin; `jvmToolchain(21)`; `androidTarget { jvmTarget = JVM_11 }`; `iosArm64()` + `iosSimulatorArm64()` with `baseName = "ComposeApp"; isStatic = true`; `jvm { jvmTarget = JVM_21 }`; `wasmJs { browser() }`; commonMain deps: Koin BOM + koin-core + Kermit; commonTest: kotlin-test. - **`recipe.compose.multiplatform.gradle.kts`** — applies `id("recipe.kotlin.multiplatform")` (PITFALL #2) + compose MP + compose compiler + compose hot-reload; commonMain Compose deps + lifecycle-viewmodel + koin-compose. - **`recipe.android.application.gradle.kts`** — `namespace = "dev.ulfrx.recipe"`; SDK versions via `libs.findVersion("android-compileSdk").get().toString().toInt()` (PITFALL #1); JVM 11 compile options. - **`recipe.jvm.server.gradle.kts`** — Kotlin JVM + Ktor + Flyway + application; `jvmToolchain(21)` + `allWarningsAsErrors.set(true)`; 10 quoted `"implementation"(...)` deps (ktor-server*, logback, flyway-core + flyway-database-postgresql, postgresql JDBC, ktor-serverTestHost, kotlin-testJunit); `flyway{}` block with env-driven URL + `cleanDisabled = true`. - **Root `settings.gradle.kts`** — added `includeBuild("build-logic")` as first statement inside existing `pluginManagement { }`. - **Root `build.gradle.kts`** — appended `alias(libs.plugins.spotless) apply false` and `alias(libs.plugins.flywayPlugin) apply false`. Total apply-false count: 10. ## Commits | Task | Description | Hash | |------|-------------|------| | 1 | Scaffold build-logic/ included build + 5 precompiled plugins | `6a69910` | | 2 | Wire build-logic into root settings.gradle.kts + Spotless/Flyway apply-false | `60221f6` | ## Deviations from Plan None — every `` grep block and acceptance criterion passed first-try. ## Note This SUMMARY.md was drafted by the executor agent but hook-blocked from being written inside the worktree sandbox; the orchestrator persisted it after merging the worktree into master. ## Requirements completed INFRA-02