用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/navikt/copilot --skill ktor-scaffold命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | ktor-scaffold |
| description | Scaffold eit nytt Ktor-prosjekt med Kotliquery, Flyway, Koin og Nais-konfigurasjon |
| license | MIT |
| compatibility | Kotlin with Ktor on Nais |
| metadata | {"domain":"backend","tags":"kotlin ktor scaffold nais kotliquery"} |
Scaffold a new Kotlin/Ktor service following Nav's standard patterns. This skill composes patterns from existing Nav skills and instructions.
Use these skills for deeper guidance on specific areas:
| Skill | When |
|---|---|
kotlin-app-config | Sealed class configuration pattern |
flyway-migration | Database migration scripts |
tokenx-auth | Service-to-service authentication |
observability-setup | Prometheus metrics and health endpoints |
api-design | REST API conventions and error handling |
Generate this directory layout:
my-service/
├── build.gradle.kts
├── settings.gradle.kts
├── gradle/
│ └── libs.versions.toml
├── src/
│ ├── main/
│ │ ├── kotlin/no/nav/myservice/
│ │ │ ├── Application.kt
│ │ │ ├── Config.kt
│ │ │ ├── Routes.kt
│ │ │ ├── Database.kt
│ │ │ └── domain/
│ │ └── resources/
│ │ ├── db/migration/
│ │ │ └── V1__initial_schema.sql
│ │ └── logback.xml
│ └── test/
│ └── kotlin/no/nav/myservice/
│ └── ApplicationTest.kt
├── .nais/
│ ├── app.yaml
│ └── app-dev.yaml
└── Dockerfile
[versions]
kotlin = "2.3.20"
ktor = "3.4.2"
kotliquery = "1.9.1"
hikaricp = "7.0.2"
flyway = "12.2.0"
postgresql = "42.7.10"
koin = "4.2.0"
logback = "1.5.32"
logstash = "9.0"
micrometer = "1.16.4"
kotest = "6.1.10"
mockk = "1.14.9"
testcontainers = "2.0.4"
mockOAuth2 = "3.0.1"
[libraries]
ktor-server-core = { module = "io.ktor:ktor-server-core", version.ref = "ktor" }
ktor-server-netty = { module = "io.ktor:ktor-server-netty", version.ref = "ktor" }
ktor-server-content-negotiation = { module = "io.ktor:ktor-server-content-negotiation", version.ref = "ktor" }
ktor-serialization-jackson = { module = "io.ktor:ktor-serialization-jackson", version.ref = "ktor" }
ktor-server-auth = { module = "io.ktor:ktor-server-auth", version.ref = "ktor" }
ktor-server-auth-jwt = { module = "io.ktor:ktor-server-auth-jwt", version.ref = "ktor" }
ktor-server-metrics-micrometer = { module = "io.ktor:ktor-server-metrics-micrometer", version.ref = }
= { module = , version.ref = }
= { module = , version.ref = }
= { module = , version.ref = }
= { module = , version.ref = }
= { module = , version.ref = }
= { module = , version.ref = }
= { module = , version.ref = }
= { module = , version.ref = }
= { module = , version.ref = }
= { module = , version.ref = }
= { module = , version.ref = }
= { module = , version.ref = }
= { module = , version.ref = }
= { module = , version.ref = }
= { module = , version.ref = }
= { module = , version.ref = }
plugins {
kotlin("jvm") version "2.1.10"
id("com.gradleup.shadow") version "9.0.0-beta6"
}
application {
mainClass.set("no.nav.myservice.ApplicationKt")
}
dependencies {
implementation(libs.ktor.server.core)
implementation(libs.ktor.server.netty)
implementation(libs.ktor.server.content.negotiation)
implementation(libs.ktor.serialization.jackson)
implementation(libs.ktor.server.auth)
implementation(libs.ktor.server.auth.jwt)
implementation(libs.ktor.server.metrics.micrometer)
implementation(libs.kotliquery)
implementation(libs.hikaricp)
implementation(libs.flyway.core)
implementation(libs.flyway.postgres)
runtimeOnly(libs.postgresql)
implementation(libs.koin.ktor)
implementation(libs.koin.logger.slf4j)
implementation(libs.logback.classic)
implementation(libs.logstash.encoder)
implementation(libs.micrometer.prometheus)
testImplementation(libs.ktor.server.test.host)
testImplementation(libs.kotest.runner)
testImplementation(libs.kotest.assertions)
testImplementation(libs.mockk)
testImplementation(libs.testcontainers.postgres)
testImplementation(libs.mock.oauth2.server)
}
tasks.test {
useJUnitPlatform()
}
package no.nav.myservice
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import org.koin.ktor.plugin.Koin
fun main() {
val config = Config.from(System.getenv())
Database.migrate(config.database)
embeddedServer(Netty, port = 8080) {
install(Koin) {
modules(appModule(config))
}
configureRouting()
configureSerialization()
configureMonitoring()
}.start(wait = true)
}
Use the sealed class pattern from kotlin-app-config skill:
package no.nav.myservice
sealed class Config(
val database: DatabaseConfig,
) {
data class Dev(private val env: Map<String, String>) : Config(
database = DatabaseConfig(
url = env.getValue("DATABASE_URL"),
username = env.getValue("DATABASE_USERNAME"),
password = env.getValue("DATABASE_PASSWORD"),
),
)
data class Prod(private val env: Map<String, String>) : Config(
database = DatabaseConfig(
url = env.getValue("DATABASE_URL"),
username = env.getValue("DATABASE_USERNAME"),
password = env.getValue("DATABASE_PASSWORD"),
),
)
data object Local : Config(
database = DatabaseConfig(
url = "jdbc:postgresql://localhost:5432/myservice",
username = "postgres",
password = "postgres",
),
)
companion object {
fun from(env: Map<String, String>): Config = when (env["NAIS_CLUSTER_NAME"]) {
"dev-gcp" -> Dev(env)
"prod-gcp" -> Prod(env)
else -> Local
}
}
}
data class DatabaseConfig(val url: String, username: String = , password: String = )
package no.nav.myservice
import com.zaxxer.hikari.HikariDataSource
import kotliquery.queryOf
import kotliquery.sessionOf
import kotliquery.using
import org.flywaydb.core.Flyway
import javax.sql.DataSource
object Database {
fun dataSource(config: DatabaseConfig): HikariDataSource = HikariDataSource().apply {
jdbcUrl = config.url
username = config.username
password = config.password
maximumPoolSize = 10
minimumIdle = 2
}
fun migrate(config: DatabaseConfig) {
Flyway.configure()
.dataSource(config.url, config.username, config.password)
.load()
.migrate()
}
}
FROM gradle:8-jdk21 AS build
WORKDIR /app
COPY build.gradle.kts settings.gradle.kts ./
COPY gradle ./gradle
RUN gradle dependencies --no-daemon
COPY src ./src
RUN gradle shadowJar --no-daemon
FROM europe-north1-docker.pkg.dev/cgr-nav/pull-through/nav.no/jre:openjdk-21
WORKDIR /app
COPY --from=build /app/build/libs/*-all.jar app.jar
CMD ["-jar", "app.jar"]
Generate using the nais-manifest prompt, ensuring:
gcp.sqlInstances/metrics/isalive and /isreadyAfter scaffolding, run:
./gradlew build
./gradlew test