Skip to content
2 changes: 1 addition & 1 deletion build/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
7 changes: 3 additions & 4 deletions src/controllers/certificateInquiry.controller.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
//certification2.controller.ts
import { Request, Response, NextFunction } from "express";
import { StatusCodes } from "http-status-codes";
import { responseFromCertificationSummary, responseFromCertification } from "../dtos/certificateInquiry.dto.js";
import { CertificationService } from "../services/certificateInquiry.service.js";

const service = new CertificationService();

// GET: 전체 자격증 목록 (요약 정보만 제공)
// 전체 자격증 목록 조회
export const handleGetAllCertifications = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
console.log("전체 자격증 요약 조회 요청");

Expand All @@ -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<void> => {
console.log("카테고리별 자격증 조회 요청");

Expand Down Expand Up @@ -61,7 +60,7 @@ export const handleGetCertificationsByCategory = async (req: Request, res: Respo
}
};

// GET: 자격증 상세 조회
// 자격증 상세 조회
export const handleGetCertificationById = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
console.log("자격증 상세 조회 요청");

Expand Down
5 changes: 2 additions & 3 deletions src/dtos/certification.dto.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
// 요청에서 받아온 데이터를 DTO로 매핑
export const mapQueryToCertificationSearch = (query: any) => {
return {
query: query.query as string,
category: query.category ? query.category : "전체",
};
};

// 자격증 데이터를 응답 형식으로 변환

export const responseFromCertification = (certification: any) => {
return {
id: certification.id,
Expand All @@ -15,7 +14,7 @@ export const responseFromCertification = (certification: any) => {
};
};

// 자격증 목록 데이터를 응답 형식으로 변환

export const responseFromCertifications = (certifications: any[]) => {
return certifications.map(responseFromCertification);
};
2 changes: 0 additions & 2 deletions src/repositories/certificateInquiry.repository.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
//certification2.repository.ts
import { prisma } from "../db.config.js";

export class CertificationRepository {
// 요약 정보 조회
async findAllSummaries() {
return prisma.certification.findMany({
select: {
Expand Down
10 changes: 0 additions & 10 deletions src/repositories/user.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[]) {
Expand Down
7 changes: 0 additions & 7 deletions src/services/quiz.service.ts
Original file line number Diff line number Diff line change
@@ -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(
Expand All @@ -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(
Expand Down
43 changes: 39 additions & 4 deletions src/services/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,34 +31,49 @@ 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<string>();
similarUsers.forEach(({ user }) => {
user.exams.forEach((exam) => {
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;
}
}



// 유사 사용자 찾기: 전체 사용자 중에서 현재 사용자와의 유사도 계산
private static async findSimilarUsers(userInfo: UserWithDetails): Promise<UserSimilarityInfo[]> {
const allUsers = await SuggestionRepository.getAllUsersWithCategories();
Expand Down Expand Up @@ -112,6 +127,26 @@ export class SuggestionService {
category: cert.category,
})).slice(0, 3);
}

// 카테고리 없는 경우
private static async getNoCategoryRecommend(userInfo: UserWithDetails): Promise<SuggestInfoDto[]> {
// 지정된 자격증 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개 조회 */
Expand Down