







1장. 플러그인 개요
1.1 소개
DX QBank는 DXCMS 위에서 동작하는 문제은행 · 온라인 시험 플랫폼 플러그인입니다. 관리자가 문제를 등록하고 시험지를 구성하면, 사용자는 웹 브라우저에서 바로 응시하고 즉시 채점 결과를 확인할 수 있습니다.1.2 주요 기능
- 문제 관리 — 객관식(단일/복수), OX, 단답형, 서술형 5가지 유형
- 이미지 삽입 — 문제 본문·선택지·해설에 이미지 직접 업로드
- 카테고리 — 다단계 카테고리로 문제 분류
- 시험지 — 문제 선택, 배점 설정, 문항·선택지 순서 섞기
- 응시 제어 — 시험 기간, 시간 제한, 재응시 허용/불가
- 자동 채점 — 객관식·OX·단답형 즉시 채점, 서술형 수동 채점
- 결과 리포트 — SVG 원형 점수, 오답 분석, 답안 해설
- 개인 현황 — 내 학습 통계, 시험별 합격 이력, 취약 문제 TOP5
- 반응형 UI — 모바일·태블릿·PC 모두 지원
- 카테고리 필터 — 헤더 네비 및 모바일 메뉴에서 카테고리별 시험 필터
1.3 요구 사항
| 항목 | 최소 요구 사항 |
| DXCMS | v8.5.0 이상 |
| PHP | 5.6 이상 (7.x / 8.x 권장) |
| MySQL / MariaDB | 5.5 이상 |
| 웹 서버 | Apache / Nginx / IIS |
| 디스크 여유 공간 | 50MB 이상 (업로드 이미지 별도) |
2장. 설치 방법
2.1 파일 복사
플러그인 ZIP 파일의 압축을 풀고 아래 두 폴더를 DXCMS 루트에 복사합니다.- plugins/dx-qbank/ — 플러그인 본체
- extend/top/00_qbank_router.php — URL 라우터 훅
2.2 플러그인 활성화
- DXCMS 관리자 → 플러그인 관리에서 DX QBank 활성화
2.3 테이블 설치
브라우저에서 아래 URL에 접속하면 7개의 DB 테이블이 자동 생성됩니다 (관리자 로그인 필요).https://사이트주소/qbank/install
※ 설치 완료 후 이 URL로 다시 접속해도 이미 존재하는 테이블은 변경되지 않습니다.
※ 설치 완료 후 이 URL로 다시 접속해도 이미 존재하는 테이블은 변경되지 않습니다.
2.4 설치 확인
- 사이트주소/qbank 접속 → 시험 목록 페이지 정상 출력 확인
- DXCMS 관리자 → DX QBank 메뉴 노출 확인
3장. 파일 구조
| 경로 | 설명 |
| plugins/dx-qbank/ | 플러그인 루트 |
| manifest.php | 플러그인 메타 정보 (이름, 버전, 요구 사항) |
| plugin.php | DXCMS 훅 등록 (관리자 메뉴, 라우터) |
| router.php | 프론트엔드 URL 분기 처리 |
| core/install.php | DB 테이블 생성 함수 |
| core/DxQBank.php | 공통 유틸리티 클래스 |
| core/DxQBankExam.php | 시험지 CRUD 클래스 |
| core/DxQBankQuestion.php | 문제 CRUD 클래스 |
| admin/index.php | 관리자 POST 처리 + 레이아웃 진입점 |
| admin/layout.php | 관리자 사이드바 레이아웃 |
| admin/blocks/*.php | 관리자 각 화면 블록 |
| views/layout.php | 프론트엔드 공통 헤더/CSS |
| views/index.php | 시험 목록 메인 페이지 |
| views/exam.php | 시험 응시 화면 |
| views/result.php | 결과/채점 화면 |
| views/my.php | 개인 학습 현황 프로필 |
| views/already_done.php | 재응시 불가 안내 |
| views/closed.php | 기간 외 시험 안내 |
| extend/top/00_qbank_router.php | DXCMS extend 훅 — URL 라우터 연결 |
4장. 데이터베이스 설계
4.1 qb_categories — 카테고리
| 컬럼 | 타입 | 설명 |
| id | INT UNSIGNED | 자동 증가 PK |
| parent_id | INT UNSIGNED | 상위 카테고리 ID (0 = 최상위) |
| name | VARCHAR(100) | 카테고리 이름 |
| sort | INT UNSIGNED | 정렬 순서 |
| q_count | INT UNSIGNED | 포함된 문제 수 (캐시) |
4.2 qb_questions — 문제
| 컬럼 | 타입 | 설명 |
| id | BIGINT UNSIGNED | 자동 증가 PK |
| category_id | INT UNSIGNED | 카테고리 FK |
| type | ENUM | single / multi / ox / short / essay |
| difficulty | ENUM | low / mid / high |
| score | DECIMAL(5,1) | 기본 배점 |
| content | TEXT | 문제 본문 (HTML 포함 가능) |
| content_html | TINYINT(1) | HTML 렌더링 여부 (1=HTML, 0=텍스트) |
| explanation | TEXT | 해설 (채점 후 표시) |
| answer_short | VARCHAR(500) | 단답형 정답 |
| tags | VARCHAR(500) | 태그 목록 (쉼표 구분) |
| used_count | INT UNSIGNED | 출제 횟수 |
| correct_cnt | INT UNSIGNED | 정답 횟수 |
| wrong_cnt | INT UNSIGNED | 오답 횟수 |
| created_by | INT UNSIGNED | 작성자 member ID |
| created_at | DATETIME | 생성일시 |
| updated_at | DATETIME | 수정일시 |
4.3 qb_options — 선택지
| 컬럼 | 타입 | 설명 |
| id | BIGINT UNSIGNED | 자동 증가 PK |
| question_id | BIGINT UNSIGNED | 문제 FK |
| content | TEXT | 선택지 내용 (HTML 포함 가능) |
| content_html | TINYINT(1) | HTML 렌더링 여부 |
| is_correct | TINYINT(1) | 정답 여부 |
| sort | INT UNSIGNED | 정렬 순서 |
4.4 qb_exams — 시험지
| 컬럼 | 타입 | 설명 |
| id | BIGINT UNSIGNED | PK |
| title | VARCHAR(200) | 시험지 제목 |
| description | TEXT | 시험 안내 |
| status | ENUM | draft / active / closed |
| time_limit | INT UNSIGNED | 시간 제한 (분, 0=무제한) |
| pass_score | DECIMAL(5,1) | 합격 기준점 |
| total_score | DECIMAL(7,1) | 총점 |
| shuffle_q | TINYINT(1) | 문제 순서 섞기 |
| shuffle_o | TINYINT(1) | 선택지 순서 섞기 |
| show_result | TINYINT(1) | 즉시 결과 공개 |
| show_answer | TINYINT(1) | 정답·해설 공개 |
| allow_retake | TINYINT(1) | 재응시 허용 |
| retake_limit | INT UNSIGNED | 재응시 최대 횟수 (0=무제한) |
| start_at | DATETIME | 응시 시작일시 |
| end_at | DATETIME | 응시 종료일시 |
| attempt_count | INT UNSIGNED | 누적 응시 수 |
4.5 qb_exam_questions — 시험지-문제 매핑
| 컬럼 | 타입 | 설명 |
| exam_id | BIGINT UNSIGNED | 시험지 FK |
| question_id | BIGINT UNSIGNED | 문제 FK |
| sort | INT UNSIGNED | 문제 순서 |
| score | DECIMAL(5,1) | 이 시험에서의 배점 |
4.6 qb_attempts — 응시 세션
| 컬럼 | 타입 | 설명 |
| id | BIGINT UNSIGNED | PK |
| exam_id | BIGINT UNSIGNED | 시험지 FK |
| member_id | INT UNSIGNED | 응시자 FK |
| status | ENUM | ongoing / submitted / graded |
| score | DECIMAL(7,1) | 획득 점수 |
| total_score | DECIMAL(7,1) | 이 응시의 총점 |
| pass | TINYINT(1) | 합격 여부 (NULL=채점 전) |
| started_at | DATETIME | 응시 시작일시 |
| submitted_at | DATETIME | 제출일시 |
| duration_sec | INT UNSIGNED | 소요 시간 (초) |
| q_order | TEXT | 문제 순서 JSON (섞기 적용 시) |
4.7 qb_answers — 답안
| 컬럼 | 타입 | 설명 |
| id | BIGINT UNSIGNED | PK |
| attempt_id | BIGINT UNSIGNED | 응시 FK |
| question_id | BIGINT UNSIGNED | 문제 FK |
| answer_text | TEXT | 주관식 답안 |
| option_ids | VARCHAR(500) | 선택한 선택지 ID (쉼표 구분) |
| is_correct | TINYINT(1) | 정답 여부 (NULL=채점 전) |
| score_given | DECIMAL(5,1) | 부여 점수 |
| grader_note | TEXT | 채점자 메모 (서술형) |
5장. 관리자 기능
관리자 메뉴 경로: DXCMS 관리자 → DX QBank
5.1 대시보드
플러그인 전체 현황을 한눈에 확인합니다.- 총 문제 수 / 총 시험지 수 / 누적 응시 수
- 최근 7일 응시 추이 차트
- 최근 응시 10건 목록 (응시자, 시험명, 점수, 합격 여부)
5.2 문제 관리
5.2.1 문제 목록
- 전체 문제 목록 (카테고리, 유형, 난이도, 정답률 표시)
- 카테고리 / 난이도 / 유형별 필터
- 문제 수정 · 삭제
5.2.2 문제 등록 · 수정
- 카테고리, 유형, 난이도, 기본 배점 설정
- 문제 본문 — contenteditable 에디터 (B/I/U 서식 + 이미지 직접 삽입)
- 선택지 — 항목별 contenteditable 에디터, 이미지 삽입 가능, 동적 추가/제거
- 해설 — 이미지 포함 HTML 서식 지원
- 태그 입력 (쉼표 구분)
- 이미지 업로드 경로: data/uploads/qbank/
5.3 카테고리 관리
- 카테고리 추가 / 삭제
- 카테고리별 문제 수 표시
- 카테고리는 헤더 네비 메뉴 · 모바일 메뉴 · 시험 목록 필터에 자동 노출
5.4 시험지 관리
5.4.1 시험지 목록
- 시험지 제목, 상태(초안/진행중/종료), 응시자 수, 총점 표시
- 시험지 편집 · 삭제
5.4.2 시험지 만들기
- 제목, 설명 입력
- 시간 제한 (분 단위, 0 = 무제한)
- 합격 기준점 설정
- 문제 순서 섞기 / 선택지 순서 섞기
- 즉시 결과 공개 / 정답·해설 공개 여부
- 재응시 허용 및 횟수 제한
- 응시 기간 설정 (시작일시 ~ 종료일시)
5.4.3 시험지 편집
- 문제 검색 및 시험지에 추가
- 카테고리 / 난이도 / 유형 필터로 문제 자동 선택
- 문제별 배점 개별 설정
- 총점 자동 계산
- 시험지 상태 변경 (초안 → 진행중 → 종료)
5.5 응시 관리
5.5.1 응시 현황
- 시험지별 · 응시자별 응시 목록
- 상태 (진행중 / 제출됨 / 채점완료) 표시
- 응시 상세 보기 — 답안 확인
5.5.2 서술형 채점
- 서술형 답안 목록 필터링
- 답안 내용 확인 후 점수 직접 입력
- 채점자 메모 입력 가능
- 채점 완료 시 합격 여부 자동 판정
6장. 프론트엔드(사용자) 기능
6.1 시험 목록 메인
- 히어로 섹션 — 로그인 사용자 이름 인사 / 비로그인 시 가입 유도
- 플랫폼 통계 바 — 진행 중인 시험 수 / 누적 응시 / 응시자 수
- 카테고리 필터 칩 — qb_categories 기준 필터링
- 시험 카드 그리드 — 카테고리 뱃지, HOT/마감임박 뱃지, 내 응시 상태 표시
- 반응형 — 1024px 이하 2열, 768px 이하 1열
6.2 시험 응시
- 응시 시작 화면 — 시험 정보 카드 (문제 수, 총점, 합격 기준, 시간, 재응시 여부)
- 스티키 상단바 — 시험명 + 남은 시간 카운트다운
- 문제 유형별 UI — 라디오(단일), 체크박스(복수), OX, 단답형 입력, 서술형 textarea
- 시간 초과 시 자동 제출
- 제출 확인 모달
6.3 결과 확인
- SVG 원형 점수 게이지 (합격=초록, 불합격=빨강)
- 점수 / 총점 / 합격 기준 3칸 요약
- 답안 확인 — 정답/오답 색상 구분, 선택지 정답 표시, 해설 출력
6.4 개인 학습 현황
- 프로필 — 이름, 아이디, 이메일, 레벨, 프로필 이미지, 합격 횟수, 총 학습 시간
- 핵심 통계 4칸 — 총 응시 / 합격 / 불합격 / 평균 정답률
- 전체 합격률 프로그레스 바
- 시험별 현황 — 최고점 프로그레스 바, 합격 여부, 마지막 결과 링크
- 자주 틀린 문제 TOP5 — 오답 횟수 순위
- 최근 응시 기록 테이블
- 반응형 — 768px 이하 2열, 640px 이하 테이블 가로 스크롤
6.5 접근 제어
| 상황 | 처리 |
| 비로그인 → 내 현황(/qbank/my) | 로그인 페이지로 리디렉트 |
| 재응시 불가 시험 재시도 | 이전 결과 안내 화면 출력 |
| 응시 기간 외 접근 | 기간 안내 화면 출력 |
| 존재하지 않는 시험 ID | 404 안내 화면 출력 |
7장. URL 구조
| URL | 설명 |
| /qbank | 시험 목록 메인 페이지 |
| /qbank?cat={카테고리ID} | 카테고리 필터링된 시험 목록 |
| /qbank/{시험ID} | 시험 응시 (시작 화면 또는 진행) |
| /qbank/{시험ID}/result/{응시ID} | 결과 확인 페이지 |
| /qbank/my | 개인 학습 현황 (로그인 필요) |
| /qbank/install | DB 테이블 설치 (관리자 전용) |
URL Rewrite가 비활성화된 환경에서는 index.php?_url=/qbank/... 형식으로 접근합니다.
8장. PHP 클래스 레퍼런스
8.1 DxQBank — 공통 유틸리티
| 메서드 | 반환값 | 설명 |
| DxQBank::db() | Database | DB 인스턴스 반환 |
| DxQBank::prefix() | string | qb_ prefix 반환 |
| DxQBank::url($path) | string | 프론트엔드 URL 생성 |
| DxQBank::adminUrl() | string | 관리자 URL 반환 |
| DxQBank::types() | array | 문제 유형 목록 반환 |
| DxQBank::difficulties() | array | 난이도 목록 반환 |
| DxQBank::getCategories() | array | 전체 카테고리 목록 |
8.2 DxQBankExam — 시험지
| 메서드 | 반환값 | 설명 |
| DxQBankExam::getList($opts) | array | 시험지 목록 조회 (페이징, 상태 필터) |
| DxQBankExam::get($id) | array|null | 시험지 단건 조회 |
| DxQBankExam::create($data) | int|false | 시험지 생성, 생성된 ID 반환 |
| DxQBankExam::update($id, $data) | bool | 시험지 수정 |
| DxQBankExam::delete($id) | bool | 시험지 삭제 |
| DxQBankExam::getQuestions($id) | array | 시험지 문제 목록 (선택지 포함) |
| DxQBankExam::startAttempt($id) | array|false | 응시 세션 시작 |
| DxQBankExam::saveAnswer($aid,...) | void | 답안 저장 |
| DxQBankExam::submit($aid) | bool | 응시 제출 + 자동 채점 |
| DxQBankExam::getAttemptAnswers($aid) | array | 응시 답안 목록 조회 |
8.3 DxQBankQuestion — 문제
| 메서드 | 반환값 | 설명 |
| DxQBankQuestion::getList($opts) | array | 문제 목록 (카테고리·유형·난이도 필터) |
| DxQBankQuestion::get($id) | array|null | 문제 단건 조회 (선택지 포함) |
| DxQBankQuestion::create($data) | int|false | 문제 생성 |
| DxQBankQuestion::update($id,$data) | bool | 문제 수정 |
| DxQBankQuestion::delete($id) | bool | 문제 삭제 |
| DxQBankQuestion::saveOptions($qid,$opts) | void | 선택지 저장 (기존 삭제 후 재삽입) |
9장. 설정 및 커스터마이징
9.1 이미지 업로드 경로
문제·해설·선택지 이미지는 아래 경로에 저장됩니다.data/uploads/qbank/YYYYMMDDHHmmss_xxxxxxxx.{확장자}
9.2 파일 크기 제한
기본값 5MB. admin/index.php의 이미지 업로드 처리 부분에서 수정 가능합니다.if ($__file['size'] > 5*1024*1024) { ... } ← 이 숫자를 변경
9.3 CSS 커스터마이징
- 프론트엔드 CSS 변수는 views/layout.php의 :root 블록에서 관리
- --primary: 주색상 / --success: 합격색 / --danger: 불합격색
- qb-* 클래스가 모든 UI 요소에 적용되어 있어 개별 오버라이드 가능
9.4 URL 슬러그 변경
기본 URL 슬러그는 /qbank 입니다. 변경하려면:- extend/top/00_qbank_router.php 의 슬러그 조건 수정
- plugin.php 의 관리자 링크 URL 수정
10장. 자주 묻는 질문 (FAQ)
A. 관리자에서 시험지를 생성하고 상태를 "진행중"으로 변경해야 합니다. 초안(draft) 상태는 사용자에게 노출되지 않습니다.
Q. 카테고리 필터 칩이 헤더에 보이지 않습니다.
A. qb_categories 테이블의 q_count 컬럼이 0인 카테고리는 필터에 표시되지 않습니다. 카테고리에 문제를 등록하면 자동으로 노출됩니다.
Q. 서술형 문제는 자동 채점이 안 되나요?
A. 서술형(essay) 유형은 자동 채점이 불가하며, 관리자 → 서술형 채점 메뉴에서 수동으로 점수를 입력해야 합니다. 채점 완료 후 합격 여부가 자동 판정됩니다.
Q. 이미지 업로드 시 "저장 실패" 오류가 납니다.
A. data/uploads/qbank/ 폴더의 쓰기 권한을 확인하세요. 폴더가 없는 경우 자동 생성을 시도하지만 권한 부족 시 실패할 수 있습니다.
Q. 기존 설치 환경에서 업데이트하면 DB가 초기화되나요?
A. 아니요. CREATE TABLE IF NOT EXISTS 방식이라 이미 존재하는 테이블은 변경되지 않습니다. 신규 컬럼 추가는 PHP로 컬럼 존재 여부를 확인 후 ALTER TABLE을 실행하므로 데이터가 유지됩니다.
라이선스
| 항목 | 내용 |
| 재배포·판매 | ❌ 금지 (원천 소스 90% 이상 수정 시 재배포 및 판매 가능) |
| 플러그인 원천 시스템 | DesignOneX 소유 |
| 상업적 사용 | ✅ 상업적 제작에만 허용, 학습용 |
| 라이선스 | 디자인원엑스 라이선스 |
⚠️ 플러그인 코어(plugin.php, core/, admin/) 자체의 재배포 및 판매는 금지됩니다.