PBD 진단 시스템 (PBD Assessment System)
이 문서는 Spective PBD 진단 시스템의 기술적 구현 가이드입니다.
목차
1. 개요
PBD(Perspective Based Disposition)는 관점기반 성향 진단 시스템으로, 개인의 인지패턴(C-PBD)과 상황패턴(S-PBD)을 측정하여 업무 성향을 분석합니다.
1.1 진단 구성
| 구분 | 설명 | 문항 수 |
|---|---|---|
| 개인PBD (Personal PBD) | 개인의 업무 성향 진단 | 100문항 |
| 준거PBD (Reference PBD) | 조직/역할 기준 성향 진단 | 20문항 (핵심 문항) |
1.2 측정 축 (Axis)
PBD는 4개의 양극성 축으로 구성됩니다:
인지패턴 (C-PBD)
├── 사고방식 (Thinking Pattern): 직관적(1) ↔ 숙고적(2)
└── 추론방식 (Reasoning Approach): 귀납적(3) ↔ 연역적(4)
상황패턴 (S-PBD)
├── 통제방식 (Control Orientation): 내적통제(5) ↔ 외적통제(6)
└── 역할방식 (Role Orientation): 개인적(7) ↔ 집단적(8)2. 문항 구조
2.1 문항 유형
Dual-Axis 7점 척도 (dual-axis-scale)
좌우 양극에 대비되는 진술이 배치되고, 7점 척도로 응답합니다.
interface DualAxisQuestion {
id: string
type: 'dual-axis-scale'
axisCode: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 // SYSTEM 코드
facetCode: string // Facet 코드
leftLabel: string // 좌측 극단 진술
rightLabel: string // 우측 극단 진술
leftAxisCode: number // 좌측이 해당하는 SYSTEM
rightAxisCode: number // 우측이 해당하는 SYSTEM
}예시:
[좌측] 나는 의사결정 시 직감에 의존한다
○ ○ ○ ○ ○ ○ ○
[우측] 나는 의사결정 시 데이터를 분석한다Likert 7점 척도 (likert-7)
단일 진술에 대한 동의 정도를 측정합니다.
interface LikertQuestion {
id: string
type: 'likert-7'
axisCode: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
facetCode: string
text: string // 진술문
direction: 'positive' | 'negative' // 점수 방향
}응답 척도:
- 1: 전혀 그렇지 않다
- 2: 그렇지 않다
- 3: 약간 그렇지 않다
- 4: 보통이다
- 5: 약간 그렇다
- 6: 그렇다
- 7: 매우 그렇다
2.2 Facet 구조
각 축당 5개의 Facet으로 구성되며, 총 20개의 Facet이 있습니다.
interface Facet {
code: string // Facet 코드
axisCode: number // 소속 축 (1-8)
name: string // Facet 명칭
description: string // 설명
questionCount: number // 해당 Facet 문항 수 (보통 5개)
}Facet 목록:
| 축 | Facet 1 | Facet 2 | Facet 3 | Facet 4 | Facet 5 |
|---|---|---|---|---|---|
| 사고방식 (1-2) | 의사결정 정보 | 정보처리 방식 | 의사결정 속도 | 실행 방식 | 오류에 대한 태도 |
| 추론방식 (3-4) | 문제의 명확성 | 목표 지향성 | 접근 방식 | 변화 대응 방식 | 리스크 수용성 |
| 통제방식 (5-6) | 목표 결정 | 실행 준거 | 규칙 적용 | 의사 결정 | 동기 부여 |
| 역할방식 (7-8) | 역할 인식 | 목표 지향성 | 관계성 | 성과 인식 | 책임 인식 |
2.3 문항 배치 규칙
interface QuestionDistribution {
totalQuestions: 100 // 개인PBD 총 문항 수
questionsPerAxis: 25 // 각 축쌍당 문항 수
questionsPerFacet: 5 // 각 Facet당 문항 수
referenceQuestions: 20 // 준거PBD 핵심 문항 수
}2.4 전체 문항 번호 계산
데이터베이스에서 DiagnosisQuestion.order는 **Facet 내 순서(1-5)**를 저장합니다. 전체 문항 번호(1-100)를 계산하려면 축, Facet, 문항 순서를 조합해야 합니다.
문항 번호 계산 공식:
/**
* 전체 문항 번호 계산
*
* @param axisOrder 축 순서 (1-4: PBD, 5: SDI)
* @param facetOrder Facet 내 순서 (1-5)
* @param questionOrder 문항 순서 (1-5, SDI는 1-10)
* @returns 전체 문항 번호 (1-110)
*/
function calculateGlobalQuestionNumber(
axisOrder: number,
facetOrder: number,
questionOrder: number,
): number {
// SDI (축 5)는 100번 이후
if (axisOrder === 5) {
return 100 + questionOrder // 101-110
}
// PBD 문항 (축 1-4)
// 공식: (axisOrder - 1) × 25 + (facetOrder - 1) × 5 + questionOrder
return (axisOrder - 1) * 25 + (facetOrder - 1) * 5 + questionOrder
}문항 번호 범위:
| 축 (Axis) | 축 순서 | Facet 범위 | 문항 번호 범위 |
|---|---|---|---|
| 사고방식 | 1 | 1-5 | 1-25 |
| 추론방식 | 2 | 1-5 | 26-50 |
| 통제방식 | 3 | 1-5 | 51-75 |
| 역할방식 | 4 | 1-5 | 76-100 |
| SDI (타당성) | 5 | 1 | 101-110 |
예시:
- Facet 1 (의사결정 정보), 문항 순서 1 →
(1-1)×25 + (1-1)×5 + 1 = 1 - Facet 6 (문제의 명확성), 문항 순서 1 →
(2-1)×25 + (1-1)×5 + 1 = 26 - Facet 11 (목표결정), 문항 순서 3 →
(3-1)×25 + (1-1)×5 + 3 = 53 - SDI 문항 5 →
100 + 5 = 105
중요: 점수 계산 시 반드시 이 공식을 사용하여 전체 문항 번호를 계산해야 합니다.
DiagnosisQuestion.order를 그대로 사용하면 모든 문항이 1-5 범위로 매핑되어 첫 번째 축(사고방식)만 계산됩니다.
3. 응답 처리
3.1 응답 데이터 구조
interface AssessmentResponse {
questionId: string
selectedValue: 1 | 2 | 3 | 4 | 5 | 6 | 7 // 7점 척도 응답값
respondedAt: Date // 응답 시각
}
interface AssessmentSession {
sessionId: string
userId: string
assessmentType: 'personal' | 'reference'
responses: AssessmentResponse[]
status: 'not_started' | 'in_progress' | 'completed'
startedAt: Date
completedAt?: Date
questionOrder: string[] // 랜덤화된 문항 순서
}3.2 응답 저장 규칙
- 즉시 저장: 각 문항 응답 시 즉시 서버에 저장
- 세션 복구: 세션 만료 후 재로그인 시 진행 상태 복구
- 문항 순서 보존: 최초 진단 시작 시 랜덤화된 순서 유지
// 응답 저장 API
interface SaveResponseInput {
sessionId: string
questionId: string
selectedValue: number
}
// 세션 복구 API
interface ResumeSessionOutput {
session: AssessmentSession
nextQuestionIndex: number
progress: {
answered: number
total: number
percentage: number
}
}4. 점수 산출
4.1 축별 점수 계산
각 축의 점수는 해당 축에 속한 25개 문항 평균값으로 계산됩니다.
참고: 점수 산출 로직은
docs/logic/20251218_진단결과값 산출 Logic.xlsx및docs/logic/example.pdf를 기반으로 합니다.
문항 범위:
| 축 | 문항 번호 | 8시스템 (음수/양수) |
|---|---|---|
| 사고방식 | 1~25 | 직관적 / 숙고적 |
| 추론방식 | 26~50 | 귀납적 / 연역적 |
| 통제방식 | 51~75 | 내적 / 외적 |
| 역할방식 | 76~100 | 개인적 / 집단적 |
점수 변환:
- 7점 척도 응답 (1-7)을 -30 ~ +30 범위로 변환
transformedScore = (response - 4) × 10(중앙값 4를 기준으로)- 1 → -30, 2 → -20, 3 → -10, 4 → 0, 5 → +10, 6 → +20, 7 → +30
- 축별 원점수(m) = 25개 문항 변환점수의 평균값
- 축별 원점수(m) 범위: -30 ~ +30
퍼센트 점수 계산:
percentScore = |m| ÷ 30 × 100
경향성 정도 판정:
| 원점수 범위 | 경향성 정도 |
|---|---|
| |m| > 20 | High |
| 10 < |m| ≤ 20 | Mid |
| 0 < |m| ≤ 10 | Low |
| m = 0 | Neutral |
중립 축 시스템 결정 (rawScore = 0):
축 평균이 정확히 0일 때, 5개 Facet의 방향성을 기반으로 시스템을 결정합니다.
참고:
docs/logic/neutral-axis-case1.pdf,docs/logic/neutral-axis-case2.pdf참조
| 케이스 | 조건 | 결정 방식 |
|---|---|---|
| CASE1 | Facet 비균등 분할 | 다수결로 시스템 결정 (예: 3개 음수, 2개 양수 → 음수 시스템) |
| CASE2 | Facet 균등 분할 | 기본값(positive) 시스템 사용 |
예시 (CASE1):
- 축 평균: 0
- Facet 1-3: 음수(-10, -10, -10)
- Facet 4-5: 양수(+10, +20)
- 결과: 3 음수 vs 2 양수 → 음수 시스템 (예: 직관적)
예시 (CASE2):
- 축 평균: 0
- Facet 1-2: 음수(-10, -10)
- Facet 3: 중립(0)
- Facet 4-5: 양수(+10, +10)
- 결과: 2 음수 vs 2 양수 → 기본값(양수) 시스템 (예: 숙고적)
interface AxisScore {
axisCode: number // 1-8
rawScore: number // -30 ~ +30 원점수 (25문항 평균)
percentScore: number // 0 ~ 100 퍼센트 점수
intensity: 'High' | 'Mid' | 'Low' | 'Neutral'
system: string // 시스템 이름 (직관적, 숙고적 등)
systemCode: 'negative' | 'positive' // 중립 축도 시스템 코드 결정됨
}
interface FacetScore {
facetCode: string
rawScore: number // -30 ~ +30 원점수 (5문항 평균)
percentScore: number // 0 ~ 100 퍼센트 점수
intensity: 'High' | 'Mid' | 'Low' | 'Neutral'
}4.2 PBD Matrix 위치 결정
interface PBDMatrixPosition {
cpbd: {
thinkingPattern: number // -3 ~ +3 (음수: 직관적, 양수: 숙고적)
reasoningApproach: number // -3 ~ +3 (음수: 귀납적, 양수: 연역적)
quadrant: 'ideation' | 'execution' | 'invention' | 'design'
}
spbd: {
controlOrientation: number // -3 ~ +3 (음수: 내적통제, 양수: 외적통제)
roleOrientation: number // -3 ~ +3 (음수: 개인적, 양수: 집단적)
quadrant:
| 'autonomous_individual'
| 'autonomous_collective'
| 'normative_individual'
| 'normative_collective'
}
}Matrix Quadrant 결정:
// C-PBD Matrix
function determineCPBDQuadrant(thinking: number, reasoning: number): string {
if (thinking < 0 && reasoning < 0)
return 'ideation' // 발상
if (thinking < 0 && reasoning >= 0)
return 'execution' // 실행
if (thinking >= 0 && reasoning < 0)
return 'invention' // 발명
return 'design' // 설계
}
// S-PBD Matrix
function determineSPBDQuadrant(control: number, role: number): string {
if (control < 0 && role < 0)
return 'autonomous_individual' // 자율형 개인
if (control < 0 && role >= 0)
return 'autonomous_collective' // 자율형 집단
if (control >= 0 && role < 0)
return 'normative_individual' // 규범형 개인
return 'normative_collective' // 규범형 집단
}4.3 A-INDEX 계산
A-INDEX는 개인 프로파일(IP)과 준거 프로파일(RP) 간의 일치도를 측정합니다.
interface AIndexCalculation {
individualProfile: PBDMatrixPosition
referenceProfile: PBDMatrixPosition
axisAlignments: {
axisCode: number
individualScore: number
referenceScore: number
difference: number
alignment: number // 0-100
}[]
overallAlignment: number // 0-100
grade: 'A1' | 'A2' | 'A3' | 'A4' | 'A5' | 'A6' | 'A7' | 'A8' | 'A9' | 'A10'
}A-INDEX 등급:
| 등급 | 범위 | 설명 |
|---|---|---|
| A1 | 0-10 | 완전히 다름 (Completely different) |
| A2 | 10-20 | 거의 반대 (Nearly opposite) |
| A3 | 20-30 | 매우 다른 (Very different) |
| A4 | 30-40 | 상당한 차이 (Significant difference) |
| A5 | 40-50 | 차이가 뚜렷 (Clearly different) |
| A6 | 50-60 | 어느 정도 차이 (Somewhat different) |
| A7 | 60-70 | 부분적인 차이 존재 (Moderate difference) |
| A8 | 70-80 | 유사하지만 차이 존재 (Similar but noticeable) |
| A9 | 80-90 | 매우 유사 (Very similar) |
| A10 | 90-100 | 거의 동일 (Minimal difference) |
4.4 타당성 지표 (Validity Indices)
진단 결과의 신뢰성을 평가하기 위한 두 가지 타당성 지표를 산출합니다.
4.4.1 SDI (사회적 바람직성 지수, Social Desirability Index)
SDI는 응답자가 실제보다 더 바람직해 보이는 답변을 했을 가능성을 측정합니다.
문항 구성:
| 문항번호 | 문항내용 | 점수방향 | 점수범위 |
|---|---|---|---|
| SDI-01 | 나는 언제나 타인에게 친절하다 | 긍정형 | 0-6 |
| SDI-02 | 나는 항상 실수를 하면 즉시 인정하고 변명하지 않는다 | 긍정형 | 0-6 |
| SDI-03 | 나는 누구에게도 화를 내지 않는다 | 긍정형 | 0-6 |
| SDI-04 | 나는 다른 사람을 실망시킨 적이 한 번도 없다 | 긍정형 | 0-6 |
| SDI-05 | 나는 규칙을 한 번도 어긴 적이 없다 | 긍정형 | 0-6 |
| SDI-06 | 나는 누구에게도 나쁜 감정을 품지 않으려고 애쓴다 | 긍정형 | 0-6 |
| SDI-07 | 나는 거짓말을 한 적이 거의 없다 | 긍정형 | 0-6 |
| SDI-08 | 나는 가끔 나의 이익을 위해 다른 사람을 이용한 적이 있다 | 부정형 | 0-6 (역산) |
| SDI-09 | 나는 남들 앞에서 잘 보이기 위해 내 감정을 숨길 때가 있다 | 부정형 | 0-6 (역산) |
| SDI-10 | 나는 가끔 타인에 대해 험담을 하곤 한다 | 부정형 | 0-6 (역산) |
점수 계산:
interface SDICalculation {
// 문항 ID 범위: SDI-01 ~ SDI-10
positiveQuestions: [
'SDI-01',
'SDI-02',
'SDI-03',
'SDI-04',
'SDI-05',
'SDI-06',
'SDI-07',
]
negativeQuestions: ['SDI-08', 'SDI-09', 'SDI-10']
}
// 응답값 변환 (7점 리커트 → 0-6점)
function transformToSdiScore(
response: 1 | 2 | 3 | 4 | 5 | 6 | 7,
direction: 'positive' | 'negative',
): number {
// 7점 척도 → 0-6 범위 변환
const baseScore = response - 1 // 0, 1, 2, 3, 4, 5, 6
if (direction === 'positive') {
return baseScore // 긍정형: 높은 응답 = 높은 SDI
}
else {
return 6 - baseScore // 부정형: 높은 응답 = 낮은 SDI (역산)
}
}
// 총점 계산
function calculateSDI(responses: Map<string, number>): number {
let total = 0
// 긍정형 문항 (SDI-01 ~ SDI-07): 0-6점
for (let i = 1; i <= 7; i++) {
const questionId = `SDI-${String(i).padStart(2, '0')}`
const response = responses.get(questionId)!
total += transformToSdiScore(response, 'positive')
}
// 부정형 문항 (SDI-08 ~ SDI-10): 역산 0-6점
for (let i = 8; i <= 10; i++) {
const questionId = `SDI-${String(i).padStart(2, '0')}`
const response = responses.get(questionId)!
total += transformToSdiScore(response, 'negative')
}
return total // 0-60 범위
}해석 기준:
| 점수 범위 | 해석 | 권장 조치 |
|---|---|---|
| 0-29 | 정상 | 진단 결과 활용 가능 |
| 30-49 | 양호 | 진단 결과 활용 가능 |
| 50-60 | 높음 | 사회적 바람직성 편향 가능성. 결과 해석 시 유의 |
주의: SDI ≥ 50인 경우, 응답자가 실제보다 더 바람직해 보이는 답변을 했을 가능성이 있습니다.
4.4.2 ICI (내적 일관성 지수, Internal Consistency Index)
ICI는 각 Facet 내 문항 응답의 일관성을 평균절대편차(MAD) 기반으로 측정합니다.
계산 방식:
- 7점 척도 응답을 -100 ~ +100 범위로 변환
- 각 Facet별 5개 문항의 평균(mean) 계산
- 각 문항과 평균의 절대편차 합계 및 평균절대편차 계산
- Facet ICI = 100 - 평균절대편차
- 전체 ICI = 20개 Facet ICI의 평균
예시 (Facet 1):
| 1번 문항 | 2번 문항 | 3번 문항 | 4번 문항 | 5번 문항 | 평균 | 절대편차합 | 평균절대편차 | ICI |
|---|---|---|---|---|---|---|---|---|
| 10 | 60 | 40 | -100 | 90 | 20 | 260 | 52 | 48 |
interface ICICalculation {
// 각 Facet별 ICI 계산 결과
facetICIs: {
facetNumber: number
questionValues: number[] // 변환된 문항값 (-100 ~ +100)
mean: number // 평균
absoluteDeviationSum: number // 절대편차합
meanAbsoluteDeviation: number // 평균절대편차
ici: number // 100 - 평균절대편차
}[]
overallICI: number // 전체 ICI (20개 Facet ICI 평균)
}
/**
* 7점 척도 응답을 -100 ~ +100 범위로 변환
* 1 → -100, 4 → 0, 7 → +100
*/
function responseToScaledValue(response: number): number {
return (response - 4) * (100 / 3)
}
/**
* ICI 계산 (MAD 기반)
*/
function calculateICI(responses: Map<number, number>): number {
const facetICIs: number[] = []
// 20개 Facet 순회
for (let facetIndex = 0; facetIndex < 20; facetIndex++) {
const startQuestion = facetIndex * 5 + 1
const questionValues: number[] = []
// 각 Facet의 5개 문항값 수집
for (let i = 0; i < 5; i++) {
const questionNumber = startQuestion + i
const response = responses.get(questionNumber)
if (response !== undefined) {
questionValues.push(responseToScaledValue(response))
}
}
if (questionValues.length === 0)
continue
// 평균 계산
const mean = questionValues.reduce((sum, v) => sum + v, 0) / questionValues.length
// 절대편차합 계산
const absoluteDeviationSum = questionValues.reduce(
(sum, v) => sum + Math.abs(v - mean),
0
)
// 평균절대편차
const meanAbsoluteDeviation = absoluteDeviationSum / questionValues.length
// Facet ICI = 100 - 평균절대편차
const facetICI = 100 - meanAbsoluteDeviation
facetICIs.push(facetICI)
}
if (facetICIs.length === 0)
return 100
// 전체 ICI = 20개 Facet ICI 평균
const overallICI = facetICIs.reduce((sum, v) => sum + v, 0) / facetICIs.length
return Math.round(overallICI * 10) / 10 // 소수점 첫째자리까지
}해석 기준:
| 점수 범위 | 해석 | 권장 조치 |
|---|---|---|
| 0-54 | 낮음 | 응답 일관성 부족. 재진단 또는 결과 활용 시 유의 |
| 55-69 | 양호 | 진단 결과 활용 가능 |
| 70-100 | 높음 | 진단 결과 신뢰도 높음 |
주의: ICI < 55인 경우, 응답의 일관성이 낮아 진단 타당성이 저하될 수 있습니다.
타당성 지표 데이터 구조:
interface ValidityScores {
ici: number // 내적 일관성 지수 (0-100)
sdi: number // 사회적 바람직성 지수 (0-60)
isValid: boolean // ici >= 55 && sdi < 50
warnings: string[] // 경고 메시지 배열
}
function evaluateValidity(ici: number, sdi: number): ValidityScores {
const warnings: string[] = []
if (ici < 55) {
warnings.push(
'내적 일관성이 낮습니다. 재진단 또는 결과 활용에 유의하세요.',
)
}
if (sdi >= 50) {
warnings.push(
'사회적 바람직성 점수가 높습니다. 실제와 달리 더 바람직해 보이는 답변을 했을 가능성이 있습니다.',
)
}
return {
ici,
sdi,
isValid: ici >= 55 && sdi < 50,
warnings,
}
}5. 결과 보고서 생성
5.1 보고서 유형
| 유형 | 입력 | 출력 | 비용 |
|---|---|---|---|
| 결과보고서A | 개인PBD 1건 | IP (Individual Profile) | 39,000원 |
| 결과보고서B | 준거PBD 1건 | RP (Reference Profile) | 20,000원 |
| 비교리포트C | IP 1건 + RP 1건 | 1:1 비교 + A-INDEX | 20,000원 |
| 비교리포트D | IP N건 + RP 1건 | N:1 비교 + A-INDEX 분포 | 500,000원 + 20,000원×(N-10) |
5.2 보고서 데이터 구조
interface ReportA {
reportId: string
userId: string
createdAt: Date
individualProfile: {
cpbd: CPBDResult
spbd: SPBDResult
behavioralPatterns: BehavioralPattern[]
structuralStrengths: string[]
structuralWeaknesses: string[]
hppa: string[] // High-Probability Performance Areas
lppa: string[] // Low-Probability Performance Areas
}
}
interface ReportB {
reportId: string
organizationName: string
createdAt: Date
referenceProfile: {
cpbd: CPBDResult
spbd: SPBDResult
behavioralPatterns: BehavioralPattern[]
desiredStrengths: string[]
riskAreas: string[]
}
}
interface ReportC {
reportId: string
createdAt: Date
individualProfile: ReportA['individualProfile']
referenceProfile: ReportB['referenceProfile']
aIndex: AIndexCalculation
gapAnalysis: GapAnalysis
}
interface ReportD {
reportId: string
createdAt: Date
referenceProfile: ReportB['referenceProfile']
participants: {
userId: string
name: string
individualProfile: ReportA['individualProfile']
aIndex: AIndexCalculation
}[]
teamProfile: TeamProfile
distributionAnalysis: DistributionAnalysis
}6. 데이터베이스 스키마
6.1 진단 관련 테이블
-- 문항 테이블
CREATE TABLE questions
(
id UUID PRIMARY KEY,
type VARCHAR(20) NOT NULL, -- 'dual-axis-scale' | 'likert-7'
axis_code INTEGER NOT NULL, -- 1-8
facet_code VARCHAR(50) NOT NULL,
text TEXT, -- Likert용 진술문
left_label TEXT, -- Dual-axis용 좌측 레이블
right_label TEXT, -- Dual-axis용 우측 레이블
left_axis_code INTEGER,
right_axis_code INTEGER,
direction VARCHAR(10), -- 'positive' | 'negative'
is_reference BOOLEAN DEFAULT false, -- 준거PBD 핵심 문항 여부
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- 진단 세션 테이블
CREATE TABLE assessment_sessions
(
id UUID PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users (id),
assessment_type VARCHAR(20) NOT NULL, -- 'personal' | 'reference'
status VARCHAR(20) NOT NULL, -- 'not_started' | 'in_progress' | 'completed'
question_order JSONB NOT NULL, -- 랜덤화된 문항 ID 배열
started_at TIMESTAMP,
completed_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- 응답 테이블
CREATE TABLE assessment_responses
(
id UUID PRIMARY KEY,
session_id UUID NOT NULL REFERENCES assessment_sessions (id),
question_id UUID NOT NULL REFERENCES questions (id),
selected_value INTEGER NOT NULL CHECK (selected_value BETWEEN 1 AND 7),
responded_at TIMESTAMP DEFAULT NOW(),
UNIQUE (session_id, question_id)
);
-- 결과 보고서 테이블
CREATE TABLE assessment_reports
(
id UUID PRIMARY KEY,
session_id UUID NOT NULL REFERENCES assessment_sessions (id),
report_type VARCHAR(10) NOT NULL, -- 'A' | 'B' | 'C' | 'D'
result_data JSONB NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);7. API 엔드포인트
7.1 진단 API
// 진단 시작
POST /api/assessment/start
Input: { assessmentType: 'personal' | 'reference' }
Output: { sessionId: string, questions: Question[], totalCount: number }
// 응답 저장
POST /api/assessment/respond
Input: { sessionId: string, questionId: string, selectedValue: number }
Output: { success: boolean, progress: { answered: number, total: number } }
// 세션 복구
GET /api/assessment/resume/:sessionId
Output: { session: AssessmentSession, nextQuestionIndex: number, progress: Progress }
// 진단 완료
POST /api/assessment/complete
Input: { sessionId: string }
Output: { reportId: string, reportType: string }7.2 보고서 API
// 보고서 조회
GET /api/reports/:reportId
Output: { report: Report }
// 비교리포트 생성
POST /api/reports/comparison
Input: {
type: 'C' | 'D',
individualReportIds: string[],
referenceReportId: string
}
Output: { reportId: string }
// PDF 다운로드
GET /api/reports/:reportId/pdf
Output: PDF Binary8. 타당성 검증
8.1 KAIST 검증 결과
PBD 진단은 KAIST 조직행동연구팀의 과학적 타당성 검증을 완료했습니다.
검증 항목:
- 내적 일관성 (Cronbach's Alpha)
- 구성타당도 (Construct Validity)
- 예측타당도 (Predictive Validity)
- 수렴타당도 (Convergent Validity)
- 판별타당도 (Discriminant Validity)
핵심 결과:
- A-INDEX는 성과를 예측하는 가장 강력하고 일관된 요인으로 검증됨
- 각 Facet의 Cronbach's Alpha > 0.7
버전: 1.1.0 최종 수정: 2025-12-24 작성자: Minsu Lee (amondnet)