217 lines
8.8 KiB
Markdown
217 lines
8.8 KiB
Markdown
# 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 (4–5 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 (4–5 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
|