| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- contextBridge
- 마이그레이션
- playwright
- typescript
- 아키텍처
- php
- React
- 인증
- 메일자동화
- 도메인설계
- electron
- 프론트엔드
- 크롤링
- 상태관리
- Vite
- sqlite
- JWT
- 배포
- next.js
- Android
- python
- FastAPI
- REST API
- 소셜로그인
- github actions
- javascript
- 보안
- Kotlin
- 백엔드
- 온디바이스AI
- Today
- Total
HM소프트
정답지 기반 자동 채점과 루브릭 설계 — 채점 플랫폼 (1) 본문

정답지 기반 자동 채점 엔진을 NestJS·Drizzle·BullMQ로 설계한 기록. auto_exact 정규화 정확 일치, 모범답안 기준 LLM 채점, all-or-nothing 게이트, 앵커 분류와 다중 표본 중앙값 투표, 재채점 변동 신뢰도 강등, 교사 승인 총점 재합산까지 자동화 정도를 조절한 결정들을 코드로 정리했다.
시리즈를 시작하며
학습 과제를 내고, 제출을 받고, 채점하고, 결과를 돌려주는 교육용 웹 플랫폼을 만들었다. 핵심은 채점을 자동화하는 것 — 정답지 기반 자동 채점과 루브릭, 그리고 AI 채점을 엮었다.
세 편으로 나눠 기록한다.
- (이 글) 정답지 기반 자동 채점과 루브릭
- 대시보드 집계 버그들 — "삭제된 과제"가 만든 함정
- 배포·운영 — Docker, 이미지 정리, 다국어
특정 기관·고객 정보는 빼고 구현만 다룬다.
채점 플로우의 전환: 수동 → 자동
처음엔 교사가 제출물을 보고 수동으로 채점을 트리거하는 구조였다. 이걸 정답지가 있는 과제는 제출과 동시에 자동 채점되도록 바꿨다. 교사의 수동 트리거를 없애니, 학생은 제출 즉시 결과를 받고 교사는 검토만 하면 된다.
[기존] 제출 → (교사 수동 채점 트리거) → 결과
[개편] 제출 → 자동 채점 → 결과 → (교사 검토/조정)
이 전환이 플랫폼의 흐름을 크게 단순화했다. 다만 자동 채점에는 "무엇을 정답으로 보느냐"가 필요했고, 그게 정답지와 루브릭이다.
문항 빌더와 채점 모드
과제는 문항으로 구성된다. 문항 빌더에서 문항 타입(객관식·구조화 답안 등)을 고르면, 그에 맞는 채점 모드가 붙는다. 여기서 UX 버그를 하나 잡았다: 문항 타입을 바꿔도 채점 모드가 이전 것으로 남아 있었다. 타입을 바꾸면 채점 모드를 리셋하도록 고쳤고, 객관식의 중복 옵션 UI도 정리했다.
function onQuestionTypeChange(next: QuestionType) {
setType(next);
setGradingMode(defaultGradingMode(next)); // 타입 변경 시 채점모드 리셋
}
루브릭 — 그리고 아카이브
서술형·구조화 답안은 루브릭(채점 기준표)으로 평가한다. 루브릭은 한 번 만들면 계속 쓰는데, 안 쓰는 루브릭이 선택 목록에 쌓이는 문제가 있었다. 그렇다고 삭제하면 과거 채점 기록과의 연결이 끊긴다.
그래서 아카이브(is_active) 방식을 택했다. 루브릭을 삭제하지 않고 비활성화한다. 선택 목록에서는 숨지만, 과거 기록은 유지되고, 되돌리기도 가능하다.
-- 삭제 대신 비활성화 (soft archive)
UPDATE rubric SET is_active = false WHERE id = :id;
-- 선택 목록은 활성만
SELECT * FROM rubric WHERE is_active = true;
이 "삭제 대신 비활성화" 패턴은 2편에서 다룰 대시보드 버그와도 직접 연결된다. 데이터를 진짜 지우지 않고 상태로 관리하면, 과거를 지키면서 현재를 깔끔하게 둘 수 있다.
AI 채점과 구조화 답안
자동 채점에는 AI 채점이 들어간다. 채점 리뷰 화면에서 구조화된 답안을 제대로 표시하도록 다듬었고, 결과가 아직 공개되지 않은 상태에서 폴링하다 발생하던 권한 오류(403)도 제거했다. AI 채점 프롬프트와 피드백 문구는 운영 일관성을 위해 표현을 통일했다.
정리하며
1편의 핵심은 채점의 자동화와 데이터 보존의 균형이다.
- 수동 트리거를 없애고 제출=자동채점으로 흐름을 단순화.
- 문항 타입과 채점 모드의 상태 동기화(타입 변경 시 리셋).
- 루브릭은 삭제가 아니라 아카이브(is_active) — 과거를 지키며 현재를 정리.
다음 2편에서는 이 "삭제하지 않고 상태로 관리"가 대시보드에서 일으킨 집계 버그들과 그 교훈을 다룬다.
'외주 개발일지' 카테고리의 다른 글
| Docker 배포 운영과 다국어 전환 구현 — 과제 채점 플랫폼 (3) (0) | 2026.06.12 |
|---|---|
| 대시보드 집계 버그 잡기 — 소프트 삭제와 '삭제된 과제' (2) (0) | 2026.06.12 |
| Next.js 15 + React 19 프론트엔드와 지도 UI — 채용 플랫폼 (3) (0) | 2026.06.12 |
| LLM 오케스트레이터로 이력서 피드백·초안 생성 — 채용 플랫폼 (4) (0) | 2026.06.12 |
| 이력서·자기소개서 엔티티 설계와 파일 업로드 — 채용 플랫폼 (2) (0) | 2026.06.12 |