From 381ce7598fdb80200d394aa008c547895a1bc361 Mon Sep 17 00:00:00 2001
From: Jan-Niclas Struewer <j.n.struewer@gmail.com>
Date: Wed, 31 Jul 2024 14:27:01 +0200
Subject: [PATCH] breaking: backup commit to prepare merge from dev branch.
 Branch is not in a working state!

---
 .../iem/app/kpi/dto/KPIHierarchyEdgeDto.kt    |   8 -
 .../iem/app/kpi/dto/KpiCalculationDto.kt      |  75 +----
 .../iem/app/kpi/entity/KPIEntity.kt           |  19 +-
 .../iem/app/kpi/enumeration/KpiKind.kt        |  78 ++---
 .../iem/app/kpi/service/KPIService.kt         | 312 +++++++++---------
 .../AggregationKPICalculationStrategy.kt      |  90 ++---
 .../strategy/MaximumKPICalculationStrategy.kt |  33 +-
 .../strategy/RatioKPICalculationStrategy.kt   |  28 +-
 .../controller/RepositoryController.kt        |   3 +-
 .../iem/app/repository/dto/RawKpiDto.kt       |   5 +-
 .../dto/RawValueKpiCreateDtoExtension.kt      |   4 +-
 .../repository/service/RepositoryService.kt   |   6 +-
 .../iem/app/tool/enumeration/ToolType.kt      |  34 +-
 .../iem/app/toolRun/service/ToolRunService.kt |   2 +-
 .../AggregationKPICalculationStrategyTest.kt  | 191 +++++------
 .../iem/kpiCalculator/adapter/KpiAdapter.kt   |   4 +-
 .../kpiCalculator/adapter/cve/CveAdapter.kt   |  12 +-
 .../adapter/cve/CveAdapterTest.kt             |   2 +-
 .../iem/kpiCalculator/core/KpiCalculator.kt   |   1 +
 .../core/hierarchy/KPIHierarchyEdgeDto.kt     |   8 +
 .../core/hierarchy/KpiCalculationNode.kt      |  48 +++
 .../core}/strategy/KPICalculationStrategy.kt  |   4 +-
 .../RawValueKPICalculationStrategy.kt         |   6 +-
 .../model/adapter/AdapterResult.kt            |   4 +-
 .../model/kpi/RawValueKpiCreateDto.kt         |   3 -
 .../kpiCalculator/model/kpi/RawValueKpiDto.kt |   3 +
 .../model/kpi/hierarchy/KpiHierarchy.kt       |   1 +
 .../{KpiNodeTest.kt => KpiHierarchyTest.kt}   |  16 +-
 28 files changed, 513 insertions(+), 487 deletions(-)
 delete mode 100644 app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/dto/KPIHierarchyEdgeDto.kt
 create mode 100644 kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/hierarchy/KPIHierarchyEdgeDto.kt
 create mode 100644 kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/hierarchy/KpiCalculationNode.kt
 rename {app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi => kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core}/strategy/KPICalculationStrategy.kt (52%)
 rename {app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi => kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core}/strategy/RawValueKPICalculationStrategy.kt (57%)
 delete mode 100644 kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/RawValueKpiCreateDto.kt
 create mode 100644 kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/RawValueKpiDto.kt
 rename kpi-calculator/model/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/hierarchy/{KpiNodeTest.kt => KpiHierarchyTest.kt} (82%)

diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/dto/KPIHierarchyEdgeDto.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/dto/KPIHierarchyEdgeDto.kt
deleted file mode 100644
index 07b2f8a9..00000000
--- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/dto/KPIHierarchyEdgeDto.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package de.fraunhofer.iem.app.kpi.dto
-
-data class KPIHierarchyEdgeDto(
-    val from: KpiCalculationDto,
-    val to: KpiCalculationDto,
-    val plannedWeight: Double,
-    val actualWeight: Double = plannedWeight
-)
diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/dto/KpiCalculationDto.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/dto/KpiCalculationDto.kt
index af8f7f74..8378ebe2 100644
--- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/dto/KpiCalculationDto.kt
+++ b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/dto/KpiCalculationDto.kt
@@ -1,68 +1,21 @@
 package de.fraunhofer.iem.app.kpi.dto
 
 import de.fraunhofer.iem.app.kpi.enumeration.toViewModel
-import de.fraunhofer.iem.app.logger.getLogger
-import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiKind
+import de.fraunhofer.iem.kpiCalculator.core.hierarchy.KpiCalculationNode
 
-class KpiCalculationDto(
-    val kind: KpiKind,
-    private val calculationStrategy: de.fraunhofer.iem.app.kpi.strategy.KPICalculationStrategy? = null,
-    private var isEmpty: Boolean = true,
-    private var value: Int? = null
-) {
-    private val hierarchyEdges: MutableList<KPIHierarchyEdgeDto> = mutableListOf()
-    private val logger = getLogger(javaClass)
-
-    fun hasChildren(): Boolean {
-        return hierarchyEdges.isNotEmpty()
-    }
-
-    fun getHierarchyEdges(): List<KPIHierarchyEdgeDto> {
-        return hierarchyEdges.toList()
-    }
-
-    fun isEmpty(): Boolean {
-        return isEmpty
-    }
-
-    fun calculateKPI() {
-        if (calculationStrategy != null) {
-            try {
-                val valueAndEdges = calculationStrategy.calculateKPI(this.hierarchyEdges)
-                this.value = valueAndEdges.first
-                this.hierarchyEdges.clear()
-                this.hierarchyEdges.addAll(valueAndEdges.second)
-
-                this.isEmpty = false
-            } catch (exception: Exception) {
-                logger.error("Exception during KPI calculation for $kind with $calculationStrategy")
-                this.isEmpty = true
-                this.value = null
-            }
-        } else {
-            this.isEmpty = true
-        }
-    }
-
-    fun getValue(): Int {
-        if (value != null && !isEmpty) {
-            return value as Int
-        } else {
-            throw Exception("Value access for empty KPIs not allowed. KpiKind $kind")
-        }
+fun KpiCalculationNode.toViewModel(): KPITreeResponseDto {
+    val children = this.hierarchyEdges.map {
+        val child = it.to.toViewModel()
+        KPITreeChildResponseDto(kpi = child, plannedWeight = it.plannedWeight, actualWeight = it.actualWeight)
     }
 
-    fun addChildKPI(kpiCreateDto: KpiCalculationDto, weight: Double) {
-        val hierarchyEdge = KPIHierarchyEdgeDto(this, kpiCreateDto, weight)
-        this.hierarchyEdges.add(hierarchyEdge)
-    }
-
-    fun toViewModel(): KPITreeResponseDto {
-        val children = this.hierarchyEdges.map {
-            val child = it.to.toViewModel()
-            KPITreeChildResponseDto(kpi = child, plannedWeight = it.plannedWeight, actualWeight = it.actualWeight)
-        }
-
-        return this.kind.toViewModel(value = value ?: -1, children = children, isEmpty = isEmpty)
-    }
+    return this.kind.toViewModel(
+        value = try {
+            //TODO: fixme
+            // getValue()
+            -1
+        } catch (e: Exception) {
+            -1
+        }, children = children, isEmpty = false // TODO: fixme
+    )
 }
diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/entity/KPIEntity.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/entity/KPIEntity.kt
index 97382493..7f9af682 100644
--- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/entity/KPIEntity.kt
+++ b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/entity/KPIEntity.kt
@@ -1,9 +1,9 @@
 package de.fraunhofer.iem.app.kpi.entity
 
-import de.fraunhofer.iem.app.kpi.dto.KpiCalculationDto
-import de.fraunhofer.iem.app.kpi.strategy.RawValueKPICalculationStrategy
 import de.fraunhofer.iem.app.toolRun.entity.ToolRunEntity
-import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiKind
+import de.fraunhofer.iem.kpiCalculator.core.hierarchy.KpiCalculationNode
+import de.fraunhofer.iem.kpiCalculator.core.hierarchy.RawKpiCalculationNode
+import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiId
 import jakarta.persistence.*
 import org.hibernate.annotations.CurrentTimestamp
 import org.hibernate.generator.EventType
@@ -11,6 +11,7 @@ import org.hibernate.proxy.HibernateProxy
 import java.sql.Timestamp
 import java.util.*
 
+
 @Entity
 @Table(name = "kpi")
 class KPIEntity(
@@ -27,17 +28,17 @@ class KPIEntity(
     val score: Int,
 
     @Enumerated(EnumType.STRING)
-    var kind: KpiKind,
+    var kind: KpiId,
 
     @CurrentTimestamp(event = [EventType.INSERT])
     @Column(name = "timestamp")
     var createdAt: Timestamp? = null
 ) {
-    fun toCalculationDto(): KpiCalculationDto {
-        return KpiCalculationDto(
+    fun toCalculationDto(): KpiCalculationNode {
+        // TODO: fixme
+        return RawKpiCalculationNode(
             kind = this.kind,
-            calculationStrategy = RawValueKPICalculationStrategy(this.score),
-            isEmpty = false
+            score = this.score,
         )
     }
 
@@ -49,7 +50,7 @@ class KPIEntity(
         val thisEffectiveClass =
             if (this is HibernateProxy) this.hibernateLazyInitializer.persistentClass else this.javaClass
         if (thisEffectiveClass != oEffectiveClass) return false
-        other as de.fraunhofer.iem.app.kpi.entity.KPIEntity
+        other as KPIEntity
 
         return id != null && id == other.id
     }
diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/enumeration/KpiKind.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/enumeration/KpiKind.kt
index 176e0e33..66ac89ae 100644
--- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/enumeration/KpiKind.kt
+++ b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/enumeration/KpiKind.kt
@@ -2,11 +2,11 @@ package de.fraunhofer.iem.app.kpi.enumeration
 
 import de.fraunhofer.iem.app.kpi.dto.KPITreeChildResponseDto
 import de.fraunhofer.iem.app.kpi.dto.KPITreeResponseDto
-import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiKind
+import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiId
 
-fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isEmpty: Boolean): KPITreeResponseDto {
+fun KpiId.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isEmpty: Boolean): KPITreeResponseDto {
     return when (this.name) {
-        KpiKind.CHECKED_IN_BINARIES.name ->
+        KpiId.CHECKED_IN_BINARIES.name ->
             KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -16,7 +16,7 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
                 isEmpty = isEmpty
             )
 
-        KpiKind.NUMBER_OF_COMMITS.name ->
+        KpiId.NUMBER_OF_COMMITS.name ->
             return KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -25,7 +25,7 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
                 isEmpty = isEmpty
             )
 
-        KpiKind.VULNERABILITY_SCORE.name ->
+        KpiId.VULNERABILITY_SCORE.name ->
             return KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -36,7 +36,7 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
                 isEmpty = isEmpty
             )
 
-        KpiKind.NUMBER_OF_SIGNED_COMMITS.name ->
+        KpiId.NUMBER_OF_SIGNED_COMMITS.name ->
             return KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -45,7 +45,7 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
                 isEmpty = isEmpty
             )
 
-        KpiKind.IS_DEFAULT_BRANCH_PROTECTED.name ->
+        KpiId.IS_DEFAULT_BRANCH_PROTECTED.name ->
             return KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -56,7 +56,7 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
                 isEmpty = isEmpty
             )
 
-        KpiKind.SECRETS.name ->
+        KpiId.SECRETS.name ->
             return KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -69,7 +69,7 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
                 isEmpty = isEmpty
             )
 
-        KpiKind.SAST_USAGE.name ->
+        KpiId.SAST_USAGE.name ->
             return KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -78,7 +78,7 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
                 isEmpty = isEmpty
             )
 
-        KpiKind.COMMENTS_IN_CODE.name ->
+        KpiId.COMMENTS_IN_CODE.name ->
             return KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -88,7 +88,7 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
                 isEmpty = isEmpty
             )
 
-        KpiKind.DOCUMENTATION_INFRASTRUCTURE.name ->
+        KpiId.DOCUMENTATION_INFRASTRUCTURE.name ->
             return KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -101,7 +101,7 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
                 isEmpty = isEmpty
             )
 
-        KpiKind.SIGNED_COMMITS_RATIO.name ->
+        KpiId.SIGNED_COMMITS_RATIO.name ->
             return KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -113,7 +113,7 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
                 isEmpty = isEmpty
             )
 
-        KpiKind.INTERNAL_QUALITY.name ->
+        KpiId.INTERNAL_QUALITY.name ->
             return KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -124,7 +124,7 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
                 order = 3
             )
 
-        KpiKind.EXTERNAL_QUALITY.name ->
+        KpiId.EXTERNAL_QUALITY.name ->
             return KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -136,7 +136,7 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
                 order = 3
             )
 
-        KpiKind.PROCESS_COMPLIANCE.name ->
+        KpiId.PROCESS_COMPLIANCE.name ->
             return KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -148,7 +148,7 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
                 order = 4
             )
 
-        KpiKind.PROCESS_TRANSPARENCY.name ->
+        KpiId.PROCESS_TRANSPARENCY.name ->
             return KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -161,7 +161,7 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
                 order = 5
             )
 
-        KpiKind.SECURITY.name ->
+        KpiId.SECURITY.name ->
             return KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -173,7 +173,7 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
                 order = 2
             )
 
-        KpiKind.MAXIMAL_VULNERABILITY.name ->
+        KpiId.MAXIMAL_VULNERABILITY.name ->
             return KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -189,7 +189,7 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
                 isEmpty = isEmpty
             )
 
-        KpiKind.ROOT.name ->
+        KpiId.ROOT.name ->
             return KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -200,7 +200,7 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
                 isEmpty = isEmpty
             )
 
-        KpiKind.DOCUMENTATION.name ->
+        KpiId.DOCUMENTATION.name ->
             return KPITreeResponseDto(
                 value = value,
                 name = this.getName(),
@@ -219,26 +219,26 @@ fun KpiKind.toViewModel(value: Int, children: List<KPITreeChildResponseDto>, isE
     }
 }
 
-fun KpiKind.getName(): String {
+fun KpiId.getName(): String {
     return when (this.name) {
-        KpiKind.ROOT.name -> "Project Health Score"
-        KpiKind.PROCESS_COMPLIANCE.name -> "Process Compliance Score"
-        KpiKind.DOCUMENTATION.name -> "Documentation"
-        KpiKind.CHECKED_IN_BINARIES.name -> "No Checked in Binaries"
-        KpiKind.INTERNAL_QUALITY.name -> "Internal Quality"
-        KpiKind.NUMBER_OF_COMMITS.name -> "Number of Commits"
-        KpiKind.MAXIMAL_VULNERABILITY.name -> "Maximal Dependency Vulnerability Score"
-        KpiKind.SECURITY.name -> "Security Score"
-        KpiKind.VULNERABILITY_SCORE.name -> "Vulnerability Score"
-        KpiKind.PROCESS_TRANSPARENCY.name -> "Process Transparency Score"
-        KpiKind.NUMBER_OF_SIGNED_COMMITS.name -> "Number of Signed Commits"
-        KpiKind.COMMENTS_IN_CODE.name -> "Comments in Code"
-        KpiKind.DOCUMENTATION_INFRASTRUCTURE.name -> "Existence of Documentation Infrastructure"
-        KpiKind.IS_DEFAULT_BRANCH_PROTECTED.name -> "Default Branch Protection"
-        KpiKind.SECRETS.name -> "Public Secrets"
-        KpiKind.SIGNED_COMMITS_RATIO.name -> "Commit Signature Ratio"
-        KpiKind.EXTERNAL_QUALITY.name -> "External Quality"
-        KpiKind.SAST_USAGE.name -> "SAST Usage"
+        KpiId.ROOT.name -> "Project Health Score"
+        KpiId.PROCESS_COMPLIANCE.name -> "Process Compliance Score"
+        KpiId.DOCUMENTATION.name -> "Documentation"
+        KpiId.CHECKED_IN_BINARIES.name -> "No Checked in Binaries"
+        KpiId.INTERNAL_QUALITY.name -> "Internal Quality"
+        KpiId.NUMBER_OF_COMMITS.name -> "Number of Commits"
+        KpiId.MAXIMAL_VULNERABILITY.name -> "Maximal Dependency Vulnerability Score"
+        KpiId.SECURITY.name -> "Security Score"
+        KpiId.VULNERABILITY_SCORE.name -> "Vulnerability Score"
+        KpiId.PROCESS_TRANSPARENCY.name -> "Process Transparency Score"
+        KpiId.NUMBER_OF_SIGNED_COMMITS.name -> "Number of Signed Commits"
+        KpiId.COMMENTS_IN_CODE.name -> "Comments in Code"
+        KpiId.DOCUMENTATION_INFRASTRUCTURE.name -> "Existence of Documentation Infrastructure"
+        KpiId.IS_DEFAULT_BRANCH_PROTECTED.name -> "Default Branch Protection"
+        KpiId.SECRETS.name -> "Public Secrets"
+        KpiId.SIGNED_COMMITS_RATIO.name -> "Commit Signature Ratio"
+        KpiId.EXTERNAL_QUALITY.name -> "External Quality"
+        KpiId.SAST_USAGE.name -> "SAST Usage"
         else -> "Unknown KPI"
     }
 }
diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/service/KPIService.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/service/KPIService.kt
index 3a2a843e..2055ca7f 100644
--- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/service/KPIService.kt
+++ b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/service/KPIService.kt
@@ -2,16 +2,14 @@ package de.fraunhofer.iem.app.kpi.service
 
 import de.fraunhofer.iem.app.kpi.dto.KPITreeChildResponseDto
 import de.fraunhofer.iem.app.kpi.dto.KPITreeResponseDto
-import de.fraunhofer.iem.app.kpi.dto.KpiCalculationDto
 import de.fraunhofer.iem.app.kpi.strategy.AggregationKPICalculationStrategy
-import de.fraunhofer.iem.app.kpi.strategy.MaximumKPICalculationStrategy
-import de.fraunhofer.iem.app.kpi.strategy.RatioKPICalculationStrategy
 import de.fraunhofer.iem.app.logger.getLogger
 import de.fraunhofer.iem.app.repository.dto.RepositoryDetailsDto
 import de.fraunhofer.iem.app.tools.occmd.enumeration.Checks
 import de.fraunhofer.iem.app.tools.occmd.json.RawResultJson
-import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiKind
-import de.fraunhofer.iem.kpiCalculator.model.kpi.RawValueKpiCreateDto
+import de.fraunhofer.iem.kpiCalculator.core.hierarchy.KpiCalculationNode
+import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiId
+import de.fraunhofer.iem.kpiCalculator.model.kpi.RawValueKpiDto
 import org.springframework.stereotype.Service
 
 @Service
@@ -52,47 +50,47 @@ class KPIService {
     /**
      * This method calculates the OccmdCreateKpiDtos based upon the given tool results.
      */
-    fun calculateOccmdKpis(rawOccmdResults: List<RawResultJson>): List<RawValueKpiCreateDto> {
-        val kpis = mutableListOf<RawValueKpiCreateDto>()
+    fun calculateOccmdKpis(rawOccmdResults: List<RawResultJson>): List<RawValueKpiDto> {
+        val kpis = mutableListOf<RawValueKpiDto>()
 
         rawOccmdResults.forEach {
             when (val check = Checks.fromString(it.check)) {
                 Checks.CheckedInBinaries ->
                     kpis.add(
-                        RawValueKpiCreateDto(
-                            kind = KpiKind.CHECKED_IN_BINARIES,
+                        RawValueKpiDto(
+                            kind = KpiId.CHECKED_IN_BINARIES,
                             score = (it.score * 100).toInt()
                         )
                     )
 
                 Checks.SastUsageBasic ->
                     kpis.add(
-                        RawValueKpiCreateDto(
-                            kind = KpiKind.SAST_USAGE,
+                        RawValueKpiDto(
+                            kind = KpiId.SAST_USAGE,
                             score = (it.score * 100).toInt()
                         )
                     )
 
                 Checks.Secrets ->
                     kpis.add(
-                        RawValueKpiCreateDto(
-                            kind = KpiKind.SECRETS,
+                        RawValueKpiDto(
+                            kind = KpiId.SECRETS,
                             score = (it.score * 100).toInt()
                         )
                     )
 
                 Checks.CommentsInCode ->
                     kpis.add(
-                        RawValueKpiCreateDto(
-                            kind = KpiKind.COMMENTS_IN_CODE,
+                        RawValueKpiDto(
+                            kind = KpiId.COMMENTS_IN_CODE,
                             score = (it.score * 100).toInt()
                         )
                     )
 
                 Checks.DocumentationInfrastructure ->
                     kpis.add(
-                        RawValueKpiCreateDto(
-                            kind = KpiKind.DOCUMENTATION_INFRASTRUCTURE,
+                        RawValueKpiDto(
+                            kind = KpiId.DOCUMENTATION_INFRASTRUCTURE,
                             score = (it.score * 100).toInt()
                         )
                     )
@@ -109,26 +107,26 @@ class KPIService {
      * Creates a named map of RepositoryCreateDtos, based upon the provided repository details.
      * This method only returns raw KPIs.
      */
-    fun calculateRepositoryDetailsKpis(repoDetailsDto: RepositoryDetailsDto): List<RawValueKpiCreateDto> {
+    fun calculateRepositoryDetailsKpis(repoDetailsDto: RepositoryDetailsDto): List<RawValueKpiDto> {
         return listOf(
-            RawValueKpiCreateDto(
-                kind = KpiKind.NUMBER_OF_COMMITS,
+            RawValueKpiDto(
+                kind = KpiId.NUMBER_OF_COMMITS,
                 score = repoDetailsDto.numberOfCommits
             ),
-            RawValueKpiCreateDto(
-                kind = KpiKind.NUMBER_OF_SIGNED_COMMITS,
+            RawValueKpiDto(
+                kind = KpiId.NUMBER_OF_SIGNED_COMMITS,
                 score = repoDetailsDto.numberOfSignedCommits
             ),
-            RawValueKpiCreateDto(
-                kind = KpiKind.IS_DEFAULT_BRANCH_PROTECTED,
+            RawValueKpiDto(
+                kind = KpiId.IS_DEFAULT_BRANCH_PROTECTED,
                 score = if (repoDetailsDto.isDefaultBranchProtected) 100 else 0
             )
         )
     }
 
-    fun getKpiTreeForRawKpis(rawKpis: List<KpiCalculationDto>): KpiCalculationDto {
+    fun getKpiTreeForRawKpis(rawKpis: List<KpiCalculationNode>): KpiCalculationNode {
         val rawValueKpis = rawKpis.toMutableList()
-        val vulnerabilities = rawValueKpis.filter { it.kind == KpiKind.VULNERABILITY_SCORE }
+        val vulnerabilities = rawValueKpis.filter { it.kind == KpiId.VULNERABILITY_SCORE }
         rawValueKpis.toMutableList().removeAll(vulnerabilities)
         val kpiMap = rawValueKpis.associateBy { it.kind }
         val rootKpi = generateKPITree(kpiMap, vulnerabilities)
@@ -138,141 +136,141 @@ class KPIService {
 
     @Suppress("MagicNumber", "LongMethod")
     private fun generateKPITree(
-        rawValueKpis: Map<KpiKind, KpiCalculationDto> = emptyMap(),
-        vulnerabilityKpis: List<KpiCalculationDto> = emptyList()
-    ): KpiCalculationDto {
-        val signedCommitsRatioKPI =
-            KpiCalculationDto(
-                kind = KpiKind.SIGNED_COMMITS_RATIO,
-                calculationStrategy = RatioKPICalculationStrategy()
-            )
-
-        signedCommitsRatioKPI.addChildKPI(
-            rawValueKpis.getOrDefault(
-                KpiKind.NUMBER_OF_COMMITS,
-                KpiCalculationDto(kind = KpiKind.NUMBER_OF_COMMITS)
-            ),
-            1.0
-        )
-
-        signedCommitsRatioKPI.addChildKPI(
-            rawValueKpis.getOrDefault(
-                KpiKind.NUMBER_OF_SIGNED_COMMITS,
-                KpiCalculationDto(kind = KpiKind.NUMBER_OF_SIGNED_COMMITS)
-            ),
-            1.0
-        )
-
-        val processComplianceKPI = KpiCalculationDto(
-            kind = KpiKind.PROCESS_COMPLIANCE,
-            calculationStrategy = AggregationKPICalculationStrategy()
-        )
-
-        processComplianceKPI.addChildKPI(
-            rawValueKpis.getOrDefault(
-                KpiKind.IS_DEFAULT_BRANCH_PROTECTED,
-                KpiCalculationDto(kind = KpiKind.IS_DEFAULT_BRANCH_PROTECTED)
-            ),
-            0.3
-        )
-
-        processComplianceKPI.addChildKPI(
-            rawValueKpis.getOrDefault(
-                KpiKind.CHECKED_IN_BINARIES,
-                KpiCalculationDto(kind = KpiKind.CHECKED_IN_BINARIES)
-            ),
-            0.2
-        )
-
-        processComplianceKPI.addChildKPI(signedCommitsRatioKPI, 0.2)
-
-        val documentationKpi = KpiCalculationDto(
-            kind = KpiKind.DOCUMENTATION,
-            calculationStrategy = AggregationKPICalculationStrategy()
-        )
-
-        documentationKpi.addChildKPI(
-            rawValueKpis.getOrDefault(
-                KpiKind.DOCUMENTATION_INFRASTRUCTURE,
-                KpiCalculationDto(kind = KpiKind.DOCUMENTATION_INFRASTRUCTURE)
-            ),
-            0.6
-        )
-
-        documentationKpi.addChildKPI(
-            rawValueKpis.getOrDefault(
-                KpiKind.COMMENTS_IN_CODE,
-                KpiCalculationDto(kind = KpiKind.COMMENTS_IN_CODE)
-            ),
-            0.4
-        )
-
-        val processTransparencyKPI = KpiCalculationDto(
-            kind = KpiKind.PROCESS_TRANSPARENCY,
-            calculationStrategy = AggregationKPICalculationStrategy()
-        )
-        processComplianceKPI.addChildKPI(documentationKpi, 0.3)
-        processTransparencyKPI.addChildKPI(signedCommitsRatioKPI, 1.0)
-
-        val securityKPI = KpiCalculationDto(
-            kind = KpiKind.SECURITY,
-            calculationStrategy = AggregationKPICalculationStrategy()
-        )
-
-        val internalQuality = KpiCalculationDto(
-            kind = KpiKind.INTERNAL_QUALITY,
-            calculationStrategy = AggregationKPICalculationStrategy()
-        )
-
-        val externalQuality = KpiCalculationDto(
-            kind = KpiKind.EXTERNAL_QUALITY,
-            calculationStrategy = AggregationKPICalculationStrategy()
-        )
-
-        externalQuality.addChildKPI(documentationKpi, 1.0)
-        internalQuality.addChildKPI(documentationKpi, 1.0)
-
-        val maximalDependencyVulnerabilityKPI = KpiCalculationDto(
-            kind = KpiKind.MAXIMAL_VULNERABILITY,
-            calculationStrategy = MaximumKPICalculationStrategy()
-        )
-
-        vulnerabilityKpis.forEach { maximalDependencyVulnerabilityKPI.addChildKPI(it, 0.0) }
-
-        securityKPI.addChildKPI(
-            rawValueKpis.getOrDefault(
-                KpiKind.SECRETS,
-                KpiCalculationDto(kind = KpiKind.SECRETS)
-            ),
-            0.3
-        )
-
-        securityKPI.addChildKPI(
-            rawValueKpis.getOrDefault(
-                KpiKind.CHECKED_IN_BINARIES,
-                KpiCalculationDto(kind = KpiKind.CHECKED_IN_BINARIES)
-            ),
-            0.2
-        )
-
-        securityKPI.addChildKPI(maximalDependencyVulnerabilityKPI, 0.5)
-
-        val rootKPI = KpiCalculationDto(
-            kind = KpiKind.ROOT,
+        rawValueKpis: Map<KpiId, KpiCalculationNode> = emptyMap(),
+        vulnerabilityKpis: List<KpiCalculationNode> = emptyList()
+    ): KpiCalculationNode {
+//        val signedCommitsRatioKPI =
+//            KpiCalculationNode(
+//                kind = KpiKind.SIGNED_COMMITS_RATIO,
+//                calculationStrategy = RatioKPICalculationStrategy()
+//            )
+//
+//        signedCommitsRatioKPI.addChildKPI(
+//            rawValueKpis.getOrDefault(
+//                KpiKind.NUMBER_OF_COMMITS,
+//                KpiCalculationNode(kind = KpiKind.NUMBER_OF_COMMITS)
+//            ),
+//            1.0
+//        )
+//
+//        signedCommitsRatioKPI.addChildKPI(
+//            rawValueKpis.getOrDefault(
+//                KpiKind.NUMBER_OF_SIGNED_COMMITS,
+//                KpiCalculationNode(kind = KpiKind.NUMBER_OF_SIGNED_COMMITS)
+//            ),
+//            1.0
+//        )
+//
+//        val processComplianceKPI = KpiCalculationNode(
+//            kind = KpiKind.PROCESS_COMPLIANCE,
+//            calculationStrategy = AggregationKPICalculationStrategy()
+//        )
+//
+//        processComplianceKPI.addChildKPI(
+//            rawValueKpis.getOrDefault(
+//                KpiKind.IS_DEFAULT_BRANCH_PROTECTED,
+//                KpiCalculationNode(kind = KpiKind.IS_DEFAULT_BRANCH_PROTECTED)
+//            ),
+//            0.3
+//        )
+//
+//        processComplianceKPI.addChildKPI(
+//            rawValueKpis.getOrDefault(
+//                KpiKind.CHECKED_IN_BINARIES,
+//                KpiCalculationNode(kind = KpiKind.CHECKED_IN_BINARIES)
+//            ),
+//            0.2
+//        )
+//
+//        processComplianceKPI.addChildKPI(signedCommitsRatioKPI, 0.2)
+//
+//        val documentationKpi = KpiCalculationNode(
+//            kind = KpiKind.DOCUMENTATION,
+//            calculationStrategy = AggregationKPICalculationStrategy()
+//        )
+//
+//        documentationKpi.addChildKPI(
+//            rawValueKpis.getOrDefault(
+//                KpiKind.DOCUMENTATION_INFRASTRUCTURE,
+//                KpiCalculationNode(kind = KpiKind.DOCUMENTATION_INFRASTRUCTURE)
+//            ),
+//            0.6
+//        )
+//
+//        documentationKpi.addChildKPI(
+//            rawValueKpis.getOrDefault(
+//                KpiKind.COMMENTS_IN_CODE,
+//                KpiCalculationNode(kind = KpiKind.COMMENTS_IN_CODE)
+//            ),
+//            0.4
+//        )
+//
+//        val processTransparencyKPI = KpiCalculationNode(
+//            kind = KpiKind.PROCESS_TRANSPARENCY,
+//            calculationStrategy = AggregationKPICalculationStrategy()
+//        )
+//        processComplianceKPI.addChildKPI(documentationKpi, 0.3)
+//        processTransparencyKPI.addChildKPI(signedCommitsRatioKPI, 1.0)
+//
+//        val securityKPI = KpiCalculationNode(
+//            kind = KpiKind.SECURITY,
+//            calculationStrategy = AggregationKPICalculationStrategy()
+//        )
+//
+//        val internalQuality = KpiCalculationNode(
+//            kind = KpiKind.INTERNAL_QUALITY,
+//            calculationStrategy = AggregationKPICalculationStrategy()
+//        )
+//
+//        val externalQuality = KpiCalculationNode(
+//            kind = KpiKind.EXTERNAL_QUALITY,
+//            calculationStrategy = AggregationKPICalculationStrategy()
+//        )
+//
+//        externalQuality.addChildKPI(documentationKpi, 1.0)
+//        internalQuality.addChildKPI(documentationKpi, 1.0)
+//
+//        val maximalDependencyVulnerabilityKPI = KpiCalculationNode(
+//            kind = KpiKind.MAXIMAL_VULNERABILITY,
+//            calculationStrategy = MaximumKPICalculationStrategy()
+//        )
+//
+//        vulnerabilityKpis.forEach { maximalDependencyVulnerabilityKPI.addChildKPI(it, 0.0) }
+//
+//        securityKPI.addChildKPI(
+//            rawValueKpis.getOrDefault(
+//                KpiKind.SECRETS,
+//                KpiCalculationNode(kind = KpiKind.SECRETS)
+//            ),
+//            0.3
+//        )
+//
+//        securityKPI.addChildKPI(
+//            rawValueKpis.getOrDefault(
+//                KpiKind.CHECKED_IN_BINARIES,
+//                KpiCalculationNode(kind = KpiKind.CHECKED_IN_BINARIES)
+//            ),
+//            0.2
+//        )
+//
+//        securityKPI.addChildKPI(maximalDependencyVulnerabilityKPI, 0.5)
+//
+        val rootKPI = KpiCalculationNode(
+            kind = KpiId.ROOT,
             calculationStrategy = AggregationKPICalculationStrategy(),
         )
 
-        rootKPI.addChildKPI(processTransparencyKPI, 0.1)
-        rootKPI.addChildKPI(processComplianceKPI, 0.1)
-        rootKPI.addChildKPI(internalQuality, 0.15)
-        rootKPI.addChildKPI(externalQuality, 0.25)
-        rootKPI.addChildKPI(securityKPI, 0.4)
+//        rootKPI.addChildKPI(processTransparencyKPI, 0.1)
+//        rootKPI.addChildKPI(processComplianceKPI, 0.1)
+//        rootKPI.addChildKPI(internalQuality, 0.15)
+//        rootKPI.addChildKPI(externalQuality, 0.25)
+//        rootKPI.addChildKPI(securityKPI, 0.4)
         return rootKPI
     }
 
     private fun calculateKPIsRecursively(
-        kpi: KpiCalculationDto,
-        visited: MutableSet<KpiCalculationDto> = mutableSetOf()
+        kpi: KpiCalculationNode,
+        visited: MutableSet<KpiCalculationNode> = mutableSetOf()
     ) {
         // Check if the KPI has already been visited
         if (visited.contains(kpi)) {
@@ -282,18 +280,18 @@ class KPIService {
         // Check if the KPI has child KPIs
         if (!kpi.hasChildren()) {
             // Leaf node, calculate the KPI value
-            kpi.calculateKPI()
+            kpi.applyStrategy()
             visited.add(kpi)
             return
         }
 
         // Recursively calculate child KPIs first
-        for (childEdge in kpi.getHierarchyEdges()) {
+        for (childEdge in kpi.hierarchyEdges) {
             calculateKPIsRecursively(childEdge.to, visited)
         }
 
         // Calculate the KPI value after processing child KPIs
-        kpi.calculateKPI()
+        kpi.applyStrategy()
         visited.add(kpi)
     }
 }
diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/AggregationKPICalculationStrategy.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/AggregationKPICalculationStrategy.kt
index 6eab9093..06b807d3 100644
--- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/AggregationKPICalculationStrategy.kt
+++ b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/AggregationKPICalculationStrategy.kt
@@ -1,8 +1,9 @@
 package de.fraunhofer.iem.app.kpi.strategy
 
-import de.fraunhofer.iem.app.kpi.dto.KPIHierarchyEdgeDto
+import de.fraunhofer.iem.kpiCalculator.core.hierarchy.KPIHierarchyEdgeDto
+import de.fraunhofer.iem.kpiCalculator.core.strategy.KPICalculationStrategy
 
-class AggregationKPICalculationStrategy : de.fraunhofer.iem.app.kpi.strategy.KPICalculationStrategy {
+class AggregationKPICalculationStrategy : KPICalculationStrategy {
 
     /**
      * This function calculates the aggregate sum of all given children.
@@ -13,47 +14,48 @@ class AggregationKPICalculationStrategy : de.fraunhofer.iem.app.kpi.strategy.KPI
      * KPIHierarchyEdgeDtos with the actual used weight.
      */
     override fun calculateKPI(children: List<KPIHierarchyEdgeDto>): Pair<Int, List<KPIHierarchyEdgeDto>> {
-        if (children.none { !it.to.isEmpty() } || children.isEmpty()) {
-            throw Exception("KPI aggregation of empty children can't be calculated.")
-        }
-
-        val emptyChildren: List<KPIHierarchyEdgeDto> = children.filter { it.to.isEmpty() }
-
-        val notEmptyChildren = children.toMutableList()
-        notEmptyChildren.removeAll(emptyChildren)
-
-        val additionalWeightPerElement: Double = if (notEmptyChildren.isNotEmpty()) {
-            val unusedWeight = emptyChildren.sumOf { it.plannedWeight }
-            unusedWeight / notEmptyChildren.size
-        } else {
-            0.0
-        }
-
-        val weightedEdges: MutableList<KPIHierarchyEdgeDto> = emptyChildren
-            .map {
-                KPIHierarchyEdgeDto(
-                    from = it.from,
-                    to = it.to,
-                    plannedWeight = it.plannedWeight,
-                    actualWeight = 0.0
-                )
-            }.toMutableList()
-
-        var value = 0
-
-        notEmptyChildren.forEach { child ->
-            val actualWeight = (child.plannedWeight + additionalWeightPerElement)
-            weightedEdges.add(
-                KPIHierarchyEdgeDto(
-                    from = child.from,
-                    to = child.to,
-                    plannedWeight = child.plannedWeight,
-                    actualWeight = actualWeight
-                )
-            )
-            value += (child.to.getValue().toFloat() * actualWeight).toInt()
-        }
-
-        return Pair(value, weightedEdges)
+//        if (children.none { !it.to.isEmpty() } || children.isEmpty()) {
+//            throw Exception("KPI aggregation of empty children can't be calculated.")
+//        }
+//
+//        val emptyChildren: List<KPIHierarchyEdgeDto> = children.filter { it.to.isEmpty() }
+//
+//        val notEmptyChildren = children.toMutableList()
+//        notEmptyChildren.removeAll(emptyChildren)
+//
+//        val additionalWeightPerElement: Double = if (notEmptyChildren.isNotEmpty()) {
+//            val unusedWeight = emptyChildren.sumOf { it.plannedWeight }
+//            unusedWeight / notEmptyChildren.size
+//        } else {
+//            0.0
+//        }
+//
+//        val weightedEdges: MutableList<KPIHierarchyEdgeDto> = emptyChildren
+//            .map {
+//                KPIHierarchyEdgeDto(
+//                    from = it.from,
+//                    to = it.to,
+//                    plannedWeight = it.plannedWeight,
+//                    actualWeight = 0.0
+//                )
+//            }.toMutableList()
+//
+//        var value = 0
+//
+//        notEmptyChildren.forEach { child ->
+//            val actualWeight = (child.plannedWeight + additionalWeightPerElement)
+//            weightedEdges.add(
+//                KPIHierarchyEdgeDto(
+//                    from = child.from,
+//                    to = child.to,
+//                    plannedWeight = child.plannedWeight,
+//                    actualWeight = actualWeight
+//                )
+//            )
+//            value += (child.to.getValue().toFloat() * actualWeight).toInt()
+//        }
+//
+//        return Pair(value, weightedEdges)
+        TODO()
     }
 }
diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/MaximumKPICalculationStrategy.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/MaximumKPICalculationStrategy.kt
index a82be9b5..0b7ed318 100644
--- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/MaximumKPICalculationStrategy.kt
+++ b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/MaximumKPICalculationStrategy.kt
@@ -1,23 +1,26 @@
 package de.fraunhofer.iem.app.kpi.strategy
 
-import de.fraunhofer.iem.app.kpi.dto.KPIHierarchyEdgeDto
+import de.fraunhofer.iem.kpiCalculator.core.hierarchy.KPIHierarchyEdgeDto
+import de.fraunhofer.iem.kpiCalculator.core.strategy.KPICalculationStrategy
 
-class MaximumKPICalculationStrategy : de.fraunhofer.iem.app.kpi.strategy.KPICalculationStrategy {
+class MaximumKPICalculationStrategy : KPICalculationStrategy {
     // TODO: Currently it's tailored to the maximum dependency vulnerability score, this should change in the future
     @Suppress("MagicNumber")
     override fun calculateKPI(children: List<KPIHierarchyEdgeDto>): Pair<Int, List<KPIHierarchyEdgeDto>> {
-        if (children.none { !it.to.isEmpty() } || children.isEmpty()) {
-            throw Exception("KPI maximum of empty children can't be calculated")
-        }
-        var maximum = 0
-        for (child in children) {
-            if (!child.to.isEmpty()) {
-                val childValue = child.to.getValue()
-                if (childValue > maximum) {
-                    maximum = childValue
-                }
-            }
-        }
-        return Pair((100 - (maximum)), children)
+//        if (children.none { !it.to.isEmpty() } || children.isEmpty()) {
+//            throw Exception("KPI maximum of empty children can't be calculated")
+//        }
+//        var maximum = 0
+//        for (child in children) {
+//            if (!child.to.isEmpty()) {
+//                val childValue = child.to.getValue()
+//                if (childValue > maximum) {
+//                    maximum = childValue
+//                }
+//            }
+//        }
+//        return Pair((100 - (maximum)), children)
+//    }
+        TODO()
     }
 }
diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/RatioKPICalculationStrategy.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/RatioKPICalculationStrategy.kt
index d6f80d0e..5b552b63 100644
--- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/RatioKPICalculationStrategy.kt
+++ b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/RatioKPICalculationStrategy.kt
@@ -1,20 +1,22 @@
 package de.fraunhofer.iem.app.kpi.strategy
 
-import de.fraunhofer.iem.app.kpi.dto.KPIHierarchyEdgeDto
+import de.fraunhofer.iem.kpiCalculator.core.hierarchy.KPIHierarchyEdgeDto
+import de.fraunhofer.iem.kpiCalculator.core.strategy.KPICalculationStrategy
 
-class RatioKPICalculationStrategy : de.fraunhofer.iem.app.kpi.strategy.KPICalculationStrategy {
+class RatioKPICalculationStrategy : KPICalculationStrategy {
     @Suppress("MagicNumber")
     override fun calculateKPI(children: List<KPIHierarchyEdgeDto>): Pair<Int, List<KPIHierarchyEdgeDto>> {
-        if (children.size != 2) {
-            throw Exception("Requires exactly two children")
-        }
-        // TODO: this is a dirty workaround to fix a copy by reference bug
-        val copiedChildren = children.toList()
-        val firstValue = children[0].to.getValue()
-        val secondValue = children[1].to.getValue()
-        if (firstValue >= secondValue) {
-            return Pair(((secondValue.toDouble() / firstValue.toDouble()) * 100).toInt(), copiedChildren)
-        }
-        return Pair(((firstValue.toDouble() / secondValue.toDouble()) * 100).toInt(), copiedChildren)
+//        if (children.size != 2) {
+//            throw Exception("Requires exactly two children")
+//        }
+//        // TODO: this is a dirty workaround to fix a copy by reference bug
+//        val copiedChildren = children.toList()
+//        val firstValue = children[0].to.getValue()
+//        val secondValue = children[1].to.getValue()
+//        if (firstValue >= secondValue) {
+//            return Pair(((secondValue.toDouble() / firstValue.toDouble()) * 100).toInt(), copiedChildren)
+//        }
+//        return Pair(((firstValue.toDouble() / secondValue.toDouble()) * 100).toInt(), copiedChildren)
+        TODO()
     }
 }
diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/controller/RepositoryController.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/controller/RepositoryController.kt
index 9a8154b2..8255e66e 100644
--- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/controller/RepositoryController.kt
+++ b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/controller/RepositoryController.kt
@@ -5,6 +5,7 @@ import de.fraunhofer.iem.app.configuration.security.JwtContentDto
 import de.fraunhofer.iem.app.configuration.security.JwtService
 import de.fraunhofer.iem.app.gitlab.service.OpenCodeGitlabApi
 import de.fraunhofer.iem.app.kpi.dto.KPITreeResponseDto
+import de.fraunhofer.iem.app.kpi.dto.toViewModel
 import de.fraunhofer.iem.app.kpi.service.KPIService
 import de.fraunhofer.iem.app.logger.getLogger
 import de.fraunhofer.iem.app.repository.dto.*
@@ -135,7 +136,7 @@ class RepositoryController(
 
         val rawKpis = repositoryEntity.getLastToolRun().kpiEntities.map {
             val calcDto = it.toCalculationDto()
-            calcDto.calculateKPI()
+            calcDto.applyStrategy()
             calcDto
         }
         return RawKpiDto(rawKpis = rawKpis)
diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/dto/RawKpiDto.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/dto/RawKpiDto.kt
index b3f66072..c2205986 100644
--- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/dto/RawKpiDto.kt
+++ b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/dto/RawKpiDto.kt
@@ -1,5 +1,6 @@
 package de.fraunhofer.iem.app.repository.dto
 
-import de.fraunhofer.iem.app.kpi.dto.KpiCalculationDto
+import de.fraunhofer.iem.kpiCalculator.core.hierarchy.KpiCalculationNode
 
-data class RawKpiDto(val rawKpis: List<KpiCalculationDto>)
+
+data class RawKpiDto(val rawKpis: List<KpiCalculationNode>)
diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/dto/RawValueKpiCreateDtoExtension.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/dto/RawValueKpiCreateDtoExtension.kt
index 572e43b0..c9c41ab8 100644
--- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/dto/RawValueKpiCreateDtoExtension.kt
+++ b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/dto/RawValueKpiCreateDtoExtension.kt
@@ -1,11 +1,11 @@
 package de.fraunhofer.iem.app.repository.dto
 
 import de.fraunhofer.iem.app.toolRun.entity.ToolRunEntity
-import de.fraunhofer.iem.kpiCalculator.model.kpi.RawValueKpiCreateDto
+import de.fraunhofer.iem.kpiCalculator.model.kpi.RawValueKpiDto
 import java.sql.Timestamp
 import java.time.Instant
 
-fun RawValueKpiCreateDto.toDbObject(toolRun: ToolRunEntity): de.fraunhofer.iem.app.kpi.entity.KPIEntity {
+fun RawValueKpiDto.toDbObject(toolRun: ToolRunEntity): de.fraunhofer.iem.app.kpi.entity.KPIEntity {
     return de.fraunhofer.iem.app.kpi.entity.KPIEntity(
         kind = this.kind,
         score = this.score,
diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/service/RepositoryService.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/service/RepositoryService.kt
index d76b1962..177a7a2b 100644
--- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/service/RepositoryService.kt
+++ b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/service/RepositoryService.kt
@@ -13,7 +13,7 @@ import de.fraunhofer.iem.app.toolRun.dto.ToolRunDto
 import de.fraunhofer.iem.app.toolRun.entity.LanguageEntity
 import de.fraunhofer.iem.app.toolRun.entity.ToolRunEntity
 import de.fraunhofer.iem.app.toolRun.repository.ToolRunRepository
-import de.fraunhofer.iem.kpiCalculator.model.kpi.RawValueKpiCreateDto
+import de.fraunhofer.iem.kpiCalculator.model.kpi.RawValueKpiDto
 import org.springframework.stereotype.Service
 import org.springframework.transaction.annotation.Propagation
 import org.springframework.transaction.annotation.Transactional
@@ -30,7 +30,7 @@ class RepositoryService(
     @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
     fun createToolRun(
         repoDto: RepositoryCreateDto,
-        kpiToolList: List<Pair<CreateToolDto, List<RawValueKpiCreateDto>>>,
+        kpiToolList: List<Pair<CreateToolDto, List<RawValueKpiDto>>>,
         languageMap: Map<String, Float>
     ) {
         val repo = getOrCreate(repoDto)
@@ -73,7 +73,7 @@ class RepositoryService(
             logger.info("Creating repository with id ${gitRepository.id}")
             repo = repositoryRepository.save(gitRepository.toDbObject())
         }
-        return repo
+        return repo!!
     }
 
 
diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/tool/enumeration/ToolType.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/tool/enumeration/ToolType.kt
index 330d15c8..0dc3b489 100644
--- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/tool/enumeration/ToolType.kt
+++ b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/tool/enumeration/ToolType.kt
@@ -2,7 +2,7 @@ package de.fraunhofer.iem.app.tool.enumeration
 
 import de.fraunhofer.iem.app.kpi.enumeration.getName
 import de.fraunhofer.iem.app.tool.dto.ToolDto
-import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiKind
+import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiId
 
 enum class ToolType {
     ORT {
@@ -10,9 +10,9 @@ enum class ToolType {
             return ToolDto(
                 name = this.getName(),
                 relevantKpis = listOf(
-                    KpiKind.MAXIMAL_VULNERABILITY.getName(),
-                    KpiKind.VULNERABILITY_SCORE.getName(),
-                    KpiKind.SECURITY.getName()
+                    KpiId.MAXIMAL_VULNERABILITY.getName(),
+                    KpiId.VULNERABILITY_SCORE.getName(),
+                    KpiId.SECURITY.getName()
                 ),
                 description = "The OSS Review Toolkit (ORT) provides information about dependencies." +
                     "For more information see https://github.com/oss-review-toolkit/ort.",
@@ -29,14 +29,14 @@ enum class ToolType {
             return ToolDto(
                 name = this.getName(),
                 relevantKpis = listOf(
-                    KpiKind.SECURITY.getName(),
-                    KpiKind.PROCESS_TRANSPARENCY.getName(),
-                    KpiKind.PROCESS_COMPLIANCE.getName(),
-                    KpiKind.SECRETS.getName(),
-                    KpiKind.COMMENTS_IN_CODE.getName(),
-                    KpiKind.DOCUMENTATION.getName(),
-                    KpiKind.SAST_USAGE.getName(),
-                    KpiKind.CHECKED_IN_BINARIES.getName()
+                    KpiId.SECURITY.getName(),
+                    KpiId.PROCESS_TRANSPARENCY.getName(),
+                    KpiId.PROCESS_COMPLIANCE.getName(),
+                    KpiId.SECRETS.getName(),
+                    KpiId.COMMENTS_IN_CODE.getName(),
+                    KpiId.DOCUMENTATION.getName(),
+                    KpiId.SAST_USAGE.getName(),
+                    KpiId.CHECKED_IN_BINARIES.getName()
                 ),
                 description = "The OCCMD provides various information about the analyzed project." +
                     "For more information see https://gitlab.opencode.de/opencode-analyzer/occmd-public.",
@@ -54,11 +54,11 @@ enum class ToolType {
             return ToolDto(
                 name = this.getName(),
                 relevantKpis = listOf(
-                    KpiKind.PROCESS_TRANSPARENCY.getName(),
-                    KpiKind.PROCESS_COMPLIANCE.getName(),
-                    KpiKind.NUMBER_OF_COMMITS.getName(),
-                    KpiKind.NUMBER_OF_SIGNED_COMMITS.getName(),
-                    KpiKind.DOCUMENTATION.getName(),
+                    KpiId.PROCESS_TRANSPARENCY.getName(),
+                    KpiId.PROCESS_COMPLIANCE.getName(),
+                    KpiId.NUMBER_OF_COMMITS.getName(),
+                    KpiId.NUMBER_OF_SIGNED_COMMITS.getName(),
+                    KpiId.DOCUMENTATION.getName(),
                 ),
                 description = "The Gitlab API is used to derive information about, e.g., the project's compliance" +
                     "to OpenCoDE's platform rules.",
diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/toolRun/service/ToolRunService.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/toolRun/service/ToolRunService.kt
index 6c0a0dad..8b9c3b7b 100644
--- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/toolRun/service/ToolRunService.kt
+++ b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/toolRun/service/ToolRunService.kt
@@ -73,7 +73,7 @@ class ToolRunService(
                 // goal is to match the behavior of the old implementation.
                 val rawValueKpiCreateDtos =
                     CveAdapter.transformDataToKpi(vulnerabilityDtos).filterIsInstance<AdapterResult.Success>()
-                        .map { it.rawValueKpiCreateDto }
+                        .map { it.rawValueKpiDto }
 
                 Pair(ortService.getToolDto(), rawValueKpiCreateDtos)
             },
diff --git a/app/backend/src/test/kotlin/de/fraunhofer/iem/app/kpi/strategy/AggregationKPICalculationStrategyTest.kt b/app/backend/src/test/kotlin/de/fraunhofer/iem/app/kpi/strategy/AggregationKPICalculationStrategyTest.kt
index 21d389d8..0e77dbd7 100644
--- a/app/backend/src/test/kotlin/de/fraunhofer/iem/app/kpi/strategy/AggregationKPICalculationStrategyTest.kt
+++ b/app/backend/src/test/kotlin/de/fraunhofer/iem/app/kpi/strategy/AggregationKPICalculationStrategyTest.kt
@@ -1,107 +1,108 @@
 package de.fraunhofer.iem.app.kpi.strategy
 
-import de.fraunhofer.iem.app.kpi.dto.KpiCalculationDto
-import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiKind
+import de.fraunhofer.iem.kpiCalculator.core.hierarchy.KpiCalculationNode
 import org.junit.jupiter.api.Test
 
 class AggregationKPICalculationStrategyTest {
 
-    private fun getRootKpiPartiallyEmpty(): KpiCalculationDto {
-        val processComplianceKPI = KpiCalculationDto(
-            kind = KpiKind.PROCESS_COMPLIANCE,
-            calculationStrategy = RawValueKPICalculationStrategy(25),
-            value = 25,
-            isEmpty = false
-        )
-
-        val processTransparencyKPI = KpiCalculationDto(
-            kind = KpiKind.PROCESS_TRANSPARENCY,
-            calculationStrategy = RawValueKPICalculationStrategy(50),
-            value = 50,
-            isEmpty = false
-        )
-
-        val securityKPI = KpiCalculationDto(
-            kind = KpiKind.SECURITY,
-            calculationStrategy = AggregationKPICalculationStrategy(),
-            value = -1,
-            isEmpty = true
-        )
-
-        val transparencyKpi = KpiCalculationDto(
-            kind = KpiKind.PROCESS_TRANSPARENCY,
-            calculationStrategy = AggregationKPICalculationStrategy(),
-            value = -1,
-            isEmpty = true
-        )
-
-        transparencyKpi.addChildKPI(
-            KpiCalculationDto(
-                kind = KpiKind.PROCESS_TRANSPARENCY,
-                calculationStrategy = RawValueKPICalculationStrategy(-1),
-                value = -1,
-                isEmpty = true
-            ),
-            1.0
-        )
-
-        val rootKPI = KpiCalculationDto(
-            kind = KpiKind.ROOT,
-            calculationStrategy = AggregationKPICalculationStrategy(),
-        )
-
-        rootKPI.addChildKPI(processTransparencyKPI, 0.25)
-        rootKPI.addChildKPI(processComplianceKPI, 0.25)
-        rootKPI.addChildKPI(transparencyKpi, 0.25)
-        rootKPI.addChildKPI(securityKPI, 0.25)
-
-        return rootKPI
-    }
-
-    private fun getRootKpiComplete(): KpiCalculationDto {
-        val processComplianceKPI = KpiCalculationDto(
-            kind = KpiKind.PROCESS_COMPLIANCE,
-            calculationStrategy = RawValueKPICalculationStrategy(25),
-            value = 25,
-            isEmpty = false
-        )
-
-        val processTransparencyKPI = KpiCalculationDto(
-            kind = KpiKind.PROCESS_TRANSPARENCY,
-            calculationStrategy = RawValueKPICalculationStrategy(50),
-            value = 50,
-            isEmpty = false
-        )
-
-        val securityKPI = KpiCalculationDto(
-            kind = KpiKind.SECURITY,
-            calculationStrategy = RawValueKPICalculationStrategy(100),
-            value = 100,
-            isEmpty = false
-        )
-
-        val rootKPI = KpiCalculationDto(
-            kind = KpiKind.ROOT,
-            calculationStrategy = AggregationKPICalculationStrategy(),
-        )
-
-        rootKPI.addChildKPI(processTransparencyKPI, 0.25)
-        rootKPI.addChildKPI(processComplianceKPI, 0.25)
-        rootKPI.addChildKPI(securityKPI, 0.5)
-
-        return rootKPI
+    private fun getRootKpiPartiallyEmpty(): KpiCalculationNode {
+        TODO()
+//        val processComplianceKPI = KpiCalculationNode(
+//            kind = KpiKind.PROCESS_COMPLIANCE,
+//            calculationStrategy = RawValueKPICalculationStrategy(25),
+//            value = 25,
+//            isEmpty = false
+//        )
+//
+//        val processTransparencyKPI = KpiCalculationNode(
+//            kind = KpiKind.PROCESS_TRANSPARENCY,
+//            calculationStrategy = RawValueKPICalculationStrategy(50),
+//            value = 50,
+//            isEmpty = false
+//        )
+//
+//        val securityKPI = KpiCalculationNode(
+//            kind = KpiKind.SECURITY,
+//            calculationStrategy = AggregationKPICalculationStrategy(),
+//            value = -1,
+//            isEmpty = true
+//        )
+//
+//        val transparencyKpi = KpiCalculationNode(
+//            kind = KpiKind.PROCESS_TRANSPARENCY,
+//            calculationStrategy = AggregationKPICalculationStrategy(),
+//            value = -1,
+//            isEmpty = true
+//        )
+//
+//        transparencyKpi.addChildKPI(
+//            KpiCalculationNode(
+//                kind = KpiKind.PROCESS_TRANSPARENCY,
+//                calculationStrategy = RawValueKPICalculationStrategy(-1),
+//                value = -1,
+//                isEmpty = true
+//            ),
+//            1.0
+//        )
+//
+//        val rootKPI = KpiCalculationNode(
+//            kind = KpiKind.ROOT,
+//            calculationStrategy = AggregationKPICalculationStrategy(),
+//        )
+//
+//        rootKPI.addChildKPI(processTransparencyKPI, 0.25)
+//        rootKPI.addChildKPI(processComplianceKPI, 0.25)
+//        rootKPI.addChildKPI(transparencyKpi, 0.25)
+//        rootKPI.addChildKPI(securityKPI, 0.25)
+//
+//        return rootKPI
+//    }
+//
+//    private fun getRootKpiComplete(): KpiCalculationNode {
+//        val processComplianceKPI = KpiCalculationNode(
+//            kind = KpiKind.PROCESS_COMPLIANCE,
+//            calculationStrategy = RawValueKPICalculationStrategy(25),
+//            value = 25,
+//            isEmpty = false
+//        )
+//
+//        val processTransparencyKPI = KpiCalculationNode(
+//            kind = KpiKind.PROCESS_TRANSPARENCY,
+//            calculationStrategy = RawValueKPICalculationStrategy(50),
+//            value = 50,
+//            isEmpty = false
+//        )
+//
+//        val securityKPI = KpiCalculationNode(
+//            kind = KpiKind.SECURITY,
+//            calculationStrategy = RawValueKPICalculationStrategy(100),
+//            value = 100,
+//            isEmpty = false
+//        )
+//
+//        val rootKPI = KpiCalculationNode(
+//            kind = KpiKind.ROOT,
+//            calculationStrategy = AggregationKPICalculationStrategy(),
+//        )
+//
+//        rootKPI.addChildKPI(processTransparencyKPI, 0.25)
+//        rootKPI.addChildKPI(processComplianceKPI, 0.25)
+//        rootKPI.addChildKPI(securityKPI, 0.5)
+//
+//        return rootKPI
     }
 
     @Test
     fun calculateKPI() {
-        val rootKpiPartiallyEmpty = getRootKpiPartiallyEmpty()
-        rootKpiPartiallyEmpty.getHierarchyEdges()
-
-        val sum = AggregationKPICalculationStrategy().calculateKPI(rootKpiPartiallyEmpty.getHierarchyEdges())
-        assert(sum.first == 37)
-
-        val rootKpi = getRootKpiComplete()
-        val sum2 = AggregationKPICalculationStrategy().calculateKPI(rootKpi.getHierarchyEdges())
-        assert(sum2.first == 68)
+//        val rootKpiPartiallyEmpty = getRootKpiPartiallyEmpty()
+//        rootKpiPartiallyEmpty.hierarchyEdges
+//
+//        val sum = AggregationKPICalculationStrategy().calculateKPI(rootKpiPartiallyEmpty.hierarchyEdges)
+//        assert(sum.first == 37)
+//
+//        val rootKpi = getRootKpiComplete()
+//        val sum2 = AggregationKPICalculationStrategy().calculateKPI(rootKpi.hierarchyEdges)
+//        assert(sum2.first == 68)
+        TODO()
     }
 }
diff --git a/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/KpiAdapter.kt b/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/KpiAdapter.kt
index 55633bc9..b7ca1357 100644
--- a/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/KpiAdapter.kt
+++ b/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/KpiAdapter.kt
@@ -1,11 +1,11 @@
 package de.fraunhofer.iem.kpiCalculator.adapter
 
 import de.fraunhofer.iem.kpiCalculator.model.adapter.AdapterResult
-import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiKind
+import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiId
 
 
 interface KpiAdapter<T> {
-    val kpiKind: KpiKind
+    val kpiId: KpiId
 
     fun transformDataToKpi(data: List<T>): List<AdapterResult>
     fun transformDataToKpi(data: T): AdapterResult = transformDataToKpi(listOf(data)).first()
diff --git a/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/cve/CveAdapter.kt b/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/cve/CveAdapter.kt
index 9cb30699..e71fdb38 100644
--- a/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/cve/CveAdapter.kt
+++ b/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/cve/CveAdapter.kt
@@ -4,20 +4,20 @@ import de.fraunhofer.iem.kpiCalculator.adapter.KpiAdapter
 import de.fraunhofer.iem.kpiCalculator.model.adapter.AdapterResult
 import de.fraunhofer.iem.kpiCalculator.model.adapter.ErrorType
 import de.fraunhofer.iem.kpiCalculator.model.adapter.VulnerabilityDto
-import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiKind
-import de.fraunhofer.iem.kpiCalculator.model.kpi.RawValueKpiCreateDto
+import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiId
+import de.fraunhofer.iem.kpiCalculator.model.kpi.RawValueKpiDto
 
 object CveAdapter : KpiAdapter<VulnerabilityDto> {
-    override val kpiKind: KpiKind
-        get() = KpiKind.VULNERABILITY_SCORE
+    override val kpiId: KpiId
+        get() = KpiId.VULNERABILITY_SCORE
 
     override fun transformDataToKpi(data: List<VulnerabilityDto>): List<AdapterResult> {
         return data
             .map {
                 return@map if (isValid(it)) {
                     AdapterResult.Success(
-                        RawValueKpiCreateDto(
-                            kind = kpiKind,
+                        RawValueKpiDto(
+                            kind = kpiId,
                             score = (it.severity * 10).toInt()
                         )
                     )
diff --git a/kpi-calculator/adapter/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/cve/CveAdapterTest.kt b/kpi-calculator/adapter/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/cve/CveAdapterTest.kt
index cb482bef..e24b0c18 100644
--- a/kpi-calculator/adapter/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/cve/CveAdapterTest.kt
+++ b/kpi-calculator/adapter/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/cve/CveAdapterTest.kt
@@ -21,7 +21,7 @@ class CveAdapterTest {
         )
         when (validKpi) {
             is AdapterResult.Success -> {
-                assert(validKpi.rawValueKpiCreateDto.score in (0..100))
+                assert(validKpi.rawValueKpiDto.score in (0..100))
             }
 
             is AdapterResult.Error -> {
diff --git a/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/KpiCalculator.kt b/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/KpiCalculator.kt
index 0d1d240a..5ffc7910 100644
--- a/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/KpiCalculator.kt
+++ b/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/KpiCalculator.kt
@@ -3,5 +3,6 @@ package de.fraunhofer.iem.kpiCalculator.core
 object KpiCalculator {
     //XXX: Setup Logger
 
+//    fun calculateKpis(root: KpiCalculationNode):
 
 }
diff --git a/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/hierarchy/KPIHierarchyEdgeDto.kt b/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/hierarchy/KPIHierarchyEdgeDto.kt
new file mode 100644
index 00000000..388207c6
--- /dev/null
+++ b/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/hierarchy/KPIHierarchyEdgeDto.kt
@@ -0,0 +1,8 @@
+package de.fraunhofer.iem.kpiCalculator.core.hierarchy
+
+data class KPIHierarchyEdgeDto(
+    val from: KpiCalculationNode,
+    val to: KpiCalculationNode,
+    val plannedWeight: Double,
+    val actualWeight: Double = plannedWeight
+)
diff --git a/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/hierarchy/KpiCalculationNode.kt b/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/hierarchy/KpiCalculationNode.kt
new file mode 100644
index 00000000..f03aa75f
--- /dev/null
+++ b/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/hierarchy/KpiCalculationNode.kt
@@ -0,0 +1,48 @@
+package de.fraunhofer.iem.kpiCalculator.core.hierarchy
+
+import de.fraunhofer.iem.kpiCalculator.core.strategy.KPICalculationStrategy
+import de.fraunhofer.iem.kpiCalculator.core.strategy.RawValueKPICalculationStrategy
+import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiId
+
+sealed class KpiCalculationResult {
+    class Kpi(val kind: KpiId, val score: Int) : KpiCalculationResult()
+    class Error(val reason: String) : KpiCalculationResult()
+}
+
+// TODO: fixme
+open class KpiCalculationNode(val kind: KpiId, private val calculationStrategy: KPICalculationStrategy) {
+
+    private val _hierarchyEdges: MutableList<KPIHierarchyEdgeDto> = mutableListOf()
+    val hierarchyEdges: List<KPIHierarchyEdgeDto>
+        get() = _hierarchyEdges
+
+    fun hasChildren(): Boolean {
+        return hierarchyEdges.isNotEmpty()
+    }
+
+    fun applyStrategy(): KpiCalculationResult {
+        return try {
+            val valueAndEdges = calculationStrategy.calculateKPI(this.hierarchyEdges)
+            val value = valueAndEdges.first
+            this._hierarchyEdges.clear()
+            this._hierarchyEdges.addAll(valueAndEdges.second)
+
+            KpiCalculationResult.Kpi(kind = this.kind, score = value)
+        } catch (exception: Exception) {
+            KpiCalculationResult.Error(exception.toString())
+        }
+    }
+
+
+    fun addChildKPI(kpiCreateDto: KpiCalculationNode, weight: Double) {
+        val hierarchyEdge = KPIHierarchyEdgeDto(this, kpiCreateDto, weight)
+        this._hierarchyEdges.add(hierarchyEdge)
+    }
+}
+
+
+class RawKpiCalculationNode(
+    score: Int,
+    kind: KpiId
+) : KpiCalculationNode(kind, RawValueKPICalculationStrategy(score))
+
diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/KPICalculationStrategy.kt b/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/strategy/KPICalculationStrategy.kt
similarity index 52%
rename from app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/KPICalculationStrategy.kt
rename to kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/strategy/KPICalculationStrategy.kt
index 8d31a145..516ea616 100644
--- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/KPICalculationStrategy.kt
+++ b/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/strategy/KPICalculationStrategy.kt
@@ -1,6 +1,6 @@
-package de.fraunhofer.iem.app.kpi.strategy
+package de.fraunhofer.iem.kpiCalculator.core.strategy
 
-import de.fraunhofer.iem.app.kpi.dto.KPIHierarchyEdgeDto
+import de.fraunhofer.iem.kpiCalculator.core.hierarchy.KPIHierarchyEdgeDto
 
 fun interface KPICalculationStrategy {
     fun calculateKPI(children: List<KPIHierarchyEdgeDto>): Pair<Int, List<KPIHierarchyEdgeDto>>
diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/RawValueKPICalculationStrategy.kt b/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/strategy/RawValueKPICalculationStrategy.kt
similarity index 57%
rename from app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/RawValueKPICalculationStrategy.kt
rename to kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/strategy/RawValueKPICalculationStrategy.kt
index 0bb577e7..86c0a134 100644
--- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/strategy/RawValueKPICalculationStrategy.kt
+++ b/kpi-calculator/core/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/core/strategy/RawValueKPICalculationStrategy.kt
@@ -1,9 +1,9 @@
-package de.fraunhofer.iem.app.kpi.strategy
+package de.fraunhofer.iem.kpiCalculator.core.strategy
 
-import de.fraunhofer.iem.app.kpi.dto.KPIHierarchyEdgeDto
+import de.fraunhofer.iem.kpiCalculator.core.hierarchy.KPIHierarchyEdgeDto
 
 class RawValueKPICalculationStrategy(private val value: Int) :
-    de.fraunhofer.iem.app.kpi.strategy.KPICalculationStrategy {
+    KPICalculationStrategy {
     override fun calculateKPI(children: List<KPIHierarchyEdgeDto>): Pair<Int, List<KPIHierarchyEdgeDto>> {
         return Pair(this.value, children)
     }
diff --git a/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/AdapterResult.kt b/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/AdapterResult.kt
index 6c71e534..bdb5acf4 100644
--- a/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/AdapterResult.kt
+++ b/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/AdapterResult.kt
@@ -1,10 +1,10 @@
 package de.fraunhofer.iem.kpiCalculator.model.adapter
 
-import de.fraunhofer.iem.kpiCalculator.model.kpi.RawValueKpiCreateDto
+import de.fraunhofer.iem.kpiCalculator.model.kpi.RawValueKpiDto
 
 enum class ErrorType { DATA_VALIDATION_ERROR }
 
 sealed class AdapterResult {
-    data class Success(val rawValueKpiCreateDto: RawValueKpiCreateDto) : AdapterResult()
+    data class Success(val rawValueKpiDto: RawValueKpiDto) : AdapterResult()
     data class Error(val type: ErrorType) : AdapterResult()
 }
diff --git a/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/RawValueKpiCreateDto.kt b/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/RawValueKpiCreateDto.kt
deleted file mode 100644
index fe82d588..00000000
--- a/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/RawValueKpiCreateDto.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package de.fraunhofer.iem.kpiCalculator.model.kpi
-
-data class RawValueKpiCreateDto(val kind: KpiKind, val score: Int)
diff --git a/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/RawValueKpiDto.kt b/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/RawValueKpiDto.kt
new file mode 100644
index 00000000..ef3e322c
--- /dev/null
+++ b/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/RawValueKpiDto.kt
@@ -0,0 +1,3 @@
+package de.fraunhofer.iem.kpiCalculator.model.kpi
+
+data class RawValueKpiDto(val kind: KpiId, val score: Int)
diff --git a/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/hierarchy/KpiHierarchy.kt b/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/hierarchy/KpiHierarchy.kt
index a7ce187e..be3d6900 100644
--- a/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/hierarchy/KpiHierarchy.kt
+++ b/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/hierarchy/KpiHierarchy.kt
@@ -20,3 +20,4 @@ data class KpiNode(val kpiId: KpiId, val strategyType: KpiStrategyId, val childr
 
 @Serializable
 data class KpiEdge(val target: KpiNode, val weight: Double)
+
diff --git a/kpi-calculator/model/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/hierarchy/KpiNodeTest.kt b/kpi-calculator/model/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/hierarchy/KpiHierarchyTest.kt
similarity index 82%
rename from kpi-calculator/model/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/hierarchy/KpiNodeTest.kt
rename to kpi-calculator/model/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/hierarchy/KpiHierarchyTest.kt
index c2872514..014b4c5e 100644
--- a/kpi-calculator/model/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/hierarchy/KpiNodeTest.kt
+++ b/kpi-calculator/model/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/model/kpi/hierarchy/KpiHierarchyTest.kt
@@ -2,13 +2,14 @@ package de.fraunhofer.iem.kpiCalculator.model.kpi.hierarchy
 
 import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiId
 import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiStrategyId
+import de.fraunhofer.iem.kpiCalculator.model.kpi.RawValueKpiDto
 import kotlinx.serialization.encodeToString
 import kotlinx.serialization.json.Json
 import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.assertDoesNotThrow
 import kotlin.test.assertEquals
 
-class KpiNodeTest {
+class KpiHierarchyTest {
     @Test
     fun constructHierarchy() {
         // This test doesn't really test any functionality. It's mainly here as a reminder to fail whenever we change something
@@ -43,4 +44,17 @@ class KpiNodeTest {
             assertEquals(hierarchy.schemaVersion, "1.0.0")
         }
     }
+
+    @Test
+    fun connectHierarchyAndData() {
+
+        val rawValueKpis = listOf(
+            RawValueKpiDto(
+                kind = KpiId.COMMENTS_IN_CODE,
+                score = 40
+            )
+        )
+        val hierarchy = DefaultHierarchy.get()
+        println(KpiHierarchy.isValid(hierarchy))
+    }
 }
-- 
GitLab