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
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
import com.jobdri.jobdri_api.domain.jobposting.dto.request.JobPostingUpdateRequest;
import com.jobdri.jobdri_api.domain.jobposting.dto.response.JobPostingGenerateResponse;
import com.jobdri.jobdri_api.domain.jobposting.dto.response.JobPostingMockGenerateResponse;
import com.jobdri.jobdri_api.domain.jobposting.dto.response.JobPostingMockQuestionResponse;
import com.jobdri.jobdri_api.domain.jobposting.dto.response.JobPostingResponse;
import com.jobdri.jobdri_api.domain.jobposting.service.JobPostingAiService;
import com.jobdri.jobdri_api.domain.jobposting.service.MockQuestionCacheService;
import com.jobdri.jobdri_api.domain.jobposting.service.MockJobPostingGenerationService;
import com.jobdri.jobdri_api.domain.jobposting.service.JobPostingService;
import com.jobdri.jobdri_api.global.apiPayload.ApiResponse;
import io.swagger.v3.oas.annotations.Operation;
Expand All @@ -32,6 +35,8 @@
public class JobPostingController {

private final JobPostingAiService jobPostingAiService;
private final MockJobPostingGenerationService mockJobPostingGenerationService;
private final MockQuestionCacheService mockQuestionCacheService;
private final JobPostingService jobPostingService;

@Operation(summary = "채용 공고 초안 생성", description = "회사 정보와 직무 정보를 바탕으로 AI가 공고 본문 초안을 생성합니다.")
Expand All @@ -55,7 +60,21 @@ public ApiResponse<JobPostingMockGenerateResponse> generateMockJobPosting(
) {
return ApiResponse.onSuccess(
"모의 공고 생성에 성공했습니다.",
jobPostingAiService.generateMockJobPosting(request)
mockJobPostingGenerationService.generate(request)
);
}

@Operation(
summary = "모의 공고 추천 질문 조회",
description = "선택한 회사/직무 기준으로 모의 공고 추천 질문을 조회합니다. 질문은 직무 기준 캐시를 재사용합니다."
)
@PostMapping("/mock/questions")
public ApiResponse<JobPostingMockQuestionResponse> getMockRecommendedQuestions(
@Valid @RequestBody JobPostingMockGenerateRequest request
) {
return ApiResponse.onSuccess(
"모의 공고 추천 질문 조회에 성공했습니다.",
new JobPostingMockQuestionResponse(mockQuestionCacheService.getRecommendedQuestions(request))
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import jakarta.validation.constraints.NotNull;

public record JobPostingMockGenerateRequest(
@NotNull(message = "회사 ID는 필수입니다.")
Long companyId,

@NotNull(message = "중분류 ID는 필수입니다.")
Long middleClassificationId,

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.jobdri.jobdri_api.domain.jobposting.dto.response;

import java.util.List;

public record JobPostingMockGenerateResponse(
String companyName,
String jobTitle,
String task,
String requirement,
String preferred,
String summary
String summary,
List<String> recommendedQuestions
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.jobdri.jobdri_api.domain.jobposting.dto.response;

import java.util.List;

public record JobPostingMockQuestionResponse(
List<String> recommendedQuestions
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.jobdri.jobdri_api.domain.jobposting.entity;

import com.jobdri.jobdri_api.domain.classification.entity.DetailClassification;
import jakarta.persistence.CollectionTable;
import jakarta.persistence.Column;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OrderColumn;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Builder(access = AccessLevel.PRIVATE)
@Table(
name = "mock_question_caches",
uniqueConstraints = @UniqueConstraint(
name = "uk_mock_question_cache_detail_version",
columnNames = {"detail_classification_id", "prompt_version"}
)
)
public class MockQuestionCache {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "detail_classification_id", nullable = false)
private DetailClassification detailClassification;

@Column(name = "prompt_version", nullable = false, length = 50)
private String promptVersion;

@Builder.Default
@ElementCollection
@CollectionTable(
name = "mock_question_cache_items",
joinColumns = @JoinColumn(name = "mock_question_cache_id")
)
@OrderColumn(name = "question_order")
@Column(name = "question_content", nullable = false, columnDefinition = "TEXT")
private List<String> questions = new ArrayList<>();

public static MockQuestionCache create(
DetailClassification detailClassification,
String promptVersion,
List<String> questions
) {
return MockQuestionCache.builder()
.detailClassification(detailClassification)
.promptVersion(promptVersion)
.questions(new ArrayList<>(questions))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,37 @@
package com.jobdri.jobdri_api.domain.jobposting.repository;

import com.jobdri.jobdri_api.domain.jobposting.entity.JobPosting;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface JobPostingRepository extends JpaRepository<JobPosting, Long> {
List<JobPosting> findAllByCompanyId(Long companyId);
List<JobPosting> findAllByDetailClassificationId(Long detailClassificationId);
List<JobPosting> findTop5ByDetailClassificationIdOrderByIdDesc(Long detailClassificationId);
List<JobPosting> findTop5ByCompanyIdOrderByIdDesc(Long companyId);

@Query(value = """
SELECT jp.*
FROM job_postings jp
WHERE jp.detail_classification_id = :detailClassificationId
OR (:companyId IS NOT NULL AND jp.company_id = :companyId)
ORDER BY
CASE
WHEN :companyId IS NOT NULL
AND jp.company_id = :companyId
AND jp.detail_classification_id = :detailClassificationId THEN 3
WHEN jp.detail_classification_id = :detailClassificationId THEN 2
WHEN :companyId IS NOT NULL
AND jp.company_id = :companyId THEN 1
ELSE 0
END DESC,
jp.id DESC
LIMIT 5
""", nativeQuery = true)
List<JobPosting> findTop5ReferencePostings(
@Param("companyId") Long companyId,
@Param("detailClassificationId") Long detailClassificationId
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.jobdri.jobdri_api.domain.jobposting.repository;

import com.jobdri.jobdri_api.domain.jobposting.entity.MockQuestionCache;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface MockQuestionCacheRepository extends JpaRepository<MockQuestionCache, Long> {
Optional<MockQuestionCache> findByDetailClassification_IdAndPromptVersion(Long detailClassificationId, String promptVersion);
}
Loading
Loading