React 기반 고등학생 진로탐색 웹앱 개발기
Big Five + HEXACO + RIASEC: React 기반 고등학생 진로탐색 웹앱 개발기
심리측정학적 근거를 갖춘 3종 검사를 하나의 SPA에 통합하고, Claude API 기반 AI 분석과 SDGs 미션 시스템까지 구현한 프로젝트의 기술적 구조를 정리합니다.

프로젝트 개요
| 항목 | 내용 |
|---|---|
| 앱 URL | https://mycareer-woad.vercel.app |
| 기술 스택 | React 18 + Vite 6 + Vercel Serverless Functions |
| AI | Claude Sonnet 4 (Anthropic API) |
| DB | Supabase (PostgreSQL + Auth + RLS) |
| 검사 도구 | RIASEC 36문항 + Big Five 30문항 + HEXACO-H 6문항 |
| 배포 | Vercel (수동 npx vercel --prod) |
1. 검사 도구 설계: 심리측정학적 근거
1-1. RIASEC 흥미검사 (36문항)
Holland(1997)의 직업 흥미 이론에 기반한 6요인 검사입니다.
요인: R(현실) · I(탐구) · A(예술) · S(사회) · E(진취) · C(관습)
문항: 요인별 6문항 (정채점 + 역채점 혼합)
척도: 5점 리커트 (1~5)
점수: 요인별 합산 (6~30점)문항은 IPIP(International Personality Item Pool) 공개 문항과 커리어넷 직업적성검사 구조를 참고하되, 고등학생의 일상 장면으로 재구성했습니다. 예를 들어 "기계를 분해하고 조립하는 것을 좋아한다" 같은 전형적 문항 대신, "새 전자기기를 사면 설명서를 보기 전에 먼저 만져본다"처럼 10대가 공감할 수 있는 상황을 사용합니다.
1-2. Big Five 성격검사 (30문항)
John & Srivastava(1999)의 BFI-44에서 축약한 BF-30 구조입니다.
요인: O(개방성) · C(성실성) · E(외향성) · A(친화성) · N(신경성)
문항: 요인별 6문항 (정채점 3 + 역채점 3)
역채점 문항: BF06, BF09, BF12, BF15, BF18, BF21, BF24, BF30
채점: 6 - 원응답값점수는 백분위(0~100)로 변환합니다. 변환 공식:
pct[dim] = Math.round(((rawSum - 6) / 24) * 100)
// rawSum 범위: 6(최저) ~ 30(최고), 유효 범위: 24
N(신경성)은 결과 표시 시 정서안정성(100 - N%)으로 역산하여 높을수록 긍정적으로 통일합니다.
1-3. HEXACO 정직-겸손성 (6문항) — Big Five 확장
Ashton & Lee(2009)의 HEXACO-PI-R 60에서 H(Honesty-Humility) 요인 문항을 선별 · 번안했습니다.
하위요인: 진실성 · 공정성 · 탐욕회피 · 겸손성
문항: 정채점 3 + 역채점 3
채점: Big Five와 동일 (5점 리커트, 역채점 6-x)왜 HEXACO 전체가 아닌 H만 추가했는가?
HEXACO의 X(외향성), C(성실성), O(개방성)는 Big Five의 E, C, O와 구조적으로 유사합니다. 중복 측정의 피로감을 피하면서 HEXACO의 핵심 차별점인 H만 추출하여 Big Five에 통합했습니다. 이를 통해 36문항(약 10분)으로 6개 성격 차원을 측정합니다.
Lee, Ashton & Novitsky(2022)의 73,000명 대학생 연구에서 경영학 전공이 모든 전공 중 H가 가장 낮았다는 결과는, H가 진로 방향성을 구분하는 데 실질적 유용성이 있음을 보여줍니다.
1-4. 프로파일 매칭 알고리즘
Big Five 5요인(O/C/E/A/N)의 백분위를 3단계(H/M/L)로 분류한 뒤, 14개 사전 정의 프로파일과 가중 유사도 매칭을 수행합니다.
// 레벨 분류
getLevel(score) → score >= 70 ? "H" : score >= 40 ? "M" : "L"
// 가중치 (Lounsbury et al., 2005 기반)
WEIGHTS = { O: 3, C: 3, E: 2, A: 2, N: 1 }
// 매칭 점수
정확 일치: 2 × weight
인접 일치(H↔M, M↔L): 1 × weight
반대(H↔L): 0
정규화 점수가 0.7 미만이면 #14 "탐색가형" (진로미결정 포용 프로파일)으로 분류합니다. H(정직-겸손성)는 프로파일 매칭에는 참여하지 않고, 결과 화면에서 별도 해석 축으로 사용됩니다. 이는 H가 "어떤 직업"보다 "어떤 방식으로 일하는가"에 대한 정보이기 때문입니다.
2. 프론트엔드 아키텍처
2-1. 상태 관리
별도 상태 관리 라이브러리 없이 React useState + 함수형 업데이트로 관리합니다. 전역 상태가 필요한 수준이 아니므로 App.jsx에서 모든 상태를 관리하고 props로 전달합니다.
App.jsx (중앙 오케스트레이터)
├── WelcomeScreen (역할 선택 + 검사 허브)
├── TestPage (RIASEC / Big5+H 공용 검사 페이지)
├── ResultScreen (RIASEC AI 분석 결과)
├── BFResult (Big Five + H 결과)
├── CrossAnalysis (교차분석)
├── MissionWorld → MissionList → MissionDraw → MissionDetail → MissionSubmit
└── AdminDashboard (교사 관리)2-2. 검사 플로우 통합
RIASEC과 Big Five+H는 동일한 TestPage 컴포넌트를 공유합니다. testMode 상태로 분기합니다.
const isRiasec = testMode === "riasec";
const isBig5 = testMode === "big5";
const currentQS = isRiasec ? QS : BIG5_QS; // 36문항 or 36문항
const currentDimsOrder = isRiasec ? DIMS_ORDER : BIG5_DIMS_ORDER; // 6요인 or 6요인
const currentTestPages = isRiasec ? TEST_PAGES : BIG5_TEST_PAGES; // 6페이지 or 6페이지
RIASEC과 Big Five+H 모두 6요인 × 6문항 = 36문항으로 구조가 동일하기 때문에, 검사 UI 코드를 완전히 재사용할 수 있습니다.
2-3. 레이더차트 (RadarChart.jsx)
N각형 범용 레이더차트 컴포넌트입니다. SVG로 직접 렌더링합니다.
// props
{ scores, dims, dimData, maxPerDim }
// dims 배열 길이에 따라 자동으로 N각형 생성
// RIASEC: 6각형 (R,I,A,S,E,C)
// Big Five: 5각형 → Big Five+H: 6각형 (O,C,E,A,N→정서안정성,H)
각도 계산: angle = (2π × i / dims.length) - π/2
축 레이블, 데이터 포인트, 배경 그리드를 모두 dims 배열 기반으로 동적 생성하므로, 차원 수가 바뀌어도 컴포넌트 코드 수정이 필요 없습니다.
2-4. 이미지 저장 (html2canvas)
결과 화면을 PNG로 저장하는 기능에서 가장 까다로운 부분은 탭 기반 UI의 전체 캡처입니다.
// 문제: 비활성 탭은 display:none → 캡처 안 됨
// 해결: onclone 콜백에서 모든 탭을 표시
onclone: (doc) => {
// 1. 숨겨진 탭 모두 표시
doc.querySelectorAll("[data-tab]").forEach(div => {
div.style.display = "block";
});
// 2. 섹션 헤더 삽입 (어떤 탭인지 구분)
// 3. 탭 바 숨김
// 4. Material Symbols → 이모지 변환 (웹폰트 렌더링 이슈)
}
Material Symbols 아이콘은 html2canvas에서 렌더링되지 않으므로, onclone에서 이모지로 대체합니다. 이 처리는 클론된 DOM에서만 이루어지므로 실제 화면에는 영향 없습니다.
3. AI 분석 파이프라인
3-1. 서버리스 구조
클라이언트 → /api/chat (Vercel Serverless) → Anthropic API (Claude Sonnet 4)
↓
접근코드 검증 + Rate Limiting (Vercel KV)3-2. 프롬프트 엔지니어링
RIASEC AI 분석 프롬프트는 검사 점수, 상위 유형, 학생의 자유 입력을 조합합니다.
// 출력 포맷 (JSON)
{
profile: "탐구-사회형 진로개척자", // 프로파일명
insight: "...", // 150자 핵심 인사이트
story: "...", // 200자 진로 스토리 (2인칭)
advice: ["활동1", "활동2", "활동3"], // 지금 해볼 수 있는 것
groups: [{ // 계열별 추천
계열: "자연과학",
이유: "...",
majors: [{ name, 계열, fit, why, highlight, unexpected, jobs }]
}]
}
3-3. AI 사용 제한
AI 비용 관리를 위해 localStorage 기반 클라이언트 사이드 제한을 적용합니다.
// AI 사용 횟수: 분석 + 세특 + 스토리 통합 2회
const AI_MAX_USES = 2;
// 모든 AI 호출 전 체크
const usage = getAIUsage();
if (usage.analysis >= AI_MAX_USES) { /* 차단 */ }
// 성공 시 카운트 증가
incrementAIUsage("analysis");
서버 사이드에서도 Rate Limiting(Vercel KV, 30req/min)과 접근코드 검증을 이중으로 적용합니다.
4. 미션 시스템
4-1. 데이터 구조
36개 시드 미션이 8개 계열에 분포합니다. 각 미션에는 실감나는 의뢰인 캐릭터가 설정되어 있습니다.
{
category: "사회계열",
title: "공정무역이 정말 공정한가?",
subtitle: "공정무역의 이상과 현실 사이의 간극을 분석합니다",
description: "안녕하세요, 저는 부산 해운대에서 공정무역 카페를 운영하는 최민재(36세)입니다...",
difficulty: 2, // 1=기초, 2=심화, 3=도전
deliverableTypes: ["essay", "proposal"],
guidingQuestions: [...],
suggestedSdgs: [1, 10, 12],
}
4-2. Supabase 연동
교사가 생성한 미션과 학생 제출물은 Supabase에 저장됩니다.
teachers ← auth.users (RLS)
classes ← teacher_id (초대코드 자동생성)
students ← class_id (학번 기반 참여)
missions ← teacher_id, class_id
submissions ← student_id, mission_id (상태: selected→submitted→cleared/revision)Row-Level Security로 교사는 자신의 데이터만, 학생(anon)은 published 미션만 접근 가능합니다.
4-3. 의뢰서 뽑기 (MissionDraw)
게이미피케이션 요소로, 봉투 개봉 애니메이션을 구현했습니다.
Phase: ready → shuffling (8회 랜덤 셔플) → reveal (봉투 등장) → opened (내용 공개)CSS 애니메이션: @keyframes envelopeFloat, flapOpen, letterRise, sealBreak, sparkle
난이도별 봉투 색상: BRONZE(기초) / SILVER(심화) / GOLD(도전)
5. 교사 관리 시스템
5-1. 인증
Supabase Auth(이메일/비밀번호) + 초대코드(댓글문의) 이중 검증입니다.
// AdminLogin.jsx
if (inviteCode.trim().toUpperCase() !== "******") {
setError("초대코드가 올바르지 않습니다");
return;
}
await teacherSignUp(email, password, name);
5-2. 학급 CRUD
createClass(name) // 6자리 초대코드 자동생성 (O, I 제외한 영숫자)
updateClass(id, { name })
deleteClass(id) // 연관 학생 데이터 함께 삭제
getClasses()
QR코드는 qrcode-generator 라이브러리로 클라이언트 사이드 생성합니다.
5-3. 리뷰 워크플로우
학생: selectMission → submitWork (에세이 링크 + SDGs + 교과 태그)
교사: reviewSubmission(id, "cleared", feedback) // 클리어
reviewSubmission(id, "revision", feedback) // 보완 요청6. H(정직-겸손성) 결과 표시 설계
H는 프로파일 매칭에 참여하지 않는 대신, 독립적인 "직업가치관" 탭으로 결과를 제공합니다.
직업가치관 탭 구성:
├── H 점수 게이지 (한국 평균 대비)
├── 가치관 유형 (원칙·공정 / 균형 / 전략·자기표현)
├── H 수준별 추천 직업
├── 프로파일 × H 교차 추천 (14개 프로파일 × 3단계)
└── 학술 출처 (HEXACO-PI-R 근거)교차 추천 예시:
H_CAREER_MAP.profileCross = {
1: { // 깊이 파고드는 설계자형
high: ["기초과학 연구원", "특허 심사관", "품질 인증 전문가"],
low: ["R&D 컨설턴트", "기술 스타트업 CTO"]
},
// ... 14개 프로파일 모두 매핑
}
7. 성능 및 배포
| 지표 | 값 |
|---|---|
| 빌드 번들 | ~1.5MB (gzip ~428KB) |
| 빌드 시간 | ~5초 (Vercel) |
| html2canvas | 동적 import (BFResult만 사용) |
| jsPDF | 동적 import |
| 정적 데이터 | 100개 학과, 36개 미션, 14개 프로파일, 80+ 직업 스토리 |
Vercel 자동 배포가 불안정하여 npx vercel --prod 수동 배포를 사용합니다.
8. 향후 개선 계획
- AI 사용 제한을 서버 사이드(Vercel KV)로 이관
- 200명 이상 파일럿 데이터 수집 후 한국 청소년 규준 수립
- HEXACO E(정서성), A(원만성) 차원 선택적 추가
- 검사 결과 PDF 리포트 자동 생성
- 교사 대시보드에 학급별 통계 시각화
참고 문헌
- Holland, J.L. (1997). Making vocational choices. Psychological Assessment Resources.
- John, O.P., & Srivastava, S. (1999). The Big Five Trait taxonomy. Handbook of Personality, 102-138.
- Soto, C.J., & John, O.P. (2017). The next Big Five Inventory (BFI-2). Journal of Personality and Social Psychology, 113(1), 117-143.
- Ashton, M.C., & Lee, K. (2009). The HEXACO-60: A short measure of the major dimensions of personality. Journal of Personality Assessment, 91(4), 340-345.
- Lee, K., Ashton, M.C., & Novitsky, N.K. (2022). HEXACO personality and university major. Personality and Individual Differences, 196, 111725.
- Gerlach, M., Farb, B., Revelle, W., & Amaral, L.A.N. (2018). A robust data-driven approach identifies four personality types. Nature Human Behaviour, 2, 735-742.
- Lounsbury, J.W. et al. (2005). Personality, career satisfaction, and life satisfaction. Journal of Career Assessment, 13(1), 25-45.
- Barrick, M.R., & Mount, M.K. (1991). The Big Five personality dimensions and job performance. Personnel Psychology, 44(1), 1-26.
앱 주소: https://mycareer-woad.vercel.app
GitHub: https://github.com/shineonyou1274/my-career