레벨테스트 신청
TESOL-LEVEL-TEST · /tesol-lab/level-test
기능
8
API 호출
1
가드레일
8
id 가 테스트 이름
구현 단계
7 / 7
개발 스펙
이 화면에서 할 수 있어야 하는 것 (4)
- STEP01 신청 — 비로그인으로 성명 · 연락처 · 이메일 · 카카오ID · 문의내용 · 상담시간대 · 약관동의를 넣는다.
- STEP02 응시 — 객관식 10문항(보기 선택) + 주관식 5문항(단어 배열)을 푼다. 합쳐서 15문항이 만점이다.
- 제출하면 정답 수를 보여주고 컨설팅 안내로 이어진다.
- 문항 수는 DB(level_test_list q1~q20)에 채워진 만큼 따른다. 하드코딩하지 않는다.
비즈니스 규칙 (11)
- 비로그인으로 신청하고 응시한다.근거: tesolLab/leveltest.php
- 신청은 apply 테이블에 type=tfrm 으로 쌓인다(현재 6,483건).근거: leveltest_v_01.php:111 hidden ap_type
- 문의내용 · 카카오ID · 상담요일 · 상담시간은 apply 의 content · kakaoid · day_type · time_range 에 들어간다.근거: leveltest_v_01.php:119~157, leveltest_form_v_01_proc.php:247
- q1~q10 은 객관식, q11~q20 은 주관식이다. 문항 성격을 번호로 가른다 — 보기 유무로 판정하면 안 된다.근거: leveltest_form_v_01.php:1002(`$x < 11`) · 1051(`$k = 11; $k < 21`)
- 주관식도 정답이 있어 함께 채점한다. 만점은 객관식 + 주관식 = 15점이다.근거: leveltest_form_v_01_proc.php:147 — E[] 하나로 순회하며 ltRight$i 판정
- 답안은 객관식 · 주관식 구분 없이 level_test_answer 한 행의 a1~a20 에 저장한다. 실데이터 295건 중 294건이 a11 이상을 채우고 있다.근거: leveltest_form_v_01_proc.php:145
- level_test_poll_answer 는 **설문(Polls)** 용이다. 주관식 답안을 여기 넣으면 안 된다.근거: leveltest_form_v_01_proc.php:171 — $clean_post["Polls"]
- 채점은 공백을 전부 지우고 비교한다. 대소문자와 문장부호는 구분한다.근거: leveltest_form_v_01_proc.php:152 `str_replace(" ", "", ...)`
- 정오는 원본과 같이 right1~right20 에 O · X 로 남긴다.근거: leveltest_form_v_01_proc.php:157
- 같은 접수번호로 두 번 제출할 수 없다.근거: leveltest_form_v_01_proc.php:141 "이미 등록된 답안지입니다."
- 객관식 보기는 한 칸에 콤마(또는 ^)로 이어져 있어 분해해 쓴다: "intersect, collapse, distribute, coexist".근거: level_test_examples.exam1~exam20, leveltest_form_v_01.php:1017
API (3)
| 메서드 | 경로 | 권한 | 모듈 · 설명 |
|---|---|---|---|
GET | /api/assessment/level-test | 공개 | 문항. questions(객관식) · subjectiveQuestions(주관식) · total(만점). 정답은 담기지 않는다. domains:assessment:assessment-web404 LEVEL_TEST_NOT_FOUND |
POST | /api/assessment/level-test/applications | 공개 | STEP01 신청 접수 → applyId 반환. domains:assessment:assessment-web400 INVALID_INPUT |
POST | /api/assessment/level-test/submissions | 공개 | 답안 제출(객관식+주관식 통합) → { rightCount, total }. domains:assessment:assessment-web400 ALREADY_SUBMITTED |
가드레일 (8) — id 가 곧 테스트 이름이다
| id | 반드시 만족해야 하는 것 | 등급 |
|---|---|---|
leveltest-no-login-required | 비로그인 상태에서 신청과 응시가 모두 가능해야 한다. | high |
leveltest-step2-exists | 신청 후 실제 문제 풀이 화면으로 이어져야 한다. 신청 폼만 있고 끝나면 안 된다. 원본 tesolLab/leveltest_form_v_01.php 대응. | high |
leveltest-answer-not-leaked | 문항 조회 응답에 정답이 절대 실리면 안 된다. | critical |
leveltest-subjective-graded | 주관식도 채점 대상이다. 만점이 객관식 개수(10)로 잘리면 안 된다 — 15 여야 한다. 실데이터 level_test_answer.right_count 최대 15. | critical |
leveltest-subjective-in-answer-table | 주관식 답안이 level_test_answer.a11~a20 에 저장돼야 한다. level_test_poll_answer 는 설문용이므로 쓰면 안 된다. | critical |
leveltest-whitespace-tolerant | 주관식 답의 띄어쓰기가 달라도 정답으로 인정해야 한다. 공백을 모두 지우고 비교한다. | high |
leveltest-no-resubmit | 같은 접수번호로 두 번째 제출은 거절해야 한다. | high |
leveltest-question-count-from-db | 문항 수는 DB 에 채워진 개수를 따른다. 20개 고정으로 렌더해 빈 문항이 나오면 안 된다. | high |
구현 계획 (7/7)
- ●LevelTest(객관식·주관식 분리) · LevelTestResult · LevelTestGrader · LevelTestRepository 정의
assessment-domain - ●LevelTestUseCase — paper · apply · submit(재제출 차단 포함)
assessment-app - ●LevelTestRepositoryAdapter — q1~q20 평탄화 컬럼, 번호로 객관식/주관식 분기
assessment-infrastructure - ●LevelTestController — 조회 · 신청 · 제출 3 엔드포인트
assessment-web - ●STEP01 신청 폼 실동작 전환(목업 readOnly 제거)
wvctesol - ●STEP02 응시 화면 · 결과 화면 신설
wvctesol - ●Next.js 를 BFF 로 전환 — Prisma 직접 접근 제거
wvctesol
서버 사이드 구현 계획 — 자바 객체별 요구사항 (6/6)
| 객체 | 모듈 | 책임 · 지켜야 할 것 |
|---|---|---|
● LevelTestrecord | assessment-domain | 레벨테스트 시험지. 문항만 담고 정답은 담지 않는다.
|
● LevelTestGraderclass | assessment-domain | 객관식 · 주관식 통합 채점.
|
● LevelTestRepositoryinterface | assessment-domain | 저장소 포트.
|
● LevelTestUseCaseservice | assessment-app | 조회 · 신청 · 제출 유스케이스.
|
● LevelTestRepositoryAdapterclass | assessment-infrastructure | q1~q20 로 펼쳐진 레거시 컬럼을 다루는 유일한 지점.
|
● LevelTestControllercontroller | assessment-web | HTTP 경계. 전부 비인증.
|
테스트 방법 (8)
| 가드레일 | 종류 | 확인 방법 |
|---|---|---|
leveltest-no-login-required | e2e | 쿠키 없이 신청 · 문항 조회 · 제출 3 단계가 모두 200 |
leveltest-step2-exists | e2e | STEP01 제출 후 /tesol-lab/level-test/exam?apply=<id> 로 이동하고 객관식 10 + 주관식 5 가 렌더된다 |
leveltest-answer-not-leaked | integration | GET /api/assessment/level-test 응답 JSON 에 answer · correct 계열 필드가 없다 |
leveltest-subjective-graded | integration | 정답 15개를 그대로 제출 → rightCount=15, total=15 |
leveltest-subjective-in-answer-table | integration | 제출 후 level_test_answer 의 a11~a15 와 right11~right15 가 채워진다 |
leveltest-whitespace-tolerant | unit | "I want to buy a couple of things." 를 제출해도 정답 처리 |
leveltest-no-resubmit | integration | 같은 applyId 로 재제출 → 400 ALREADY_SUBMITTED |
leveltest-question-count-from-db | e2e | 응시 화면의 입력 name 이 a_1~a_15 만 존재하고 a_16 이상은 없다 |
정하지 못한 것 · 확인이 필요한 것
- 원본에는 응시 후 **설문(Polls)** 단계가 더 있다(Frame46.png 이후, level_test_poll · level_test_poll_answer). 아직 구현하지 않았다 — 별도 작업으로 뺄지 결정 필요.
- 원본에 step1~4 분할 버전도 있지만 step5.php 가 없어 미완성이다. 운영본은 leveltest_form_v_01.php.
스냅샷

기능 목록 (8)
데이터
- ·API 조회
/api/marketing/content/tesol-lab/level-test
입력
- ·폼
1개 - ·제출 버튼
1개 - ·입력 필드
8개
액션
- ·서버 액션
applyForLevelTest
상태
- ·화면 상태
prefix, mid, last
하드코딩
- ·하드코딩 데이터
phone - ·하드코딩 데이터
answers
화면 이동
← 이 화면으로 오는 곳
TESOL-LEVEL-TEST-EXAM/tesol-lab/level-test/examGNB
이 화면에서 가는 곳 →
PRIVACY/privacyTESOL-LEVEL-TEST-EXAM/tesol-lab/level-test/examTESOL-LEVEL-TEST-RESULT/tesol-lab/level-test/result
연결
API
/api/marketing/content/tesol-lab/level-test
소스
src/app/tesol-lab/level-test/page.tsx