Commit Graph

9 Commits

Author SHA1 Message Date
c1cc713bbb feat(02-01): wire Phase 2 dependency aliases without bumping Ktor
Task 02-01-02. Adds Phase 2 deps to the version catalog and routes
them into composeApp + server build files. Ktor stays pinned at
3.4.1 per the resolved Open Question — patch bump deferred unless a
concrete incompatibility appears.

Catalog (gradle/libs.versions.toml):
- Versions: appauth, appauth-ios, androidx-security-crypto, exposed,
  hikari, multiplatformSettings, testcontainers, plus the
  kotlinCocoapods plugin alias.
- Libraries: ktor server auth/auth-jwt/call-logging/status-pages,
  ktor client core/auth/content-negotiation/logging/okhttp/darwin/cio,
  ktor-serializationKotlinxJsonMpp (the multiplatform variant; the
  -jvm one stays for server), AppAuth, AndroidX Security Crypto,
  multiplatform-settings + coroutines, Exposed core/jdbc/java-time,
  HikariCP, Testcontainers postgresql + junit-jupiter.

composeApp/build.gradle.kts:
- Apply kotlinSerialization (alias) and kotlin.native.cocoapods (by
  id — the plugin is shipped inside the Kotlin Gradle plugin already
  on the classpath via recipe.kotlin.multiplatform; alias-applying
  it would request a fresh version and fail).
- Cocoapods block: ComposeApp baseName + isStatic, ../iosApp/Podfile,
  iOS deployment target 15.0, AppAuth pod pulled from
  libs.versions.appauth.ios.get() — no literal pin in the build
  file (verify-no-version-literals.sh stays green).
- Common deps: Ktor client family, MPP serialization, multiplatform
  settings; Android: AppAuth-Android + Security Crypto + OkHttp
  engine; iOS: Darwin engine; JVM: CIO engine.

server/build.gradle.kts: Adds Ktor server auth/JWT/CallLogging/
StatusPages, Exposed DSL trio, Hikari, kotlinx.serialization-json,
plus testImplementation testcontainers postgresql + junit-jupiter.

Deviations:
- Rule 3 (blocking): manifestPlaceholders["appAuthRedirectScheme"]
  = "recipe" added to Android defaultConfig because AppAuth-Android's
  bundled manifest declares a ${appAuthRedirectScheme} placeholder
  that breaks AGP merge before Plan 02-04 lands the full <intent-filter>.
- Rule 3 (blocking): top-level group/version on composeApp (required
  by the cocoapods podspec generator) pushes the Compose Resources
  Res-class package off recipe.composeapp.generated.resources, breaking
  Phase 1 App.kt imports. Lock the package via compose.resources {
  packageOfResClass = "recipe.composeapp.generated.resources" }.
- Rule 3 (housekeeping): *.podspec is generated by the cocoapods
  plugin on every build; ignored.

Verification:
- ./gradlew :composeApp:dependencies --configuration debugCompileClasspath
  :server:dependencies --configuration runtimeClasspath: PASS
  (the plan-stated androidMainCompileClasspath name doesn't exist
  under this AGP/Gradle combo; debugCompileClasspath is the
  functional equivalent and resolves all new deps).
- ./gradlew :composeApp:compileDebugKotlinAndroid :server:compileKotlin: PASS
- ./gradlew :composeApp:compileKotlinIosSimulatorArm64: PASS (cinterop
  pulls AppAuth pod cleanly).
- ./tools/verify-no-version-literals.sh: PASS
- ./tools/verify-shared-pure.sh: PASS
- All Task 2 grep acceptance criteria satisfied.
2026-04-28 10:52:40 +02:00
04b3d9b1d5 Remove unnecessary convention plugins 2026-04-26 22:22:28 +02:00
68655eae1a Phase 1 work 2026-04-24 20:21:03 +02:00
6972839fd0 merge(01-05): server /health + Flyway + HOCON + fail-loud DB boot 2026-04-24 18:41:51 +02:00
59d069591b test(01-05): rewrite ApplicationTest to assert GET /health without Postgres
- Replace testRoot template assertion with 'health endpoint returns 200 with status ok'
- Compose only configureRouting() in testApplication — NOT Application.module()
- This keeps the test independent of Database.migrate / running Postgres (D-11 test invariant)
- Install ContentNegotiation { json() } inside application { } — production module() does it,
  but the test composes routing directly and must install the plugin itself
- All imports explicit (D-11 allWarningsAsErrors); no wildcards
- Body checked via substring for "status" + "ok" — robust to JSON field ordering

Note: ./gradlew :server:test runtime verification deferred to Plan 07 (integration build)
since build-logic/recipe.jvm.server plugin is being authored in parallel Plan 02 worktree.
2026-04-24 18:23:14 +02:00
daefe6c26d refactor(01-05): rewrite Application.kt with ContentNegotiation, Flyway boot, /health
- Remove wildcard Ktor imports (D-11 allWarningsAsErrors safety) — all imports explicit
- Install ContentNegotiation { json() } for @Serializable response bodies
- Call Database.migrate(this) at boot — fails loudly if Postgres unreachable
- Extract configureRouting() extension so tests can compose routing without DB
- Replace template root greeting with GET /health → {"status":"ok"} (D-16)
- main() shape unchanged: embeddedServer(Netty, SERVER_PORT, "0.0.0.0", ...)
2026-04-24 18:22:37 +02:00
d316a4805e refactor(01-03): apply recipe.jvm.server + recipe.quality to server module
- Replaces alias(kotlinJvm) + alias(ktor) + application with id("recipe.jvm.server") + id("recipe.quality") — application plugin now applied by the convention
- Removes per-module dep lines (logback, ktor-serverCore, ktor-serverNetty, ktor-serverTestHost, kotlin-testJunit) — all bundled in recipe.jvm.server
- Keeps module-only config: group/version coordinates, application { mainClass.set } + applicationDefaultJvmArgs, implementation(projects.shared)
- File shrinks 23 -> 18 lines; no version literals leak
2026-04-24 18:22:09 +02:00
24018efe67 feat(01-05): add HOCON config, Flyway migration dir, fail-loud Database.migrate
- application.conf: HOCON with ktor.deployment.port (8080 + ${?PORT}) and
  database.url/user/password (localhost defaults + ${?DATABASE_URL/USER/PASSWORD})
- db/migration/.gitkeep: placeholder so classpath:db/migration resolves
- Database.kt: object Database.migrate(app) reads HOCON config, runs Flyway
  with baselineOnMigrate + validateOnMigrate + cleanDisabled, throws
  IllegalStateException on any failure (D-16 fail-loud contract)
- SLF4J (not Kermit); server logs url+user only, never password
2026-04-24 18:22:08 +02:00
bf8b46bff2 Initial commit 2026-04-23 22:50:48 +02:00