Phase 1 work
This commit is contained in:
21
.editorconfig
Normal file
21
.editorconfig
Normal file
@@ -0,0 +1,21 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{kt,kts}]
|
||||
# ktlint configuration for Compose Multiplatform.
|
||||
# - function-naming is disabled because @Composable functions and Kotlin/Native
|
||||
# entry-point factories (e.g. MainViewController) are PascalCase by convention.
|
||||
# - filename is disabled because Compose-Multiplatform entry-point files
|
||||
# (jvmMain/main.kt, webMain/main.kt) follow the Kotlin `fun main()` convention.
|
||||
ktlint_standard_function-naming = disabled
|
||||
ktlint_standard_filename = disabled
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
@@ -4,13 +4,13 @@ milestone: v1.0
|
||||
milestone_name: milestone
|
||||
current_plan: 1
|
||||
status: executing
|
||||
last_updated: "2026-04-24T16:11:23.051Z"
|
||||
last_updated: "2026-04-24T17:39:22.205Z"
|
||||
progress:
|
||||
total_phases: 11
|
||||
completed_phases: 0
|
||||
total_plans: 7
|
||||
completed_plans: 0
|
||||
percent: 0
|
||||
completed_plans: 4
|
||||
percent: 57
|
||||
---
|
||||
|
||||
# Project State: Recipe
|
||||
@@ -25,11 +25,11 @@ progress:
|
||||
|
||||
## Current Position
|
||||
|
||||
Phase: 01 (Project Infrastructure & Module Wiring) — EXECUTING
|
||||
Plan: 1 of 7
|
||||
**Current focus:** Phase 01 — Project Infrastructure & Module Wiring
|
||||
Phase: --phase (01) — EXECUTING
|
||||
Plan: 1 of --name
|
||||
**Current focus:** Phase --phase — 01
|
||||
**Current plan:** 1
|
||||
**Status:** Executing Phase 01
|
||||
**Status:** Executing Phase --phase
|
||||
**Phase progress:** 0 / 11 phases complete
|
||||
**Progress bar:** `░░░░░░░░░░░░░░░░░░░░` 0%
|
||||
|
||||
|
||||
@@ -53,3 +53,17 @@ kotlin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Relax allWarningsAsErrors for KLIB-merging metadata tasks. KotlinCompileCommon
|
||||
// aggregates dependency KLIBs and surfaces upstream "duplicated unique_name"
|
||||
// resolver warnings caused by androidx.lifecycle 2.10.0 (Android-only) and
|
||||
// org.jetbrains.androidx.lifecycle 2.10.0 (CMP) co-publishing artifacts with
|
||||
// matching KLIB unique_names. This is an upstream Compose-Multiplatform 1.10 +
|
||||
// lifecycle 2.10 ecosystem condition (KT-62515-style), not actionable in our
|
||||
// source — so we keep -Werror on real source compilation tasks but disable it
|
||||
// for the metadata-aggregation step where no user code is being compiled.
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompileCommon>().configureEach {
|
||||
compilerOptions {
|
||||
allWarningsAsErrors.set(false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
plugins {
|
||||
// AGP must apply BEFORE recipe.kotlin.multiplatform — the latter calls androidTarget(),
|
||||
// which requires the Android Gradle Plugin to already be on the project. Gradle applies
|
||||
// plugin IDs in declaration order, so recipe.android.application is listed first.
|
||||
id("recipe.android.application")
|
||||
id("recipe.kotlin.multiplatform")
|
||||
id("recipe.compose.multiplatform")
|
||||
id("recipe.android.application")
|
||||
id("recipe.quality")
|
||||
}
|
||||
|
||||
|
||||
@@ -10,12 +10,15 @@ import androidx.compose.foundation.layout.safeContentPadding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
|
||||
import recipe.composeapp.generated.resources.Res
|
||||
import recipe.composeapp.generated.resources.compose_multiplatform
|
||||
|
||||
@@ -25,7 +28,8 @@ fun App() {
|
||||
MaterialTheme {
|
||||
var showContent by remember { mutableStateOf(false) }
|
||||
Column(
|
||||
modifier = Modifier
|
||||
modifier =
|
||||
Modifier
|
||||
.background(MaterialTheme.colorScheme.primaryContainer)
|
||||
.safeContentPadding()
|
||||
.fillMaxSize(),
|
||||
|
||||
@@ -3,6 +3,7 @@ package dev.ulfrx.recipe.di
|
||||
import org.koin.dsl.module
|
||||
|
||||
// Phase 2 adds authModule; Phase 4 adds syncModule; Phase 5 adds catalogModule; etc.
|
||||
val appModule = module {
|
||||
val appModule =
|
||||
module {
|
||||
// intentionally empty in Phase 1
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ import org.koin.core.KoinApplication
|
||||
import org.koin.core.context.startKoin
|
||||
import org.koin.dsl.KoinAppDeclaration
|
||||
|
||||
fun initKoin(config: KoinAppDeclaration? = null): KoinApplication = startKoin {
|
||||
fun initKoin(config: KoinAppDeclaration? = null): KoinApplication =
|
||||
startKoin {
|
||||
config?.invoke(this)
|
||||
modules(appModule)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class ComposeAppCommonTest {
|
||||
|
||||
@Test
|
||||
fun example() {
|
||||
assertEquals(3, 1 + 2)
|
||||
|
||||
@@ -17,7 +17,9 @@ fun main() {
|
||||
}
|
||||
|
||||
@Serializable
|
||||
private data class Health(val status: String)
|
||||
private data class Health(
|
||||
val status: String,
|
||||
)
|
||||
|
||||
fun Application.module() {
|
||||
install(ContentNegotiation) {
|
||||
|
||||
@@ -8,14 +8,24 @@ object Database {
|
||||
private val log = LoggerFactory.getLogger(Database::class.java)
|
||||
|
||||
fun migrate(app: Application) {
|
||||
val url = app.environment.config.property("database.url").getString()
|
||||
val user = app.environment.config.property("database.user").getString()
|
||||
val password = app.environment.config.property("database.password").getString()
|
||||
val url =
|
||||
app.environment.config
|
||||
.property("database.url")
|
||||
.getString()
|
||||
val user =
|
||||
app.environment.config
|
||||
.property("database.user")
|
||||
.getString()
|
||||
val password =
|
||||
app.environment.config
|
||||
.property("database.password")
|
||||
.getString()
|
||||
|
||||
log.info("Connecting to {} as {} and running Flyway migrations", url, user)
|
||||
|
||||
runCatching {
|
||||
Flyway.configure()
|
||||
Flyway
|
||||
.configure()
|
||||
.dataSource(url, user, password)
|
||||
.locations("classpath:db/migration")
|
||||
.baselineOnMigrate(true)
|
||||
|
||||
@@ -12,9 +12,9 @@ import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class ApplicationTest {
|
||||
|
||||
@Test
|
||||
fun `health endpoint returns 200 with status ok`() = testApplication {
|
||||
fun `health endpoint returns 200 with status ok`() =
|
||||
testApplication {
|
||||
application {
|
||||
install(ContentNegotiation) {
|
||||
json()
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
plugins {
|
||||
// AGP must apply BEFORE recipe.kotlin.multiplatform — the latter calls androidTarget(),
|
||||
// which requires the Android Gradle Plugin to already be on the project. Gradle applies
|
||||
// plugin IDs in declaration order, so com.android.library is listed first.
|
||||
alias(libs.plugins.androidLibrary)
|
||||
id("recipe.kotlin.multiplatform")
|
||||
id("recipe.quality")
|
||||
alias(libs.plugins.androidLibrary)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
@@ -25,12 +28,18 @@ kotlin {
|
||||
|
||||
android {
|
||||
namespace = "dev.ulfrx.recipe.shared"
|
||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||
compileSdk =
|
||||
libs.versions.android.compileSdk
|
||||
.get()
|
||||
.toInt()
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
defaultConfig {
|
||||
minSdk = libs.versions.android.minSdk.get().toInt()
|
||||
minSdk =
|
||||
libs.versions.android.minSdk
|
||||
.get()
|
||||
.toInt()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ package dev.ulfrx.recipe
|
||||
|
||||
import android.os.Build
|
||||
|
||||
class AndroidPlatform : Platform {
|
||||
public class AndroidPlatform : Platform {
|
||||
override val name: String = "Android ${Build.VERSION.SDK_INT}"
|
||||
}
|
||||
|
||||
actual fun getPlatform(): Platform = AndroidPlatform()
|
||||
public actual fun getPlatform(): Platform = AndroidPlatform()
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
package dev.ulfrx.recipe
|
||||
|
||||
const val SERVER_PORT = 8080
|
||||
public const val SERVER_PORT: Int = 8080
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package dev.ulfrx.recipe
|
||||
|
||||
class Greeting {
|
||||
public class Greeting {
|
||||
private val platform = getPlatform()
|
||||
|
||||
fun greet(): String {
|
||||
return "Hello, ${platform.name}!"
|
||||
}
|
||||
public fun greet(): String = "Hello, ${platform.name}!"
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package dev.ulfrx.recipe
|
||||
|
||||
interface Platform {
|
||||
val name: String
|
||||
public interface Platform {
|
||||
public val name: String
|
||||
}
|
||||
|
||||
expect fun getPlatform(): Platform
|
||||
public expect fun getPlatform(): Platform
|
||||
|
||||
@@ -4,7 +4,6 @@ import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class SharedCommonTest {
|
||||
|
||||
@Test
|
||||
fun example() {
|
||||
assertEquals(3, 1 + 2)
|
||||
|
||||
@@ -2,8 +2,8 @@ package dev.ulfrx.recipe
|
||||
|
||||
import platform.UIKit.UIDevice
|
||||
|
||||
class IOSPlatform : Platform {
|
||||
public class IOSPlatform : Platform {
|
||||
override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
|
||||
}
|
||||
|
||||
actual fun getPlatform(): Platform = IOSPlatform()
|
||||
public actual fun getPlatform(): Platform = IOSPlatform()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package dev.ulfrx.recipe
|
||||
|
||||
class JVMPlatform : Platform {
|
||||
public class JVMPlatform : Platform {
|
||||
override val name: String = "Java ${System.getProperty("java.version")}"
|
||||
}
|
||||
|
||||
actual fun getPlatform(): Platform = JVMPlatform()
|
||||
public actual fun getPlatform(): Platform = JVMPlatform()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package dev.ulfrx.recipe
|
||||
|
||||
class WasmPlatform : Platform {
|
||||
public class WasmPlatform : Platform {
|
||||
override val name: String = "Web with Kotlin/Wasm"
|
||||
}
|
||||
|
||||
actual fun getPlatform(): Platform = WasmPlatform()
|
||||
public actual fun getPlatform(): Platform = WasmPlatform()
|
||||
|
||||
Reference in New Issue
Block a user