Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,14 @@ jobs:
- name: .env 파일 생성
env:
DOT_ENV: ${{ secrets.DOT_ENV }}
AI_API_KEY: ${{ secrets.AI_API_KEY }}
AI_BASE_URL: ${{ secrets.AI_BASE_URL }}
run: |
mkdir -p "${{ env.BACKEND_DIR }}"
printf "%s" "${DOT_ENV}" > "${{ env.BACKEND_DIR }}/.env"
echo "" >> "${{ env.BACKEND_DIR }}/.env"
echo "AI_API_KEY=${AI_API_KEY}" >> "${{ env.BACKEND_DIR }}/.env"
echo "AI_BASE_URL=${AI_BASE_URL}" >> "${{ env.BACKEND_DIR }}/.env"

- name: Docker Buildx 설치
uses: docker/setup-buildx-action@v3
Expand Down Expand Up @@ -216,4 +221,4 @@ jobs:
| xargs -r docker rmi
} || true

echo "✅ 배포 완료!"
echo "✅ 배포 완료!"
2 changes: 2 additions & 0 deletions back/.env.default
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ DB_USERNAME=NEED_TO_SET
DB_PASSWORD=NEED_TO_SET
MAIL_USERNAME=NEED_TO_SET
MAIL_PASSWORD=NEED_TO_SET
AI_API_KEY=NEED_TO_SET
AI_BASE_URL=NEED_TO_SET
9 changes: 9 additions & 0 deletions back/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ plugins {
id("org.springframework.boot") version "3.5.5"
id("io.spring.dependency-management") version "1.1.7"
}
val springAiVersion by extra("1.0.3")

group = "com"
version = "0.0.1-SNAPSHOT"
Expand Down Expand Up @@ -72,6 +73,14 @@ dependencies {

// Sentry
implementation("io.sentry:sentry-spring-boot-starter-jakarta:8.19.1")

// AI
implementation("org.springframework.ai:spring-ai-starter-model-openai")
}
dependencyManagement {
imports {
mavenBom("org.springframework.ai:spring-ai-bom:$springAiVersion")
}
}

tasks.withType<Test> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.back.domain.roadmap.roadmap.dto.response;

public record TextFieldIntegrationResponse(
String learningAdvice,
String recommendedResources,
String learningGoals
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@ public interface MentorRoadmapRepository extends JpaRepository<MentorRoadmap, Lo
boolean existsByMentor(Mentor mentor);

/**
* 직업 ID로 멘토 로드맵 목록 조회 (노드 포함)
* 직업 ID로 멘토 로드맵 목록 조회 (노드 및 Task 포함)
* - 특정 직업에 속한 멘토들의 로드맵 목록 조회
* - 통합된 직업 로드맵 생성용
* - Task까지 fetch하여 트랜잭션 외부에서도 접근 가능하도록 보장
*/
@Query("""
SELECT mr FROM MentorRoadmap mr
SELECT DISTINCT mr FROM MentorRoadmap mr
LEFT JOIN FETCH mr.nodes n
LEFT JOIN FETCH n.task t
WHERE mr.mentor.jobId = :jobId
ORDER BY mr.id, n.stepOrder
""")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class JobRoadmapBatchIntegrator {
private final JobRoadmapIntegrationProcessor processor;
private static final int MAX_RETRY = 3;

@Scheduled(fixedDelay = 120000) // 2분
@Scheduled(fixedDelay = 3600000) // 1시간 (3600000ms)
public void integrate() {
List<JobRoadmapIntegrationQueue> pendingQueues = queueRepository.findAllOrderByRequestedAt();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
@Slf4j
public class JobRoadmapIntegrationProcessor {
private final JobRoadmapIntegrationQueueRepository queueRepository;
private final JobRoadmapIntegrationServiceV2 integrationService;
private final JobRoadmapIntegrationServiceV3 integrationService;

/**
* 단일 큐 항목 처리 (통합 + 큐 삭제를 하나의 트랜잭션으로)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.back.domain.job.job.entity.Job;
import com.back.domain.job.job.repository.JobRepository;
import com.back.domain.roadmap.roadmap.dto.response.TextFieldIntegrationResponse;
import com.back.domain.roadmap.roadmap.entity.JobRoadmap;
import com.back.domain.roadmap.roadmap.entity.JobRoadmapNodeStat;
import com.back.domain.roadmap.roadmap.entity.MentorRoadmap;
Expand Down Expand Up @@ -33,6 +34,7 @@ public class JobRoadmapIntegrationServiceV2 {
private final TaskRepository taskRepository;
private final JobRoadmapNodeStatRepository jobRoadmapNodeStatRepository;
private final com.back.domain.roadmap.roadmap.repository.RoadmapNodeRepository roadmapNodeRepository;
private final TextFieldIntegrationService textFieldIntegrationService;

// --- 통합 알고리즘 상수 ---
private final double BRANCH_THRESHOLD = 0.25;
Expand Down Expand Up @@ -280,11 +282,20 @@ private Map<String, RoadmapNode> createNodes(AggregationResult aggregation, Map<
Double avgImportance = calculateAverage(aggregation.descriptions.importances.get(key));
Integer avgEstimatedHours = calculateIntegerAverage(aggregation.descriptions.estimatedHours.get(key));

List<String> advices = aggregation.descriptions.getLearningAdvices().getOrDefault(key, Collections.emptyList());
List<String> resources = aggregation.descriptions.getRecommendedResources().getOrDefault(key, Collections.emptyList());
List<String> goals = aggregation.descriptions.getLearningGoals().getOrDefault(key, Collections.emptyList());

TextFieldIntegrationResponse integratedTexts = textFieldIntegrationService.integrateTextFields(advices, resources, goals);

RoadmapNode node = RoadmapNode.builder()
.taskName(aggNode.displayName)
.learningAdvice(mergeTopDescriptions(aggregation.descriptions.learningAdvices.get(key)))
.recommendedResources(mergeTopDescriptions(aggregation.descriptions.recommendedResources.get(key)))
.learningGoals(mergeTopDescriptions(aggregation.descriptions.learningGoals.get(key)))
//.learningAdvice(mergeTopDescriptions(aggregation.descriptions.learningAdvices.get(key)))
.learningAdvice(integratedTexts.learningAdvice())
//.recommendedResources(mergeTopDescriptions(aggregation.descriptions.recommendedResources.get(key)))
.recommendedResources(integratedTexts.recommendedResources())
//.learningGoals(mergeTopDescriptions(aggregation.descriptions.learningGoals.get(key)))
.learningGoals(integratedTexts.learningGoals())
.difficulty(avgDifficulty != null ? avgDifficulty.intValue() : null)
.importance(avgImportance != null ? avgImportance.intValue() : null)
.estimatedHours(avgEstimatedHours)
Expand Down
Loading