[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6E214WFY1J4ATHVBART41JP":3,"skill-same:01M6E214WFY1J4ATHVBART41JP":62},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":29,"linkOnly":30,"markdownContent":31,"markdownBody":32,"frontMatter":33,"refName":35,"commitSha":36,"skillDirectory":37,"forksCount":13,"repositoryHtmlUrl":38,"repositoryHomepageUrl":39,"ownerHtmlUrl":40,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":41,"install":42,"resources":55},"01M6E214WFY1J4ATHVBART41JP","kotlin-patterns",null,"Coroutine'ler, null safety ve DSL builder'lar ile sağlam, verimli ve sürdürülebilir Kotlin uygulamaları oluşturmak için idiomatic Kotlin kalıpları, en iyi uygulamalar ve konvansiyonlar.","7dvq6yrkgs-stack\u002Fplaywright","7dvq6yrkgs-stack","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F251638143?v=4","01M6E061J2AMGWYZ6TK7Y8NM74","01M6E061PQCQJGQMPBERMCFN5G",0,"Apache-2.0","https:\u002F\u002Fgithub.com\u002F7dvq6yrkgs-stack\u002Fplaywright\u002Fblob\u002Fmain\u002Fskills\u002Fkotlin-patterns\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",[23,24,25,26,27,28],"kotlin patterns","kotlin","patterns","Safety","builder","en","2026-11-10 10:12:30",false,"---\nname: kotlin-patterns\ndescription: Coroutine'ler, null safety ve DSL builder'lar ile sağlam, verimli ve sürdürülebilir Kotlin uygulamaları oluşturmak için idiomatic Kotlin kalıpları, en iyi uygulamalar ve konvansiyonlar.\norigin: ECC\n---\n\n# Kotlin Geliştirme Kalıpları\n\nSağlam, verimli ve sürdürülebilir uygulamalar oluşturmak için idiomatic Kotlin kalıpları ve en iyi uygulamalar.\n\n## Ne Zaman Kullanılır\n\n- Yeni Kotlin kodu yazarken\n- Kotlin kodunu incelerken\n- Mevcut Kotlin kodunu refactor ederken\n- Kotlin modülleri veya kütüphaneleri tasarlarken\n- Gradle Kotlin DSL build'lerini yapılandırırken\n\n## Nasıl Çalışır\n\nBu skill yedi temel alanda idiomatic Kotlin konvansiyonlarını uygular: tip sistemi ve safe-call operatörleri kullanarak null safety, `val` ve data class'larda `copy()` ile immutability, exhaustive tip hiyerarşileri için sealed class'lar ve interface'ler, coroutine'ler ve `Flow` ile yapılandırılmış eşzamanlılık, inheritance olmadan davranış eklemek için extension fonksiyonlar, `@DslMarker` ve lambda receiver'lar kullanarak tip güvenli DSL builder'lar, ve build yapılandırması için Gradle Kotlin DSL.\n\n## Örnekler\n\n**Elvis operatörü ile null safety:**\n```kotlin\nfun getUserEmail(userId: String): String {\n    val user = userRepository.findById(userId)\n    return user?.email ?: \"unknown@example.com\"\n}\n```\n\n**Exhaustive sonuçlar için sealed class:**\n```kotlin\nsealed class Result\u003Cout T> {\n    data class Success\u003CT>(val data: T) : Result\u003CT>()\n    data class Failure(val error: AppError) : Result\u003CNothing>()\n    data object Loading : Result\u003CNothing>()\n}\n```\n\n**async\u002Fawait ile yapılandırılmış eşzamanlılık:**\n```kotlin\nsuspend fun fetchUserWithPosts(userId: String): UserProfile =\n    coroutineScope {\n        val user = async { userService.getUser(userId) }\n        val posts = async { postService.getUserPosts(userId) }\n        UserProfile(user = user.await(), posts = posts.await())\n    }\n```\n\n## Temel İlkeler\n\n### 1. Null Safety\n\nKotlin'in tip sistemi nullable ve non-nullable tipleri ayırır. Tam olarak kullanın.\n\n```kotlin\n\u002F\u002F İyi: Varsayılan olarak non-nullable tipler kullan\nfun getUser(id: String): User {\n    return userRepository.findById(id)\n        ?: throw UserNotFoundException(\"User $id not found\")\n}\n\n\u002F\u002F İyi: Safe call'lar ve Elvis operatörü\nfun getUserEmail(userId: String): String {\n    val user = userRepository.findById(userId)\n    return user?.email ?: \"unknown@example.com\"\n}\n\n\u002F\u002F Kötü: Nullable tipleri zorla açma\nfun getUserEmail(userId: String): String {\n    val user = userRepository.findById(userId)\n    return user!!.email \u002F\u002F null ise NPE fırlatır\n}\n```\n\n### 2. Varsayılan Olarak Immutability\n\n`var` yerine `val` tercih edin, mutable koleksiyonlar yerine immutable olanları.\n\n```kotlin\n\u002F\u002F İyi: Immutable veri\ndata class User(\n    val id: String,\n    val name: String,\n    val email: String,\n)\n\n\u002F\u002F İyi: copy() ile dönüştürme\nfun updateEmail(user: User, newEmail: String): User =\n    user.copy(email = newEmail)\n\n\u002F\u002F İyi: Immutable koleksiyonlar\nval users: List\u003CUser> = listOf(user1, user2)\nval filtered = users.filter { it.email.isNotBlank() }\n\n\u002F\u002F Kötü: Mutable state\nvar currentUser: User? = null \u002F\u002F Mutable global state'ten kaçın\nval mutableUsers = mutableListOf\u003CUser>() \u002F\u002F Gerçekten gerekmedikçe kaçın\n```\n\n### 3. Expression Body'ler ve Tek İfadeli Fonksiyonlar\n\nKısa, okunabilir fonksiyonlar için expression body'ler kullanın.\n\n```kotlin\n\u002F\u002F İyi: Expression body\nfun isAdult(age: Int): Boolean = age >= 18\n\nfun formatFullName(first: String, last: String): String =\n    \"$first $last\".trim()\n\nfun User.displayName(): String =\n    name.ifBlank { email.substringBefore('@') }\n\n\u002F\u002F İyi: Expression olarak when\nfun statusMessage(code: Int): String = when (code) {\n    200 -> \"OK\"\n    404 -> \"Not Found\"\n    500 -> \"Internal Server Error\"\n    else -> \"Unknown status: $code\"\n}\n\n\u002F\u002F Kötü: Gereksiz block body\nfun isAdult(age: Int): Boolean {\n    return age >= 18\n}\n```\n\n### 4. Value Objeler İçin Data Class'lar\n\nÖncelikle veri tutan tipler için data class'lar kullanın.\n\n```kotlin\n\u002F\u002F İyi: copy, equals, hashCode, toString ile data class\ndata class CreateUserRequest(\n    val name: String,\n    val email: String,\n    val role: Role = Role.USER,\n)\n\n\u002F\u002F İyi: Tip güvenliği için value class (runtime'da sıfır maliyet)\n@JvmInline\nvalue class UserId(val value: String) {\n    init {\n        require(value.isNotBlank()) { \"UserId cannot be blank\" }\n    }\n}\n\n@JvmInline\nvalue class Email(val value: String) {\n    init {\n        require('@' in value) { \"Invalid email: $value\" }\n    }\n}\n\nfun getUser(id: UserId): User = userRepository.findById(id)\n```\n\n## Sealed Class'lar ve Interface'ler\n\n### Kısıtlı Hiyerarşileri Modelleme\n\n```kotlin\n\u002F\u002F İyi: Exhaustive when için sealed class\nsealed class Result\u003Cout T> {\n    data class Success\u003CT>(val data: T) : Result\u003CT>()\n    data class Failure(val error: AppError) : Result\u003CNothing>()\n    data object Loading : Result\u003CNothing>()\n}\n\nfun \u003CT> Result\u003CT>.getOrNull(): T? = when (this) {\n    is Result.Success -> data\n    is Result.Failure -> null\n    is Result.Loading -> null\n}\n\nfun \u003CT> Result\u003CT>.getOrThrow(): T = when (this) {\n    is Result.Success -> data\n    is Result.Failure -> throw error.toException()\n    is Result.Loading -> throw IllegalStateException(\"Still loading\")\n}\n```\n\n### API Yanıtları İçin Sealed Interface'ler\n\n```kotlin\nsealed interface ApiError {\n    val message: String\n\n    data class NotFound(override val message: String) : ApiError\n    data class Unauthorized(override val message: String) : ApiError\n    data class Validation(\n        override val message: String,\n        val field: String,\n    ) : ApiError\n    data class Internal(\n        override val message: String,\n        val cause: Throwable? = null,\n    ) : ApiError\n}\n\nfun ApiError.toStatusCode(): Int = when (this) {\n    is ApiError.NotFound -> 404\n    is ApiError.Unauthorized -> 401\n    is ApiError.Validation -> 422\n    is ApiError.Internal -> 500\n}\n```\n\n## Scope Fonksiyonlar\n\n### Her Birini Ne Zaman Kullanmalı\n\n```kotlin\n\u002F\u002F let: Nullable'ı veya scope edilmiş sonucu dönüştür\nval length: Int? = name?.let { it.trim().length }\n\n\u002F\u002F apply: Bir nesneyi yapılandır (nesneyi döndürür)\nval user = User().apply {\n    name = \"Alice\"\n    email = \"alice@example.com\"\n}\n\n\u002F\u002F also: Yan etkiler (nesneyi döndürür)\nval user = createUser(request).also { logger.info(\"Created user: ${it.id}\") }\n\n\u002F\u002F run: Receiver ile block çalıştır (sonucu döndürür)\nval result = connection.run {\n    prepareStatement(sql)\n    executeQuery()\n}\n\n\u002F\u002F with: run'ın extension olmayan formu\nval csv = with(StringBuilder()) {\n    appendLine(\"name,email\")\n    users.forEach { appendLine(\"${it.name},${it.email}\") }\n    toString()\n}\n```\n\n## Extension Fonksiyonlar\n\n### Inheritance Olmadan Fonksiyonalite Ekleme\n\n```kotlin\n\u002F\u002F İyi: Domain'e özgü extension'lar\nfun String.toSlug(): String =\n    lowercase()\n        .replace(Regex(\"[^a-z0-9\\\\s-]\"), \"\")\n        .replace(Regex(\"\\\\s+\"), \"-\")\n        .trim('-')\n\nfun Instant.toLocalDate(zone: ZoneId = ZoneId.systemDefault()): LocalDate =\n    atZone(zone).toLocalDate()\n\n\u002F\u002F İyi: Koleksiyon extension'ları\nfun \u003CT> List\u003CT>.second(): T = this[1]\n\nfun \u003CT> List\u003CT>.secondOrNull(): T? = getOrNull(1)\n\n\u002F\u002F İyi: Scope edilmiş extension'lar (global namespace'i kirletmez)\nclass UserService {\n    private fun User.isActive(): Boolean =\n        status == Status.ACTIVE && lastLogin.isAfter(Instant.now().minus(30, ChronoUnit.DAYS))\n\n    fun getActiveUsers(): List\u003CUser> = userRepository.findAll().filter { it.isActive() }\n}\n```\n\n## Coroutine'ler\n\n### Yapılandırılmış Eşzamanlılık\n\n```kotlin\n\u002F\u002F İyi: coroutineScope ile yapılandırılmış eşzamanlılık\nsuspend fun fetchUserWithPosts(userId: String): UserProfile =\n    coroutineScope {\n        val userDeferred = async { userService.getUser(userId) }\n        val postsDeferred = async { postService.getUserPosts(userId) }\n\n        UserProfile(\n            user = userDeferred.await(),\n            posts = postsDeferred.await(),\n        )\n    }\n\n\u002F\u002F İyi: child'lar bağımsız başarısız olabildiğinde supervisorScope\nsuspend fun fetchDashboard(userId: String): Dashboard =\n    supervisorScope {\n        val user = async { userService.getUser(userId) }\n        val notifications = async { notificationService.getRecent(userId) }\n        val recommendations = async { recommendationService.getFor(userId) }\n\n        Dashboard(\n            user = user.await(),\n            notifications = try {\n                notifications.await()\n            } catch (e: CancellationException) {\n                throw e\n            } catch (e: Exception) {\n                emptyList()\n            },\n            recommendations = try {\n                recommendations.await()\n            } catch (e: CancellationException) {\n                throw e\n            } catch (e: Exception) {\n                emptyList()\n            },\n        )\n    }\n```\n\n### Reactive Stream'ler İçin Flow\n\n```kotlin\n\u002F\u002F İyi: Uygun hata işleme ile cold flow\nfun observeUsers(): Flow\u003CList\u003CUser>> = flow {\n    while (currentCoroutineContext().isActive) {\n        val users = userRepository.findAll()\n        emit(users)\n        delay(5.seconds)\n    }\n}.catch { e ->\n    logger.error(\"Error observing users\", e)\n    emit(emptyList())\n}\n\n\u002F\u002F İyi: Flow operatörleri\nfun searchUsers(query: Flow\u003CString>): Flow\u003CList\u003CUser>> =\n    query\n        .debounce(300.milliseconds)\n        .distinctUntilChanged()\n        .filter { it.length >= 2 }\n        .mapLatest { q -> userRepository.search(q) }\n        .catch { emit(emptyList()) }\n```\n\n## DSL Builder'lar\n\n### Tip Güvenli Builder'lar\n\n```kotlin\n\u002F\u002F İyi: @DslMarker ile DSL\n@DslMarker\nannotation class HtmlDsl\n\n@HtmlDsl\nclass HTML {\n    private val children = mutableListOf\u003CElement>()\n\n    fun head(init: Head.() -> Unit) {\n        children += Head().apply(init)\n    }\n\n    fun body(init: Body.() -> Unit) {\n        children += Body().apply(init)\n    }\n\n    override fun toString(): String = children.joinToString(\"\\n\")\n}\n\nfun html(init: HTML.() -> Unit): HTML = HTML().apply(init)\n\n\u002F\u002F Kullanım\nval page = html {\n    head { title(\"My Page\") }\n    body {\n        h1(\"Welcome\")\n        p(\"Hello, World!\")\n    }\n}\n```\n\n## Gradle Kotlin DSL\n\n### build.gradle.kts Yapılandırması\n\n```kotlin\n\u002F\u002F En son versiyonları kontrol et: https:\u002F\u002Fkotlinlang.org\u002Fdocs\u002Freleases.html\nplugins {\n    kotlin(\"jvm\") version \"2.3.10\"\n    kotlin(\"plugin.serialization\") version \"2.3.10\"\n    id(\"io.ktor.plugin\") version \"3.4.0\"\n    id(\"org.jetbrains.kotlinx.kover\") version \"0.9.7\"\n    id(\"io.gitlab.arturbosch.detekt\") version \"1.23.8\"\n}\n\ngroup = \"com.example\"\nversion = \"1.0.0\"\n\nkotlin {\n    jvmToolchain(21)\n}\n\ndependencies {\n    \u002F\u002F Ktor\n    implementation(\"io.ktor:ktor-server-core:3.4.0\")\n    implementation(\"io.ktor:ktor-server-netty:3.4.0\")\n    implementation(\"io.ktor:ktor-server-content-negotiation:3.4.0\")\n    implementation(\"io.ktor:ktor-serialization-kotlinx-json:3.4.0\")\n\n    \u002F\u002F Exposed\n    implementation(\"org.jetbrains.exposed:exposed-core:1.0.0\")\n    implementation(\"org.jetbrains.exposed:exposed-dao:1.0.0\")\n    implementation(\"org.jetbrains.exposed:exposed-jdbc:1.0.0\")\n    implementation(\"org.jetbrains.exposed:exposed-kotlin-datetime:1.0.0\")\n\n    \u002F\u002F Koin\n    implementation(\"io.insert-koin:koin-ktor:4.2.0\")\n\n    \u002F\u002F Coroutines\n    implementation(\"org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2\")\n\n    \u002F\u002F Test\n    testImplementation(\"io.kotest:kotest-runner-junit5:6.1.4\")\n    testImplementation(\"io.kotest:kotest-assertions-core:6.1.4\")\n    testImplementation(\"io.kotest:kotest-property:6.1.4\")\n    testImplementation(\"io.mockk:mockk:1.14.9\")\n    testImplementation(\"io.ktor:ktor-server-test-host:3.4.0\")\n    testImplementation(\"org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2\")\n}\n\ntasks.withType\u003CTest> {\n    useJUnitPlatform()\n}\n\ndetekt {\n    config.setFrom(files(\"config\u002Fdetekt\u002Fdetekt.yml\"))\n    buildUponDefaultConfig = true\n}\n```\n\n## Hata İşleme Kalıpları\n\n### Domain Operasyonları İçin Result Tipi\n\n```kotlin\n\u002F\u002F İyi: Kotlin'in Result'ını veya özel sealed class kullan\nsuspend fun createUser(request: CreateUserRequest): Result\u003CUser> = runCatching {\n    require(request.name.isNotBlank()) { \"Name cannot be blank\" }\n    require('@' in request.email) { \"Invalid email format\" }\n\n    val user = User(\n        id = UserId(UUID.randomUUID().toString()),\n        name = request.name,\n        email = Email(request.email),\n    )\n    userRepository.save(user)\n    user\n}\n\n\u002F\u002F İyi: Result'ları zincirle\nval displayName = createUser(request)\n    .map { it.name }\n    .getOrElse { \"Unknown\" }\n```\n\n### require, check, error\n\n```kotlin\n\u002F\u002F İyi: Net mesajlarla ön koşullar\nfun withdraw(account: Account, amount: Money): Account {\n    require(amount.value > 0) { \"Amount must be positive: $amount\" }\n    check(account.balance >= amount) { \"Insufficient balance: ${account.balance} \u003C $amount\" }\n\n    return account.copy(balance = account.balance - amount)\n}\n```\n\n## Hızlı Referans: Kotlin İdiyomları\n\n| İdiyom | Açıklama |\n|-------|-------------|\n| `val` over `var` | Immutable değişkenleri tercih et |\n| `data class` | equals\u002FhashCode\u002Fcopy ile value objeler için |\n| `sealed class\u002Finterface` | Kısıtlı tip hiyerarşileri için |\n| `value class` | Sıfır maliyetli tip güvenli sarmalayıcılar için |\n| Expression `when` | Exhaustive pattern matching |\n| Safe call `?.` | Null-safe member erişimi |\n| Elvis `?:` | Nullable'lar için varsayılan değer |\n| `let`\u002F`apply`\u002F`also`\u002F`run`\u002F`with` | Temiz kod için scope fonksiyonlar |\n| Extension fonksiyonlar | Inheritance olmadan davranış ekle |\n| `copy()` | Data class'larda immutable güncellemeler |\n| `require`\u002F`check` | Ön koşul assertion'ları |\n| Coroutine `async`\u002F`await` | Yapılandırılmış concurrent execution |\n| `Flow` | Cold reactive stream'ler |\n| `sequence` | Lazy evaluation |\n| Delegation `by` | Inheritance olmadan implementasyonu yeniden kullan |\n\n## Kaçınılması Gereken Anti-Kalıplar\n\n```kotlin\n\u002F\u002F Kötü: Nullable tipleri zorla açma\nval name = user!!.name\n\n\u002F\u002F Kötü: Java'dan platform tipi sızıntısı\nfun getLength(s: String) = s.length \u002F\u002F Güvenli\nfun getLength(s: String?) = s?.length ?: 0 \u002F\u002F Java'dan null'ları işle\n\n\u002F\u002F Kötü: Mutable data class'lar\ndata class MutableUser(var name: String, var email: String)\n\n\u002F\u002F Kötü: Kontrol akışı için exception kullanma\ntry {\n    val user = findUser(id)\n} catch (e: NotFoundException) {\n    \u002F\u002F Beklenen durumlar için exception kullanma\n}\n\n\u002F\u002F İyi: Nullable dönüş veya Result kullan\nval user: User? = findUserOrNull(id)\n\n\u002F\u002F Kötü: Coroutine scope'u görmezden gelme\nGlobalScope.launch { \u002F* GlobalScope'tan kaçın *\u002F }\n\n\u002F\u002F İyi: Yapılandırılmış eşzamanlılık kullan\ncoroutineScope {\n    launch { \u002F* Uygun şekilde scope edilmiş *\u002F }\n}\n\n\u002F\u002F Kötü: Derin iç içe scope fonksiyonlar\nuser?.let { u ->\n    u.address?.let { a ->\n        a.city?.let { c -> process(c) }\n    }\n}\n\n\u002F\u002F İyi: Doğrudan null-safe zincir\nuser?.address?.city?.let { process(it) }\n```\n\n**Hatırla**: Kotlin kodu kısa ama okunabilir olmalı. Güvenlik için tip sisteminden yararlanın, immutability tercih edin ve eşzamanlılık için coroutine'ler kullanın. Şüpheye düştüğünüzde, derleyicinin size yardım etmesine izin verin.\n","# Kotlin Geliştirme Kalıpları\n\nSağlam, verimli ve sürdürülebilir uygulamalar oluşturmak için idiomatic Kotlin kalıpları ve en iyi uygulamalar.\n\n## Ne Zaman Kullanılır\n\n- Yeni Kotlin kodu yazarken\n- Kotlin kodunu incelerken\n- Mevcut Kotlin kodunu refactor ederken\n- Kotlin modülleri veya kütüphaneleri tasarlarken\n- Gradle Kotlin DSL build'lerini yapılandırırken\n\n## Nasıl Çalışır\n\nBu skill yedi temel alanda idiomatic Kotlin konvansiyonlarını uygular: tip sistemi ve safe-call operatörleri kullanarak null safety, `val` ve data class'larda `copy()` ile immutability, exhaustive tip hiyerarşileri için sealed class'lar ve interface'ler, coroutine'ler ve `Flow` ile yapılandırılmış eşzamanlılık, inheritance olmadan davranış eklemek için extension fonksiyonlar, `@DslMarker` ve lambda receiver'lar kullanarak tip güvenli DSL builder'lar, ve build yapılandırması için Gradle Kotlin DSL.\n\n## Örnekler\n\n**Elvis operatörü ile null safety:**\n```kotlin\nfun getUserEmail(userId: String): String {\n    val user = userRepository.findById(userId)\n    return user?.email ?: \"unknown@example.com\"\n}\n```\n\n**Exhaustive sonuçlar için sealed class:**\n```kotlin\nsealed class Result\u003Cout T> {\n    data class Success\u003CT>(val data: T) : Result\u003CT>()\n    data class Failure(val error: AppError) : Result\u003CNothing>()\n    data object Loading : Result\u003CNothing>()\n}\n```\n\n**async\u002Fawait ile yapılandırılmış eşzamanlılık:**\n```kotlin\nsuspend fun fetchUserWithPosts(userId: String): UserProfile =\n    coroutineScope {\n        val user = async { userService.getUser(userId) }\n        val posts = async { postService.getUserPosts(userId) }\n        UserProfile(user = user.await(), posts = posts.await())\n    }\n```\n\n## Temel İlkeler\n\n### 1. Null Safety\n\nKotlin'in tip sistemi nullable ve non-nullable tipleri ayırır. Tam olarak kullanın.\n\n```kotlin\n\u002F\u002F İyi: Varsayılan olarak non-nullable tipler kullan\nfun getUser(id: String): User {\n    return userRepository.findById(id)\n        ?: throw UserNotFoundException(\"User $id not found\")\n}\n\n\u002F\u002F İyi: Safe call'lar ve Elvis operatörü\nfun getUserEmail(userId: String): String {\n    val user = userRepository.findById(userId)\n    return user?.email ?: \"unknown@example.com\"\n}\n\n\u002F\u002F Kötü: Nullable tipleri zorla açma\nfun getUserEmail(userId: String): String {\n    val user = userRepository.findById(userId)\n    return user!!.email \u002F\u002F null ise NPE fırlatır\n}\n```\n\n### 2. Varsayılan Olarak Immutability\n\n`var` yerine `val` tercih edin, mutable koleksiyonlar yerine immutable olanları.\n\n```kotlin\n\u002F\u002F İyi: Immutable veri\ndata class User(\n    val id: String,\n    val name: String,\n    val email: String,\n)\n\n\u002F\u002F İyi: copy() ile dönüştürme\nfun updateEmail(user: User, newEmail: String): User =\n    user.copy(email = newEmail)\n\n\u002F\u002F İyi: Immutable koleksiyonlar\nval users: List\u003CUser> = listOf(user1, user2)\nval filtered = users.filter { it.email.isNotBlank() }\n\n\u002F\u002F Kötü: Mutable state\nvar currentUser: User? = null \u002F\u002F Mutable global state'ten kaçın\nval mutableUsers = mutableListOf\u003CUser>() \u002F\u002F Gerçekten gerekmedikçe kaçın\n```\n\n### 3. Expression Body'ler ve Tek İfadeli Fonksiyonlar\n\nKısa, okunabilir fonksiyonlar için expression body'ler kullanın.\n\n```kotlin\n\u002F\u002F İyi: Expression body\nfun isAdult(age: Int): Boolean = age >= 18\n\nfun formatFullName(first: String, last: String): String =\n    \"$first $last\".trim()\n\nfun User.displayName(): String =\n    name.ifBlank { email.substringBefore('@') }\n\n\u002F\u002F İyi: Expression olarak when\nfun statusMessage(code: Int): String = when (code) {\n    200 -> \"OK\"\n    404 -> \"Not Found\"\n    500 -> \"Internal Server Error\"\n    else -> \"Unknown status: $code\"\n}\n\n\u002F\u002F Kötü: Gereksiz block body\nfun isAdult(age: Int): Boolean {\n    return age >= 18\n}\n```\n\n### 4. Value Objeler İçin Data Class'lar\n\nÖncelikle veri tutan tipler için data class'lar kullanın.\n\n```kotlin\n\u002F\u002F İyi: copy, equals, hashCode, toString ile data class\ndata class CreateUserRequest(\n    val name: String,\n    val email: String,\n    val role: Role = Role.USER,\n)\n\n\u002F\u002F İyi: Tip güvenliği için value class (runtime'da sıfır maliyet)\n@JvmInline\nvalue class UserId(val value: String) {\n    init {\n        require(value.isNotBlank()) { \"UserId cannot be blank\" }\n    }\n}\n\n@JvmInline\nvalue class Email(val value: String) {\n    init {\n        require('@' in value) { \"Invalid email: $value\" }\n    }\n}\n\nfun getUser(id: UserId): User = userRepository.findById(id)\n```\n\n## Sealed Class'lar ve Interface'ler\n\n### Kısıtlı Hiyerarşileri Modelleme\n\n```kotlin\n\u002F\u002F İyi: Exhaustive when için sealed class\nsealed class Result\u003Cout T> {\n    data class Success\u003CT>(val data: T) : Result\u003CT>()\n    data class Failure(val error: AppError) : Result\u003CNothing>()\n    data object Loading : Result\u003CNothing>()\n}\n\nfun \u003CT> Result\u003CT>.getOrNull(): T? = when (this) {\n    is Result.Success -> data\n    is Result.Failure -> null\n    is Result.Loading -> null\n}\n\nfun \u003CT> Result\u003CT>.getOrThrow(): T = when (this) {\n    is Result.Success -> data\n    is Result.Failure -> throw error.toException()\n    is Result.Loading -> throw IllegalStateException(\"Still loading\")\n}\n```\n\n### API Yanıtları İçin Sealed Interface'ler\n\n```kotlin\nsealed interface ApiError {\n    val message: String\n\n    data class NotFound(override val message: String) : ApiError\n    data class Unauthorized(override val message: String) : ApiError\n    data class Validation(\n        override val message: String,\n        val field: String,\n    ) : ApiError\n    data class Internal(\n        override val message: String,\n        val cause: Throwable? = null,\n    ) : ApiError\n}\n\nfun ApiError.toStatusCode(): Int = when (this) {\n    is ApiError.NotFound -> 404\n    is ApiError.Unauthorized -> 401\n    is ApiError.Validation -> 422\n    is ApiError.Internal -> 500\n}\n```\n\n## Scope Fonksiyonlar\n\n### Her Birini Ne Zaman Kullanmalı\n\n```kotlin\n\u002F\u002F let: Nullable'ı veya scope edilmiş sonucu dönüştür\nval length: Int? = name?.let { it.trim().length }\n\n\u002F\u002F apply: Bir nesneyi yapılandır (nesneyi döndürür)\nval user = User().apply {\n    name = \"Alice\"\n    email = \"alice@example.com\"\n}\n\n\u002F\u002F also: Yan etkiler (nesneyi döndürür)\nval user = createUser(request).also { logger.info(\"Created user: ${it.id}\") }\n\n\u002F\u002F run: Receiver ile block çalıştır (sonucu döndürür)\nval result = connection.run {\n    prepareStatement(sql)\n    executeQuery()\n}\n\n\u002F\u002F with: run'ın extension olmayan formu\nval csv = with(StringBuilder()) {\n    appendLine(\"name,email\")\n    users.forEach { appendLine(\"${it.name},${it.email}\") }\n    toString()\n}\n```\n\n## Extension Fonksiyonlar\n\n### Inheritance Olmadan Fonksiyonalite Ekleme\n\n```kotlin\n\u002F\u002F İyi: Domain'e özgü extension'lar\nfun String.toSlug(): String =\n    lowercase()\n        .replace(Regex(\"[^a-z0-9\\\\s-]\"), \"\")\n        .replace(Regex(\"\\\\s+\"), \"-\")\n        .trim('-')\n\nfun Instant.toLocalDate(zone: ZoneId = ZoneId.systemDefault()): LocalDate =\n    atZone(zone).toLocalDate()\n\n\u002F\u002F İyi: Koleksiyon extension'ları\nfun \u003CT> List\u003CT>.second(): T = this[1]\n\nfun \u003CT> List\u003CT>.secondOrNull(): T? = getOrNull(1)\n\n\u002F\u002F İyi: Scope edilmiş extension'lar (global namespace'i kirletmez)\nclass UserService {\n    private fun User.isActive(): Boolean =\n        status == Status.ACTIVE && lastLogin.isAfter(Instant.now().minus(30, ChronoUnit.DAYS))\n\n    fun getActiveUsers(): List\u003CUser> = userRepository.findAll().filter { it.isActive() }\n}\n```\n\n## Coroutine'ler\n\n### Yapılandırılmış Eşzamanlılık\n\n```kotlin\n\u002F\u002F İyi: coroutineScope ile yapılandırılmış eşzamanlılık\nsuspend fun fetchUserWithPosts(userId: String): UserProfile =\n    coroutineScope {\n        val userDeferred = async { userService.getUser(userId) }\n        val postsDeferred = async { postService.getUserPosts(userId) }\n\n        UserProfile(\n            user = userDeferred.await(),\n            posts = postsDeferred.await(),\n        )\n    }\n\n\u002F\u002F İyi: child'lar bağımsız başarısız olabildiğinde supervisorScope\nsuspend fun fetchDashboard(userId: String): Dashboard =\n    supervisorScope {\n        val user = async { userService.getUser(userId) }\n        val notifications = async { notificationService.getRecent(userId) }\n        val recommendations = async { recommendationService.getFor(userId) }\n\n        Dashboard(\n            user = user.await(),\n            notifications = try {\n                notifications.await()\n            } catch (e: CancellationException) {\n                throw e\n            } catch (e: Exception) {\n                emptyList()\n            },\n            recommendations = try {\n                recommendations.await()\n            } catch (e: CancellationException) {\n                throw e\n            } catch (e: Exception) {\n                emptyList()\n            },\n        )\n    }\n```\n\n### Reactive Stream'ler İçin Flow\n\n```kotlin\n\u002F\u002F İyi: Uygun hata işleme ile cold flow\nfun observeUsers(): Flow\u003CList\u003CUser>> = flow {\n    while (currentCoroutineContext().isActive) {\n        val users = userRepository.findAll()\n        emit(users)\n        delay(5.seconds)\n    }\n}.catch { e ->\n    logger.error(\"Error observing users\", e)\n    emit(emptyList())\n}\n\n\u002F\u002F İyi: Flow operatörleri\nfun searchUsers(query: Flow\u003CString>): Flow\u003CList\u003CUser>> =\n    query\n        .debounce(300.milliseconds)\n        .distinctUntilChanged()\n        .filter { it.length >= 2 }\n        .mapLatest { q -> userRepository.search(q) }\n        .catch { emit(emptyList()) }\n```\n\n## DSL Builder'lar\n\n### Tip Güvenli Builder'lar\n\n```kotlin\n\u002F\u002F İyi: @DslMarker ile DSL\n@DslMarker\nannotation class HtmlDsl\n\n@HtmlDsl\nclass HTML {\n    private val children = mutableListOf\u003CElement>()\n\n    fun head(init: Head.() -> Unit) {\n        children += Head().apply(init)\n    }\n\n    fun body(init: Body.() -> Unit) {\n        children += Body().apply(init)\n    }\n\n    override fun toString(): String = children.joinToString(\"\\n\")\n}\n\nfun html(init: HTML.() -> Unit): HTML = HTML().apply(init)\n\n\u002F\u002F Kullanım\nval page = html {\n    head { title(\"My Page\") }\n    body {\n        h1(\"Welcome\")\n        p(\"Hello, World!\")\n    }\n}\n```\n\n## Gradle Kotlin DSL\n\n### build.gradle.kts Yapılandırması\n\n```kotlin\n\u002F\u002F En son versiyonları kontrol et: https:\u002F\u002Fkotlinlang.org\u002Fdocs\u002Freleases.html\nplugins {\n    kotlin(\"jvm\") version \"2.3.10\"\n    kotlin(\"plugin.serialization\") version \"2.3.10\"\n    id(\"io.ktor.plugin\") version \"3.4.0\"\n    id(\"org.jetbrains.kotlinx.kover\") version \"0.9.7\"\n    id(\"io.gitlab.arturbosch.detekt\") version \"1.23.8\"\n}\n\ngroup = \"com.example\"\nversion = \"1.0.0\"\n\nkotlin {\n    jvmToolchain(21)\n}\n\ndependencies {\n    \u002F\u002F Ktor\n    implementation(\"io.ktor:ktor-server-core:3.4.0\")\n    implementation(\"io.ktor:ktor-server-netty:3.4.0\")\n    implementation(\"io.ktor:ktor-server-content-negotiation:3.4.0\")\n    implementation(\"io.ktor:ktor-serialization-kotlinx-json:3.4.0\")\n\n    \u002F\u002F Exposed\n    implementation(\"org.jetbrains.exposed:exposed-core:1.0.0\")\n    implementation(\"org.jetbrains.exposed:exposed-dao:1.0.0\")\n    implementation(\"org.jetbrains.exposed:exposed-jdbc:1.0.0\")\n    implementation(\"org.jetbrains.exposed:exposed-kotlin-datetime:1.0.0\")\n\n    \u002F\u002F Koin\n    implementation(\"io.insert-koin:koin-ktor:4.2.0\")\n\n    \u002F\u002F Coroutines\n    implementation(\"org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2\")\n\n    \u002F\u002F Test\n    testImplementation(\"io.kotest:kotest-runner-junit5:6.1.4\")\n    testImplementation(\"io.kotest:kotest-assertions-core:6.1.4\")\n    testImplementation(\"io.kotest:kotest-property:6.1.4\")\n    testImplementation(\"io.mockk:mockk:1.14.9\")\n    testImplementation(\"io.ktor:ktor-server-test-host:3.4.0\")\n    testImplementation(\"org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2\")\n}\n\ntasks.withType\u003CTest> {\n    useJUnitPlatform()\n}\n\ndetekt {\n    config.setFrom(files(\"config\u002Fdetekt\u002Fdetekt.yml\"))\n    buildUponDefaultConfig = true\n}\n```\n\n## Hata İşleme Kalıpları\n\n### Domain Operasyonları İçin Result Tipi\n\n```kotlin\n\u002F\u002F İyi: Kotlin'in Result'ını veya özel sealed class kullan\nsuspend fun createUser(request: CreateUserRequest): Result\u003CUser> = runCatching {\n    require(request.name.isNotBlank()) { \"Name cannot be blank\" }\n    require('@' in request.email) { \"Invalid email format\" }\n\n    val user = User(\n        id = UserId(UUID.randomUUID().toString()),\n        name = request.name,\n        email = Email(request.email),\n    )\n    userRepository.save(user)\n    user\n}\n\n\u002F\u002F İyi: Result'ları zincirle\nval displayName = createUser(request)\n    .map { it.name }\n    .getOrElse { \"Unknown\" }\n```\n\n### require, check, error\n\n```kotlin\n\u002F\u002F İyi: Net mesajlarla ön koşullar\nfun withdraw(account: Account, amount: Money): Account {\n    require(amount.value > 0) { \"Amount must be positive: $amount\" }\n    check(account.balance >= amount) { \"Insufficient balance: ${account.balance} \u003C $amount\" }\n\n    return account.copy(balance = account.balance - amount)\n}\n```\n\n## Hızlı Referans: Kotlin İdiyomları\n\n| İdiyom | Açıklama |\n|-------|-------------|\n| `val` over `var` | Immutable değişkenleri tercih et |\n| `data class` | equals\u002FhashCode\u002Fcopy ile value objeler için |\n| `sealed class\u002Finterface` | Kısıtlı tip hiyerarşileri için |\n| `value class` | Sıfır maliyetli tip güvenli sarmalayıcılar için |\n| Expression `when` | Exhaustive pattern matching |\n| Safe call `?.` | Null-safe member erişimi |\n| Elvis `?:` | Nullable'lar için varsayılan değer |\n| `let`\u002F`apply`\u002F`also`\u002F`run`\u002F`with` | Temiz kod için scope fonksiyonlar |\n| Extension fonksiyonlar | Inheritance olmadan davranış ekle |\n| `copy()` | Data class'larda immutable güncellemeler |\n| `require`\u002F`check` | Ön koşul assertion'ları |\n| Coroutine `async`\u002F`await` | Yapılandırılmış concurrent execution |\n| `Flow` | Cold reactive stream'ler |\n| `sequence` | Lazy evaluation |\n| Delegation `by` | Inheritance olmadan implementasyonu yeniden kullan |\n\n## Kaçınılması Gereken Anti-Kalıplar\n\n```kotlin\n\u002F\u002F Kötü: Nullable tipleri zorla açma\nval name = user!!.name\n\n\u002F\u002F Kötü: Java'dan platform tipi sızıntısı\nfun getLength(s: String) = s.length \u002F\u002F Güvenli\nfun getLength(s: String?) = s?.length ?: 0 \u002F\u002F Java'dan null'ları işle\n\n\u002F\u002F Kötü: Mutable data class'lar\ndata class MutableUser(var name: String, var email: String)\n\n\u002F\u002F Kötü: Kontrol akışı için exception kullanma\ntry {\n    val user = findUser(id)\n} catch (e: NotFoundException) {\n    \u002F\u002F Beklenen durumlar için exception kullanma\n}\n\n\u002F\u002F İyi: Nullable dönüş veya Result kullan\nval user: User? = findUserOrNull(id)\n\n\u002F\u002F Kötü: Coroutine scope'u görmezden gelme\nGlobalScope.launch { \u002F* GlobalScope'tan kaçın *\u002F }\n\n\u002F\u002F İyi: Yapılandırılmış eşzamanlılık kullan\ncoroutineScope {\n    launch { \u002F* Uygun şekilde scope edilmiş *\u002F }\n}\n\n\u002F\u002F Kötü: Derin iç içe scope fonksiyonlar\nuser?.let { u ->\n    u.address?.let { a ->\n        a.city?.let { c -> process(c) }\n    }\n}\n\n\u002F\u002F İyi: Doğrudan null-safe zincir\nuser?.address?.city?.let { process(it) }\n```\n\n**Hatırla**: Kotlin kodu kısa ama okunabilir olmalı. Güvenlik için tip sisteminden yararlanın, immutability tercih edin ve eşzamanlılık için coroutine'ler kullanın. Şüpheye düştüğünüzde, derleyicinin size yardım etmesine izin verin.\n",{"name":5,"origin":34,"description":7},"ECC","main","a2e3284ed4488780397ee2f78217366e11470dfb","skills\u002Fkotlin-patterns","https:\u002F\u002Fgithub.com\u002F7dvq6yrkgs-stack\u002Fplaywright","https:\u002F\u002Fplaywright.dev","https:\u002F\u002Fgithub.com\u002F7dvq6yrkgs-stack","2026-04-25 06:04:45",{"source":8,"skillName":5,"commands":43,"prompt":53,"zipAvailable":54},[44,47,50],{"tool":45,"command":46},"npx","npx skills add 7dvq6yrkgs-stack\u002Fplaywright --skill kotlin-patterns",{"tool":48,"command":49},"bunx","bunx skills add 7dvq6yrkgs-stack\u002Fplaywright --skill kotlin-patterns",{"tool":51,"command":52},"pnpm","pnpm dlx skills add 7dvq6yrkgs-stack\u002Fplaywright --skill kotlin-patterns","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002F7dvq6yrkgs-stack\u002Fplaywright\u002Fblob\u002Fmain\u002Fskills\u002Fkotlin-patterns\u002FSKILL.md",true,[56],{"path":57,"resourceType":58,"resourceTypeDesc":59,"sizeBytes":60,"sourceHtmlUrl":61},".skillfish.json","REFERENCE","参考文档",245,"https:\u002F\u002Fgithub.com\u002F7dvq6yrkgs-stack\u002Fplaywright\u002Fblob\u002Fmain\u002Fskills\u002Fkotlin-patterns\u002F.skillfish.json",[63,93,103,113,128,143],{"skillNo":64,"name":65,"nameZh":6,"description":66,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":67,"categories":68,"keywords":81,"publishedAt":29},"01M6E3XK4PRPMQHM7Y98FQPTY1","zyte-api-automation","Automate Zyte API tasks via Rube MCP (Composio). Always search tools first for current schemas.","https:\u002F\u002Fgithub.com\u002F7dvq6yrkgs-stack\u002Fplaywright\u002Fblob\u002Fmain\u002Fskills\u002Fzyte-api-automation\u002FSKILL.md",[69,70,73,76],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},{"categoryNo":71,"categoryName":72,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":74,"categoryName":75,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":77,"categoryName":78,"taxonomyType":79,"taxonomyTypeDesc":80},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[82,83,84,85,86,87,88,89,90,91,92],"zyte api automation","api","automation","MCP","tasks","search","Tools","first","automate","composio","via",{"skillNo":94,"name":95,"nameZh":6,"description":96,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":97,"categories":98,"keywords":101,"publishedAt":29},"01M6E3XFX6QSTR1QR59NFXJTMA","zylvie-automation","Automate Zylvie tasks via Rube MCP (Composio). Always search tools first for current schemas.","https:\u002F\u002Fgithub.com\u002F7dvq6yrkgs-stack\u002Fplaywright\u002Fblob\u002Fmain\u002Fskills\u002Fzylvie-automation\u002FSKILL.md",[99,100],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},{"categoryNo":74,"categoryName":75,"taxonomyType":20,"taxonomyTypeDesc":21},[102,84,90,85,86,87,88,89,91,92],"zylvie automation",{"skillNo":104,"name":105,"nameZh":6,"description":106,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":107,"categories":108,"keywords":111,"publishedAt":29},"01M6E3XCX2GDYYCHN58ZJHT37M","zoominfo-automation","Automate Zoominfo tasks via Rube MCP (Composio). Always search tools first for current schemas.","https:\u002F\u002Fgithub.com\u002F7dvq6yrkgs-stack\u002Fplaywright\u002Fblob\u002Fmain\u002Fskills\u002Fzoominfo-automation\u002FSKILL.md",[109,110],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},{"categoryNo":74,"categoryName":75,"taxonomyType":20,"taxonomyTypeDesc":21},[112,84,87,88,89,90,91,92,86,85],"zoominfo automation",{"skillNo":114,"name":115,"nameZh":6,"description":116,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":117,"categories":118,"keywords":121,"publishedAt":29},"01M6E3X9WJ2T73216WQHHTB9BD","zoho_mail-automation","Automate Zoho Mail tasks via Rube MCP (Composio): email sending, folders, labels, and mailbox management. Always search tools first for current schemas.","https:\u002F\u002Fgithub.com\u002F7dvq6yrkgs-stack\u002Fplaywright\u002Fblob\u002Fmain\u002Fskills\u002Fzoho_mail-automation\u002FSKILL.md",[119,120],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},{"categoryNo":74,"categoryName":75,"taxonomyType":20,"taxonomyTypeDesc":21},[122,123,124,84,85,86,87,125,88,89,90,126,91,127,92],"mail","zoho mail automation","zoho","email","management","mailbox",{"skillNo":129,"name":130,"nameZh":6,"description":131,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":132,"categories":133,"keywords":139,"publishedAt":29},"01M6E3X719W648XZBW1EC6JQ64","zoho_invoice-automation","Automate Zoho Invoice tasks via Rube MCP (Composio): invoices, estimates, expenses, clients, and payment tracking. Always search tools first for current schemas.","https:\u002F\u002Fgithub.com\u002F7dvq6yrkgs-stack\u002Fplaywright\u002Fblob\u002Fmain\u002Fskills\u002Fzoho_invoice-automation\u002FSKILL.md",[134,135,136],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},{"categoryNo":74,"categoryName":75,"taxonomyType":20,"taxonomyTypeDesc":21},{"categoryNo":137,"categoryName":138,"taxonomyType":79,"taxonomyTypeDesc":80},"01JBSEEDCAT000000000000040","财务",[140,124,84,86,87,88,89,90,141,142,91,92,85],"zoho invoice automation","tracking","payment",{"skillNo":144,"name":145,"nameZh":6,"description":146,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":147,"categories":148,"keywords":151,"publishedAt":29},"01M6E3X28JYTC3QTK32AQF7BYB","zoho_inventory-automation","Automate Zoho Inventory tasks via Rube MCP (Composio): items, orders, warehouses, shipments, and stock management. Always search tools first for current schemas.","https:\u002F\u002Fgithub.com\u002F7dvq6yrkgs-stack\u002Fplaywright\u002Fblob\u002Fmain\u002Fskills\u002Fzoho_inventory-automation\u002FSKILL.md",[149,150],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},{"categoryNo":74,"categoryName":75,"taxonomyType":20,"taxonomyTypeDesc":21},[84,152,124,153,89,90,88,87,86,85,91,92,154,155,126],"inventory","zoho inventory automation","stock","orders"]