From 8a918b976dc54157a8cc264ba11fa2961a64fce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=83=9C=ED=98=84?= Date: Fri, 26 Sep 2025 13:48:22 +0900 Subject: [PATCH 01/24] =?UTF-8?q?chore:=20JobMapper=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/site/icebang/domain/workflow/mapper/JobMapper.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/user-service/src/main/java/site/icebang/domain/workflow/mapper/JobMapper.java b/apps/user-service/src/main/java/site/icebang/domain/workflow/mapper/JobMapper.java index e03ac06d..8e2c53a0 100644 --- a/apps/user-service/src/main/java/site/icebang/domain/workflow/mapper/JobMapper.java +++ b/apps/user-service/src/main/java/site/icebang/domain/workflow/mapper/JobMapper.java @@ -12,4 +12,7 @@ public interface JobMapper { List findJobsByWorkflowId(Long workflowId); List findTasksByJobId(Long jobId); + + JobDto findJobById(Long id); + void insertJob(JobDto job); } From 0dc53d561191f81cc6c07ded9417076b896cdf88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=83=9C=ED=98=84?= Date: Fri, 26 Sep 2025 14:37:06 +0900 Subject: [PATCH 02/24] =?UTF-8?q?feat:=20Job=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EC=B4=88=EC=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/controller/JobController.java | 35 +++++ .../domain/workflow/service/JobService.java | 28 ++++ .../resources/mybatis/mapper/JobMapper.xml | 27 ++++ .../e2e/scenario/JobCreateFlowE2eTest.java | 148 ++++++++++++++++++ 4 files changed, 238 insertions(+) create mode 100644 apps/user-service/src/main/java/site/icebang/domain/workflow/controller/JobController.java create mode 100644 apps/user-service/src/main/java/site/icebang/domain/workflow/service/JobService.java create mode 100644 apps/user-service/src/test/java/site/icebang/e2e/scenario/JobCreateFlowE2eTest.java diff --git a/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/JobController.java b/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/JobController.java new file mode 100644 index 00000000..f7c2dbe0 --- /dev/null +++ b/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/JobController.java @@ -0,0 +1,35 @@ +package site.icebang.domain.workflow.controller; + +import java.util.Map; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import lombok.RequiredArgsConstructor; +import site.icebang.domain.workflow.dto.JobDto; +import site.icebang.domain.workflow.service.JobService; + +@RestController +@RequestMapping("/v0/jobs") +@RequiredArgsConstructor +public class JobController { + + private final JobService jobService; + + @PostMapping + public ResponseEntity> createJob(@RequestBody JobDto dto) { + JobDto created = jobService.createJob(dto); + return ResponseEntity.status(HttpStatus.CREATED) + .body(Map.of("success", true, "data", created)); + } + + @GetMapping("/{id}") + public ResponseEntity> getJob(@PathVariable Long id) { + JobDto job = jobService.findById(id); + if (job == null) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of("success", false)); + } + return ResponseEntity.ok(Map.of("success", true, "data", job)); + } +} diff --git a/apps/user-service/src/main/java/site/icebang/domain/workflow/service/JobService.java b/apps/user-service/src/main/java/site/icebang/domain/workflow/service/JobService.java new file mode 100644 index 00000000..05f14b24 --- /dev/null +++ b/apps/user-service/src/main/java/site/icebang/domain/workflow/service/JobService.java @@ -0,0 +1,28 @@ +package site.icebang.domain.workflow.service; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import lombok.RequiredArgsConstructor; +import site.icebang.domain.workflow.dto.JobDto; +import site.icebang.domain.workflow.mapper.JobMapper; + +@Service +@RequiredArgsConstructor +public class JobService { + + private final JobMapper jobMapper; + + @Transactional + public JobDto createJob(JobDto dto) { + if (dto.getName() == null || dto.getName().isBlank()) { + throw new IllegalArgumentException("job name is required"); + } + jobMapper.insertJob(dto); + return jobMapper.findJobById(dto.getId()); + } + + public JobDto findById(Long id) { + return jobMapper.findJobById(id); + } +} diff --git a/apps/user-service/src/main/resources/mybatis/mapper/JobMapper.xml b/apps/user-service/src/main/resources/mybatis/mapper/JobMapper.xml index 5b959db3..f5cd2ed0 100644 --- a/apps/user-service/src/main/resources/mybatis/mapper/JobMapper.xml +++ b/apps/user-service/src/main/resources/mybatis/mapper/JobMapper.xml @@ -23,6 +23,33 @@ + + INSERT INTO job ( + name, + description, + is_enabled, + created_at, + created_by, + updated_at, + updated_by + ) VALUES ( + #{name}, + #{description}, + #{isEnabled}, + #{createdAt}, + #{createdBy}, + #{updatedAt}, + #{updatedBy} + ) + + + + + SELECT t.* + FROM task t + WHERE t.id = #{id} + + + SELECT * FROM task_io_data + WHERE task_run_id = #{taskRunId} AND io_type = 'OUTPUT' + ORDER BY id DESC + LIMIT 1 + + \ No newline at end of file diff --git a/apps/user-service/src/main/resources/mybatis/mapper/TaskRunMapper.xml b/apps/user-service/src/main/resources/mybatis/mapper/TaskRunMapper.xml index 61ec3cf0..322a9f04 100644 --- a/apps/user-service/src/main/resources/mybatis/mapper/TaskRunMapper.xml +++ b/apps/user-service/src/main/resources/mybatis/mapper/TaskRunMapper.xml @@ -26,4 +26,15 @@ finished_at = #{finishedAt} WHERE id = #{id} + + \ No newline at end of file From c595a51629083883a26ad7dd25e33a56881a75fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B2=BD=EB=AF=BC?= <153978154+kakusiA@users.noreply.github.com> Date: Mon, 29 Sep 2025 16:55:26 +0900 Subject: [PATCH 20/24] =?UTF-8?q?fix:=20blogger=20post=5Furl=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#233)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: blogger post_url 추가 * sytle: 코드 포맷팅 --- .../app/service/blog/blogger_blog_post_adapter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/pre-processing-service/app/service/blog/blogger_blog_post_adapter.py b/apps/pre-processing-service/app/service/blog/blogger_blog_post_adapter.py index 1a2b66f5..5d6ef5e0 100644 --- a/apps/pre-processing-service/app/service/blog/blogger_blog_post_adapter.py +++ b/apps/pre-processing-service/app/service/blog/blogger_blog_post_adapter.py @@ -50,6 +50,7 @@ def _write_content(self, title: str, content: str, tags: List[str] = None) -> No result = self.api_service.create_post_via_api(title, content, labels=tags) # 결과 로깅 print(f"포스트 생성 완료: {result.get('published_url', 'URL 없음')}") + return result.get("published_url") except Exception as e: raise BlogPostPublishException("Blogger", f"포스트 작성 실패: {str(e)}") From 23dc63fbe17bdabcd0890792d578611cffc1f4f9 Mon Sep 17 00:00:00 2001 From: Yousung Jung Date: Mon, 29 Sep 2025 17:07:46 +0900 Subject: [PATCH 21/24] =?UTF-8?q?Workflow=20run=20=EC=8B=9C=20history?= =?UTF-8?q?=EA=B0=80=20insert=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20?= =?UTF-8?q?=EB=B2=84=EA=B7=B8=20(#234)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `@Async`와 `@Transactinon` 동시에 사용했던 문제 --- .../domain/workflow/service/WorkflowExecutionService.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/user-service/src/main/java/site/icebang/domain/workflow/service/WorkflowExecutionService.java b/apps/user-service/src/main/java/site/icebang/domain/workflow/service/WorkflowExecutionService.java index 2e1ca782..073d81ce 100644 --- a/apps/user-service/src/main/java/site/icebang/domain/workflow/service/WorkflowExecutionService.java +++ b/apps/user-service/src/main/java/site/icebang/domain/workflow/service/WorkflowExecutionService.java @@ -8,7 +8,6 @@ import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -51,7 +50,6 @@ public class WorkflowExecutionService { private final TaskExecutionService taskExecutionService; private final WorkflowMapper workflowMapper; - @Transactional @Async("traceExecutor") public void executeWorkflow(Long workflowId, RequestContext context) { WorkflowRun workflowRun = WorkflowRun.start(workflowId, context.getTraceId()); From 50e364115f9b9f5879ba6545fb5db1917c9b5fb0 Mon Sep 17 00:00:00 2001 From: Yousung Jung Date: Mon, 29 Sep 2025 18:40:48 +0900 Subject: [PATCH 22/24] =?UTF-8?q?Task=20io=20data=20=EC=A1=B0=ED=9A=8C=20a?= =?UTF-8?q?pi=20(#235)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: gitingore에 key, blogger 설정 추가 * feat: Task io data api --- apps/pre-processing-service/.gitignore | 2 ++ .../workflow/controller/TaskController.java | 29 +++++++++++++++++++ .../workflow/mapper/TaskIoDataMapper.java | 7 +++++ .../workflow/service/WorkflowService.java | 20 +++++++++++++ .../mybatis/mapper/TaskIoDataMapper.xml | 15 ++++++++++ 5 files changed, 73 insertions(+) create mode 100644 apps/pre-processing-service/.gitignore diff --git a/apps/pre-processing-service/.gitignore b/apps/pre-processing-service/.gitignore new file mode 100644 index 00000000..26d2fb2d --- /dev/null +++ b/apps/pre-processing-service/.gitignore @@ -0,0 +1,2 @@ +/blogger +/key \ No newline at end of file diff --git a/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/TaskController.java b/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/TaskController.java index fd3ce8f4..c0ba5542 100644 --- a/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/TaskController.java +++ b/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/TaskController.java @@ -1,5 +1,6 @@ package site.icebang.domain.workflow.controller; +import java.util.List; import java.util.Map; import org.springframework.http.HttpStatus; @@ -9,7 +10,9 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import site.icebang.common.dto.ApiResponse; import site.icebang.domain.workflow.dto.TaskDto; +import site.icebang.domain.workflow.model.TaskIoData; import site.icebang.domain.workflow.service.WorkflowService; @RestController @@ -33,4 +36,30 @@ public ResponseEntity> getTask(@PathVariable Long id) { } return ResponseEntity.ok(Map.of("success", true, "data", task)); } + + /** + * Task Run ID 목록으로 Task IO 데이터 조회 + * + * @param taskRunIds Task Run ID 목록 (쉼표로 구분) + * @param ioType IO 타입 필터 ("INPUT", "OUTPUT", 미지정시 모두 조회) + * @param limit 조회 제한 수 (선택사항) + * @return Task IO 데이터 목록 (created_at 기준 내림차순 정렬) + */ + @GetMapping("/io-data") + public ResponseEntity>> getTaskIoData( + @RequestParam List taskRunIds, + @RequestParam(required = false) String ioType, + @RequestParam(required = false) Integer limit) { + + try { + List ioData = + workflowService.getTaskIoDataByTaskRunIds(taskRunIds, ioType, limit); + return ResponseEntity.ok(ApiResponse.success(ioData, "Task IO 데이터 조회 성공")); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body( + ApiResponse.error( + "Task IO 데이터 조회 실패: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR)); + } + } } diff --git a/apps/user-service/src/main/java/site/icebang/domain/workflow/mapper/TaskIoDataMapper.java b/apps/user-service/src/main/java/site/icebang/domain/workflow/mapper/TaskIoDataMapper.java index 6f44de02..dffeeb8e 100644 --- a/apps/user-service/src/main/java/site/icebang/domain/workflow/mapper/TaskIoDataMapper.java +++ b/apps/user-service/src/main/java/site/icebang/domain/workflow/mapper/TaskIoDataMapper.java @@ -1,8 +1,10 @@ package site.icebang.domain.workflow.mapper; +import java.util.List; import java.util.Optional; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import site.icebang.domain.workflow.model.TaskIoData; @@ -11,4 +13,9 @@ public interface TaskIoDataMapper { void insert(TaskIoData taskIoData); Optional findOutputByTaskRunId(Long taskRunId); + + List findByTaskRunIds( + @Param("taskRunIds") List taskRunIds, + @Param("ioType") String ioType, + @Param("limit") Integer limit); } diff --git a/apps/user-service/src/main/java/site/icebang/domain/workflow/service/WorkflowService.java b/apps/user-service/src/main/java/site/icebang/domain/workflow/service/WorkflowService.java index 69a55002..6362d061 100644 --- a/apps/user-service/src/main/java/site/icebang/domain/workflow/service/WorkflowService.java +++ b/apps/user-service/src/main/java/site/icebang/domain/workflow/service/WorkflowService.java @@ -24,8 +24,10 @@ import site.icebang.domain.schedule.service.QuartzScheduleService; import site.icebang.domain.workflow.dto.*; import site.icebang.domain.workflow.mapper.JobMapper; +import site.icebang.domain.workflow.mapper.TaskIoDataMapper; import site.icebang.domain.workflow.mapper.TaskMapper; import site.icebang.domain.workflow.mapper.WorkflowMapper; +import site.icebang.domain.workflow.model.TaskIoData; /** * 워크플로우의 '정의'와 관련된 비즈니스 로직을 처리하는 서비스 클래스입니다. @@ -52,6 +54,7 @@ public class WorkflowService implements PageableService { private final QuartzScheduleService quartzScheduleService; private final JobMapper jobMapper; private final TaskMapper taskMapper; + private final TaskIoDataMapper taskIoDataMapper; /** * 워크플로우 목록을 페이징 처리하여 조회합니다. @@ -248,6 +251,23 @@ public TaskDto findTaskById(Long id) { return taskMapper.findTaskById(id); } + /** + * Task Run ID 목록으로 Task IO 데이터 조회 + * + * @param taskRunIds Task Run ID 목록 + * @param ioType IO 타입 필터 ("INPUT", "OUTPUT", null이면 모두 조회) + * @param limit 조회 제한 수 (null이면 모두 조회) + * @return Task IO 데이터 목록 (created_at 기준 내림차순 정렬) + */ + @Transactional(readOnly = true) + public List getTaskIoDataByTaskRunIds( + List taskRunIds, String ioType, Integer limit) { + if (taskRunIds == null || taskRunIds.isEmpty()) { + return List.of(); + } + return taskIoDataMapper.findByTaskRunIds(taskRunIds, ioType, limit); + } + /** 기본 입력값 검증 */ private void validateBasicInput(WorkflowCreateDto dto, BigInteger createdBy) { if (dto == null) { diff --git a/apps/user-service/src/main/resources/mybatis/mapper/TaskIoDataMapper.xml b/apps/user-service/src/main/resources/mybatis/mapper/TaskIoDataMapper.xml index fa0dd73c..4feaaa33 100644 --- a/apps/user-service/src/main/resources/mybatis/mapper/TaskIoDataMapper.xml +++ b/apps/user-service/src/main/resources/mybatis/mapper/TaskIoDataMapper.xml @@ -13,4 +13,19 @@ ORDER BY id DESC LIMIT 1 + + \ No newline at end of file From c1e39a137985d6f8dd48b2b54d9e857f69c30f96 Mon Sep 17 00:00:00 2001 From: thkim7 Date: Mon, 29 Sep 2025 18:48:15 +0900 Subject: [PATCH 23/24] =?UTF-8?q?fix:=20rag=5Fcreate=20=EB=AC=B8=EC=A0=9C?= =?UTF-8?q?=20=EC=83=9D=EA=B8=B4=EA=B1=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/mybatis/mapper/TaskRunMapper.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/user-service/src/main/resources/mybatis/mapper/TaskRunMapper.xml b/apps/user-service/src/main/resources/mybatis/mapper/TaskRunMapper.xml index 322a9f04..0bdf8cb0 100644 --- a/apps/user-service/src/main/resources/mybatis/mapper/TaskRunMapper.xml +++ b/apps/user-service/src/main/resources/mybatis/mapper/TaskRunMapper.xml @@ -31,8 +31,7 @@ SELECT tr.* FROM task_run tr JOIN task t ON tr.task_id = t.id - WHERE tr.job_run_id = #{jobRunId} - AND t.name = #{taskName} + where t.name = #{taskName} AND tr.status = 'SUCCESS' ORDER BY tr.id DESC LIMIT 1 From 7cef1e7b53d188127ecd2bf505fb7fa176c0db6f Mon Sep 17 00:00:00 2001 From: JiHoon Date: Mon, 29 Sep 2025 18:50:30 +0900 Subject: [PATCH 24/24] =?UTF-8?q?hofix=20:=20=ED=99=98=EA=B2=BD=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/deploy-fastapi.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-fastapi.yml b/.github/workflows/deploy-fastapi.yml index a05caa39..4f064350 100644 --- a/.github/workflows/deploy-fastapi.yml +++ b/.github/workflows/deploy-fastapi.yml @@ -43,7 +43,8 @@ jobs: echo "IMAGE_DOWNLOAD_TIMEOUT=${{ secrets.IMAGE_DOWNLOAD_TIMEOUT }}" >> .env.prod echo "MAX_IMAGE_SIZE_MB=${{ secrets.MAX_IMAGE_SIZE_MB }}" >> .env.prod echo "MECAB_PATH=${{ secrets.MECAB_PATH }}" >> .env.prod - echo "MECABRC=${{ secrets.MECABRC }}" >> .env.prod + echo "MECABRC=${{ secrets.MECABRC }}" >> .env.prod + echo "GOOGLE_APPLICATION_CREDENTIALS=${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}" >> .env.prod - name: Set repo lowercase run: echo "REPO_LC=${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV