Repository: BaghdadTeam/PlanMate
Pull request #23: refactor/project-refactor
Author: login: Abdelrahman-El-Gendy
Created: 2025-05-05T18:09:54Z | Merged: 2025-05-07T16:40:52Z



Diff:
diff --git a/src/main/kotlin/data/datasource/mapper/project/ProjectMapper.kt b/src/main/kotlin/data/datasource/mapper/project/ProjectMapper.kt
index 098e867a..59eb9783 100644
--- a/src/main/kotlin/data/datasource/mapper/project/ProjectMapper.kt
+++ b/src/main/kotlin/data/datasource/mapper/project/ProjectMapper.kt
@@ -4,7 +4,7 @@ import org.baghdad.data.datasource.CsvMapper
 import org.baghdad.logic.model.entities.ProjectEntity
 import java.util.UUID
 
-class ProjectMapper: CsvMapper<ProjectEntity> {
+class ProjectMapper : CsvMapper<ProjectEntity> {
     override fun header(): String {
         return "id,name,creatorId"
     }
@@ -14,7 +14,7 @@ class ProjectMapper: CsvMapper<ProjectEntity> {
         return ProjectEntity(
             id = UUID.fromString(project[ProjectColumns.ID]),
             name = project[ProjectColumns.NAME],
-            creatorId = project[ProjectColumns.CREATOR_ID]
+            creatorId = UUID.fromString(project[ProjectColumns.CREATOR_ID])
         )
     }
 
diff --git a/src/main/kotlin/data/local/ProjectDataSource.kt b/src/main/kotlin/data/local/ProjectDataSource.kt
index 985cf7fb..9c1fc8e6 100644
--- a/src/main/kotlin/data/local/ProjectDataSource.kt
+++ b/src/main/kotlin/data/local/ProjectDataSource.kt
@@ -4,6 +4,7 @@ import org.baghdad.data.datasource.DataSource
 import org.baghdad.logic.model.entities.ProjectEntity
 import org.baghdad.logic.model.entities.StateEntity
 import org.baghdad.logic.model.entities.TaskEntity
+import org.baghdad.logic.model.exceptions.ProjectNotFoundException
 import java.util.UUID
 
 class ProjectDataSource(
@@ -20,14 +21,15 @@ class ProjectDataSource(
         return projectDataSource.loadAll()
     }
 
-    fun getProjectById(id: String): ProjectEntity? {
-        return projectDataSource.loadAll().find { it.id.toString() == id }
+    fun getProjectById(id: UUID): ProjectEntity {
+        return projectDataSource.loadAll().find { it.id == id }
+            .takeIf { it != null }?: throw ProjectNotFoundException("No project found")
     }
 
     fun updateProject(project: ProjectEntity) {
         val allData = projectDataSource.loadAll().toMutableList()
         val projectIndex = allData.indexOfFirst { it.id == project.id }
-        if (projectIndex == -1) throw Exception("No project found")
+        if (projectIndex == -1) throw ProjectNotFoundException("No project found")
         allData[projectIndex] = project
         projectDataSource.update(allData)
     }
@@ -35,7 +37,7 @@ class ProjectDataSource(
     fun deleteProject(projectId: UUID) {
         val projects = projectDataSource.loadAll().toMutableList()
         val project = projects.indexOfFirst { it.id == projectId }
-        if (project == -1) throw Exception("No project found")
+        if (project == -1) throw ProjectNotFoundException("No project found")
 
         val projectStates = projectStatesDataSource.loadAll().toMutableList()
         val tasks = taskDataSource.loadAll().toMutableList()
diff --git a/src/main/kotlin/data/repositories/project/ProjectRepositoryImpl.kt b/src/main/kotlin/data/repositories/project/ProjectRepositoryImpl.kt
new file mode 100644
index 00000000..8f77618e
--- /dev/null
+++ b/src/main/kotlin/data/repositories/project/ProjectRepositoryImpl.kt
@@ -0,0 +1,30 @@
+package org.baghdad.data.repository.project
+
+import org.baghdad.data.local.ProjectDataSource
+import org.baghdad.logic.model.entities.ProjectEntity
+import org.baghdad.logic.repositories.ProjectRepository
+import java.util.UUID
+
+class ProjectRepositoryImpl(
+    private val dataSource: ProjectDataSource
+) : ProjectRepository {
+    override fun createProject(project: ProjectEntity) {
+        dataSource.createProject(project)
+    }
+
+    override fun getProjectById(id: UUID): ProjectEntity {
+        return dataSource.getProjectById(id)
+    }
+
+    override fun getAllProjects(): List<ProjectEntity> {
+        return dataSource.getAllProjects()
+    }
+
+    override fun deleteProject(id: UUID) {
+        dataSource.deleteProject(id)
+    }
+
+    override fun editProject(project: ProjectEntity) {
+        dataSource.updateProject(project)
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/di/UiModule.kt b/src/main/kotlin/di/UiModule.kt
index 2b48c39c..1b48c964 100644
--- a/src/main/kotlin/di/UiModule.kt
+++ b/src/main/kotlin/di/UiModule.kt
@@ -1,41 +1,22 @@
 package org.baghdad.di
 
-import org.baghdad.logic.usecase.projectstates.DeleteStateForProjectUseCase
-import org.baghdad.presentation.authentication.LoginUi
-import org.baghdad.presentation.authentication.LogoutUi
-import org.baghdad.presentation.projectStates.AddStateToProjectUI
-import org.baghdad.presentation.projectStates.EditProjectStateUI
-import org.baghdad.presentation.projectStates.GetAllStatesPerProjectUI
-import org.baghdad.presentation.projectStates.GetStateByIdUI
+import org.baghdad.presentation.project.CreateProjectUi
+import org.baghdad.presentation.project.DeleteProjectUi
+import org.baghdad.presentation.project.ListProjectUi
 import org.baghdad.presentation.task.*
 import org.koin.dsl.module
 
 val uiModule = module {
 
-    // region  :: TASKS ::
     single { CreateTaskUI(get(), get(), get(), get()) }
     single { DeleteTaskUI(get(), get(), get(), get()) }
     single { GetTasksByStateIdUI(get(), get(), get()) }
     single { GetTasksByStateIdUI(get(), get(), get()) }
     single { UpdateTaskUI(get(), get(), get(), get()) }
     single { GetTaskByIdUI(get(), get(), get()) }
-    // endregion
 
-    // region  :: PROJECT STATES ::
-
-    single { AddStateToProjectUI(get(), get(), get(), get()) }
-    single { EditProjectStateUI(get(), get(), get(), get()) }
-    single { DeleteStateForProjectUseCase(get(), get(), get()) }
-    single { GetAllStatesPerProjectUI(get(), get(), get()) }
-    single { GetStateByIdUI(get(), get(), get()) }
-
-    // endregion
-
-    // region  :: PROJECTS ::
-    // endregion
-
-    // region  :: Auth ::
-    single { LoginUi(get(), get(), get()) }
-    single { LogoutUi(get(), get(), get()) }
-    // endregion
+    // --------------------ProjectUi----------------------
+    single { CreateProjectUi(get()) }
+    single { DeleteProjectUi(get()) }
+    single { ListProjectUi(get()) }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/di/UseCaseModule.kt b/src/main/kotlin/di/UseCaseModule.kt
index ea976e53..f0254365 100644
--- a/src/main/kotlin/di/UseCaseModule.kt
+++ b/src/main/kotlin/di/UseCaseModule.kt
@@ -1,10 +1,17 @@
 package org.baghdad.di
 
 import org.baghdad.logic.usecase.StateTransitionUseCase
-import org.baghdad.logic.usecase.authentication.LoginUseCase
-import org.baghdad.logic.usecase.authentication.LogoutUseCase
-import org.baghdad.logic.usecase.projectstates.*
-import org.baghdad.logic.usecase.task.*
+import org.baghdad.logic.usecase.project.CreateProjectUseCase
+import org.baghdad.logic.usecase.project.DeleteProjectUseCase
+import org.baghdad.logic.usecase.project.EditProjectUseCase
+import org.baghdad.logic.usecase.project.GetAllProjectsUseCase
+import org.baghdad.logic.usecase.task.CreateTaskUseCase
+import org.baghdad.logic.usecase.task.DeleteTaskUseCase
+import org.baghdad.logic.usecase.task.GetAllTasksUseCase
+import org.baghdad.logic.usecase.task.GetTaskByIdUseCase
+import org.baghdad.logic.usecase.task.GetTasksByProjectIdUseCase
+import org.baghdad.logic.usecase.task.GetTasksByStateIdUseCase
+import org.baghdad.logic.usecase.task.UpdateTaskUseCase
 import org.koin.dsl.module
 
 val useCaseModule = module {
@@ -20,22 +27,12 @@ val useCaseModule = module {
     single { GetTaskByIdUseCase(get()) }
     single { GetAllTasksUseCase(get()) }
     single { GetTasksByProjectIdUseCase(get()) }
-    // endregion
-
-    // region  ::  Project States Use Cases  ::
-
-    single { AddStateToProjectUseCase(get(), get(), get()) }
-    single { DeleteStateForProjectUseCase(get(), get(), get()) }
-    single { GetAllStatesPerProjectUseCase(get()) }
-    single { GetStateByIdUseCase(get()) }
-    single { EditProjectStatesUseCase(get(), get(), get()) }
-
-    // endregion
-
-    // region  ::  Authentication Use Cases  ::
 
-    single { LoginUseCase(get(), get(), get()) }
-    single { LogoutUseCase(get()) }
+    // region  ::  Project Use Cases  ::
 
+    single { CreateProjectUseCase(get(), get()) }
+    single { DeleteProjectUseCase(get(), get()) }
+    single { EditProjectUseCase(get(), get()) }
+    single { GetAllProjectsUseCase(get()) }
     // endregion
 }
\ No newline at end of file
diff --git a/src/main/kotlin/logic/model/entities/ProjectEntity.kt b/src/main/kotlin/logic/model/entities/ProjectEntity.kt
index 717e90f1..438b57ff 100644
--- a/src/main/kotlin/logic/model/entities/ProjectEntity.kt
+++ b/src/main/kotlin/logic/model/entities/ProjectEntity.kt
@@ -5,5 +5,5 @@ import java.util.UUID
 data class ProjectEntity(
     val id: UUID = UUID.randomUUID(),
     val name: String,
-    val creatorId: String
-)
+    val creatorId: UUID
+)
\ No newline at end of file
diff --git a/src/main/kotlin/logic/model/exceptions/ProjectExceptions.kt b/src/main/kotlin/logic/model/exceptions/ProjectExceptions.kt
new file mode 100644
index 00000000..6470e148
--- /dev/null
+++ b/src/main/kotlin/logic/model/exceptions/ProjectExceptions.kt
@@ -0,0 +1,5 @@
+package org.baghdad.logic.model.exceptions
+
+class ProjectNotFoundException(message: String) : Exception(message)
+class EmptyProjectNameException(message: String) : IllegalArgumentException(message)
+class AccessDeniedException(message: String) : Exception(message)
\ No newline at end of file
diff --git a/src/main/kotlin/logic/repositories/ProjectRepository.kt b/src/main/kotlin/logic/repositories/ProjectRepository.kt
index 2b3b23c3..0a672ccb 100644
--- a/src/main/kotlin/logic/repositories/ProjectRepository.kt
+++ b/src/main/kotlin/logic/repositories/ProjectRepository.kt
@@ -1,11 +1,13 @@
 package org.baghdad.logic.repositories
 
 import org.baghdad.logic.model.entities.ProjectEntity
+import java.util.UUID
 
 interface ProjectRepository {
 
     fun createProject(project: ProjectEntity)
-    fun getProjectById(id: String): ProjectEntity?
+    fun getProjectById(id: UUID): ProjectEntity
     fun getAllProjects(): List<ProjectEntity>
-    fun deleteProject(id: String): Boolean
+    fun deleteProject(id: UUID)
+    fun editProject(project: ProjectEntity)
 }
\ No newline at end of file
diff --git a/src/main/kotlin/logic/usecase/project/CreateProjectUseCase.kt b/src/main/kotlin/logic/usecase/project/CreateProjectUseCase.kt
new file mode 100644
index 00000000..cb95fa95
--- /dev/null
+++ b/src/main/kotlin/logic/usecase/project/CreateProjectUseCase.kt
@@ -0,0 +1,22 @@
+package org.baghdad.logic.usecase.project
+
+import org.baghdad.logic.model.entities.ProjectEntity
+import org.baghdad.logic.model.entities.UserType
+import org.baghdad.logic.model.exceptions.AccessDeniedException
+import org.baghdad.logic.model.exceptions.EmptyProjectNameException
+import org.baghdad.logic.repositories.ProjectRepository
+import org.baghdad.logic.repositories.UserRepository
+import java.util.UUID
+
+class CreateProjectUseCase(
+    private val projectRepository: ProjectRepository,
+    private val userRepository: UserRepository
+) {
+    operator fun invoke(projectName: String, userId : UUID){
+        val user = userRepository.getUserById(userId)
+        if (user.type != UserType.Admin) throw AccessDeniedException("Not authorized")
+        if (projectName.isBlank()) throw EmptyProjectNameException("Project name can't be empty")
+        val project = ProjectEntity(name = projectName, creatorId = user.id)
+        projectRepository.createProject(project)
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/logic/usecase/project/DeleteProjectUseCase.kt b/src/main/kotlin/logic/usecase/project/DeleteProjectUseCase.kt
new file mode 100644
index 00000000..d6ce174a
--- /dev/null
+++ b/src/main/kotlin/logic/usecase/project/DeleteProjectUseCase.kt
@@ -0,0 +1,18 @@
+package org.baghdad.logic.usecase.project
+
+import org.baghdad.logic.model.entities.UserType
+import org.baghdad.logic.model.exceptions.AccessDeniedException
+import org.baghdad.logic.repositories.ProjectRepository
+import org.baghdad.logic.repositories.UserRepository
+import java.util.UUID
+
+class DeleteProjectUseCase(
+    private val projectRepository: ProjectRepository,
+    private val userRepository: UserRepository
+) {
+    operator fun invoke(projectId: UUID,userId : UUID){
+        val user = userRepository.getUserById(userId)
+        if (user.type != UserType.Admin) throw AccessDeniedException("Not authorized")
+        projectRepository.deleteProject(projectId)
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/logic/usecase/project/EditProjectUseCase.kt b/src/main/kotlin/logic/usecase/project/EditProjectUseCase.kt
new file mode 100644
index 00000000..41bc1558
--- /dev/null
+++ b/src/main/kotlin/logic/usecase/project/EditProjectUseCase.kt
@@ -0,0 +1,24 @@
+package org.baghdad.logic.usecase.project
+
+import org.baghdad.logic.model.entities.UserType
+import org.baghdad.logic.model.exceptions.AccessDeniedException
+import org.baghdad.logic.model.exceptions.EmptyProjectNameException
+import org.baghdad.logic.repositories.ProjectRepository
+import org.baghdad.logic.repositories.UserRepository
+import java.util.UUID
+
+class EditProjectUseCase(
+    private val projectRepository: ProjectRepository,
+    private val userRepository: UserRepository
+
+) {
+    operator fun invoke(projectId: UUID, projectNewName: String, userId: UUID) {
+        val user = userRepository.getUserById(userId)
+        if (user.type != UserType.Admin) throw AccessDeniedException("Not authorized")
+        if (projectNewName.isBlank()) throw EmptyProjectNameException("Project name can't be empty")
+
+        val existing = projectRepository.getProjectById(projectId)
+        val updated = existing.copy(name = projectNewName)
+        projectRepository.editProject(updated)
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/logic/usecase/project/GetAllProjectsUseCase.kt b/src/main/kotlin/logic/usecase/project/GetAllProjectsUseCase.kt
new file mode 100644
index 00000000..4ba5bc97
--- /dev/null
+++ b/src/main/kotlin/logic/usecase/project/GetAllProjectsUseCase.kt
@@ -0,0 +1,10 @@
+package org.baghdad.logic.usecase.project
+
+import org.baghdad.logic.model.entities.ProjectEntity
+import org.baghdad.logic.repositories.ProjectRepository
+
+class GetAllProjectsUseCase(private val projectRepository: ProjectRepository) {
+    operator fun invoke():List<ProjectEntity>{
+        return projectRepository.getAllProjects()
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/presentation/project/CreateProjectUi.kt b/src/main/kotlin/presentation/project/CreateProjectUi.kt
new file mode 100644
index 00000000..4b2f0a33
--- /dev/null
+++ b/src/main/kotlin/presentation/project/CreateProjectUi.kt
@@ -0,0 +1,18 @@
+package org.baghdad.presentation.project
+
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.usecase.project.CreateProjectUseCase
+
+class CreateProjectUi(
+    private val createProjectUseCase: CreateProjectUseCase
+) {
+    fun createProject(user: UserEntity) {
+        println("=== Create Project ===")
+        print("Enter project name: ")
+        val name = readln()
+
+//        when (val result = createProjectUseCase(name, user)) {
+//            is org.baghdad.logic.usecase.common.Result.Success -> println("Project \"$name\" created successfully.")
+//        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/presentation/project/DeleteProjectUi.kt b/src/main/kotlin/presentation/project/DeleteProjectUi.kt
new file mode 100644
index 00000000..621e8325
--- /dev/null
+++ b/src/main/kotlin/presentation/project/DeleteProjectUi.kt
@@ -0,0 +1,25 @@
+package org.baghdad.presentation.project
+
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.usecase.project.DeleteProjectUseCase
+
+class DeleteProjectUi(
+    private val deleteProjectUseCase: DeleteProjectUseCase
+) {
+    fun deleteProject(user: UserEntity) {
+        println("=== Delete Project ===")
+        print("Enter project ID: ")
+        val idInput = readln()
+
+        val projectId = idInput.toUUIDOrNull()
+        if (projectId == null) {
+            println("Invalid UUID format.")
+            return
+        }
+
+//        when (val result = deleteProjectUseCase(projectId, user)) {
+//            is org.baghdad.logic.usecase.common.Result.Success -> println("Project deleted successfully.")
+//            is Result.Failure -> println(result.message)
+//        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/presentation/project/EditProjectUi.kt b/src/main/kotlin/presentation/project/EditProjectUi.kt
new file mode 100644
index 00000000..d0be221b
--- /dev/null
+++ b/src/main/kotlin/presentation/project/EditProjectUi.kt
@@ -0,0 +1,31 @@
+package org.baghdad.presentation.project
+
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.usecase.project.EditProjectUseCase
+import java.util.*
+
+fun String.toUUIDOrNull(): UUID? =
+    runCatching { UUID.fromString(this) }.getOrNull()
+
+class EditProjectUi(
+    private val editProjectUseCase: EditProjectUseCase
+) {
+    fun editProject(user: UserEntity) {
+        println("=== Edit Project ===")
+        print("Enter project ID: ")
+        val idInput = readln()
+        print("Enter new project name: ")
+        val newName = readln()
+
+        val projectId = idInput.toUUIDOrNull()
+        if (projectId == null) {
+            println("Invalid UUID format.")
+            return
+        }
+
+//        when (val result = editProjectUseCase(projectId, newName, user)) {
+//            is Result.Success -> println("Project updated successfully.")
+//            is Result.Failure -> println(result.message)
+//        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/presentation/project/ListProjectUi.kt b/src/main/kotlin/presentation/project/ListProjectUi.kt
new file mode 100644
index 00000000..232e5d10
--- /dev/null
+++ b/src/main/kotlin/presentation/project/ListProjectUi.kt
@@ -0,0 +1,30 @@
+package org.baghdad.presentation.project
+
+import org.baghdad.logic.usecase.project.GetAllProjectsUseCase
+
+class ListProjectUi(
+    private val listProjectsUseCase: GetAllProjectsUseCase
+) {
+
+
+    fun listProjects() {
+        println("=== List of Projects ===")
+        val projects = listProjectsUseCase()
+        if (projects.isEmpty()) {
+            println("No projects found.")
+            return
+        }
+
+        println("+--------------------------------------+----------------------+----------------------+")
+        println("| Project ID                           | Name                 | Created By           |")
+        println("+--------------------------------------+----------------------+----------------------+")
+        for (project in projects) {
+            println(
+                "| ${project.id} | ${project.name.padEnd(20)} | ${
+                    project.creatorId.toString().padEnd(20)
+                } |"
+            )
+        }
+        println("+--------------------------------------+----------------------+----------------------+")
+    }
+}
diff --git a/src/test/kotlin/data/datasource/mapper/ProjectMapperTest.kt b/src/test/kotlin/data/datasource/mapper/ProjectMapperTest.kt
index 1d40e7a5..a2e741f8 100644
--- a/src/test/kotlin/data/datasource/mapper/ProjectMapperTest.kt
+++ b/src/test/kotlin/data/datasource/mapper/ProjectMapperTest.kt
@@ -26,7 +26,7 @@ class ProjectMapperTest {
         // Given
         val uuid = UUID.randomUUID()
         val name = "New Project"
-        val creatorId = "creator123"
+        val creatorId = UUID.randomUUID()
         val line = "$uuid,$name,$creatorId"
 
         // When
@@ -60,7 +60,7 @@ class ProjectMapperTest {
         // Given
         val uuid = UUID.randomUUID()
         val name = "Project X"
-        val creatorId = "user42"
+        val creatorId = UUID.randomUUID()
         val entity = ProjectEntity(
             id = uuid,
             name = name,
diff --git a/src/test/kotlin/data/local/ProjectDataSourceTest.kt b/src/test/kotlin/data/local/ProjectDataSourceTest.kt
index 087a8042..12bdafe8 100644
--- a/src/test/kotlin/data/local/ProjectDataSourceTest.kt
+++ b/src/test/kotlin/data/local/ProjectDataSourceTest.kt
@@ -1,2 +1,176 @@
 package data.local
 
+import io.mockk.Runs
+import io.mockk.every
+import io.mockk.just
+import io.mockk.mockk
+import io.mockk.verify
+import org.baghdad.data.datasource.DataSource
+import org.baghdad.data.local.ProjectDataSource
+import org.baghdad.logic.model.entities.ProjectEntity
+import org.baghdad.logic.model.entities.StateEntity
+import org.baghdad.logic.model.entities.TaskEntity
+import org.baghdad.logic.model.exceptions.ProjectNotFoundException
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.assertThrows
+import java.util.UUID
+import kotlin.test.Test
+
+class ProjectDataSourceTest {
+    private lateinit var dataSource: DataSource<ProjectEntity>
+    private lateinit var projectStatesDataSource: DataSource<StateEntity>
+    private lateinit var taskDataSource: DataSource<TaskEntity>
+    private lateinit var projectDataSource: ProjectDataSource
+
+
+    @BeforeEach
+    fun setup() {
+        dataSource = mockk(relaxed = true)
+        projectStatesDataSource = mockk(relaxed = true)
+        taskDataSource = mockk(relaxed = true)
+        projectDataSource = ProjectDataSource(dataSource, projectStatesDataSource, taskDataSource)
+    }
+
+    @Test
+    fun `should return data when there is a projects`() {
+        // Given
+        val projects = listOf(ProjectEntity(name = "Project 1", creatorId = UUID.randomUUID()))
+        every { dataSource.loadAll() } returns projects
+
+        // When
+        val result = projectDataSource.getAllProjects()
+
+        // Then
+        assert(result == projects)
+
+    }
+
+    @Test
+    fun `should throw ProjectNotFoundException when updateProject and there is no projects`() {
+        // Given
+        val project = ProjectEntity(name = "Project 1", creatorId = UUID.randomUUID())
+        every { dataSource.loadAll() } returns emptyList()
+
+        // When & Then
+        assertThrows<ProjectNotFoundException> { projectDataSource.updateProject(project) }
+
+    }
+
+    @Test
+    fun `should throw ProjectNotFoundException when deleteProject and there is no projects`() {
+        // Given
+        val project = ProjectEntity(name = "Project 1", creatorId = UUID.randomUUID())
+        every { dataSource.loadAll() } returns emptyList()
+
+        // When & Then
+        assertThrows<ProjectNotFoundException> { projectDataSource.deleteProject(project.id) }
+
+    }
+
+    @Test
+    fun `createProject should call append on data source`() {
+        // Given
+        val project = ProjectEntity(name = "Project 1", creatorId = UUID.randomUUID())
+        every { dataSource.append(project) } just Runs
+
+        // When
+        projectDataSource.createProject(project)
+
+        // Then
+        verify { dataSource.append(project) }
+    }
+
+    @Test
+    fun `should return project when there is a project with same id`() {
+        // Given
+        val projects = ProjectEntity(name = "Project 1", creatorId = UUID.randomUUID())
+        every { dataSource.loadAll() } returns listOf(projects)
+
+        // When
+        val result = projectDataSource.getProjectById(projects.id)
+
+        // Then
+        assert(result == projects)
+    }
+
+    @Test
+    fun `should throw ProjectNotFoundException when there is no project with same id`() {
+        // Given
+        val projects = ProjectEntity(name = "Project 1", creatorId = UUID.randomUUID())
+        every { dataSource.loadAll() } returns listOf(projects)
+
+        // When & Then
+        assertThrows<ProjectNotFoundException> { projectDataSource.getProjectById(UUID.randomUUID()) }
+    }
+
+    @Test
+    fun `should return updated project when can update it successfully`() {
+        // Given
+        val allProjects = listOf(
+            ProjectEntity(name = "Project 1", creatorId = UUID.randomUUID()),
+            ProjectEntity(name = "Project 2", creatorId = UUID.randomUUID())
+        )
+        val updatedProject = ProjectEntity(
+            name = "Project 3",
+            creatorId = UUID.randomUUID()
+        ).copy(id = allProjects[1].id)
+
+        every { dataSource.loadAll() } returns allProjects
+        every { dataSource.update(listOf(updatedProject)) } just Runs
+
+        // When
+        projectDataSource.updateProject(updatedProject)
+
+        // Then
+        verify {
+            dataSource.update(match {
+                it.any { project -> project.id == updatedProject.id && updatedProject.name == "Project 3" }
+            })
+        }
+    }
+
+    @Test
+    fun `should delete project with its states and tasks when delete it successfully`() {
+        // Given
+        val allProjects = listOf(
+            ProjectEntity(name = "Project 1", creatorId = UUID.randomUUID()),
+        )
+        val projectIdToDelete = allProjects[0].id
+        val projectStates = listOf(
+            StateEntity(
+                name = "State 1",
+                projectId = projectIdToDelete,
+                creatorId = UUID.randomUUID()
+            )
+        )
+        val staetIdtoDelete = projectStates[0].id
+        val tasks = listOf(
+            TaskEntity(
+                title = "Task 1",
+                description = "Description 1",
+                stateId = UUID.randomUUID(),
+                creatorId = UUID.randomUUID(),
+                projectId = projectStates[0].id
+            )
+        )
+        val taskToRemove = tasks[0].id
+        every { dataSource.loadAll() } returns allProjects
+        every { projectStatesDataSource.loadAll() } returns projectStates
+        every { taskDataSource.loadAll() } returns tasks
+
+        every { dataSource.update(any()) } just Runs
+        every { projectStatesDataSource.update(any()) } just Runs
+        every { taskDataSource.update(any()) } just Runs
+
+        // when
+        projectDataSource.deleteProject(projectIdToDelete)
+
+        // Then
+        verify {
+            dataSource.update(match { list -> list.none { it.id == projectIdToDelete } })
+            dataSource.update(match { list -> list.none { it.id == staetIdtoDelete } })
+            dataSource.update(match { list -> list.none { it.id == taskToRemove } })
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/kotlin/data/repositories/project/ProjectRepositoryImplTest.kt b/src/test/kotlin/data/repositories/project/ProjectRepositoryImplTest.kt
new file mode 100644
index 00000000..b077a7c4
--- /dev/null
+++ b/src/test/kotlin/data/repositories/project/ProjectRepositoryImplTest.kt
@@ -0,0 +1,92 @@
+package data.repositories.project
+
+import com.google.common.truth.Truth.assertThat
+import helpers.task.TaskEntityTestData
+import io.mockk.every
+import io.mockk.mockk
+import io.mockk.verify
+import org.baghdad.data.local.ProjectDataSource
+import org.baghdad.data.repository.project.ProjectRepositoryImpl
+import org.baghdad.logic.model.entities.ProjectEntity
+import org.junit.jupiter.api.BeforeEach
+import java.util.UUID
+import kotlin.test.Test
+
+class ProjectRepositoryImplTest {
+    private lateinit var dataSource: ProjectDataSource
+    private lateinit var projectRepository: ProjectRepositoryImpl
+
+    @BeforeEach
+    fun setUp() {
+        dataSource = mockk(relaxed = true)
+        projectRepository = ProjectRepositoryImpl(dataSource)
+    }
+
+    @Test
+    fun `should return all projects from dataSource`() {
+        // Given
+        val projects = listOf(
+            ProjectEntity(name = "Project 1", creatorId = UUID.randomUUID()),
+        )
+        every { dataSource.getAllProjects() } returns projects
+
+        // When
+        val result = projectRepository.getAllProjects()
+
+        // Then
+        assertThat(result == projects).isTrue()
+
+    }
+
+    @Test
+    fun `should return true when project is found by id`() {
+        // Given
+
+        val project = ProjectEntity(name = "Project 1", creatorId = UUID.randomUUID())
+
+        every { dataSource.getProjectById(project.id) } returns project
+
+        // When
+        val result = projectRepository.getProjectById(project.id)
+
+        // Then
+        assertThat(result).isEqualTo(project)
+
+    }
+
+    @Test
+    fun `editProject should call dataSource editProject`() {
+        // Given
+        val project = ProjectEntity(name = "Project 1", creatorId = UUID.randomUUID())
+
+        // Then
+        projectRepository.editProject(project)
+
+        // When
+        verify { projectRepository.editProject(project) }
+    }
+
+    @Test
+    fun `deleteProject should call dataSource deleteProject`() {
+        // Given
+        val project = ProjectEntity(name = "Project 1", creatorId = UUID.randomUUID())
+
+        // Then
+        projectRepository.deleteProject(project.id)
+
+        // When
+        verify { projectRepository.deleteProject(project.id) }
+    }
+
+    @Test
+    fun `createProject should call dataSource createProject`() {
+        // Given
+        val project = ProjectEntity(name = "Project 1", creatorId = UUID.randomUUID())
+
+        // Then
+        projectRepository.createProject(project)
+
+        // When
+        verify { projectRepository.createProject(project) }
+    }
+}
diff --git a/src/test/kotlin/logic/usecase/project/CreateProjectUseCaseTest.kt b/src/test/kotlin/logic/usecase/project/CreateProjectUseCaseTest.kt
new file mode 100644
index 00000000..c88ac52a
--- /dev/null
+++ b/src/test/kotlin/logic/usecase/project/CreateProjectUseCaseTest.kt
@@ -0,0 +1,68 @@
+package logic.usecase.project
+
+import helpers.authentication.createUserHelper
+import io.mockk.every
+import io.mockk.just
+import io.mockk.mockk
+import io.mockk.runs
+import io.mockk.verify
+import org.baghdad.logic.model.entities.UserType
+import org.baghdad.logic.model.exceptions.AccessDeniedException
+import org.baghdad.logic.model.exceptions.EmptyProjectNameException
+import org.baghdad.logic.repositories.ProjectRepository
+import org.baghdad.logic.repositories.UserRepository
+import org.baghdad.logic.usecase.project.CreateProjectUseCase
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.assertThrows
+import kotlin.test.Test
+
+class CreateProjectUseCaseTest {
+    lateinit var projectRepository: ProjectRepository
+    lateinit var userRepository: UserRepository
+    lateinit var createProjectUseCase: CreateProjectUseCase
+
+    @BeforeEach
+    fun setUp() {
+        projectRepository = mockk()
+        userRepository = mockk()
+        createProjectUseCase = CreateProjectUseCase(projectRepository, userRepository)
+    }
+
+    @Test
+    fun `should return True when project is created with valid name and creator`() {
+        // Given
+        val projectName = "Test Project"
+        val user = createUserHelper()
+
+        every { userRepository.getUserById(user.id) } returns user
+        every { projectRepository.createProject(any()) } just runs
+
+        // When
+        createProjectUseCase(projectName, user.id)
+
+        // Then
+        verify { projectRepository.createProject(any()) }
+    }
+
+    @Test
+    fun `should throw EmptyProjectNameException when project name is empty`() {
+        // Given
+        val projectName = ""
+        val user = createUserHelper()
+        every { userRepository.getUserById(user.id) } returns user
+
+        // When & Then
+        assertThrows<EmptyProjectNameException> { createProjectUseCase(projectName, user.id) }
+    }
+
+    @Test
+    fun `should throw AccessDeniedException when user is not admin`() {
+        // Given
+        val projectName = "Test Project"
+        val user = createUserHelper().copy(type = UserType.Mate)
+        every { userRepository.getUserById(user.id) } returns user
+
+        // When & Then
+        assertThrows<AccessDeniedException> { createProjectUseCase(projectName, user.id) }
+    }
+}
diff --git a/src/test/kotlin/logic/usecase/project/DeleteProjectUseCaseTest.kt b/src/test/kotlin/logic/usecase/project/DeleteProjectUseCaseTest.kt
new file mode 100644
index 00000000..346e7e59
--- /dev/null
+++ b/src/test/kotlin/logic/usecase/project/DeleteProjectUseCaseTest.kt
@@ -0,0 +1,57 @@
+package logic.usecase.project
+
+import helpers.authentication.createUserHelper
+import io.mockk.every
+import io.mockk.mockk
+import io.mockk.verify
+import org.baghdad.logic.model.entities.ProjectEntity
+import org.baghdad.logic.model.entities.UserType
+import org.baghdad.logic.model.exceptions.AccessDeniedException
+import org.baghdad.logic.repositories.ProjectRepository
+import org.baghdad.logic.repositories.UserRepository
+import org.baghdad.logic.usecase.project.DeleteProjectUseCase
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.assertThrows
+import java.util.UUID
+import kotlin.test.Test
+
+class DeleteProjectUseCaseTest {
+    lateinit var projectRepository: ProjectRepository
+    lateinit var userRepository: UserRepository
+    lateinit var deleteProjectUseCase: DeleteProjectUseCase
+
+    @BeforeEach
+    fun setUp() {
+        projectRepository = mockk(relaxed = true)
+        userRepository = mockk(relaxed = true)
+        deleteProjectUseCase = DeleteProjectUseCase(projectRepository, userRepository)
+    }
+
+    @Test
+    fun `should delete project when call DeleteProjectUseCase`() {
+        // Given
+        val project = ProjectEntity(name = "aboud", creatorId = UUID.randomUUID())
+        val user = createUserHelper()
+        every { userRepository.getUserById(user.id) } returns user
+
+
+        // When
+        deleteProjectUseCase.invoke(project.id, user.id)
+
+        // Then
+        verify { projectRepository.deleteProject(project.id) }
+    }
+
+    @Test
+    fun `should throw AccessDeniedException when user is not admin`() {
+        // Given
+        val project = ProjectEntity(name = "aboud", creatorId = UUID.randomUUID())
+        val user = createUserHelper().copy(type = UserType.Mate)
+        every { userRepository.getUserById(user.id) } returns user
+
+        // When & Then
+        assertThrows<AccessDeniedException> { deleteProjectUseCase.invoke(project.id, user.id) }
+    }
+}
+
+
diff --git a/src/test/kotlin/logic/usecase/project/EditProjectUseCaseTest.kt b/src/test/kotlin/logic/usecase/project/EditProjectUseCaseTest.kt
new file mode 100644
index 00000000..607a4563
--- /dev/null
+++ b/src/test/kotlin/logic/usecase/project/EditProjectUseCaseTest.kt
@@ -0,0 +1,86 @@
+package logic.usecase.project
+
+import helpers.authentication.createUserHelper
+import io.mockk.every
+import io.mockk.just
+import io.mockk.mockk
+import io.mockk.runs
+import io.mockk.verify
+import org.baghdad.logic.model.entities.ProjectEntity
+import org.baghdad.logic.model.entities.UserType
+import org.baghdad.logic.model.exceptions.AccessDeniedException
+import org.baghdad.logic.model.exceptions.EmptyProjectNameException
+import org.baghdad.logic.repositories.ProjectRepository
+import org.baghdad.logic.repositories.UserRepository
+import org.baghdad.logic.usecase.project.EditProjectUseCase
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.assertThrows
+import java.util.UUID
+import kotlin.test.Test
+
+class EditProjectUseCaseTest {
+    lateinit var projectRepository: ProjectRepository
+    lateinit var userRepository: UserRepository
+    lateinit var editProjectUseCase: EditProjectUseCase
+
+    @BeforeEach
+    fun setUp() {
+        projectRepository = mockk(relaxed = true)
+        userRepository = mockk(relaxed = true)
+        editProjectUseCase = EditProjectUseCase(projectRepository, userRepository)
+    }
+
+    @Test
+    fun `should edit project when call EditProjectUseCase`() {
+        // Given
+        val project = ProjectEntity(name = "aboud", creatorId = UUID.randomUUID())
+        val user = createUserHelper().copy(type = UserType.Admin)
+
+        every { userRepository.getUserById(user.id) } returns user
+        every { projectRepository.getProjectById(project.id) } returns project
+
+        every { projectRepository.editProject(project) } just runs
+
+        // When
+        editProjectUseCase.invoke(project.id, project.name, user.id)
+
+        // Then
+        verify { projectRepository.editProject(project) }
+    }
+
+    @Test
+    fun `should throw AccessDeniedException when user is not admin`() {
+        // Given
+        val projectName = "Test Project"
+        val project = ProjectEntity(name = "aboud", creatorId = UUID.randomUUID())
+        val user = createUserHelper().copy(type = UserType.Mate)
+        every { userRepository.getUserById(user.id) } returns user
+
+        // When & Then
+        assertThrows<AccessDeniedException> {
+            editProjectUseCase.invoke(
+                projectId = project.id,
+                projectName,
+                user.id
+            )
+        }
+    }
+
+    @Test
+    fun `should throw EmptyProjectNameException when project name is empty`() {
+        // Given
+        val projectName = ""
+        val project = ProjectEntity(name = "aboud", creatorId = UUID.randomUUID())
+        val user = createUserHelper()
+        every { userRepository.getUserById(user.id) } returns user
+
+        // When & Then
+        assertThrows<EmptyProjectNameException> {
+            editProjectUseCase.invoke(
+                projectId = project.id,
+                projectName,
+                user.id
+            )
+        }
+    }
+}
diff --git a/src/test/kotlin/logic/usecase/report/ReportServiceTest.kt b/src/test/kotlin/logic/usecase/report/ReportServiceTest.kt
index c00ca3da..3eb00cf3 100644
--- a/src/test/kotlin/logic/usecase/report/ReportServiceTest.kt
+++ b/src/test/kotlin/logic/usecase/report/ReportServiceTest.kt
@@ -31,7 +31,7 @@ class ReportServiceTest {
 
         reportService = ReportService(projectRepo, taskRepo, stateRepo)
 
-        val project = ProjectEntity(id = projectId, name = "Test Project", creatorId = user1Id.toString())
+        val project = ProjectEntity(id = projectId, name = "Test Project", creatorId = user1Id)
 
         val states = listOf(
             StateEntity(id = state1Id, name = "To Do", projectId = projectId, creatorId = user1Id),


Reviews:
user: login: YoussefmSaber
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-05-07T15:41:03Z
user: login: YoussefmSaber
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-07T15:57:27Z
user: login: haideraljawasim
body: Great work! you just need to add the missing test files that mentioned in the review .
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T16:13:26Z
user: login: Dunya4mars
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T16:40:39Z

Review comments:
diff_hunk: @@ -20,22 +21,24 @@ class ProjectDataSource(
         return projectDataSource.loadAll()
     }
 
-    fun getProjectById(id: String): ProjectEntity? {
-        return projectDataSource.loadAll().find { it.id.toString() == id }
+    fun getProjectById(id: UUID): ProjectEntity {
+        return projectDataSource.loadAll().find { it.id == id }
+            .takeIf { it != null }?: throw ProjectNotFoundException("No project found")
     }
 
     fun updateProject(project: ProjectEntity) {
         val allData = projectDataSource.loadAll().toMutableList()
         val projectIndex = allData.indexOfFirst { it.id == project.id }
-        if (projectIndex == -1) throw Exception("No project found")
+        if (projectIndex == -1) throw ProjectNotFoundException("No project found")
         allData[projectIndex] = project
+        println(allData)
path: src/main/kotlin/data/local/ProjectDataSource.kt
user: login: YoussefmSaber
body: remove this println
created_at: 2025-05-07T15:36:44Z
author_association: COLLABORATOR
diff_hunk: @@ -20,22 +27,12 @@ val useCaseModule = module {
     single { GetTaskByIdUseCase(get()) }
     single { GetAllTasksUseCase(get()) }
     single { GetTasksByProjectIdUseCase(get()) }
-    // endregion
-
-    // region  ::  Project States Use Cases  ::
-
-    single { AddStateToProjectUseCase(get(), get(), get()) }
-    single { DeleteStateForProjectUseCase(get(), get(), get()) }
-    single { GetAllStatesPerProjectUseCase(get()) }
-    single { GetStateByIdUseCase(get()) }
-    single { EditProjectStatesUseCase(get(), get(), get()) }
-
path: src/main/kotlin/di/UseCaseModule.kt
user: login: YoussefmSaber
body: Why did you remove these usecases from the module
created_at: 2025-05-07T15:37:33Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,6 @@
+package org.baghdad.logic.usecase.common
+
+sealed class Result<out T> {
+    data class Success<T>(val data: T? = null) : Result<T>()
+    data class Failure(val message: String) : Result<Nothing>()
+}
path: src/main/kotlin/logic/usecase/common/Result.kt
user: login: YoussefmSaber
body: Didn't we say we will use throw exception this time, no need for this result class
created_at: 2025-05-07T15:38:07Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,23 @@
+package org.baghdad.logic.usecase.project
+
+import org.baghdad.logic.model.entities.ProjectEntity
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.model.entities.UserType
+import org.baghdad.logic.model.exceptions.AccessDeniedException
+import org.baghdad.logic.model.exceptions.EmptyProjectNameException
+import org.baghdad.logic.repositories.ProjectRepository
+import org.baghdad.logic.repositories.UserRepository
+import java.util.UUID
+
+class CreateProjectUseCase(
+    private val projectRepository: ProjectRepository,
+    private val userRepository: UserRepository
+) {
+    operator fun invoke(projectName: String, userId : UUID){
+        val user = userRepository.getUserById(userId)
+        if (user.type.name != UserType.Admin.name) throw AccessDeniedException("Not authorized")
path: src/main/kotlin/logic/usecase/project/CreateProjectUseCase.kt
user: login: YoussefmSaber
body: just match the enums, no need to get the name
it will do the same thing
what you did here just like this
instead of 1 == 1
you did "1" == "1"
created_at: 2025-05-07T15:39:15Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,19 @@
+package org.baghdad.logic.usecase.project
+
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.model.entities.UserType
+import org.baghdad.logic.model.exceptions.AccessDeniedException
+import org.baghdad.logic.repositories.ProjectRepository
+import org.baghdad.logic.repositories.UserRepository
+import java.util.UUID
+
+class DeleteProjectUseCase(
+    private val projectRepository: ProjectRepository,
+    private val userRepository: UserRepository
+) {
+    operator fun invoke(projectId: UUID,userId : UUID){
+        val user = userRepository.getUserById(userId)
+        if (user.type.name != UserType.Admin.name) throw AccessDeniedException("Not authorized")
path: src/main/kotlin/logic/usecase/project/DeleteProjectUseCase.kt
user: login: YoussefmSaber
body: same thing here
created_at: 2025-05-07T15:39:33Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,19 @@
+package org.baghdad.presentation.project
+
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.usecase.common.Result
+import org.baghdad.logic.usecase.project.CreateProjectUseCase
+
+class CreateProjectUi(
+    private val createProjectUseCase: CreateProjectUseCase
+) {
+    fun createProject(user: UserEntity) {
+        println("=== Create Project ===")
+        print("Enter project name: ")
+        val name = readln()
+
+//        when (val result = createProjectUseCase(name, user)) {
+//            is org.baghdad.logic.usecase.common.Result.Success -> println("Project \"$name\" created successfully.")
+//        }
path: src/main/kotlin/presentation/project/CreateProjectUi.kt
user: login: YoussefmSaber
body: if it's not gonna be used just delete it
created_at: 2025-05-07T15:39:58Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,26 @@
+package org.baghdad.presentation.project
+
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.usecase.common.Result
+import org.baghdad.logic.usecase.project.DeleteProjectUseCase
+
+class DeleteProjectUi(
+    private val deleteProjectUseCase: DeleteProjectUseCase
+) {
+    fun deleteProject(user: UserEntity) {
+        println("=== Delete Project ===")
+        print("Enter project ID: ")
+        val idInput = readln()
+
+        val projectId = idInput.toUUIDOrNull()
+        if (projectId == null) {
+            println("Invalid UUID format.")
+            return
+        }
+
+//        when (val result = deleteProjectUseCase(projectId, user)) {
+//            is org.baghdad.logic.usecase.common.Result.Success -> println("Project deleted successfully.")
+//            is Result.Failure -> println(result.message)
+//        }
path: src/main/kotlin/presentation/project/DeleteProjectUi.kt
user: login: YoussefmSaber
body: same here, if not will be used, just delete it
created_at: 2025-05-07T15:40:17Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,26 @@
+package org.baghdad.presentation.project
+
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.usecase.common.Result
+import org.baghdad.logic.usecase.project.DeleteProjectUseCase
+
+class DeleteProjectUi(
+    private val deleteProjectUseCase: DeleteProjectUseCase
+) {
+    fun deleteProject(user: UserEntity) {
+        println("=== Delete Project ===")
+        print("Enter project ID: ")
+        val idInput = readln()
+
+        val projectId = idInput.toUUIDOrNull()
+        if (projectId == null) {
+            println("Invalid UUID format.")
+            return
+        }
+
+//        when (val result = deleteProjectUseCase(projectId, user)) {
+//            is org.baghdad.logic.usecase.common.Result.Success -> println("Project deleted successfully.")
+//            is Result.Failure -> println(result.message)
+//        }
path: src/main/kotlin/presentation/project/DeleteProjectUi.kt
user: login: haideraljawasim
body: No testing !!
created_at: 2025-05-07T16:08:55Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-05T18:15:10Z
body: ### 🛡️ Code Coverage Report
|Overall Project|85.52%|:x:|
|:-|:-|:-:|

> There is no coverage information present for the Files changed
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-06T14:52:15Z
body: ### 🛡️ Code Coverage Report
|Overall Project|84.8%|:x:|
|:-|:-|:-:|

> There is no coverage information present for the Files changed
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-06T18:40:05Z
body: ### 🛡️ Code Coverage Report
|Overall Project|87.83%|:x:|
|:-|:-|:-:|

> There is no coverage information present for the Files changed
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-06T20:15:28Z
body: ### 🛡️ Code Coverage Report
|Overall Project|88.59%|:x:|
|:-|:-|:-:|

> There is no coverage information present for the Files changed
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-07T15:31:25Z
body: ### 🛡️ Code Coverage Report
|Overall Project|90.36%|:green_apple:|
|:-|:-|:-:|

> There is no coverage information present for the Files changed
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-07T15:39:04Z
body: ### 🛡️ Code Coverage Report
|Overall Project|90.36%|:green_apple:|
|:-|:-|:-:|

> There is no coverage information present for the Files changed
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-07T15:49:40Z
body: ### 🛡️ Code Coverage Report
|Overall Project|90.35%|:green_apple:|
|:-|:-|:-:|

> There is no coverage information present for the Files changed
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-07T15:58:13Z
body: ### 🛡️ Code Coverage Report
|Overall Project|91.1%|:green_apple:|
|:-|:-|:-:|

> There is no coverage information present for the Files changed
author_association: NONE