Files
movienight-backend/build.gradle.kts
T
skettiks 43be102d4e refactor: обновить use case слои и интеграцию Jellyfin
Основные изменения: укрупнены use case-интерфейсы, контроллеры переведены на цельные зависимости, логика доступных фильмов перенесена в FilmLibraryService, добавлены проверки существования фильма и улучшена обработка ошибок API.

Метрики: FilmService больше не зависит напрямую от Micrometer для counters, используется BusinessMetricsPort; добавлены TimedAspect и duration-метрики через @Timed для create/edit/delete фильмов.

Jellyfin: event handling переведен на транзакционную модель, sync учитывает runtime-ошибки, добавлены plugin-token/web-url настройки, webhook и sync endpoints защищены X-MovieNight-Plugin-Token.

Плагин: добавлен Jellyfin plugin в plugins/jellyfin, backend принимает push-sync payload, sync-state доступен плагину, pull-sync вынесен в /api/integrations/jellyfin/pull-sync, README описывает фактический контракт.

API и DTO: добавлены RecommendationResponse, ContentTypeParser, validation annotations, обработка validation errors и ResponseStatusException, endpoint /api/users/me.

БД: добавлена V7 cleanup-миграция для legacy ratings/jellyfin_id объектов; V4/V5 в этот коммит не включались.

Проверка: .\gradlew.bat check --stacktrace проходит полностью.
2026-05-22 12:32:16 +03:00

208 lines
5.2 KiB
Kotlin

import com.google.protobuf.gradle.id
import io.gitlab.arturbosch.detekt.Detekt
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.springframework.boot.gradle.tasks.bundling.BootJar
plugins {
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.kotlin.spring)
alias(libs.plugins.spring.boot)
alias(libs.plugins.spring.dependency.management)
alias(libs.plugins.protobuf)
alias(libs.plugins.ktlint)
alias(libs.plugins.detekt)
jacoco
}
apply(plugin = "org.springframework.boot.aot")
apply(from = "$rootDir/gradle/docker.gradle.kts")
group = "com.project"
version = "0.0.1"
description = "MovieNight project"
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
dependencies {
implementation(platform(libs.sentry.bom))
implementation(libs.spring.boot.starter.web)
implementation(libs.spring.boot.starter.actuator)
implementation(libs.spring.boot.starter.aop)
implementation(libs.spring.boot.starter.security)
implementation(libs.spring.boot.starter.cache)
implementation(libs.spring.boot.starter.data.jdbc)
implementation(libs.spring.boot.starter.validation)
implementation(libs.spring.doc)
implementation(libs.flyway.database.postgresql)
implementation(libs.kotlin.reflect)
implementation(libs.micrometer.tracing.bridge.otel)
implementation(libs.opentelemetry.exporter.otlp)
implementation(libs.sentry.spring.boot.starter)
implementation(libs.spring.boot.starter.oauth2.client)
runtimeOnly(libs.micrometer.registry.prometheus)
runtimeOnly(libs.h2)
runtimeOnly(libs.postgresql)
developmentOnly(libs.spring.boot.devtools)
testImplementation(libs.spring.boot.starter.test)
testImplementation(libs.kotlin.test.junit5)
testImplementation(libs.mockk)
testRuntimeOnly(libs.junit.platform.launcher)
}
tasks.withType<KotlinCompile> {
compilerOptions {
freeCompilerArgs.set(
listOf(
"-Xjsr305=strict",
"-Xjvm-default=all",
"-opt-in=kotlin.RequiresOptIn",
"-opt-in=kotlin.ExperimentalStdlibApi",
),
)
jvmTarget.set(JvmTarget.JVM_21)
allWarningsAsErrors.set(false)
}
}
tasks.withType<JavaCompile> {
sourceCompatibility = "21"
targetCompatibility = "21"
options.encoding = "UTF-8"
options.isIncremental = true
}
kotlin {
compilerOptions {
freeCompilerArgs.addAll("-Xannotation-default-target=param-property")
}
}
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:${libs.versions.protoc.get()}"
}
plugins {
id("grpc") {
artifact = "io.grpc:protoc-gen-grpc-java:${libs.versions.grpc.java.get()}"
}
}
generateProtoTasks {
all().forEach {
it.plugins {
id("grpc") {
option("@generated=omit")
}
}
}
}
}
tasks.withType<Test> {
useJUnitPlatform()
testLogging {
events("passed", "skipped", "failed")
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
showStandardStreams = false
}
maxParallelForks = maxOf(1, Runtime.getRuntime().availableProcessors() / 2)
minHeapSize = "512m"
maxHeapSize = "2048m"
}
tasks.processResources {
filesMatching("**/application.y{a,}ml") {
filter { line ->
line.replace("\${project.version}", project.version.toString())
}
}
}
tasks.named<BootJar>("bootJar") {
archiveFileName.set("${project.name}-${project.version}.jar")
layered {
enabled.set(true)
}
}
tasks.named<Jar>("jar") {
enabled = false
}
tasks.withType<org.gradle.api.tasks.bundling.AbstractArchiveTask>().configureEach {
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
}
ktlint {
version.set(libs.versions.ktlint.get())
debug.set(false)
verbose.set(true)
android.set(false)
outputToConsole.set(true)
ignoreFailures.set(false)
enableExperimentalRules.set(true)
filter {
exclude("**/build/**")
exclude("**/generated/**")
}
}
detekt {
toolVersion = libs.versions.detekt.get()
buildUponDefaultConfig = true
allRules = false
config.setFrom(files("$projectDir/config/detekt/detekt.yaml"))
baseline = file("$projectDir/config/detekt/baseline.xml")
}
tasks.withType<Detekt>().configureEach {
jvmTarget = "21"
reports {
html.required.set(true)
xml.required.set(true)
sarif.required.set(true)
txt.required.set(false)
}
}
jacoco {
toolVersion = libs.versions.jacoco.get()
}
tasks.jacocoTestReport {
dependsOn(tasks.test)
reports {
xml.required.set(true)
html.required.set(true)
csv.required.set(false)
}
finalizedBy(tasks.jacocoTestCoverageVerification)
}
tasks.jacocoTestCoverageVerification {
violationRules {
rule {
limit {
minimum = "0.10".toBigDecimal()
}
}
}
}
tasks.check {
dependsOn(tasks.ktlintCheck)
dependsOn(tasks.detekt)
dependsOn(tasks.jacocoTestReport)
}