박현정 박현정 07-15
250715 박현정 프로젝트 관련 기능 추가(생성, 조회, 수정, 삭제)
@9682d70b639a9df84c333b07846fecfb08164c99
src/main/java/kr/co/takensoft/ai/system/common/idgen/context/ContextIdgen.java
--- src/main/java/kr/co/takensoft/ai/system/common/idgen/context/ContextIdgen.java
+++ src/main/java/kr/co/takensoft/ai/system/common/idgen/context/ContextIdgen.java
@@ -17,4 +17,92 @@
         idgenServiceImpl.setTblNm("USID");
         return idgenServiceImpl;
     }
+
+    // 프로젝트 정보
+    @Bean(name = "projectIdgn")
+    public IdgenService project() {
+        IdgenService idgenServiceImpl = new IdgenService();
+        idgenServiceImpl.setCipers(15);
+        idgenServiceImpl.setFillChar('0');
+        idgenServiceImpl.setPrefix("PRJT_");
+        idgenServiceImpl.setTblNm("PRJT");
+        return idgenServiceImpl;
+    }
+
+    // 피드백 정보
+    @Bean(name = "feedbackIdgn")
+    public IdgenService feedback() {
+        IdgenService idgenServiceImpl = new IdgenService();
+        idgenServiceImpl.setCipers(15);
+        idgenServiceImpl.setFillChar('0');
+        idgenServiceImpl.setPrefix("FEBK_");
+        idgenServiceImpl.setTblNm("FEBK");
+        return idgenServiceImpl;
+    }
+
+    // 피드백 채팅 정보
+    @Bean(name = "feedbackChatIdgn")
+    public IdgenService feedbackChat() {
+        IdgenService idgenServiceImpl = new IdgenService();
+        idgenServiceImpl.setCipers(15);
+        idgenServiceImpl.setFillChar('0');
+        idgenServiceImpl.setPrefix("FBCH_");
+        idgenServiceImpl.setTblNm("FBCH");
+        return idgenServiceImpl;
+    }
+
+    // 프로젝트 주석 정보
+    @Bean(name = "projectCommentIdgn")
+    public IdgenService projectComment() {
+        IdgenService idgenServiceImpl = new IdgenService();
+        idgenServiceImpl.setCipers(15);
+        idgenServiceImpl.setFillChar('0');
+        idgenServiceImpl.setPrefix("PJCM_");
+        idgenServiceImpl.setTblNm("PJCM");
+        return idgenServiceImpl;
+    }
+
+    // 프로젝트 주석 정보
+    @Bean(name = "projectGroupIdgn")
+    public IdgenService projectGroup() {
+        IdgenService idgenServiceImpl = new IdgenService();
+        idgenServiceImpl.setCipers(15);
+        idgenServiceImpl.setFillChar('0');
+        idgenServiceImpl.setPrefix("PJGP_");
+        idgenServiceImpl.setTblNm("PJGP");
+        return idgenServiceImpl;
+    }
+
+    // 프로젝트 이미지 정보
+    @Bean(name = "projectImageIdgn")
+    public IdgenService projectImage() {
+        IdgenService idgenServiceImpl = new IdgenService();
+        idgenServiceImpl.setCipers(15);
+        idgenServiceImpl.setFillChar('0');
+        idgenServiceImpl.setPrefix("PJIG_");
+        idgenServiceImpl.setTblNm("PJIG");
+        return idgenServiceImpl;
+    }
+
+    // 프로젝트 로그 정보
+    @Bean(name = "projectLogIdgn")
+    public IdgenService projectLog() {
+        IdgenService idgenServiceImpl = new IdgenService();
+        idgenServiceImpl.setCipers(15);
+        idgenServiceImpl.setFillChar('0');
+        idgenServiceImpl.setPrefix("PJLG_");
+        idgenServiceImpl.setTblNm("PJLG");
+        return idgenServiceImpl;
+    }
+
+    // 프로젝트 참여자 정보
+    @Bean(name = "projectMemberIdgn")
+    public IdgenService projectMember() {
+        IdgenService idgenServiceImpl = new IdgenService();
+        idgenServiceImpl.setCipers(15);
+        idgenServiceImpl.setFillChar('0');
+        idgenServiceImpl.setPrefix("PJUS_");
+        idgenServiceImpl.setTblNm("PJUS");
+        return idgenServiceImpl;
+    }
 }
(파일 끝에 줄바꿈 문자 없음)
 
src/main/java/kr/co/takensoft/ai/system/project/dao/ProjectDAO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/project/dao/ProjectDAO.java
@@ -0,0 +1,119 @@
+package kr.co.takensoft.ai.system.project.dao;
+import kr.co.takensoft.ai.system.project.dto.ProjectDTO;
+import kr.co.takensoft.ai.system.project.dto.ProjectSearchReqDTO;
+import kr.co.takensoft.ai.system.project.vo.ProjectVO;
+import org.egovframe.rte.psl.dataaccess.mapper.Mapper;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * @author 박현정
+ * @since 2025.07.09
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.09  |    박현정     | 최초 등록
+ *
+ * 프로젝트 관련 DAO
+ */
+@Mapper("projectDAO")
+public interface ProjectDAO {
+
+    /**
+     * @param projectVO - 프로젝트 정보
+     * @return int - 프로젝트 등록 결과
+     *
+     * 프로젝트 등록
+     */
+    int saveProject(ProjectVO projectVO);
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @return List<ProjectVO> - 사용자가 참여하는 프로젝트 목록
+     *
+     * 프로젝트 목록 조회
+     */
+    List<ProjectDTO> findProjectsByMemberId(String memberId);
+
+    /**
+     * @param projectId - 프로젝트 아이디
+     * @return ProjectVO - 프로젝트 정보
+     *
+     * 프로젝트 정보 조회
+     */
+    Optional<ProjectVO> findById(String projectId);
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @return int - 사용자가 생성한 프로젝트 개수
+     *
+     * 사용자가 생성한 프로젝트 개수 조회
+     */
+    int countCreatedByMemberId(String memberId);
+
+    /**
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @return int - 프로젝트 정보 수정 결과
+     *
+     * 대표 프로젝트 해제
+     */
+    int unsetProjectMain(String projectGroupId);
+
+    /**
+     * @param projectId - 프로젝트 아이디
+     * @return boolean - 프로젝트 존재 여부 확인 결과
+     *
+     * 프로젝트 존재 여부 확인
+     */
+    boolean existsById(String projectId);
+
+    /**
+     * @param projectId - 프로젝트 아이디
+     * @return String - 프로젝트 그룹 아이디
+     *
+     * 프로젝트 그룹 아이디 조회
+     */
+    Optional<String> findProjectGroupIdByProjectId(String projectId);
+
+    /**
+     * @param projectId - 프로젝트 아이디
+     * @param projectName - 변경할 프로젝트 이름
+     * @return int - 프로젝트 이름 변경 결과
+     *
+     * 프로젝트 이름 변경
+     */
+    int updateProjectName(String projectId, String projectName);
+
+    /**
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @return int - 프로젝트 삭제 결과 (use_at = 'N')
+     *
+     * 그룹 내 프로젝트 모두 삭제 (use_at = 'N')
+     */
+    int deactivateProjectsByGroupId(String projectGroupId);
+
+    /**
+     * @param projectId - 프로젝트 아이디
+     * @return int - 프로젝트 정보 수정 결과
+     *
+     * 대표 프로젝트 설정
+     */
+    int setProjectMain(String projectId);
+
+    /**
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @param projectId - 프로젝트 아이디(created의 기준점이 되는 프로젝트)
+     * @return int - 프로젝트 삭제 결과 (use_at = 'N')
+     *
+     * 그룹 내에서 기준 프로젝트 이후에 생성된 프로젝트 모두 삭제 (use_at = 'N')
+     */
+    int deactivateProjectsCreatedAfter(String projectGroupId, String projectId);
+
+    /**
+     * @param searchReqDTO - 프로젝트 목록 검색 조건
+     * @return List<ProjectVO> - 프로젝트 목록 정보
+     *
+     * 프로젝트 목록 조회
+     */
+    List<ProjectVO> findAllProjects(ProjectSearchReqDTO searchReqDTO);
+}
 
src/main/java/kr/co/takensoft/ai/system/project/dto/InsertProjectDTO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/project/dto/InsertProjectDTO.java
@@ -0,0 +1,26 @@
+package kr.co.takensoft.ai.system.project.dto;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * @author 박현정
+ * @since 2025.07.14
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.14  |    박현정    | 최초 등록
+ *
+ * 프로젝트 정보 등록 관련 DTO
+ */
+@Setter
+@Getter
+@NoArgsConstructor
+public class InsertProjectDTO {
+
+    private String imageFileName; // 프로젝트 이미지 파일 이름
+    private String imageFileUrl; // 프로젝트 이미지 파일 경로
+    private String summary; // 프로젝트 주석 요약
+    private String comment; // 프로젝트 주석 내용
+
+}
 
src/main/java/kr/co/takensoft/ai/system/project/dto/ProjectDTO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/project/dto/ProjectDTO.java
@@ -0,0 +1,60 @@
+package kr.co.takensoft.ai.system.project.dto;
+
+import kr.co.takensoft.ai.system.project.vo.ProjectVO;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * @author 박현정
+ * @since 2025.07.11
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.11  |    박현정    | 최초 등록
+ *
+ * 프로젝트 조회 관련 DTO
+ */
+@Setter
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+public class ProjectDTO {
+
+    private String projectId; // 프로젝트 아이디
+    private String projectGroupId; // 프로젝트 그룹 아이디
+    private String projectName; //	프로젝트 이름
+    private String isMain; // 대표 프로젝트 여부 ( N: 대표 아님, Y: 대표)
+//    private List<ProjectMemberDTO> projectMembers; // 프로젝트 참여자 정보 목록
+//    private ProjectCommentDTO projectComment; // 프로젝트 주석 정보
+//    private ProjectImageDTO projectImage; // 이미지 정보
+    private String createdAt; // 생성일자
+    private String updatedAt; // 수정일자
+
+    public static ProjectDTO from
+            (ProjectVO projectVO) {
+        return new ProjectDTO(
+                projectVO.getProjectId(),
+                projectVO.getProjectGroupId(),
+                projectVO.getProjectName(),
+                projectVO.getIsMain(),
+                projectVO.getCreatedAt(),
+                projectVO.getUpdatedAt()
+        );
+    }
+
+//    public static ProjectDTO from
+//            (ProjectVO projectVO, List<ProjectMemberVO> projectMemberVOS, ProjectCommentVO commentVO, ProjectImageVO imageVO) {
+//        return new ProjectDTO(
+//                projectVO.getProjectId(),
+//                projectVO.getProjectGroupId(),
+//                projectVO.getProjectName(),
+//                projectVO.getIsMain(),
+//                projectMemberVOS.stream().map(ProjectMemberDTO::from).collect(Collectors.toList()),
+//                ProjectCommentDTO.from(commentVO),
+//                ProjectImageDTO.from(imageVO),
+//                projectVO.getCreatedAt(),
+//                projectVO.getUpdatedAt()
+//        );
+//    }
+}
 
src/main/java/kr/co/takensoft/ai/system/project/dto/ProjectSearchReqDTO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/project/dto/ProjectSearchReqDTO.java
@@ -0,0 +1,26 @@
+package kr.co.takensoft.ai.system.project.dto;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * @author 박현정
+ * @since 2025.07.15
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.15  |    박현정    | 최초 등록
+ *
+ * 프로젝트 검색 요청 관련 DTO
+ */
+@Setter
+@Getter
+@NoArgsConstructor
+public class ProjectSearchReqDTO {
+
+    private String memberId; // 사용자 아이디
+    private String projectGroupId; // 프로젝트 그룹 아이디
+    private String projectName; // 프로젝트 이름
+    private String isMain; // 대표 프로젝트 여부('N' : 대표 아님, 'Y' : 대표)
+
+}
 
src/main/java/kr/co/takensoft/ai/system/project/dto/UpdateProjectDTO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/project/dto/UpdateProjectDTO.java
@@ -0,0 +1,25 @@
+package kr.co.takensoft.ai.system.project.dto;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * @author 박현정
+ * @since 2025.07.14
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.14  |    박현정    | 최초 등록
+ *
+ * 프로젝트 정보 수정 관련 DTO
+ */
+@Setter
+@Getter
+@NoArgsConstructor
+public class UpdateProjectDTO {
+
+    private String imageFileName; // 프로젝트 이미지 파일 이름
+    private String imageFileUrl; // 프로젝트 이미지 파일 경로
+    private String summary; // 프로젝트 주석 요약
+    private String comment; // 프로젝트 주석 내용
+}
 
src/main/java/kr/co/takensoft/ai/system/project/dto/UpdateProjectNameDTO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/project/dto/UpdateProjectNameDTO.java
@@ -0,0 +1,21 @@
+package kr.co.takensoft.ai.system.project.dto;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * @author 박현정
+ * @since 2025.07.14
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.14  |    박현정    | 최초 등록
+ *
+ * 프로젝트 이름 변경 관련 DTO
+ */
+@Setter
+@Getter
+@NoArgsConstructor
+public class UpdateProjectNameDTO {
+    private String projectName;
+}
 
src/main/java/kr/co/takensoft/ai/system/project/service/ProjectService.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/project/service/ProjectService.java
@@ -0,0 +1,133 @@
+package kr.co.takensoft.ai.system.project.service;
+
+import kr.co.takensoft.ai.system.project.dto.*;
+import kr.co.takensoft.ai.system.project.vo.ProjectVO;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author 박현정
+ * @since 2025.07.09
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.09  |    박현정   | 최초 등록
+ *
+ * 프로젝트 관련 인터페이스
+ */
+public interface ProjectService {
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param projectDTO - 생성할 프로젝트 정보
+     * @return 등록 성공 여부
+     *
+     * 프로젝트 등록
+     */
+    @Transactional
+    public int saveProject(String memberId, InsertProjectDTO projectDTO);
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @return 프로젝트 이름
+     *
+     * 프로젝트 이름 자동 생성
+     */
+    public String generateProjectNameForMember(String memberId);
+
+    /**
+     * @param index - 숫자
+     * @return 알파벳
+     *
+     * 숫자를 알파벳으로 변경(0 -> 'A', 1 -> 'B', ... 25 -> 'Z', 26 -> 'AA', ...)
+     */
+    public String numberToAlphabet(int index);
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @return 프로젝트 리스트
+     *
+     * 사용자가 참여한 프로젝트 목록 조회
+     */
+    public List<ProjectDTO> findProjectsByMemberId(String memberId);
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @return 사용자가 생성한 프로젝트 개수
+     *
+     * 사용자가 생성한 프로젝트 개수 조회
+     */
+    public int countCreatedByMember(String memberId);
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param projectId - 수정 프로젝트 아이디
+     * @param projectDTO - 수정 프로젝트 정보를 담은 DTO 객체
+     * @return 수정 성공 여부
+     *
+     * 프로젝트 정보 수정
+     */
+    @Transactional
+    public int updateProject(String memberId, String projectId, UpdateProjectDTO projectDTO);
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param projectId - 복제할 프로젝트 아이디
+     * @return 복제 성공 여부
+     *
+     * 프로젝트 복제
+     */
+    @Transactional
+    public int duplicateProject(String memberId, String projectId);
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param projectId - 프로젝트 아이디
+     * @param projectDTO - 이름 변경 정보를 담은 DTO 객체
+     * @return 이름 변경 성공 여부
+     *
+     * 프로젝트 이름 변경
+     */
+    @Transactional
+    public int renameProject(String memberId, String projectId, UpdateProjectNameDTO projectDTO);
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param projectId - 프로젝트 아이디
+     * @return 프로젝트 삭제 성공 여부
+     *
+     * 프로젝트 삭제 (use_at = 'N')
+     */
+    @Transactional
+    public int deleteProject(String memberId, String projectId);
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param projectId - 복원할 프로젝트 아이디
+     * @return 복원 성공 여부
+     *
+     * 이전 프로젝트 복원
+     */
+    @Transactional
+    public int restoreProject(String memberId, String projectId);
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param projectId - 복원할 프로젝트 아이디
+     * @return HashMap<String, Object> - 프로젝트 상세 정보를 담은 객체
+     *
+     * 프로젝트 상세 조회
+     */
+    public HashMap<String, Object> findProject(String memberId, String projectId);
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param searchReqDTO - 프로젝트 목록 검색 조건
+     * @return HashMap<String, Object> - 프로젝트 목록 정보를 담은 객체
+     *
+     * 프로젝트 목록 조회
+     */
+    public HashMap<String, Object> findAllProjects(String memberId, ProjectSearchReqDTO searchReqDTO);
+}
 
src/main/java/kr/co/takensoft/ai/system/project/service/impl/ProjectServiceImpl.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/project/service/impl/ProjectServiceImpl.java
@@ -0,0 +1,325 @@
+package kr.co.takensoft.ai.system.project.service.impl;
+
+import kr.co.takensoft.ai.system.common.idgen.service.IdgenService;
+import kr.co.takensoft.ai.system.project.dao.ProjectDAO;
+import kr.co.takensoft.ai.system.project.dto.*;
+import kr.co.takensoft.ai.system.project.service.ProjectService;
+import kr.co.takensoft.ai.system.project.vo.ProjectVO;
+import kr.co.takensoft.ai.system.projectComment.dto.ProjectCommentDTO;
+import kr.co.takensoft.ai.system.projectComment.service.ProjectCommentService;
+import kr.co.takensoft.ai.system.projectComment.vo.ProjectCommentVO;
+import kr.co.takensoft.ai.system.projectGroup.service.ProjectGroupService;
+import kr.co.takensoft.ai.system.projectImage.dto.ProjectImageDTO;
+import kr.co.takensoft.ai.system.projectImage.service.ProjectImageService;
+import kr.co.takensoft.ai.system.projectImage.vo.ProjectImageVO;
+import kr.co.takensoft.ai.system.projectMember.dto.ProjectMemberDTO;
+import kr.co.takensoft.ai.system.projectMember.service.ProjectMemberService;
+import kr.co.takensoft.ai.system.projectMember.vo.ProjectMemberVO;
+import lombok.RequiredArgsConstructor;
+import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author : 박현정
+ * @since  : 2025.07.09
+ * @modification
+ *      since   |    author    | description
+ *  2025.07.09  |     박현정    | 최초 등록
+ *
+ * 프로젝트 관련 서비스
+ */
+@Service("projectService")
+@RequiredArgsConstructor
+public class ProjectServiceImpl extends EgovAbstractServiceImpl implements ProjectService {
+
+    private final ProjectDAO projectDAO;
+    private final IdgenService projectIdgn;
+    private final ProjectGroupService projectGroupService;
+    private final ProjectMemberService projectMemberService;
+    private final ProjectImageService projectImageService;
+    private final ProjectCommentService projectCommentService;
+    //private final ProjectLogService projectLogService;
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param projectDTO - 생성할 프로젝트 정보
+     * @return 등록 성공 여부
+     *
+     * 프로젝트 등록
+     */
+    @Override
+    public int saveProject(String memberId, InsertProjectDTO projectDTO) {
+
+        try {
+            String projectId = projectIdgn.getNextStringId(); // 프로젝트 구분 아이디 생성
+            String projectGroupId = projectGroupService.saveProjectGroup(); // 프로젝트 그룹 객체 아이디 가져오기
+            String isOwner = "Y"; // 프로젝트 대표자 여부 'Y'
+            projectMemberService.saveProjectMember(projectGroupId, memberId, isOwner); // 프로젝트 참여자 객체 생성
+            projectImageService.saveProjectImage(projectId, projectDTO.getImageFileName(), projectDTO.getImageFileUrl()); // 프로젝트 이미지 객체 생성
+            projectCommentService.saveProjectComment(memberId, projectId, projectDTO.getSummary(), projectDTO.getComment()); // 프로젝트 주석 객체 생성
+            String projectName = generateProjectNameForMember(memberId); // 프로젝트 이름 생성
+            ProjectVO projectVO = new ProjectVO(projectId, projectGroupId, projectName); // 프로젝트 정보 등록
+            return projectDAO.saveProject(projectVO);
+        }  catch (Exception e) {
+            e.printStackTrace();
+            return -1;
+        }
+    }
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @return 프로젝트 이름
+     *
+     * 프로젝트 이름 자동 생성
+     */
+    @Override
+    public String generateProjectNameForMember(String memberId) {
+
+        int memberProjectCount = countCreatedByMember(memberId); // 사용자가 생성한 프로젝트 개수
+        return "프로젝트 " + numberToAlphabet(memberProjectCount);
+    }
+
+    /**
+     * @param index - 숫자
+     * @return 알파벳
+     *
+     * 숫자를 알파벳으로 변경(0 -> 'A', 1 -> 'B', ... 25 -> 'Z', 26 -> 'AA', ...)
+     */
+    @Override
+    public String numberToAlphabet(int index) {
+
+        StringBuilder sb = new StringBuilder();
+        index ++;
+
+        while(index > 0) {
+            index --;
+            char ch = (char) ('A'+(index % 26));
+            sb.insert(0, ch);
+            index /= 26;
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @return 프로젝트 리스트
+     *
+     * 사용자가 참여한 프로젝트 목록 조회
+     */
+    @Override
+    public List<ProjectDTO> findProjectsByMemberId(String memberId) {
+        return projectDAO.findProjectsByMemberId(memberId);
+    }
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @return 사용자가 생성한 프로젝트 개수
+     *
+     * 사용자가 생성한 프로젝트 개수 조회
+     */
+    @Override
+    public int countCreatedByMember(String memberId) {
+        return projectDAO.countCreatedByMemberId(memberId);
+    }
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param projectId - 수정 프로젝트 아이디
+     * @param projectDTO - 수정 프로젝트 정보를 담은 DTO 객체
+     * @return 수정 성공 여부
+     *
+     * 프로젝트 정보 수정
+     */
+    @Override
+    @Transactional
+    public int updateProject(String memberId, String projectId, UpdateProjectDTO projectDTO) {
+        try {
+            ProjectVO projectVO = projectDAO.findById(projectId)
+                    .orElseThrow(() -> new IllegalArgumentException("프로젝트가 존재하지 않습니다.")); // 기존 프로젝트 가져오기
+            if(!projectVO.getIsMain().equals("Y")) { // 기존 프로젝트 대표 여부 확인하기
+                throw new IllegalStateException("대표 프로젝트가 아닙니다.");
+            }
+            String projectGroupId = projectVO.getProjectGroupId(); // 기존 프로젝트 그룹 아이디 가져오기
+            projectMemberService.validateProjectMember(projectGroupId, memberId); // 프로젝트 참여자 존재 여부 검증
+            projectDAO.unsetProjectMain(projectVO.getProjectGroupId()); // 기존 프로젝트를 대표 프로젝트 해제
+
+            String updateProjectId = projectIdgn.getNextStringId(); // 프로젝트 구분 아이디 생성
+            projectImageService.saveProjectImage(updateProjectId, projectDTO.getImageFileName(), projectDTO.getImageFileUrl()); // 프로젝트 이미지 객체 생성
+            projectCommentService.saveProjectComment(memberId, updateProjectId, projectDTO.getSummary(), projectDTO.getComment()); // 프로젝트 주석 객체 생성
+            String projectName = projectVO.getProjectName(); // 기존 프로젝트 이름 가져오기
+            ProjectVO updateProjectVO = new ProjectVO(updateProjectId, projectGroupId, projectName); // 프로젝트 정보 등록(새로운 버전)
+            return projectDAO.saveProject(updateProjectVO);
+        }  catch (Exception e) {
+            e.printStackTrace();
+            return -1;
+        }
+    }
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param currentProjectId - 복제할 프로젝트 아이디
+     * @return 복제 성공 여부
+     *
+     * 프로젝트 복제
+     */
+    @Override
+    @Transactional
+    public int duplicateProject(String memberId, String currentProjectId) {
+        try {
+            ProjectVO currentProjectVO = projectDAO.findById(currentProjectId)
+                    .orElseThrow(() -> new IllegalArgumentException("프로젝트가 존재하지 않습니다.")); // 기존 프로젝트 가져오기
+            String currentProjectGroupId = currentProjectVO.getProjectGroupId(); // 기존 프로젝트 그룹 아이디 가져오기
+            projectMemberService.validateProjectMember(currentProjectGroupId, memberId); // 기존 프로젝트 참여자 존재 여부 검증
+
+            String projectId = projectIdgn.getNextStringId(); // 복제 프로젝트 구분 아이디 생성
+            String projectGroupId = projectGroupService.saveProjectGroup(); // 복제 프로젝트 그룹 객체 아이디 가져오기
+            String isOwner = "Y"; // 프로젝트 대표자 여부 'Y'
+            projectMemberService.saveProjectMember(projectGroupId, memberId, isOwner); // 복제 프로젝트 참여자 객체 생성
+            ProjectImageVO imageVO = projectImageService.findImage(currentProjectVO.getImageId()); // 기존 프로젝트 이미지 가져오기
+            ProjectCommentVO commentVO = projectCommentService.findComment(currentProjectVO.getCommentId()); // 기존 프로젝트 주석 가져오기
+            projectImageService.saveProjectImage(projectId, imageVO.getFileName(), imageVO.getFileUrl()); // 복제 프로젝트 이미지 객체 생성(기존 프로젝트 이미지 복사)
+            projectCommentService.saveProjectComment(memberId, projectId, commentVO.getSummary(), commentVO.getComment()); // 복제 프로젝트 주석 객체 생성(기존 프로젝트 주석 복사)
+            String projectName = "";
+            if(currentProjectVO.getIsMain().equals("Y")){ // 대표 프로젝트를 복제하는 경우 이름 생성
+                projectName = "[복사본] " + currentProjectVO.getProjectName();
+            } else if(currentProjectVO.getIsMain().equals("N")) { // 프로젝트 이전 버전의 사본을 생성하는 경우 이름 생성
+                projectName = "[사본] " + currentProjectVO.getProjectName();
+            }
+
+            ProjectVO projectVO = new ProjectVO(projectId, projectGroupId, projectName); // 복제 프로젝트 정보 등록
+            return projectDAO.saveProject(projectVO);
+        }  catch (Exception e) {
+            e.printStackTrace();
+            return -1;
+        }
+    }
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param projectId - 프로젝트 아이디
+     * @param projectDTO - 이름 변경 정보를 담은 DTO 객체
+     * @return 이름 변경 성공 여부
+     *
+     * 프로젝트 이름 변경
+     */
+    @Override
+    @Transactional
+    public int renameProject(String memberId, String projectId, UpdateProjectNameDTO projectDTO) {
+        try {
+            ProjectVO projectVO = projectDAO.findById(projectId)
+                    .orElseThrow(() -> new IllegalArgumentException("프로젝트가 존재하지 않습니다.")); // 프로젝트 가져오기
+            String projectGroupId = projectVO.getProjectGroupId(); // 프로젝트 그룹 아이디 가져오기
+            projectMemberService.validateProjectMember(projectGroupId, memberId); // 프로젝트 참여자 존재 여부 검증
+            return projectDAO.updateProjectName(projectId, projectDTO.getProjectName()); // 프로젝트 이름 변경
+        }  catch (Exception e) {
+            e.printStackTrace();
+            return -1;
+        }
+    }
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @return 프로젝트 삭제 성공 여부
+     *
+     * 프로젝트 삭제 (use_at = 'N')
+     */
+    @Override
+    @Transactional
+    public int deleteProject(String memberId, String projectGroupId) {
+        try {
+            projectGroupService.validateExistence(projectGroupId);  // 프로젝트 그룹 존재 여부 검증
+            projectMemberService.validateProjectMember(projectGroupId, memberId); // 프로젝트 참여자 존재 여부 검증
+            projectGroupService.deleteProjectGroup(projectGroupId); // 프로젝트 그룹 삭제(use_at = 'N')
+            return projectDAO.deactivateProjectsByGroupId(projectGroupId); // 프로젝트 삭제(use_at = 'N')
+        }  catch (Exception e) {
+            e.printStackTrace();
+            return -1;
+        }
+    }
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param projectId - 복원할 프로젝트 아이디
+     * @return 복원 성공 여부
+     *
+     * 이전 프로젝트 복원
+     */
+    @Override
+    @Transactional
+    public int restoreProject(String memberId, String projectId) {
+        try {
+            ProjectVO projectVO = projectDAO.findById(projectId)
+                    .orElseThrow(() -> new IllegalArgumentException("프로젝트가 존재하지 않습니다.")); // 프로젝트 가져오기
+            String projectGroupId = projectVO.getProjectGroupId(); // 프로젝트 그룹 아이디 가져오기
+            projectMemberService.validateProjectMember(projectGroupId, memberId); // 프로젝트 참여자 존재 여부 검증
+            projectDAO.unsetProjectMain(projectGroupId); // 현재 프로젝트 대표 프로젝트 해제
+            projectDAO.setProjectMain(projectId); // 복원할 프로젝트를 대표 프로젝트로 설정
+            return projectDAO.deactivateProjectsCreatedAfter(projectGroupId, projectId); // 복원할 프로젝트 이후에 생성된 프로젝트 삭제
+        }  catch (Exception e) {
+            e.printStackTrace();
+            return -1;
+        }
+    }
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param projectId - 복원할 프로젝트 아이디
+     * @return HashMap<String, Object> - 프로젝트 상세 정보를 담은 객체
+     *
+     * 프로젝트 상세 조회
+     */
+    @Override
+    public HashMap<String, Object> findProject(String memberId, String projectId) {
+        try {
+            HashMap<String, Object> result = new HashMap<>();
+            ProjectVO projectVO = projectDAO.findById(projectId)
+                    .orElseThrow(() -> new IllegalArgumentException("프로젝트가 존재하지 않습니다.")); // 프로젝트 가져오기
+            String projectGroupId = projectVO.getProjectGroupId(); // 프로젝트 그룹 아이디 가져오기
+            projectMemberService.validateProjectMember(projectGroupId, memberId); // 프로젝트 참여자 존재 여부 검증
+            List<ProjectMemberVO> projectMemberVOS = projectMemberService.findProjectMembers(projectGroupId); // 프로젝트 참여자 목록 가져오기
+            ProjectImageVO imageVO = projectImageService.findImage(projectVO.getImageId()); // 프로젝트 이미지 가져오기
+            ProjectCommentVO commentVO = projectCommentService.findComment(projectVO.getCommentId()); // 프로젝트 주석 가져오기
+            List<ProjectMemberDTO> projectMemberDTOS = projectMemberVOS.stream()
+                    .map(ProjectMemberDTO::from).collect(Collectors.toList()); // 프로젝트 참여자 목록 dto 객체에 담기
+            result.put("project", ProjectDTO.from(projectVO));
+            result.put("projectMember", projectMemberDTOS);
+            result.put("projectComment", ProjectCommentDTO.from(commentVO));
+            result.put("projectImage", ProjectImageDTO.from(imageVO));
+            return result; // 프로젝트 상세 조회 결과 응답
+        }  catch (Exception e) {
+            e.printStackTrace();
+            throw e;
+        }
+    }
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param searchReqDTO - 프로젝트 목록 검색 조건
+     * @return HashMap<String, Object> - 프로젝트 목록 정보를 담은 객체
+     *
+     * 프로젝트 목록 조회
+     */
+    @Override
+    public HashMap<String, Object> findAllProjects(String memberId, ProjectSearchReqDTO searchReqDTO) {
+
+        try {
+            HashMap<String, Object> result = new HashMap<>();
+            searchReqDTO.setMemberId(memberId); // 검색 조건에 사용자 아이디 추가
+            List<ProjectDTO> projectDTOS = projectDAO.findAllProjects(searchReqDTO)
+                    .stream().map(ProjectDTO::from).collect(Collectors.toList()); // 프로젝트 목록 조회
+            result.put("projects", projectDTOS); // 프로젝트 목록을 결과에 담기
+            return result;
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+            throw e;
+        }
+    }
+}
 
src/main/java/kr/co/takensoft/ai/system/project/vo/ProjectVO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/project/vo/ProjectVO.java
@@ -0,0 +1,43 @@
+package kr.co.takensoft.ai.system.project.vo;
+
+import kr.co.takensoft.ai.system.project.dto.UpdateProjectDTO;
+import kr.co.takensoft.ai.system.projectComment.vo.ProjectCommentVO;
+import kr.co.takensoft.ai.system.projectImage.vo.ProjectImageVO;
+import kr.co.takensoft.ai.system.projectMember.vo.ProjectMemberVO;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * @author 박현정
+ * @since 2025.07.09
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.09  |    박현정     | 최초 등록
+ *
+ *
+ * 프로젝트 관련 VO
+ */
+@Getter
+@NoArgsConstructor
+public class ProjectVO {
+    private String projectId; // 프로젝트 아이디
+    private String projectGroupId; // 프로젝트 그룹 아이디
+    private String projectName; //	프로젝트 이름
+    private String isMain; // 대표 프로젝트 여부 ( N: 대표 아님, Y: 대표)
+    private String useAt; // 프로젝트 사용 여부 (N : 사용 안함, Y : 사용)
+    private String imageId; // 프로젝트 이미지 아이디
+    private String commentId; // 프로젝트 주석 아이디
+    private String createdAt; // 생성일자
+    private String updatedAt; // 수정일자
+
+    // 프로젝트 생성용 생성자
+    public ProjectVO(String projectId, String projectGroupId, String projectName) {
+        this.projectId = projectId;
+        this.projectGroupId = projectGroupId;
+        this.projectName = projectName;
+        this.isMain = "Y";
+        this.useAt = "Y";
+    }
+}
 
src/main/java/kr/co/takensoft/ai/system/project/web/ProjectController.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/project/web/ProjectController.java
@@ -0,0 +1,157 @@
+package kr.co.takensoft.ai.system.project.web;
+
+import kr.co.takensoft.ai.system.auth.vo.MemberVO;
+import kr.co.takensoft.ai.system.project.dto.InsertProjectDTO;
+import kr.co.takensoft.ai.system.project.dto.ProjectSearchReqDTO;
+import kr.co.takensoft.ai.system.project.dto.UpdateProjectDTO;
+import kr.co.takensoft.ai.system.project.dto.UpdateProjectNameDTO;
+import kr.co.takensoft.ai.system.project.service.ProjectService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+
+/*
+ * @author : 박현정
+ * @since  : 2025.07.09
+ * @modification
+ *      since   |    author    | description
+ *  2025.07.09  |     박현정    | 최초 등록
+ *
+ * 사용자 정보 관련 서비스
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping(value = "/api/project")
+public class ProjectController {
+
+    private final ProjectService projectService;
+    private final String MEMBER_ID = "test";
+
+    /**
+     * @param insertProjectDTO - 생성할 프로젝트 정보
+     * @return ResponseEntity - 프로젝트 등록 결과를 포함하는 응답
+     *
+     * 프로젝트 등록
+     */
+    @PostMapping("/saveProject.json")
+    public ResponseEntity<?> saveProject(@RequestBody InsertProjectDTO insertProjectDTO) {
+        HashMap<String, Object> result = new HashMap<>();
+        String memberId = MEMBER_ID;
+        result.put("result", projectService.saveProject(memberId, insertProjectDTO));
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    /**
+     * @return ResponseEntity - 사용자가 참여한 프로젝트 목록을 포함하는 응답
+     *
+     * 사용자가 참여한 프로젝트 목록 조회
+     */
+    @PostMapping("/findAllByMemberId.json")
+    public ResponseEntity<?> findAllByMemberId() {
+        HashMap<String, Object> result = new HashMap<>();
+        String memberId = MEMBER_ID;
+        result.put("result", projectService.findProjectsByMemberId(memberId));
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    /**
+     * @param projectId - 수정 프로젝트 아이디
+     * @param updateProjectDTO - 수정 프로젝트 정보
+     * @return ResponseEntity - 프로젝트 정보 수정 처리 결과를 포함하는 응답
+     *
+     * 프로젝트 정보 수정
+     */
+    @PostMapping("/{projectId}/updateProject.json")
+    public ResponseEntity<?> updateCategory(@PathVariable String projectId, @RequestBody UpdateProjectDTO updateProjectDTO) {
+        HashMap<String, Object> result = new HashMap<>();
+        String memberId = MEMBER_ID;
+        result.put("result", projectService.updateProject(memberId, projectId, updateProjectDTO));
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    /**
+     * @param projectId - 복제할 프로젝트 아이디
+     * @return ResponseEntity - 프로젝트 복제 결과를 포함하는 응답
+     *
+     * 프로젝트 복제
+     */
+    @PostMapping("/{projectId}/duplicateProject.json")
+    public ResponseEntity<?> duplicateProject(@PathVariable String projectId) {
+        HashMap<String, Object> result = new HashMap<>();
+        String memberId = MEMBER_ID;
+        result.put("result", projectService.duplicateProject(memberId, projectId));
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    /**
+     * @param projectId - 이름 변경할 프로젝트 아이디
+     * @return ResponseEntity - 프로젝트 이름 수정 결과를 포함하는 응답
+     *
+     * 프로젝트 이름 변경
+     */
+    @PostMapping("/{projectId}/renameProject.json")
+    public ResponseEntity<?> renameProject(@PathVariable String projectId, @RequestBody UpdateProjectNameDTO updateProjectNameDTO) {
+        HashMap<String, Object> result = new HashMap<>();
+        String memberId = MEMBER_ID;
+        result.put("result", projectService.renameProject(memberId, projectId, updateProjectNameDTO));
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    /**
+     * @param projectGroupId - 삭제할 프로젝트 그룹 아이디
+     * @return ResponseEntity - 프로젝트 삭제 결과를 포함하는 응답
+     *
+     * 프로젝트 삭제 (use_at = 'N')
+     */
+    @PostMapping("/{projectGroupId}/deleteProject.json")
+    public ResponseEntity<?> deleteProject(@PathVariable String projectGroupId) {
+        HashMap<String, Object> result = new HashMap<>();
+        String memberId = MEMBER_ID;
+        result.put("result", projectService.deleteProject(memberId, projectGroupId));
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    /**
+     * @param projectId - 복원할 프로젝트 아이디
+     * @return ResponseEntity - 프로젝트 복원 결과를 포함하는 응답
+     *
+     * 프로젝트 이전 버전 복원
+     */
+    @PostMapping("/{projectId}/restoreProject.json")
+    public ResponseEntity<?> restoreProject(@PathVariable String projectId) {
+        HashMap<String, Object> result = new HashMap<>();
+        String memberId = MEMBER_ID;
+        result.put("result", projectService.restoreProject(memberId, projectId));
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    /**
+     * @param projectId - 프로젝트 아이디
+     * @return ResponseEntity - 프로젝트 상세 조회 정보를 포함하는 응답
+     *
+     * 프로젝트 상세 조회
+     */
+    @PostMapping("/{projectId}/findProject.json")
+    public ResponseEntity<?> findProject(@PathVariable String projectId) {
+        HashMap<String, Object> result = new HashMap<>();
+        String memberId = MEMBER_ID;
+        result.put("result", projectService.findProject(memberId, projectId));
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    /**
+     * @return ResponseEntity - 프로젝트 목록 정보를 포함하는 응답
+     *
+     * 프로젝트 목록 조회
+     */
+    @PostMapping("/findAllProjects.json")
+    public ResponseEntity<?> findAllProjects(@RequestBody ProjectSearchReqDTO projectSearchReqDTO) {
+        HashMap<String, Object> result = new HashMap<>();
+        String memberId = MEMBER_ID;
+        result.put("result", projectService.findAllProjects(memberId, projectSearchReqDTO));
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+}
 
src/main/java/kr/co/takensoft/ai/system/projectComment/dao/ProjectCommentDAO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectComment/dao/ProjectCommentDAO.java
@@ -0,0 +1,35 @@
+package kr.co.takensoft.ai.system.projectComment.dao;
+
+import kr.co.takensoft.ai.system.feedback.vo.FeedbackVO;
+import kr.co.takensoft.ai.system.projectComment.vo.ProjectCommentVO;
+import kr.co.takensoft.ai.system.projectImage.vo.ProjectImageVO;
+import org.egovframe.rte.psl.dataaccess.mapper.Mapper;
+
+/**
+ * @author 박현정
+ * @since 2025.07.10
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.10  |    박현정     | 최초 등록
+ *
+ * 프로젝트 주석 관련 DAO
+ */
+@Mapper("projectCommentDAO")
+public interface ProjectCommentDAO {
+
+    /**
+     * @param projectCommentVO - 프로젝트 주석 정보
+     * @return int - 프로젝트 주석 등록 결과
+     *
+     * 프로젝트 주석 등록
+     */
+    int saveProjectComment(ProjectCommentVO projectCommentVO);
+
+    /**
+     * @param commentId - 프로젝트 주석 아이디
+     * @return ProjectCommentVO - 프로젝트 주석 정보
+     *
+     * 프로젝트 주석 정보 조회
+     */
+    ProjectCommentVO findById(String commentId);
+}
 
src/main/java/kr/co/takensoft/ai/system/projectComment/dto/ProjectCommentDTO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectComment/dto/ProjectCommentDTO.java
@@ -0,0 +1,43 @@
+package kr.co.takensoft.ai.system.projectComment.dto;
+
+import kr.co.takensoft.ai.system.projectComment.vo.ProjectCommentVO;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * @author 박현정
+ * @since 2025.07.15
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.15  |    박현정    | 최초 등록
+ *
+ * 프로젝트 주석 조회 관련 DTO
+ */
+@Setter
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+public class ProjectCommentDTO {
+
+    private String projectCommentId; // 프로젝트 주석 아이디
+    private String memberId; // 주석 작성자 아이디
+    private String memberName; // 주석 작성자 이름
+    private String summary; // 주석 요약
+    private String comment; // 주석 내용
+    private String createdAt; // 생성일자
+    private String updatedAt; // 수정일자
+
+    public static ProjectCommentDTO from(ProjectCommentVO commentVO) {
+        return new ProjectCommentDTO(
+                commentVO.getProjectCommentId(),
+                commentVO.getMemberId(),
+                commentVO.getMemberName(),
+                commentVO.getSummary(),
+                commentVO.getComment(),
+                commentVO.getCreatedAt(),
+                commentVO.getUpdatedAt()
+        );
+    }
+}
 
src/main/java/kr/co/takensoft/ai/system/projectComment/service/ProjectCommentService.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectComment/service/ProjectCommentService.java
@@ -0,0 +1,38 @@
+package kr.co.takensoft.ai.system.projectComment.service;
+
+import kr.co.takensoft.ai.system.project.dto.InsertProjectDTO;
+import kr.co.takensoft.ai.system.projectComment.vo.ProjectCommentVO;
+import kr.co.takensoft.ai.system.projectImage.vo.ProjectImageVO;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * @author 박현정
+ * @since 2025.07.14
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.14  |    박현정   | 최초 등록
+ *
+ * 프로젝트 주석 관련 인터페이스
+ */
+public interface ProjectCommentService {
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param projectId - 프로젝트 아이디
+     * @param summary - 주석 요약
+     * @param comment - 주석 내용
+     * @return 등록 성공 여부
+     *
+     * 프로젝트 주석 등록
+     */
+    @Transactional
+    public int saveProjectComment(String memberId, String projectId, String summary, String comment);
+
+    /**
+     * @param commentId - 프로젝트 주석 아이디
+     * @return ProjectCommentVO - 프로젝트 주석 정보
+     *
+     * 프로젝트 주석 정보 조회
+     */
+    public ProjectCommentVO findComment(String commentId);
+}
 
src/main/java/kr/co/takensoft/ai/system/projectComment/service/impl/ProjectCommentServiceImpl.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectComment/service/impl/ProjectCommentServiceImpl.java
@@ -0,0 +1,54 @@
+package kr.co.takensoft.ai.system.projectComment.service.impl;
+
+import kr.co.takensoft.ai.system.common.idgen.service.IdgenService;
+import kr.co.takensoft.ai.system.projectComment.dao.ProjectCommentDAO;
+import kr.co.takensoft.ai.system.projectComment.service.ProjectCommentService;
+import kr.co.takensoft.ai.system.projectComment.vo.ProjectCommentVO;
+import lombok.RequiredArgsConstructor;
+import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author : 박현정
+ * @since  : 2025.07.14
+ * @modification
+ *      since   |    author    | description
+ *  2025.07.14  |     박현정    | 최초 등록
+ *
+ * 프로젝트 주석 관련 서비스
+ */
+@Service("projectCommentService")
+@RequiredArgsConstructor
+public class ProjectCommentServiceImpl extends EgovAbstractServiceImpl implements ProjectCommentService {
+
+    private final ProjectCommentDAO projectCommentDAO;
+    private final IdgenService projectCommentIdgn;
+
+    /**
+     * @param memberId - 사용자 아이디
+     * @param projectId - 프로젝트 아이디
+     * @param summary - 주석 요약
+     * @param comment - 주석 내용
+     * @return 등록 성공 여부
+     *
+     * 프로젝트 주석 등록
+     */
+    @Override
+    public int saveProjectComment(String memberId, String projectId, String summary, String comment) {
+
+        String projectCommentId = projectCommentIdgn.getNextStringId(); // 프로젝트 주석 구분 아이디 생성
+        ProjectCommentVO projectCommentVO = new ProjectCommentVO(projectCommentId, projectId, memberId, summary, comment); // 주석 정보 등록
+        return projectCommentDAO.saveProjectComment(projectCommentVO);
+    }
+
+    /**
+     * @param commentId - 프로젝트 주석 아이디
+     * @return ProjectCommentVO - 프로젝트 주석 정보
+     *
+     * 프로젝트 주석 정보 조회
+     */
+    @Override
+    public ProjectCommentVO findComment(String commentId) {
+        return projectCommentDAO.findById(commentId);
+    }
+}
 
src/main/java/kr/co/takensoft/ai/system/projectComment/vo/ProjectCommentVO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectComment/vo/ProjectCommentVO.java
@@ -0,0 +1,38 @@
+package kr.co.takensoft.ai.system.projectComment.vo;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author 박현정
+ * @since 2025.07.10
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.10  |    박현정     | 최초 등록
+ *
+ *
+ * 프로젝트 주석 관련 VO
+ */
+@Getter
+@NoArgsConstructor
+public class ProjectCommentVO {
+
+    private String projectCommentId; // 프로젝트 주석 아이디
+    private String projectId; // 프로젝트 아이디
+    private String memberId; // 주석 작성자 아이디
+    private String memberName; // 주석 작성자 이름
+    private String summary; // 주석 요약
+    private String comment; // 주석 내용
+    private String useAt; // 사용 여부 (N : 사용 안함, Y : 사용)
+    private String createdAt; // 생성일자
+    private String updatedAt; // 수정일자
+
+    public ProjectCommentVO(String projectCommentId, String projectId, String memberId, String summary, String comment) {
+        this.projectCommentId = projectCommentId;
+        this.projectId = projectId;
+        this.memberId = memberId;
+        this.summary = summary;
+        this.comment = comment;
+        this.useAt = "Y";
+    }
+}
 
src/main/java/kr/co/takensoft/ai/system/projectGroup/dao/ProjectGroupDAO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectGroup/dao/ProjectGroupDAO.java
@@ -0,0 +1,41 @@
+package kr.co.takensoft.ai.system.projectGroup.dao;
+
+import kr.co.takensoft.ai.system.projectGroup.vo.ProjectGroupVO;
+import org.egovframe.rte.psl.dataaccess.mapper.Mapper;
+
+/**
+ * @author 박현정
+ * @since 2025.07.10
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.10  |    박현정     | 최초 등록
+ *
+ * 프로젝트 그룹 관련 DAO
+ */
+@Mapper("projectGroupDAO")
+public interface ProjectGroupDAO {
+
+    /**
+     * @param projectGroupVO - 프로젝트 그룹 정보
+     * @return int - 프로젝트 그룹 등록 결과
+     *
+     * 프로젝트 그룹 등록
+     */
+    int saveProjectGroup(ProjectGroupVO projectGroupVO);
+
+    /**
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @return
+     *
+     * 프로젝트 그룹 삭제 (use_at = 'N')
+     */
+    void deactivateGroupProjectById(String projectGroupId);
+
+    /**
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @return boolean - 프로젝트 그룹 존재 여부
+     *
+     * 프로젝트 그룹 존재 여부 확인
+     */
+    boolean existsById(String projectGroupId);
+}
 
src/main/java/kr/co/takensoft/ai/system/projectGroup/service/ProjectGroupService.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectGroup/service/ProjectGroupService.java
@@ -0,0 +1,41 @@
+package kr.co.takensoft.ai.system.projectGroup.service;
+
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * @author 박현정
+ * @since 2025.07.10
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.10  |    박현정   | 최초 등록
+ *
+ * 프로젝트 그룹 관련 인터페이스
+ */
+public interface ProjectGroupService {
+
+    /**
+     * @param
+     * @return 프로젝트 그룹 id
+     *
+     * 프로젝트 그룹 등록
+     */
+    @Transactional
+    public String saveProjectGroup();
+
+    /**
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @return
+     *
+     * 프로젝트 그룹 삭제 (use_at = 'N')
+     */
+    @Transactional
+    void deleteProjectGroup(String projectGroupId);
+
+    /**
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @return
+     *
+     * 프로젝트 그룹 존재 여부 검사
+     */
+    void validateExistence(String projectGroupId);
+}
 
src/main/java/kr/co/takensoft/ai/system/projectGroup/service/impl/ProjectGroupServiceImpl.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectGroup/service/impl/ProjectGroupServiceImpl.java
@@ -0,0 +1,78 @@
+package kr.co.takensoft.ai.system.projectGroup.service.impl;
+
+import kr.co.takensoft.ai.system.common.idgen.service.IdgenService;
+import kr.co.takensoft.ai.system.project.vo.ProjectVO;
+import kr.co.takensoft.ai.system.projectGroup.dao.ProjectGroupDAO;
+import kr.co.takensoft.ai.system.projectGroup.service.ProjectGroupService;
+import kr.co.takensoft.ai.system.projectGroup.vo.ProjectGroupVO;
+import lombok.RequiredArgsConstructor;
+import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+/*
+ * @author : 박현정
+ * @since  : 2025.07.10
+ * @modification
+ *      since   |    author    | description
+ *  2025.07.10  |     박현정    | 최초 등록
+ *
+ * 프로젝트 그룹 관련 서비스
+ */
+@Service("projectGroupService")
+@RequiredArgsConstructor
+public class ProjectGroupServiceImpl extends EgovAbstractServiceImpl implements ProjectGroupService {
+
+    private final ProjectGroupDAO projectGroupDAO;
+    private final IdgenService projectGroupIdgn;
+
+    /**
+     * @param
+     * @return 프로젝트 그룹 id
+     *
+     * 프로젝트 그룹 등록
+     */
+    @Override
+    @Transactional
+    public String saveProjectGroup() {
+
+        try{
+            String projectGroupId = projectGroupIdgn.getNextStringId(); // 프로젝트 그룹 구분 아이디 생성
+            ProjectGroupVO projectGroupVO = new ProjectGroupVO(projectGroupId);
+            int result = projectGroupDAO.saveProjectGroup(projectGroupVO);
+            return result > 0 ? projectGroupId : null;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @return
+     *
+     * 프로젝트 그룹 삭제 (use_at = 'N')
+     */
+    @Override
+    @Transactional
+    public void deleteProjectGroup(String projectGroupId) {
+        try{
+            projectGroupDAO.deactivateGroupProjectById(projectGroupId);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @return
+     *
+     * 프로젝트 그룹 존재 여부 검사
+     */
+    @Override
+    public void validateExistence(String projectGroupId) {
+        if(!projectGroupDAO.existsById(projectGroupId)) {
+            throw new IllegalArgumentException("프로젝트 그룹이 존재하지 않습니다.");
+        }
+    }
+}
 
src/main/java/kr/co/takensoft/ai/system/projectGroup/vo/ProjectGroupVO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectGroup/vo/ProjectGroupVO.java
@@ -0,0 +1,30 @@
+package kr.co.takensoft.ai.system.projectGroup.vo;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author 박현정
+ * @since 2025.07.10
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.10  |    박현정     | 최초 등록
+ *
+ *
+ * 프로젝트 그룹 관련 VO
+ */
+@Getter
+@NoArgsConstructor
+public class ProjectGroupVO {
+
+    private String projectGroupId; // 프로젝트 그룹 아이디
+    private String useAt; // 사용 여부 (N : 사용 안함, Y : 사용)
+    private String createdAt; // 생성일자
+    private String updatedAt; // 수정일자
+
+    // 프로젝트 그룹 생성용 생성자
+    public ProjectGroupVO(String projectGroupId) {
+        this.projectGroupId = projectGroupId;
+        this.useAt = "Y";
+    }
+}
 
src/main/java/kr/co/takensoft/ai/system/projectImage/dao/ProjectImageDAO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectImage/dao/ProjectImageDAO.java
@@ -0,0 +1,37 @@
+package kr.co.takensoft.ai.system.projectImage.dao;
+
+import kr.co.takensoft.ai.system.project.vo.ProjectVO;
+import kr.co.takensoft.ai.system.projectComment.vo.ProjectCommentVO;
+import kr.co.takensoft.ai.system.projectImage.vo.ProjectImageVO;
+import org.egovframe.rte.psl.dataaccess.mapper.Mapper;
+
+import java.util.Optional;
+
+/**
+ * @author 박현정
+ * @since 2025.07.10
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.10  |    박현정     | 최초 등록
+ *
+ * 프로젝트 이미지 파일 관련 DAO
+ */
+@Mapper("projectImageDAO")
+public interface ProjectImageDAO {
+
+    /**
+     * @param projectImageVO - 프로젝트 이미지 파일 정보
+     * @return int - 프로젝트 이미지 파일 등록 결과
+     *
+     * 프로젝트 이미지 파일 등록
+     */
+    int saveProjectImage(ProjectImageVO projectImageVO);
+
+    /**
+     * @param imageId - 프로젝트 이미지 아이디
+     * @return ProjectImageVO - 프로젝트 이미지 정보
+     *
+     * 프로젝트 이미지 정보 조회
+     */
+    ProjectImageVO findById(String imageId);
+}
 
src/main/java/kr/co/takensoft/ai/system/projectImage/dto/ProjectImageDTO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectImage/dto/ProjectImageDTO.java
@@ -0,0 +1,39 @@
+package kr.co.takensoft.ai.system.projectImage.dto;
+
+import kr.co.takensoft.ai.system.projectImage.vo.ProjectImageVO;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * @author 박현정
+ * @since 2025.07.15
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.15  |    박현정    | 최초 등록
+ *
+ * 프로젝트 이미지 조회 관련 DTO
+ */
+@Setter
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+public class ProjectImageDTO {
+
+    private String projectImageId; // 프로젝트 이미지 아이디
+    private String fileName; // 이미지 파일 이름
+    private String fileUrl; // 이미지 파일 경로
+    private String createdAt; // 생성일자
+    private String updatedAt; // 수정일자
+
+    public static ProjectImageDTO from(ProjectImageVO imageVO) {
+        return new ProjectImageDTO(
+                imageVO.getProjectImageId(),
+                imageVO.getFileName(),
+                imageVO.getFileUrl(),
+                imageVO.getCreatedAt(),
+                imageVO.getUpdatedAt()
+        );
+    }
+}
 
src/main/java/kr/co/takensoft/ai/system/projectImage/service/ProjectImageService.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectImage/service/ProjectImageService.java
@@ -0,0 +1,35 @@
+package kr.co.takensoft.ai.system.projectImage.service;
+
+import kr.co.takensoft.ai.system.projectImage.vo.ProjectImageVO;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * @author 박현정
+ * @since 2025.07.14
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.14  |    박현정   | 최초 등록
+ *
+ * 프로젝트 이미지 관련 인터페이스
+ */
+public interface ProjectImageService {
+
+    /**
+     * @param projectId - 프로젝트 아이디
+     * @param fileName - 이미지 파일 이름
+     * @param fileUrl - 이미지 파일 경로
+     * @return 등록 성공 여부
+     *
+     * 프로젝트 이미지 등록
+     */
+    @Transactional
+    public int saveProjectImage(String projectId, String fileName, String fileUrl);
+
+    /**
+     * @param imageId - 프로젝트 이미지 아이디
+     * @return ProjectImageVO - 프로젝트 이미지 정보
+     *
+     * 프로젝트 이미지 정보 조회
+     */
+    public ProjectImageVO findImage(String imageId);
+}
 
src/main/java/kr/co/takensoft/ai/system/projectImage/service/impl/ProjectImageServiceImpl.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectImage/service/impl/ProjectImageServiceImpl.java
@@ -0,0 +1,55 @@
+package kr.co.takensoft.ai.system.projectImage.service.impl;
+
+import kr.co.takensoft.ai.system.common.idgen.service.IdgenService;
+import kr.co.takensoft.ai.system.projectComment.vo.ProjectCommentVO;
+import kr.co.takensoft.ai.system.projectImage.dao.ProjectImageDAO;
+import kr.co.takensoft.ai.system.projectImage.service.ProjectImageService;
+import kr.co.takensoft.ai.system.projectImage.vo.ProjectImageVO;
+import lombok.RequiredArgsConstructor;
+import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * @author : 박현정
+ * @since  : 2025.07.14
+ * @modification
+ *      since   |    author    | description
+ *  2025.07.14  |     박현정    | 최초 등록
+ *
+ * 프로젝트 이미지 관련 서비스
+ */
+@Service("projectImageService")
+@RequiredArgsConstructor
+public class ProjectImageServiceImpl extends EgovAbstractServiceImpl implements ProjectImageService {
+
+    private final ProjectImageDAO projectImageDAO;
+    private final IdgenService projectImageIdgn;
+
+    /**
+     * @param projectId - 프로젝트 아이디
+     * @param fileName - 이미지 파일 이름
+     * @param fileUrl - 이미지 파일 경로
+     * @return 등록 성공 여부
+     *
+     * 프로젝트 이미지 등록
+     */
+    @Override
+    public int saveProjectImage(String projectId, String fileName, String fileUrl) {
+
+        String projectImageId = projectImageIdgn.getNextStringId(); // 프로젝트 주석 구분 아이디 생성
+        ProjectImageVO projectImageVO = new ProjectImageVO(projectImageId, projectId, fileName, fileUrl); // 주석 정보 등록
+        return projectImageDAO.saveProjectImage(projectImageVO);
+    }
+
+    /**
+     * @param imageId - 프로젝트 이미지 아이디
+     * @return ProjectImageVO - 프로젝트 이미지 정보
+     *
+     * 프로젝트 이미지 정보 조회
+     */
+    @Override
+    public ProjectImageVO findImage(String imageId) {
+        return projectImageDAO.findById(imageId);
+    }
+}
 
src/main/java/kr/co/takensoft/ai/system/projectImage/vo/ProjectImageVO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectImage/vo/ProjectImageVO.java
@@ -0,0 +1,36 @@
+package kr.co.takensoft.ai.system.projectImage.vo;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author 박현정
+ * @since 2025.07.10
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.10  |    박현정     | 최초 등록
+ *
+ *
+ * 프로젝트 이미지 관련 VO
+ */
+@Getter
+@NoArgsConstructor
+public class ProjectImageVO {
+
+    private String projectImageId; // 프로젝트 이미지 아이디
+    private String projectId; // 프로젝트 아이디
+    private String fileName; // 이미지 파일 이름
+    private String fileUrl; // 이미지 파일 경로
+    private String useAt; // 사용 여부 (N : 사용 안함, Y : 사용)
+    private String createdAt; // 생성일자
+    private String updatedAt; // 수정일자
+
+    // 프로젝트 이미지 생성용 생성자
+    public ProjectImageVO(String projectImageId, String projectId, String fileName, String fileUrl) {
+        this.projectImageId = projectImageId;
+        this.projectId = projectId;
+        this.fileName = fileName;
+        this.fileUrl = fileUrl;
+        this.useAt = "Y";
+    }
+}
 
src/main/java/kr/co/takensoft/ai/system/projectMember/dao/ProjectMemberDAO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectMember/dao/ProjectMemberDAO.java
@@ -0,0 +1,45 @@
+package kr.co.takensoft.ai.system.projectMember.dao;
+
+import kr.co.takensoft.ai.system.projectComment.vo.ProjectCommentVO;
+import kr.co.takensoft.ai.system.projectMember.vo.ProjectMemberVO;
+import org.egovframe.rte.psl.dataaccess.mapper.Mapper;
+
+import java.util.List;
+
+/**
+ * @author 박현정
+ * @since 2025.07.10
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.10  |    박현정     | 최초 등록
+ *
+ * 프로젝트 참여자 관련 DAO
+ */
+@Mapper("projectMemberDAO")
+public interface ProjectMemberDAO {
+
+    /**
+     * @param projectMemberVO - 프로젝트 참여자 정보
+     * @return int - 프로젝트 참여자 등록 결과
+     *
+     * 프로젝트 참여자 등록
+     */
+    int saveProjectMember(ProjectMemberVO projectMemberVO);
+
+    /**
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @param memberId - 사용자 아이디
+     * @return boolean - 프로젝트 참여자 존재 여부 검증
+     *
+     * 프로젝트 참여자 존재 여부 검증
+     */
+    boolean existsByProjectGroupIdAndMemberId(String projectGroupId, String memberId);
+
+    /**
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @return List<ProjectMemberVO> - 프로젝트 참여자 목록
+     *
+     * 프로젝트 참여자 목록 조회
+     */
+    List<ProjectMemberVO> findAllByGroupId(String projectGroupId);
+}
 
src/main/java/kr/co/takensoft/ai/system/projectMember/dto/ProjectMemberDTO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectMember/dto/ProjectMemberDTO.java
@@ -0,0 +1,41 @@
+package kr.co.takensoft.ai.system.projectMember.dto;
+
+import kr.co.takensoft.ai.system.projectMember.vo.ProjectMemberVO;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * @author 박현정
+ * @since 2025.07.15
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.15  |    박현정    | 최초 등록
+ *
+ * 프로젝트 참여자 조회 관련 DTO
+ */
+@Setter
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+public class ProjectMemberDTO {
+
+    private String projectMemberId; // 프로젝트 참여자 아이디
+    private String memberId; // 참여자 아이디
+    private String memberName; // 참여자 이름
+    private String isOwner; // 프로젝트 대표자 여부 ( N: 대표자 아님, Y: 대표자)
+    private String createdAt; // 생성일자
+    private String updatedAt; // 수정일자
+
+    public static ProjectMemberDTO from(ProjectMemberVO projectMemberVO) {
+        return new ProjectMemberDTO(
+                projectMemberVO.getProjectMemberId(),
+                projectMemberVO.getMemberId(),
+                projectMemberVO.getMemberName(),
+                projectMemberVO.getIsOwner(),
+                projectMemberVO.getCreatedAt(),
+                projectMemberVO.getUpdatedAt()
+        );
+    }
+}
 
src/main/java/kr/co/takensoft/ai/system/projectMember/service/ProjectMemberService.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectMember/service/ProjectMemberService.java
@@ -0,0 +1,43 @@
+package kr.co.takensoft.ai.system.projectMember.service;
+
+import kr.co.takensoft.ai.system.projectMember.vo.ProjectMemberVO;
+
+import java.util.List;
+
+/**
+ * @author 박현정
+ * @since 2025.07.10
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.10  |    박현정   | 최초 등록
+ *
+ * 프로젝트 참여자 인터페이스
+ */
+public interface ProjectMemberService {
+
+    /**
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @param memberId - 사용자 아이디
+     * @param isOwner - 프로젝트 대표자 여부
+     * @return 등록 성공 여부
+     *
+     * 프로젝트 참여자 등록
+     */
+    public int saveProjectMember(String projectGroupId, String memberId, String isOwner);
+
+    /**
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @param memberId - 사용자 아이디
+     *
+     * 프로젝트 참여자 여부 검증
+     */
+    void validateProjectMember(String projectGroupId, String memberId);
+
+    /**
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @return List<ProjectMemberVO> - 프로젝트 참여자 목록
+     *
+     * 프로젝트 참여자 목록 조회
+     */
+    List<ProjectMemberVO> findProjectMembers(String projectGroupId);
+}
 
src/main/java/kr/co/takensoft/ai/system/projectMember/service/impl/ProjectMemberServiceImpl.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectMember/service/impl/ProjectMemberServiceImpl.java
@@ -0,0 +1,77 @@
+package kr.co.takensoft.ai.system.projectMember.service.impl;
+
+import kr.co.takensoft.ai.system.common.idgen.service.IdgenService;
+import kr.co.takensoft.ai.system.projectMember.dao.ProjectMemberDAO;
+import kr.co.takensoft.ai.system.projectMember.service.ProjectMemberService;
+import kr.co.takensoft.ai.system.projectMember.vo.ProjectMemberVO;
+import lombok.RequiredArgsConstructor;
+import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * @author : 박현정
+ * @since  : 2025.07.10
+ * @modification
+ *      since   |    author    | description
+ *  2025.07.10  |     박현정    | 최초 등록
+ *
+ * 프로젝트 참여자 관련 서비스
+ */
+@Service("projectMemberService")
+@RequiredArgsConstructor
+public class ProjectMemberServiceImpl extends EgovAbstractServiceImpl implements ProjectMemberService {
+
+    private final ProjectMemberDAO projectMemberDAO;
+    private final IdgenService projectMemberIdgn;
+
+    /**
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @param memberId - 사용자 아이디
+     * @param isOwner - 프로젝트 대표자 여부
+     * @return 등록 성공 여부
+     *
+     * 프로젝트 참여자 등록
+     */
+    @Override
+    public int saveProjectMember(String projectGroupId, String memberId, String isOwner) {
+
+        try {
+            String projectMemberId = projectMemberIdgn.getNextStringId(); // 프로젝트 참여자 구분 아이디 생성
+            ProjectMemberVO projectMemberVO = new ProjectMemberVO(projectMemberId, projectGroupId, memberId, isOwner);
+            return projectMemberDAO.saveProjectMember(projectMemberVO);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return -1;
+        }
+    }
+
+    /**
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @param memberId - 사용자 아이디
+     *
+     * 프로젝트 참여자 여부 검증
+     */
+    @Override
+    public void validateProjectMember(String projectGroupId, String memberId) {
+        if(!projectMemberDAO.existsByProjectGroupIdAndMemberId(projectGroupId, memberId)){
+            try {
+                throw new IllegalAccessException("이 프로젝트에 참여한 멤버가 아닙니다.");
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * @param projectGroupId - 프로젝트 그룹 아이디
+     * @return List<ProjectMemberVO> - 프로젝트 참여자 목록
+     *
+     * 프로젝트 참여자 목록 조회
+     */
+    @Override
+    public List<ProjectMemberVO> findProjectMembers(String projectGroupId) {
+        return projectMemberDAO.findAllByGroupId(projectGroupId);
+    }
+}
 
src/main/java/kr/co/takensoft/ai/system/projectMember/vo/ProjectMemberVO.java (added)
+++ src/main/java/kr/co/takensoft/ai/system/projectMember/vo/ProjectMemberVO.java
@@ -0,0 +1,37 @@
+package kr.co.takensoft.ai.system.projectMember.vo;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author 박현정
+ * @since 2025.07.10
+ * @modification
+ *     since    |    author    | description
+ *  2025.07.10  |    박현정     | 최초 등록
+ *
+ *
+ * 프로젝트 참여자 관련 VO
+ */
+@Getter
+@NoArgsConstructor
+public class ProjectMemberVO {
+
+    private String projectMemberId; // 프로젝트 참여자 아이디
+    private String projectGroupId; // 프로젝트 그룹 아이디
+    private String memberId; // 참여자 아이디
+    private String memberName; // 참여자 이름
+    private String isOwner; // 프로젝트 대표자 여부 ( N: 대표자 아님, Y: 대표자)
+    private String useAt; // 사용 여부 (N : 사용 안함, Y : 사용)
+    private String createdAt; // 생성일자
+    private String updatedAt; // 수정일자
+
+    // 프로젝트 참여자 생성용 생성자
+    public ProjectMemberVO(String projectMemberId, String projectGroupId, String memberId, String isOwner) {
+        this.projectMemberId = projectMemberId;
+        this.projectGroupId = projectGroupId;
+        this.memberId = memberId;
+        this.isOwner = isOwner;
+        this.useAt = "Y";
+    }
+}
 
src/main/resources/mybatis/mapper/project/project-SQL.xml (added)
+++ src/main/resources/mybatis/mapper/project/project-SQL.xml
@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="kr.co.takensoft.ai.system.project.dao.ProjectDAO">
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.11
+        내   용 :  프로젝트 resultMap
+    -->
+    <resultMap id="ProjectMap" type="ProjectVO">
+        <result property="projectId" column="project_id" />
+        <result property="projectGroupId" column="project_group_id" />
+        <result property="projectName" column="project_name" />
+        <result property="isMain" column="is_main" />
+        <result property="useAt" column="use_at" />
+        <result property="imageId" column="project_image_id"/>
+        <result property="commentId" column="project_comment_id"/>
+        <result property="createdAt" column="created_at" />
+        <result property="updatedAt" column="updated_at" />
+    </resultMap>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.11
+        내    용 : 활성(사용중) 데이터만 조회하도록 필터링
+    -->
+    <sql id="activeOnly">
+        use_at = 'Y'
+    </sql>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.09
+        내    용 : 프로젝트 등록
+    -->
+    <insert id="saveProject" parameterType="projectVO">
+        INSERT INTO project
+            (project_id,
+            project_group_id,
+            project_name,
+            is_main,
+            use_at,
+            created_at,
+            updated_at
+            )
+        VALUES (
+            #{projectId},
+            #{projectGroupId},
+            #{projectName},
+            #{isMain},
+            #{useAt},
+            CURRENT_TIMESTAMP,
+            CURRENT_TIMESTAMP
+        )
+    </insert>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.11
+        내    용 : 사용자가 참여하는 모든 프로젝트 조회
+    -->
+    <select id="findProjectsByMemberId" resultMap="ProjectMap" parameterType="String">
+        SELECT
+            p.project_id,
+            p.project_group_id,
+            p.project_name,
+            p.is_main,
+            p.use_at,
+            pm.is_owner,
+            TO_CHAR(p.created_at, 'YYYY-MM-DD HH24:MI') AS created_at,
+            TO_CHAR(p.updated_at, 'YYYY-MM-DD HH24:MI') AS updated_at
+        FROM project_member pm
+        JOIN project p ON pm.project_group_id = p.project_group_id
+        WHERE pm.member_id = #{memberId}
+        AND pm.use_at = 'Y'
+        AND p.use_at = 'Y'
+        AND p.is_main = 'Y'
+    </select>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.14
+        내    용 : 프로젝트 조회
+    -->
+    <select id="findById" resultMap="ProjectMap" parameterType="String">
+        SELECT
+            p.project_id,
+            p.project_group_id,
+            p.project_name,
+            p.is_main,
+            p.use_at,
+            i.project_image_id,
+            c.project_comment_id,
+            TO_CHAR(p.created_at, 'YYYY-MM-DD HH24:MI') AS created_at,
+            TO_CHAR(p.updated_at, 'YYYY-MM-DD HH24:MI') AS updated_at
+        FROM project p
+        LEFT JOIN project_comment c ON p.project_id = c.project_id
+        LEFT JOIN project_image i ON p.project_id = i.project_id
+        WHERE p.project_id = #{projectId}
+        AND p.use_at = 'Y'
+        AND c.use_at = 'Y'
+        AND i.use_at = 'Y'
+    </select>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.10
+        내    용 : 사용자가 생성한 프로젝트 개수 조회
+    -->
+    <select id="countCreatedByMemberId">
+        SELECT COUNT(*)
+        FROM project_member pm
+        JOIN project p ON pm.project_group_id = p.project_group_id
+        WHERE member_id = #{memberId}
+        AND pm.is_owner = 'Y'
+        AND p.is_main = 'Y'
+    </select>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.14
+        내   용 : 대표 프로젝트 해제
+    -->
+    <update id="unsetProjectMain" parameterType="String">
+        UPDATE project
+        <set>
+            is_main = 'N',
+            updated_at = CURRENT_TIMESTAMP
+        </set>
+        WHERE project_group_id = #{projectGroupId}
+        AND is_main = 'Y'
+        AND use_at = 'Y'
+    </update>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.14
+        내   용 : 프로젝트 존재 여부 확인
+    -->
+    <select id="existsById" resultType="boolean" parameterType="String">
+        SELECT EXISTS (
+            SELECT 1
+            FROM project
+            WHERE project_id = #{projectId}
+            AND use_at = 'Y'
+        )
+    </select>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.14
+        내   용 : 프로젝트 그룹 아이디 조회
+    -->
+    <select id="findProjectGroupIdByProjectId" resultType="String" parameterType="String">
+        SELECT project_group_id
+        FROM project
+        WHERE project_id = #{projectId}
+        AND use_at = 'Y'
+    </select>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.14
+        내   용 : 프로젝트 이름 변경
+    -->
+    <update id="updateProjectName" parameterType="String">
+        UPDATE project
+        <set>
+            project_name = #{projectName},
+            updated_at = CURRENT_TIMESTAMP
+        </set>
+        WHERE project_id = #{projectId}
+        AND use_at = 'Y'
+    </update>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.14
+        내   용 : 그룹 내 프로젝트 모두 삭제 (use_at = 'N')
+    -->
+    <update id="deactivateProjectsByGroupId" parameterType="String">
+        UPDATE project
+        <set>
+            use_at = 'N',
+            updated_at = CURRENT_TIMESTAMP
+        </set>
+        WHERE project_group_id = #{projectGroupId}
+        AND use_at = 'Y'
+    </update>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.14
+        내   용 : 대표 프로젝트 설정
+    -->
+    <update id="setProjectMain" parameterType="String">
+        UPDATE project
+        <set>
+            is_main = 'Y',
+            updated_at = CURRENT_TIMESTAMP
+        </set>
+        WHERE project_id = #{projectId}
+        AND is_main = 'N'
+        AND use_at = 'Y'
+    </update>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.14
+        내   용 : 그룹 내에서 특정 프로젝트 이후에 생성된 프로젝트 모두 삭제 (use_at = 'N')
+    -->
+    <update id="deactivateProjectsCreatedAfter" parameterType="String">
+        UPDATE project
+        <set>
+            use_at = 'N',
+            updated_at = CURRENT_TIMESTAMP
+        </set>
+        WHERE project_group_id = #{projectGroupId}
+        AND created_at > (
+            SELECT created_at
+            FROM project
+            WHERE project_id = #{projectId}
+        )
+    </update>
+
+    <select id="findAllProjects" parameterType="ProjectSearchReqDTO" resultMap="ProjectMap">
+        SELECT
+            p.project_id,
+            p.project_group_id,
+            p.project_name,
+            p.is_main,
+            p.created_at,
+            p.updated_at
+        FROM project p
+        JOIN project_member pm ON p.project_group_id = pm.project_group_id
+        <where>
+            <if test="memberId != null">
+                pm.member_id = #{memberId}
+            </if>
+            <if test="projectGroupId != null">
+                AND p.project_group_id = #{projectGroupId}
+            </if>
+            <if test="isMain != null">
+                AND p.is_main = #{isMain}
+            </if>
+            <if test="projectName != null and isMain != ''">
+                AND p.project_name ILIKE CONCAT('%', #{projectName}, '%')
+            </if>
+        </where>
+    </select>
+
+
+</mapper>(파일 끝에 줄바꿈 문자 없음)
 
src/main/resources/mybatis/mapper/projectComment/projectComment-SQL.xml (added)
+++ src/main/resources/mybatis/mapper/projectComment/projectComment-SQL.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="kr.co.takensoft.ai.system.projectComment.dao.ProjectCommentDAO">
+
+    <!--
+    작 성 자 : 박현정
+    작 성 일 : 2025.07.15
+    내   용 :  프로젝트 주석 resultMap
+-->
+    <resultMap id="ProjectCommentMap" type="ProjectCommentVO">
+        <result property="projectCommentId" column="project_comment_id"/>
+        <result property="projectId" column="project_id"/>
+        <result property="memberId" column="member_id"/>
+        <result property="memberName" column="member_name"/>
+        <result property="summary" column="summary"/>
+        <result property="comment" column="comment"/>
+        <result property="useAt" column="use_at"/>
+        <result property="createdAt" column="created_at"/>
+        <result property="updatedAt" column="updated_at"/>
+    </resultMap>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.10
+        내    용 : 프로젝트 주석 등록
+    -->
+    <insert id="saveProjectComment" parameterType="projectCommentVO">
+        INSERT INTO project_comment
+            (project_comment_id,
+            project_id,
+            member_id,
+            summary,
+            "comment",
+            use_at,
+            created_at,
+            updated_at)
+        VALUES (
+            #{projectCommentId},
+            #{projectId},
+            #{memberId},
+            #{summary},
+            #{comment},
+            #{useAt},
+            CURRENT_TIMESTAMP,
+            CURRENT_TIMESTAMP
+        )
+    </insert>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.11
+        내    용 : 활성(사용중) 데이터만 조회하도록 필터링
+    -->
+    <sql id="activeOnly">
+        use_at = 'Y'
+    </sql>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.15
+        내    용 : 프로젝트 주석 조회
+    -->
+    <select id="findById" parameterType="String" resultMap="ProjectCommentMap">
+        SELECT
+            c.project_comment_id,
+            c.project_id,
+            c.member_id,
+            m.member_name,
+            c.summary,
+            c."comment",
+            c.use_at,
+            TO_CHAR(c.created_at, 'YYYY-MM-DD HH24:MI') AS created_at,
+            TO_CHAR(c.updated_at, 'YYYY-MM-DD HH24:MI') AS updated_at
+        FROM project_comment c
+        LEFT JOIN member m ON c.member_id = m.member_id
+        WHERE project_comment_id = #{commentId}
+        AND c.use_at = 'Y'
+    </select>
+
+</mapper>(파일 끝에 줄바꿈 문자 없음)
 
src/main/resources/mybatis/mapper/projectGroup/projectGroup-SQL.xml (added)
+++ src/main/resources/mybatis/mapper/projectGroup/projectGroup-SQL.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="kr.co.takensoft.ai.system.projectGroup.dao.ProjectGroupDAO">
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.10
+        내    용 : 프로젝트 그룹 등록
+    -->
+    <insert id="saveProjectGroup" parameterType="ProjectGroupVO">
+        INSERT INTO project_group
+            (project_group_id,
+            use_at,
+            created_at,
+            updated_at)
+        VALUES (
+            #{projectGroupId},
+            #{useAt},
+            CURRENT_TIMESTAMP,
+            CURRENT_TIMESTAMP
+        )
+    </insert>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.14
+        내    용 : 프로젝트 그룹 삭제 (use_at = 'N')
+    -->
+    <update id="deactivateGroupProjectById" parameterType="String">
+        UPDATE project_group
+        <set>
+            use_at = 'N',
+            updated_at = CURRENT_TIMESTAMP
+        </set>
+        WHERE project_group_id = #{projectGroupId}
+        AND use_at = 'Y'
+    </update>
+
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.11
+        내    용 : 활성(사용중) 데이터만 조회하도록 필터링
+    -->
+    <sql id="activeOnly">
+        use_at = 'Y'
+    </sql>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.14
+        내   용 : 프로젝트 그룹 존재 여부 확인
+    -->
+    <select id="existsById" resultType="boolean" parameterType="String">
+        SELECT EXISTS (
+            SELECT 1
+            FROM project_group
+            WHERE project_group_id = #{projectGroupId}
+            AND use_at = 'Y'
+        )
+    </select>
+
+
+</mapper>(파일 끝에 줄바꿈 문자 없음)
 
src/main/resources/mybatis/mapper/projectImage/projectImage-SQL.xml (added)
+++ src/main/resources/mybatis/mapper/projectImage/projectImage-SQL.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="kr.co.takensoft.ai.system.projectImage.dao.ProjectImageDAO">
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.15
+        내   용 :  프로젝트 이미지 resultMap
+    -->
+    <resultMap id="ProjectImageMap" type="ProjectImageVO">
+        <result property="projectImageId" column="project_image_id"/>
+        <result property="projectId" column="project_id"/>
+        <result property="fileName" column="file_name"/>
+        <result property="fileUrl" column="file_url"/>
+        <result property="useAt" column="use_at"/>
+        <result property="createdAt" column="created_at"/>
+        <result property="updatedAt" column="updated_at"/>
+    </resultMap>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.11
+        내    용 : 활성(사용중) 데이터만 조회하도록 필터링
+    -->
+    <sql id="activeOnly">
+        use_at = 'Y'
+    </sql>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.10
+        내    용 : 프로젝트 이미지 등록
+    -->
+    <insert id="saveProjectImage" parameterType="ProjectImageVO">
+        INSERT INTO project_image
+            (project_image_id,
+            project_id,
+            file_name,
+            file_url,
+            use_at,
+            created_at,
+            updated_at)
+        VALUES (
+            #{projectImageId},
+            #{projectId},
+            #{fileName},
+            #{fileUrl},
+            #{useAt},
+            CURRENT_TIMESTAMP,
+            CURRENT_TIMESTAMP
+        )
+    </insert>
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.15
+        내    용 : 프로젝트 이미지 조회
+    -->
+    <select id="findById" parameterType="String" resultMap="ProjectImageMap">
+        SELECT
+            project_image_id,
+            project_id,
+            file_name,
+            file_url,
+            use_at,
+            TO_CHAR(created_at, 'YYYY-MM-DD HH24:MI') AS created_at,
+            TO_CHAR(updated_at, 'YYYY-MM-DD HH24:MI') AS updated_at
+        FROM project_image
+        WHERE project_image_id = #{imageId}
+        AND use_at = 'Y'
+    </select>
+
+</mapper>(파일 끝에 줄바꿈 문자 없음)
 
src/main/resources/mybatis/mapper/projectMember/projectMember-SQL.xml (added)
+++ src/main/resources/mybatis/mapper/projectMember/projectMember-SQL.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="kr.co.takensoft.ai.system.projectMember.dao.ProjectMemberDAO">
+
+    <!--
+        작 성 자 : 박현정
+        작 성 일 : 2025.07.15
+        내   용 :  프로젝트 참여자 resultMap
+    -->
+    <resultMap id="ProjectMemberMap" type="ProjectMemberVO">
+        <result property="projectMemberId" column="project_member_id"/>
+        <result property="projectGroupId" column="project_group_id"/>
+        <result property="memberId" column="member_id"/>
+        <result property="memberName" column="member_name"/>
+        <result property="isOwner" column="is_owner"/>
+        <result property="useAt" column="use_at"/>
+        <result property="createdAt" column="created_at"/>
+        <result property="updatedAt" column="updated_at"/>
+    </resultMap>
+
+    <!--
+    작 성 자 : 박현정
+    작 성 일 : 2025.07.11
+    내    용 : 활성(사용중) 데이터만 조회하도록 필터링
+    -->
+    <sql id="activeOnly">
+        use_at = 'Y'
+    </sql>
+
+    <!--
+    작 성 자 : 박현정
+    작 성 일 : 2025.07.10
+    내    용 : 프로젝트 참여자 등록
+    -->
+    <insert id="saveProjectMember" parameterType="projectMemberVO">
+        INSERT INTO project_member
+            (project_member_id,
+            project_group_id,
+            member_id,
+            is_owner,
+            use_at,
+            created_at,
+            updated_at
+            )
+        VALUES (
+            #{projectMemberId},
+            #{projectGroupId},
+            #{memberId},
+            #{isOwner},
+            #{useAt},
+            CURRENT_TIMESTAMP,
+            CURRENT_TIMESTAMP
+        )
+    </insert>
+
+    <!--
+    작 성 자 : 박현정
+    작 성 일 : 2025.07.10
+    내    용 : 프로젝트 참여자 존재 여부 확인
+    -->
+    <select id="existsByProjectGroupIdAndMemberId" resultType="boolean">
+        SELECT EXISTS (
+            SELECT 1
+            FROM project_member
+            WHERE project_group_id = #{projectGroupId}
+            AND member_id = #{memberId}
+        )
+    </select>
+
+    <!--
+    작 성 자 : 박현정
+    작 성 일 : 2025.07.15
+    내    용 : 프로젝트 참여자 조회 (프로젝트 그룹 아이디로 검색)
+    -->
+    <select id="findAllByGroupId" resultMap="ProjectMemberMap" parameterType="String">
+        SELECT
+            pm.project_member_id,
+            pm.project_group_id,
+            pm.member_id,
+            m.member_name,
+            pm.is_owner,
+            pm.use_at,
+            TO_CHAR(pm.created_at, 'YYYY-MM-DD HH24:MI') AS created_at,
+            TO_CHAR(pm.updated_at, 'YYYY-MM-DD HH24:MI') AS updated_at
+        FROM project_member pm
+        JOIN member m ON pm.member_id = m.member_id
+        WHERE pm.project_group_id = #{projectGroupId}
+        AND pm.use_at = 'Y'
+        AND m.use_at = 'Y'
+    </select>
+
+</mapper>(파일 끝에 줄바꿈 문자 없음)
Add a comment
List