diff --git a/build/swagger.yaml b/build/swagger.yaml index ca3f666..4fb477c 100644 --- a/build/swagger.yaml +++ b/build/swagger.yaml @@ -5,7 +5,7 @@ info: description: 공각심 API 문서 servers: - url: 'http://localhost:3000/' - - url: 'http://13.125.231.189:3000/' + - url: 'http://13.209.11.7:3000/' components: securitySchemes: BearerAuth: diff --git a/src/controllers/certificateInquiry.controller.ts b/src/controllers/certificateInquiry.controller.ts index 62570d9..8faa810 100644 --- a/src/controllers/certificateInquiry.controller.ts +++ b/src/controllers/certificateInquiry.controller.ts @@ -1,4 +1,3 @@ -//certification2.controller.ts import { Request, Response, NextFunction } from "express"; import { StatusCodes } from "http-status-codes"; import { responseFromCertificationSummary, responseFromCertification } from "../dtos/certificateInquiry.dto.js"; @@ -6,7 +5,7 @@ import { CertificationService } from "../services/certificateInquiry.service.js" const service = new CertificationService(); -// GET: 전체 자격증 목록 (요약 정보만 제공) +// 전체 자격증 목록 조회 export const handleGetAllCertifications = async (req: Request, res: Response, next: NextFunction): Promise => { console.log("전체 자격증 요약 조회 요청"); @@ -29,7 +28,7 @@ export const handleGetAllCertifications = async (req: Request, res: Response, ne } }; -// GET: 카테고리별 자격증 조회 (요약 정보만 제공) +// 카테고리별 자격증 조회 export const handleGetCertificationsByCategory = async (req: Request, res: Response, next: NextFunction): Promise => { console.log("카테고리별 자격증 조회 요청"); @@ -61,7 +60,7 @@ export const handleGetCertificationsByCategory = async (req: Request, res: Respo } }; -// GET: 자격증 상세 조회 +// 자격증 상세 조회 export const handleGetCertificationById = async (req: Request, res: Response, next: NextFunction): Promise => { console.log("자격증 상세 조회 요청"); diff --git a/src/dtos/certification.dto.ts b/src/dtos/certification.dto.ts index 3185a28..a8dc82a 100644 --- a/src/dtos/certification.dto.ts +++ b/src/dtos/certification.dto.ts @@ -1,4 +1,3 @@ -// 요청에서 받아온 데이터를 DTO로 매핑 export const mapQueryToCertificationSearch = (query: any) => { return { query: query.query as string, @@ -6,7 +5,7 @@ export const mapQueryToCertificationSearch = (query: any) => { }; }; -// 자격증 데이터를 응답 형식으로 변환 + export const responseFromCertification = (certification: any) => { return { id: certification.id, @@ -15,7 +14,7 @@ export const responseFromCertification = (certification: any) => { }; }; -// 자격증 목록 데이터를 응답 형식으로 변환 + export const responseFromCertifications = (certifications: any[]) => { return certifications.map(responseFromCertification); }; diff --git a/src/repositories/certificateInquiry.repository.ts b/src/repositories/certificateInquiry.repository.ts index 8e7523d..6bc84f7 100644 --- a/src/repositories/certificateInquiry.repository.ts +++ b/src/repositories/certificateInquiry.repository.ts @@ -1,8 +1,6 @@ - //certification2.repository.ts import { prisma } from "../db.config.js"; export class CertificationRepository { - // 요약 정보 조회 async findAllSummaries() { return prisma.certification.findMany({ select: { diff --git a/src/repositories/user.repository.ts b/src/repositories/user.repository.ts index e5d6e24..7b145b4 100644 --- a/src/repositories/user.repository.ts +++ b/src/repositories/user.repository.ts @@ -123,16 +123,6 @@ export class SuggestionRepository { }); } - // static async findSimilarUsersCertifications(userInfo: UserWithDetails) { - // const categoryNames = userInfo.users.map((uc) => uc.category.name); - - // return prisma.certification.findMany({ - // where: { - // category: { in: categoryNames }, - // }, - // take: 3, - // }); - // } // 신규 사용자와 일치하는 사용자가 없다면, 랜덤으로 certification에서 자동 3개 추천 static async findDefaultCertificationsByCategory(categoryNames: string[]) { diff --git a/src/services/quiz.service.ts b/src/services/quiz.service.ts index 225c389..9208b21 100644 --- a/src/services/quiz.service.ts +++ b/src/services/quiz.service.ts @@ -1,7 +1,6 @@ import { QuizRepository } from "../repositories/quiz.repository.js"; const repository = new QuizRepository(); -const SUBJECT_OPTIONAL_CERTIFICATIONS = ["TOEIC", "한국사능력검정시험 심화", "한국사능력검정시험 기본", "정보처리기사 필기"]; export class QuizService { async getQuizzesByCertificationAndType( @@ -21,12 +20,6 @@ export class QuizService { }; } - // ✅ 특정 자격증이면 subjects를 강제로 "1과목"으로 변경 - if (certificationNames.some(cert => SUBJECT_OPTIONAL_CERTIFICATIONS.includes(cert))) { - console.log(`🔹 ${certificationNames}는 특정 자격증이므로 "1과목"으로 변경`); - subjects = ["1과목"]; - } - // ✅ 랜덤 선택된 `selectedQuizType`으로 퀴즈 조회 const selectedQuizType = quizTypes[Math.floor(Math.random() * quizTypes.length)]; let quizzes = await repository.findQuizzesByCertification( diff --git a/src/services/user.service.ts b/src/services/user.service.ts index 16bf824..deb1fc1 100644 --- a/src/services/user.service.ts +++ b/src/services/user.service.ts @@ -31,12 +31,12 @@ export class SuggestionService { if (!users || users.length < 1) { console.log("사용자가 카테고리를 선택하지 않았습니다."); - return await this.getDefaultRecommendations(userInfo); + return await this.getNoCategoryRecommend(userInfo); } const similarUsers = await this.findSimilarUsers(userInfo); - if (similarUsers.length > 0) { + if (Array.isArray(similarUsers) && similarUsers.length > 0) { // 유사 사용자들의 exam 제목 추출 (중복 제거) const examTitlesSet = new Set(); similarUsers.forEach(({ user }) => { @@ -44,14 +44,28 @@ export class SuggestionService { examTitlesSet.add(exam.title); }); }); + const examTitles = Array.from(examTitlesSet); - + + // 만약 추출된 exam 제목이 없으면 기본 추천 호출 + if (examTitles.length === 0) { + return await this.getDefaultRecommendations(userInfo); + } + // exam 제목과 Certification.name이 일치하는 자격증 조회 const recommendedCertifications = await SuggestionRepository.getCertificationsByExamTitles(examTitles); + + // 만약 추천된 자격증이 없으면 기본 추천 호출 + if (!recommendedCertifications || recommendedCertifications.length === 0) { + return await this.getDefaultRecommendations(userInfo); + } + return this.mapToDto(recommendedCertifications); } - + + // 유사 사용자가 없는 경우 기본 추천 실행 return await this.getDefaultRecommendations(userInfo); + } catch (error) { console.error("추천 생성 중 오류:", error); throw error; @@ -59,6 +73,7 @@ export class SuggestionService { } + // 유사 사용자 찾기: 전체 사용자 중에서 현재 사용자와의 유사도 계산 private static async findSimilarUsers(userInfo: UserWithDetails): Promise { const allUsers = await SuggestionRepository.getAllUsersWithCategories(); @@ -112,6 +127,26 @@ export class SuggestionService { category: cert.category, })).slice(0, 3); } + + // 카테고리 없는 경우 + private static async getNoCategoryRecommend(userInfo: UserWithDetails): Promise { + // 지정된 자격증 ID 목록 + const defaultCertificationIds = [1, 8, 27]; // TOEIC, 컴퓨터활용능력 1급 필기, 테셋 + + const defaultCertifications = await prisma.certification.findMany({ + where: { + id: { in: defaultCertificationIds }, + }, + select: { + id: true, + name: true, + category: true, + }, + orderBy: { id: 'asc' }, + }); + + return this.mapToDto(defaultCertifications); + } } /** 가장 임박한 시험 최대 3개 조회 */