diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/KPIDto.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/KPIDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8c5e774e87afba0c951960e93069925b33a4d162
--- /dev/null
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/KPIDto.kt
@@ -0,0 +1,31 @@
+package de.fraunhofer.iem.dataprovider.kpi
+
+import de.fraunhofer.iem.dataprovider.kpi.model.KPI
+import de.fraunhofer.iem.dataprovider.kpi.strategy.KPICalculationStrategy
+import java.sql.Timestamp
+import java.time.Instant
+
+
+class KPIDto(val name: String, val description: String, val isRoot: Boolean, private val calculationStrategy: KPICalculationStrategy) {
+    val hierarchyEdges: MutableList<KPIHierarchyEdgeDto> = mutableListOf<KPIHierarchyEdgeDto>()
+    var value: Int? = null
+
+    fun calculateKPI() {
+       this.value = calculationStrategy.calculateKPI(this.hierarchyEdges);
+    }
+
+    fun addChildKPI(kpiDto: KPIDto, weight: Double) {
+        val hierarchyEdge = KPIHierarchyEdgeDto(this, kpiDto, weight)
+        this.hierarchyEdges.add(hierarchyEdge)
+    }
+}
+
+fun KPIDto.toDbObject(): KPI {
+    val kpi = KPI()
+    kpi.name = this.name
+    kpi.value = this.value
+    kpi.description = this.description
+    kpi.isRoot = this.isRoot
+    kpi.timestamp = Timestamp.from(Instant.now())
+    return kpi
+}
\ No newline at end of file
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/KPIHierarchyEdgeDto.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/KPIHierarchyEdgeDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f0bd29077bd1658325702cc79c7a609ab60fee8c
--- /dev/null
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/KPIHierarchyEdgeDto.kt
@@ -0,0 +1,3 @@
+package de.fraunhofer.iem.dataprovider.kpi
+
+data class KPIHierarchyEdgeDto (val from: KPIDto, val to: KPIDto, val weight: Double)
\ No newline at end of file
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/model/KPI.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/model/KPI.kt
new file mode 100644
index 0000000000000000000000000000000000000000..fc1f2b3702022c9f40aec712f59fc2bb95f78d88
--- /dev/null
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/model/KPI.kt
@@ -0,0 +1,51 @@
+package de.fraunhofer.iem.dataprovider.kpi.model
+
+import de.fraunhofer.iem.dataprovider.toolRun.model.Repository
+import jakarta.persistence.*
+import org.hibernate.annotations.JdbcTypeCode
+import org.hibernate.type.SqlTypes
+import java.sql.Timestamp
+import java.util.*
+
+@Entity
+@Table(name = "kpi")
+class KPI {
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    @Column(name = "id", nullable = false)
+    var id: UUID? = null
+
+    @ManyToOne
+    @JoinColumn(name = "repository_id")
+    var repository: Repository? = null
+
+    @OneToMany(mappedBy = "from", cascade = [CascadeType.MERGE, CascadeType.REMOVE], orphanRemoval = true)
+    var hierarchyEdges: MutableSet<KPIHierarchyEdge> = mutableSetOf()
+
+    @Column(name = "value")
+    var value: Int? = null
+
+    @Column(name = "isRoot")
+    var isRoot: Boolean? = null
+
+    @Column(name = "name")
+    var name: String? = null
+
+    @Column(name = "description")
+    var description: String? = null
+
+    @JdbcTypeCode(SqlTypes.TIMESTAMP)
+    @Column(name = "timestamp")
+    var timestamp: Timestamp? = null
+
+    fun addHierarchyEdges(kpiHierarchyEdges: Collection<KPIHierarchyEdge>) {
+        kpiHierarchyEdges.forEach {
+            this.addHierarchyEdge(it)
+        }
+    }
+
+    fun addHierarchyEdge(hierarchyEdge: KPIHierarchyEdge) {
+        hierarchyEdge.from = this
+        this.hierarchyEdges.add(hierarchyEdge)
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/model/KPIHierarchyEdge.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/model/KPIHierarchyEdge.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6994560f93a2b26b438c77aec9e3aa5c1ea88bd9
--- /dev/null
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/model/KPIHierarchyEdge.kt
@@ -0,0 +1,24 @@
+package de.fraunhofer.iem.dataprovider.kpi.model
+
+import jakarta.persistence.*
+import java.util.*
+
+@Entity
+@Table(name = "kpi_hierarchy_edge")
+class KPIHierarchyEdge {
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    @Column(name = "id", nullable = false)
+    var id: UUID? = null
+
+    @ManyToOne(cascade = [CascadeType.MERGE])
+    @JoinColumn(name = "from_id")
+    var from: KPI? = null
+
+    @ManyToOne(cascade = [CascadeType.MERGE])
+    @JoinColumn(name = "to_id")
+    var to: KPI? = null
+
+    @Column(name = "weight")
+    var weight: Double? = null
+}
\ No newline at end of file
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/repository/KPIHierarchyEdgeRepository.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/repository/KPIHierarchyEdgeRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5d455ef31b09b1b26aa62cf7baf8da69ecd64166
--- /dev/null
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/repository/KPIHierarchyEdgeRepository.kt
@@ -0,0 +1,7 @@
+package de.fraunhofer.iem.dataprovider.kpi.repository
+
+import de.fraunhofer.iem.dataprovider.kpi.model.KPIHierarchyEdge
+import org.springframework.data.jpa.repository.JpaRepository
+import java.util.*
+
+interface KPIHierarchyEdgeRepository: JpaRepository<KPIHierarchyEdge, UUID> {}
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/repository/KPIRepository.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/repository/KPIRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6a9ddd84aef58704d55282a3cf1c2ec4e11c955d
--- /dev/null
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/repository/KPIRepository.kt
@@ -0,0 +1,9 @@
+package de.fraunhofer.iem.dataprovider.kpi.repository
+
+import de.fraunhofer.iem.dataprovider.kpi.model.KPI
+import org.springframework.data.jpa.repository.JpaRepository
+import java.util.*
+
+interface KPIRepository : JpaRepository<KPI, UUID> {
+    fun findByRepository_Id(id: UUID): List<KPI>
+}
\ No newline at end of file
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/service/KPIService.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/service/KPIService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..46863bf5dc9c8dcf8540cae28c72b667c2f85c09
--- /dev/null
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/service/KPIService.kt
@@ -0,0 +1,93 @@
+package de.fraunhofer.iem.dataprovider.kpi.service
+
+import de.fraunhofer.iem.dataprovider.kpi.KPIDto
+import de.fraunhofer.iem.dataprovider.kpi.model.KPI
+import de.fraunhofer.iem.dataprovider.kpi.model.KPIHierarchyEdge
+import de.fraunhofer.iem.dataprovider.kpi.repository.KPIHierarchyEdgeRepository
+import de.fraunhofer.iem.dataprovider.kpi.repository.KPIRepository
+import de.fraunhofer.iem.dataprovider.kpi.toDbObject
+import de.fraunhofer.iem.dataprovider.logger.getLogger
+import de.fraunhofer.iem.dataprovider.toolRun.model.Repository
+import org.springframework.stereotype.Service
+
+@Service
+class KPIService(private val kpiRepository: KPIRepository, private val kpiHierarchyEdgeRepository: KPIHierarchyEdgeRepository) {
+
+    private val logger = getLogger(javaClass)
+
+    private fun calculateKPIsRecursively(kpi: KPIDto, visited: MutableSet<KPIDto>) {
+        // Check if the KPI has already been visited
+        if (visited.contains(kpi)) {
+            return
+        }
+
+        // Check if the KPI has child KPIs
+        if (kpi.hierarchyEdges.isEmpty()) {
+            // Leaf node, calculate the KPI value
+            kpi.calculateKPI()
+            visited.add(kpi)
+            return
+        }
+
+        // Recursively calculate child KPIs first
+        for (childEdge in kpi.hierarchyEdges) {
+            calculateKPIsRecursively(childEdge.to, visited)
+        }
+
+        // Calculate the KPI value after processing child KPIs
+        kpi.calculateKPI()
+        visited.add(kpi)
+    }
+
+    fun calculateKPIs(rootKPI: KPIDto) {
+        val visited: MutableSet<KPIDto> = mutableSetOf()
+        calculateKPIsRecursively(rootKPI, visited)
+    }
+
+    fun storeAndPurgeOld(repository: Repository, rootKPI: KPIDto) {
+        purgeAllKPIs(repository)
+        val kpiDtoToEntityMapping: MutableMap<KPIDto, KPI> = mutableMapOf()
+        storeKPI(repository, rootKPI, kpiDtoToEntityMapping)
+    }
+
+    private fun storeKPI(repository: Repository, kpi: KPIDto, kpiDtoToEntityMapping: MutableMap<KPIDto, KPI>) {
+        // already visited
+        if (kpiDtoToEntityMapping.contains(kpi)) {
+            return;
+        }
+
+        if (kpi.hierarchyEdges.isEmpty()) {
+            // leaf node
+            val kpiEntity = kpi.toDbObject()
+            kpiEntity.repository = repository
+
+            kpiDtoToEntityMapping[kpi] = kpiEntity
+            kpiRepository.save(kpiEntity)
+            logger.info("Storing leaf node ${kpi.name}")
+            return;
+        }
+
+        for (childEdge in kpi.hierarchyEdges) {
+            storeKPI(repository, childEdge.to, kpiDtoToEntityMapping)
+        }
+
+        val kpiEntity = kpi.toDbObject()
+        kpiEntity.repository = repository
+        kpiDtoToEntityMapping[kpi] = kpiEntity
+        kpiRepository.save(kpiEntity)
+        logger.info("Storing node ${kpi.name}")
+        for (hierarchyEdge in kpi.hierarchyEdges) {
+            val hierarchyEdgeEntity = KPIHierarchyEdge()
+            hierarchyEdgeEntity.from = kpiEntity
+            hierarchyEdgeEntity.to = kpiDtoToEntityMapping[hierarchyEdge.to]
+            hierarchyEdgeEntity.weight = hierarchyEdge.weight
+            kpiHierarchyEdgeRepository.save(hierarchyEdgeEntity)
+            logger.info("Storing edge ${hierarchyEdge.weight}: From ${hierarchyEdge.from.name} to ${hierarchyEdge.to.name}")
+        }
+    }
+
+    private fun purgeAllKPIs(repository: Repository) {
+        val kpis: List<KPI> = kpiRepository.findByRepository_Id(repository.id!!)
+        kpiRepository.deleteAll(kpis)
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/strategy/AggregationKPICalculationStrategy.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/strategy/AggregationKPICalculationStrategy.kt
new file mode 100644
index 0000000000000000000000000000000000000000..292617cfb6e48855643285e1787c7222456f690e
--- /dev/null
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/strategy/AggregationKPICalculationStrategy.kt
@@ -0,0 +1,16 @@
+package de.fraunhofer.iem.dataprovider.kpi.strategy
+
+import de.fraunhofer.iem.dataprovider.kpi.KPIHierarchyEdgeDto
+
+class AggregationKPICalculationStrategy: KPICalculationStrategy {
+    override fun calculateKPI(children: List<KPIHierarchyEdgeDto>): Int {
+        var aggregate = 0;
+        for (child in children) {
+            if (child.to.value != null) {
+                val childValue = child.to.value!!;
+                aggregate += (childValue.toFloat() * child.weight).toInt();
+            }
+        }
+        return aggregate;
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/strategy/KPICalculationStrategy.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/strategy/KPICalculationStrategy.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2519be7d76dfedd65973f48c43fc0a8b03f13ed1
--- /dev/null
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/strategy/KPICalculationStrategy.kt
@@ -0,0 +1,8 @@
+package de.fraunhofer.iem.dataprovider.kpi.strategy
+
+import de.fraunhofer.iem.dataprovider.kpi.KPIHierarchyEdgeDto
+
+interface KPICalculationStrategy {
+    fun calculateKPI(children: List<KPIHierarchyEdgeDto>): Int;
+}
+
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/strategy/RatioKPICalculationStrategy.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/strategy/RatioKPICalculationStrategy.kt
new file mode 100644
index 0000000000000000000000000000000000000000..668167891155434e1b5e51542811695f66d4590d
--- /dev/null
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/strategy/RatioKPICalculationStrategy.kt
@@ -0,0 +1,17 @@
+package de.fraunhofer.iem.dataprovider.kpi.strategy
+
+import de.fraunhofer.iem.dataprovider.kpi.KPIHierarchyEdgeDto
+
+class RatioKPICalculationStrategy(): KPICalculationStrategy {
+    override fun calculateKPI(children: List<KPIHierarchyEdgeDto>): Int {
+        if (children.size != 2) {
+            throw Exception("Requires exactly two children")
+        }
+        val firstValue = children[0].to.value
+        val secondValue = children[1].to.value
+        if (firstValue!! >= secondValue!!) {
+            return ((secondValue / firstValue) * 100).toInt();
+        }
+        return ((firstValue / secondValue) * 100).toInt();
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/strategy/RawValueKPICalculationStrategy.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/strategy/RawValueKPICalculationStrategy.kt
new file mode 100644
index 0000000000000000000000000000000000000000..73d6a9b4011129df8cd591243dc37bd1a786e322
--- /dev/null
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/strategy/RawValueKPICalculationStrategy.kt
@@ -0,0 +1,9 @@
+package de.fraunhofer.iem.dataprovider.kpi.strategy
+
+import de.fraunhofer.iem.dataprovider.kpi.KPIHierarchyEdgeDto
+
+class RawValueKPICalculationStrategy(val value: Int): KPICalculationStrategy {
+    override fun calculateKPI(children: List<KPIHierarchyEdgeDto>): Int {
+        return this.value;
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/TaskManager.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/TaskManager.kt
index d69796995469a866489b062e000c96853ceee3e7..fedefcae593637865ddbcf05a318c4995cd45335 100644
--- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/TaskManager.kt
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/TaskManager.kt
@@ -1,6 +1,7 @@
 package de.fraunhofer.iem.dataprovider.taskManager
 
 import de.fraunhofer.iem.dataprovider.gitlab.OpenCodeGitlabConfiguration
+import de.fraunhofer.iem.dataprovider.kpi.service.KPIService
 import de.fraunhofer.iem.dataprovider.logger.getLogger
 import de.fraunhofer.iem.dataprovider.taskManager.model.*
 import de.fraunhofer.iem.dataprovider.taskManager.tasks.*
@@ -27,7 +28,8 @@ import java.util.*
 class TaskManager(
         private val config: Config,
         private val openCodeGitlabConfiguration: OpenCodeGitlabConfiguration,
-        private val toolRunService: ToolRunService
+        private val toolRunService: ToolRunService,
+        private val kpiService: KPIService
 ) {
 
     // The used default dispatcher is ok for CPU-bound workloads. However,
@@ -126,35 +128,30 @@ class TaskManager(
                         toolRunService
                     )
 
-                    val gitlabTask = GetRepositoryDetailsTask(
-                            event.repoId,
-                            openCodeGitlabConfiguration,
-                            toolRunService,
-                            ::addEvent
-                    )
-
                     taskIds.add(odcTask.taskID)
                     taskIds.add(detektTask.taskID)
-                    taskIds.add(gitlabTask.taskID)
 
                     dependentEvents[groupId] = taskIds
 
                     worker.addTask(odcTask)
                     worker.addTask(detektTask)
-                    worker.addTask(gitlabTask)
                 }
 
                 is SarifProcessGroupDone -> {
+                    logger.info("Done with Sarif Task")
                     val eventGroup = dependentEvents[event.groupId]
-
                     if (eventGroup != null) {
                         eventGroup.remove(event.taskId)
                         if (eventGroup.isEmpty()) {
-                            worker.addTask(MetricsTask(event.repoId, toolRunService, ::addEvent))
+                            logger.info("Adding repository details task")
+                            worker.addTask(GetRepositoryDetailsTask(event.repoId, openCodeGitlabConfiguration, toolRunService, ::addEvent))
                         }
                     }
                 }
 
+                is GetRepositoryDetailsDone -> {
+                    worker.addTask(MetricsTask(event.repoId, toolRunService, kpiService, ::addEvent))
+                }
 
                 else -> {
                     logger.info("Received event without special handling associated $event")
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/model/Event.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/model/Event.kt
index 83952b82c059090a2cdb055887ef0339b45d7fc3..c05208f79850642cc03a79bbe60aac0b2d4642ae 100644
--- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/model/Event.kt
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/model/Event.kt
@@ -19,4 +19,4 @@ class SarifProcessDone(override val taskId: UUID, val repoId: UUID, val sarif: S
 class SarifProcessGroupDone(override val taskId: UUID, val repoId: UUID, val groupId: UUID, val sarif: Sarif) :
     TaskDone()
 
-class GetRepositoryDetailsDone(override val taskId: UUID, val repositoryDetailsEntity: RepositoryDetails) : TaskDone()
+class GetRepositoryDetailsDone(override val taskId: UUID, val repoId: UUID, val repositoryDetailsEntity: RepositoryDetails) : TaskDone()
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/GetRepositoryDetailsTask.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/GetRepositoryDetailsTask.kt
index d1bb20eebb8044727cba711449f8141d957e51c1..e85c940c84fa49339dff39671f65865e7f539e57 100644
--- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/GetRepositoryDetailsTask.kt
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/GetRepositoryDetailsTask.kt
@@ -33,7 +33,7 @@ class GetRepositoryDetailsTask(
             logger.info("Collected repository details from $repoId (${repositoryDetailsDto}) successfully")
             val repositoryDetailsEntity = toolRunService.createRepositoryDetails(repositoryDetailsDto);
             logger.info("Stored repository details for $repoId (${repositoryDetailsEntity}) successfully")
-            responseChannel(GetRepositoryDetailsDone(taskID, repositoryDetailsEntity))
+            responseChannel(GetRepositoryDetailsDone(taskID, repoId, repositoryDetailsEntity))
         } else {
             logger.error("Repository $repoId can not be found in the database")
         }
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/MetricsTask.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/MetricsTask.kt
index 9b583dd61c0524d562daa948e62796aaaaf32c82..42549ccc3f31b9b78af36d3759468ba6c5885d40 100644
--- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/MetricsTask.kt
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/MetricsTask.kt
@@ -1,17 +1,52 @@
 package de.fraunhofer.iem.dataprovider.taskManager.tasks
 
+import de.fraunhofer.iem.dataprovider.kpi.KPIDto
+import de.fraunhofer.iem.dataprovider.kpi.service.KPIService
 import de.fraunhofer.iem.dataprovider.taskManager.model.Event
+import de.fraunhofer.iem.dataprovider.kpi.strategy.AggregationKPICalculationStrategy
+import de.fraunhofer.iem.dataprovider.kpi.strategy.RatioKPICalculationStrategy
+import de.fraunhofer.iem.dataprovider.kpi.strategy.RawValueKPICalculationStrategy
 import de.fraunhofer.iem.dataprovider.toolRun.ToolRunService
+import de.fraunhofer.iem.dataprovider.toolRun.model.RepositoryDetails
 import java.util.*
 
 class MetricsTask(
     val repoId: UUID,
     private val toolRunService: ToolRunService,
-
+    private val kpiService: KPIService,
     override val responseChannel: suspend (task: Event) -> Unit
 ) : Task() {
     override suspend fun execute() {
         logger.info("Starting metrics task for repoId $repoId")
-        toolRunService.getLatestToolRunsForRepo(repoId)
+        val repository = toolRunService.findRepoByID(repoId);
+        val repositoryDetails = toolRunService.getLatestRepositoryDetailsByRepositoryId(repoId);
+        if (repositoryDetails != null && repository != null) {
+            val rootKPI = generateKPITree(repositoryDetails)
+            kpiService.calculateKPIs(rootKPI)
+            kpiService.storeAndPurgeOld(repository, rootKPI)
+        }
+    }
+
+    private fun generateKPITree(repositoryDetails: RepositoryDetails): KPIDto {
+        // lowest level leaves
+        val numberOfCommitsKPI = KPIDto( "Number of commits", "Overall transparency score between 0-100 :-)", false, RawValueKPICalculationStrategy(repositoryDetails.numberOfCommits!!))
+        val numberOfSignedCommitsKPI = KPIDto("Number of signed commits", "Overall transparency score between 0-100 :-)", false, RawValueKPICalculationStrategy(repositoryDetails.numberOfSignedCommits!!))
+        val isDefaultBranchProtectedKPI = KPIDto( "Is Default Branch Protected", "Is the default branch protected?", false, RawValueKPICalculationStrategy(if (repositoryDetails.isDefaultBranchProtected == true) 100 else 0))
+
+        val signedCommitsRatioKPI = KPIDto( "Signed Commit Ratio", "Ratio between signed and all commits", false, RatioKPICalculationStrategy())
+        signedCommitsRatioKPI.addChildKPI(numberOfCommitsKPI, 1.0)
+        signedCommitsRatioKPI.addChildKPI(numberOfSignedCommitsKPI, 1.0)
+
+        // second level
+        val securityKPI = KPIDto(  "Security score", "Overall project security score between 0-100 :-)", false, AggregationKPICalculationStrategy())
+        val transparencyKPI = KPIDto( "Transparency score", "Overall transparency score between 0-100 :-)", false, AggregationKPICalculationStrategy())
+        securityKPI.addChildKPI(isDefaultBranchProtectedKPI, 0.5)
+        securityKPI.addChildKPI(signedCommitsRatioKPI, 0.5)
+        transparencyKPI.addChildKPI(signedCommitsRatioKPI, 1.0)
+
+        val rootKPI = KPIDto( "Project score", "Overall project score between 0-100 :-)", true, AggregationKPICalculationStrategy())
+        rootKPI.addChildKPI(securityKPI, 0.5)
+        rootKPI.addChildKPI(transparencyKPI, 0.5)
+        return rootKPI
     }
 }
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/toolRun/RepositoryDetailsRepository.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/toolRun/RepositoryDetailsRepository.kt
index 3d51a9d055f9fce679c2ee6dfc38d92ae1e23732..a13b4997cbe95c8202fb0487aeaf505544167548 100644
--- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/toolRun/RepositoryDetailsRepository.kt
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/toolRun/RepositoryDetailsRepository.kt
@@ -1,8 +1,11 @@
 package de.fraunhofer.iem.dataprovider.toolRun
 
 import de.fraunhofer.iem.dataprovider.toolRun.model.RepositoryDetails
+import org.springframework.data.domain.Sort
 import org.springframework.data.jpa.repository.JpaRepository
 import java.util.*
 
 
-interface RepositoryDetailsRepository : JpaRepository<RepositoryDetails, UUID> {}
+interface RepositoryDetailsRepository : JpaRepository<RepositoryDetails, UUID> {
+    fun findFirstByRepository_IdOrderByTimestampDesc(id: UUID): Optional<RepositoryDetails>
+}
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/toolRun/ToolRunService.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/toolRun/ToolRunService.kt
index c62e2cbcb4b31df425d9d98c1bf9058f63b64232..7985c50ad71ca9e012ec137fa77ac4451946fe02 100644
--- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/toolRun/ToolRunService.kt
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/toolRun/ToolRunService.kt
@@ -137,4 +137,20 @@ class ToolRunService(
     fun createRepositoryDetails(repositoryDetailsDto: RepositoryDetailsDto): RepositoryDetails {
         return repositoryDetailsRepository.save(repositoryDetailsDto.toDbObject())
     }
+
+    fun getLatestRepositoryDetailsByRepositoryId(repositoryId: UUID): RepositoryDetails? {
+        val repositoryDetails = repositoryDetailsRepository.findFirstByRepository_IdOrderByTimestampDesc(repositoryId);
+        if (repositoryDetails.isEmpty) {
+            return null
+        }
+        return repositoryDetails.get();
+    }
+
+    fun getRepositoryDetailsById(id: UUID): RepositoryDetails? {
+        val repositoryDetails = repositoryDetailsRepository.findById(id);
+        if (repositoryDetails.isEmpty) {
+            return null
+        }
+        return repositoryDetails.get()
+    }
 }