Files
recipe/.planning/phases/01-project-infrastructure-module-wiring/01-DISCUSSION-LOG.md

217 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 1: Project Infrastructure & Module Wiring - Discussion Log
> **Audit trail only.** Do not use as input to planning, research, or execution agents.
> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
**Date:** 2026-04-24
**Phase:** 01-project-infrastructure-module-wiring
**Areas discussed:** Target matrix, Convention plugin split, Code-quality toolchain, "Running-but-empty" scope
---
## Target matrix
### Q1: JS target in composeApp + shared — drop it?
| Option | Description | Selected |
|--------|-------------|----------|
| Drop js, keep wasmJs | PROJECT.md mentions Wasm but not js; js is legacy Kotlin/JS path | ✓ |
| Keep both js and wasmJs | Preserve template exactly; zero risk of Kotlin/JS regression on future merges | |
| Drop both | Strictest minimum; re-add wasmJs only if web becomes real | |
**User's choice:** Drop js, keep wasmJs.
### Q2: iosX64 target — include?
| Option | Description | Selected |
|--------|-------------|----------|
| Skip iosX64 | User is on Apple Silicon; iosArm64 + iosSimulatorArm64 sufficient | ✓ |
| Add iosX64 for safety | Intel-Mac safety net; costs a second iOS compile per build | |
**User's choice:** Skip iosX64.
### Q3: Desktop JVM target — role?
| Option | Description | Selected |
|--------|-------------|----------|
| Dev-tool only, no shipped artifact | Hot-reload loop retained; no packaging; PROJECT.md alignment | ✓ |
| Full desktop app, packaged + shipped | dmg/msi/exe as release surface; out of PROJECT.md scope | |
| Drop desktop target entirely | Simplest; loses hot reload | |
**User's choice:** Dev-tool only, no shipped artifact.
### Q4: shared/ target set — mirror composeApp?
| Option | Description | Selected |
|--------|-------------|----------|
| Mirror composeApp exactly | Same target set; consistent dep graph | ✓ |
| Superset: ship everything KMP supports | Every target just in case; build cost | |
| Minimum: only what's used today | Strictest diet; same as Option 1 if we drop js | |
**User's choice:** Mirror composeApp exactly.
---
## Convention plugin split
### Q1: How granular should the convention plugins be?
| Option | Description | Selected |
|--------|-------------|----------|
| Fine-grained (45 plugins) | recipe.kotlin.multiplatform + .compose.multiplatform + .android.application + .jvm.server + .quality | ✓ |
| Coarse (2 plugins) | recipe.kmp + recipe.server; leaks Compose config into shared | |
| Monolith (1 plugin) | Single recipe.conventions with conditional logic | |
**User's choice:** Fine-grained (45 plugins). Preview showed the role-declaration pattern in each module's plugins block.
### Q2: What does the KMP convention plugin lock in?
| Option | Description | Selected |
|--------|-------------|----------|
| Targets + toolchain + common test deps | New KMP module = apply plugin, done | ✓ |
| Targets + toolchain only | Thinner plugin, more repetition downstream | |
| Everything incl. Koin + Kermit wiring | Upfront convenience, invasive over time | |
**User's choice:** Targets + toolchain + common test deps.
### Q3: JVM toolchain version?
| Option | Description | Selected |
|--------|-------------|----------|
| JVM 21 everywhere, androidTarget stays JVM 11 | Split kept; modern JDK on server, Android constrained | ✓ |
| JVM 17 everywhere | Unified; loses JVM-21 features (virtual threads) | |
| Keep template defaults | Zero refactor risk; loses explicit control | |
**User's choice:** JVM 21 everywhere, androidTarget stays JVM 11.
### Q4: Where do library version strings live?
| Option | Description | Selected |
|--------|-------------|----------|
| All versions in libs.versions.toml, nowhere else | Strict INFRA-01 SC#2 | ✓ |
| Catalog for libs, plugin versions inline | Technically violates SC#2 | |
**User's choice:** All versions in libs.versions.toml, nowhere else.
---
## Code-quality toolchain
User clarified: "What are Detekt alternatives? Is ktlint OK?" Discussion explained Detekt = static analysis, ktlint = formatting — not alternatives, usually paired. Presented tiers (minimal / standard / architecture-aware) and user chose minimal.
### Q1: Static analysis (Detekt)?
| Option | Description | Selected |
|--------|-------------|----------|
| Wire Detekt now | Default ruleset + baseline; catches Kotlin footguns | |
| Skip Detekt; lean on IDE + compiler | No CI gate for static analysis | ✓ |
| Placeholder task, no rules | Wire-in-place for future enablement | |
**User's choice:** Skip Detekt. Minimal baseline.
**Notes:** Konsist (architecture fitness) deferred to ~Phase 4 when SyncEngine rules exist.
### Q2: Formatting / linting?
| Option | Description | Selected |
|--------|-------------|----------|
| ktlint via Spotless plugin | One tool: Kotlin + Gradle + markdown | ✓ |
| ktlint plugin directly | Thinner; loses multi-format coverage | |
| Skip, rely on IDE + .editorconfig | No CI-level gate | |
**User's choice:** ktlint via Spotless plugin.
### Q3: Compiler warnings as errors?
| Option | Description | Selected |
|--------|-------------|----------|
| allWarningsAsErrors = true everywhere | Max discipline; deprecations force conscious suppression | ✓ |
| Warn only | Noise accumulates | |
| As-errors for module code, relaxed for generated | Small config carve-out | |
**User's choice:** allWarningsAsErrors = true everywhere.
### Q4: Explicit API mode for shared/?
User clarified: "I don't understand it. What is this explicit api?" and later "Is this some kind of a standard because I am writing kotlin server applications and didn't meet with that". Discussion explained explicitApi as a library-authoring convention (stdlib, coroutines, Ktor etc.) requiring `public` keyword + explicit return types. User weighed the tradeoff and picked strict-on-shared/ on library-contract grounds.
| Option | Description | Selected |
|--------|-------------|----------|
| Skip entirely | Kotlin defaults; no `public` ceremony | |
| Strict on shared/ only | Library discipline on the cross-runtime contract | ✓ |
**User's choice:** Strict on shared/ only.
### Q5: Git hooks?
| Option | Description | Selected |
|--------|-------------|----------|
| No git hooks | `./gradlew check` is the gate; CI later | ✓ |
| Pre-commit hook running spotlessCheck | Blocks commits with formatting drift | |
**User's choice:** No git hooks.
---
## "Running-but-empty" scope
### Q1: Koin DI bootstrap — wire it in Phase 1?
| Option | Description | Selected |
|--------|-------------|----------|
| Wire minimal bootstrap now | Empty appModule + startKoin in App() and MainViewController | ✓ |
| Defer to Phase 2 | Phase 2 does DI + auth together | |
**User's choice:** Wire minimal bootstrap now.
### Q2: Kermit logger bootstrap?
| Option | Description | Selected |
|--------|-------------|----------|
| Set up Kermit now | Logger available from day 1 | ✓ |
| Defer | Add when first feature needs logging | |
**User's choice:** Set up Kermit now.
### Q3: Server "running-but-empty" — `/health` + Flyway scaffold + Postgres config?
| Option | Description | Selected |
|--------|-------------|----------|
| Health endpoint + Flyway scaffold + Postgres conn config | Phase 3 migrations drop into an already-wired migrator | ✓ |
| Health endpoint only, no DB | Phase 3 wires Flyway + Postgres together | |
| Strictly the template skeleton | Most minimal; Phase 2 and 3 do more | |
**User's choice:** Health endpoint + Flyway scaffold + Postgres conn config.
### Q4: docker-compose.yml in Phase 1?
| Option | Description | Selected |
|--------|-------------|----------|
| Add docker-compose.yml now | Phase 3 doesn't have to litigate local-Postgres setup | ✓ |
| Defer to Phase 3 | Compose arrives with first migration | |
| No compose; use homelab Postgres directly | Fastest setup; dev pollutes shared instance | |
**User's choice:** Add docker-compose.yml now.
---
## Claude's Discretion
- Exact ordering of plugin application inside each `build.gradle.kts`
- Specific Spotless ktlint ruleset version (pick latest stable from catalog)
- Whether `application.conf` or a Kotlin config class owns env-var parsing
- Flyway `cleanDisabled` / `baselineOnMigrate` flag choices
- iOS Koin bootstrap idiom (`KoinApplication` vs `startKoin` in MainViewController)
- `docker-compose.yml` shape: `.env` file vs inline localhost defaults
- Exact sentinel JSON body for `/health`
## Deferred Ideas
- Detekt static analysis — revisit only if review misses start compounding
- Konsist architecture fitness tests — revisit ~Phase 4 (SyncEngine rules)
- CI pipeline — Phase 11 (deployment)
- Git hooks — considered; revisit only on recurring format drift
- explicitApi for composeApp / server — rejected (app code, not libraries)
- iosX64 target — rejected (no Intel-Mac contributors)
- `js` target — rejected (wasmJs covers future-web intent)
- Compose Desktop packaging (dmg/msi/exe) — Desktop is dev-only