서원대학교 e-campus, 확정 수강 시간표, 통합정보시스템 ERP를 한 대의 터미널에서 보는 비공식 학생 CLI입니다.
학교 연동은 lib/back 에 있고, 화면은 lib/front/tui 입니다. 웹 서버를 띄우지 않습니다. 이 프로세스가 학교 서버에 직접 접속합니다.
현재 버전은 v1.0.0 입니다.
서원대학교 공식 SDK가 아닙니다.
Node.js 22+ · TypeScript · 키보드 TUI · 학교 서버 직접 연동
실행 장면 · 핵심 기능 · 키보드 조작 · 실행 방법 · 문서
이 저장소는 seowon-client-web을 개발하고 확장하기 전에 학교 연동과 기능 흐름을 검증하는 MVP 성격의 터미널 클라이언트입니다. 먼저 CLI에서 실제 e-campus·시간표·ERP 응답과 예외 상황을 확인한 뒤, 여러 학생이 브라우저에서 사용하는 웹 기능으로 확장합니다.
seowon-cli: 단일 사용자·터미널 중심의 연동 검증, 기능 실험, 문제 사례 기록seowon-client-web: 검증된 기능을 여러 사용자와 웹 화면에 맞게 확장하는 제품 저장소- 이 저장소의 CLI 화면이나 내부 호출 구조가 웹 프로젝트의 최종 UI·API 구조를 그대로 의미하지는 않습니다.
학교 연동은 서비스별 클라이언트를 사용합니다.
| 구성 요소 | 위치 | 담당 역할 |
|---|---|---|
| e-campus LMS | ecampus.seowon.ac.kr · EcampusClient |
로그인, 과제·공지·자료·이러닝, 이번 학기 성적 |
| 확정 수강 시간표 | sugangh.seowon.ac.kr · CourseRegistrationClient |
확정 수강 목록으로 시간표 |
| 통합정보 ERP | info.seowon.ac.kr · ErpClient |
지난 학기 성적. 이번 학기 LMS 성적과 다름 |
| 조회 묶음 | lib/back/campus.ts |
로그인 세션 하나에서 메뉴가 부르는 함수 |
| 터미널 화면 | lib/front/tui |
메뉴, 표, 저장 폴더 선택 |
ERP ≠ e-campus 성적. 지난 학기는
info.seowon.ac.kr, 이번 학기 강의실 성적은ecampus.seowon.ac.kr입니다.
터미널
학번 · 비밀번호
│
▼
lib/front/tui/cli.ts
│
▼
lib/back/campus.ts 메모리 세션 하나
├─ client.cookieJar ecampus
├─ courseReg.cookieJar 시간표
└─ erp.cookieJar 지난 성적
자동 로그인은 .env의 SEOWON_SID · SEOWON_PW를 사용합니다. 테마 설정은 data/tui-config.json 에 저장됩니다.
추적 로그는 fetchAcademicOverview() 처럼 부른 함수 이름과 소요 시간이고, 그 아래에는 lib/back 기준 service · engine 파일을 적습니다.
| 기능 | 설명 |
|---|---|
| 🔑 로그인 | 학번 입력 또는 .env 의 SEOWON_SID · SEOWON_PW |
| 🔥 지금 할 것 | 지금 제출 기간의 미제출 과제와, 지금 학습 기간의 미학습 차시 |
| 📝 과제 | 전체 · 지금 할 수 있는 과제 · 미제출 · 제출한 과제. 제출과 파일 삭제 |
| 📢 공지 · 📁 자료 | 과목별 본문과 첨부. 저장 위치를 고른 뒤 받는다 |
| 💻 이러닝 | 전체 조회는 기간이 지난 차시도 포함. 수강하기는 이캠퍼스 메인. 학습률은 과목별 진도 방식과 대체 방식을 사용해 이력 중 가장 높은 값을 읽음 |
| 🗓️ 시간표 | 과목과 시간. PNG 저장은 과목 선택과 별도 메뉴 |
| 📊 성적 | 이번 학기는 e-campus, 지난 학기는 ERP 등급·평점 |
| 📌 전체 현황 | 기간과 관계없는 미제출 과제, 기간 안 미완료 차시. 0이 아니면 밝은 빨강 |
| ⚙️ 설정 | 테마 색, 메뉴를 바꿀 때 화면 지우기, 캐시 비우기 |
| 📚 문서 정리 (Dev) | README·docs 색인·버그 수정 기록 위치를 확인 |
| 🧪 함수 전수 조사 (Dev) | 개발용 함수 점검. 과제 제출과 로그아웃은 건너뜀 |
파일을 받을 때는 매번 폴더를 고릅니다. 그 폴더에서 s 를 누르면 저장하고, Esc 는 취소입니다. 첨부·영상·시간표 PNG 는 받는 동안 한 줄 진행 막대가 100%까지 찬 뒤 지워지고, 그 다음에 저장 결과가 나옵니다.
아래 이미지는 가상 과목·교수·강의실로 생성한 설명용 시간표입니다.
학번 로그인 또는 .env 로그인이 끝나면 아래 메뉴를 같은 세션으로 오갑니다. 2~9, C, T 는 로그인이 있어야 열립니다. 1 로그인, I 프로그램 정보, 0 종료는 로그인 전에도 있습니다.
flowchart TD
login["1. 학번 로그인 또는 .env 로그인"] --> mem["2. 로그인 세션"]
mem --> menu["3. 사이드바에서 메뉴를 고른다"]
menu --> lms["e-campus<br/>지금 할 것 · 과제 · 공지 · 자료 · 이러닝 · 이번 성적 · 전체 현황"]
menu --> tt["시간표<br/>과목 목록 또는 PNG 저장"]
menu --> erp["ERP<br/>지난 성적"]
lms --> stay["4. 같은 세션으로 다음 메뉴"]
tt --> stay
erp --> stay
stay --> close["5. 0 종료"]
close --> gone["메모리 세션 삭제"]
메뉴 구성은 다음과 같습니다.
사이드바
├── 1 🔑 로그인
│ ├── 1 학번 로그인
│ ├── 2 .env 로 로그인 SEOWON_SID · SEOWON_PW
│ ├── 3 로그아웃 이 프로세스 세션만 지움
│ └── 4 지금 할 것 보러 가기
├── 2 🔥 지금 할 것 지금 기간의 미제출 과제 + 미학습 차시
│ ├── 과제 행 → 과제 동작
│ └── 차시 행 → 학습률만 표시
├── 3 📝 과제
│ ├── 1 전체 과제
│ ├── 2 지금 할 수 있는 과제 제출 기간이 열린 미제출
│ ├── 3 미제출 과제 기간이 닫혀도 제출 파일이 없으면 포함
│ ├── 4 제출한 과제
│ └── 과제 동작
│ ├── v 상세 다시 보기
│ ├── a 참고첨부 다운로드
│ ├── s 제출파일 다운로드
│ ├── u 파일 제출 · 업로드
│ ├── x 제출파일 삭제 후 반영
│ ├── n 제출파일 이름 변경 후 반영
│ └── b 뒤로
├── 4 📢 공지 목록 → 본문 → 첨부 저장
├── 5 📁 강의실 자료 목록 → 첨부 저장
├── 6 💻 이러닝
│ ├── 1 전체 조회 기간이 지난 차시도 포함. 퍼센트는 안 물음
│ ├── 2 들을 차시 지금 학습 기간의 미학습·학습중만
│ ├── 3 학습률 전체 조회와 같은 차시. 퍼센트만 추가
│ └── 차시 동작
│ ├── s 수강하기 이캠퍼스 메인 열기
│ ├── d 영상 다운로드
│ └── b 뒤로
├── 7 🗓️ 시간표
│ ├── 1 과목 목록 과목 · 시간 · 교수 · 학점 · 구분
│ └── 2 PNG 저장 폴더를 고른 뒤 timetable.png
├── 8 📊 성적
│ ├── 1 현재 성적 (e-campus) 과목 · 등급 · 총점 · 조회 가능 여부
│ └── 2 지난 성적 (ERP) 학기 → 과목(구분 · 학점 · 등급 · 평점)
├── 9 📌 전체 현황
│ ├── 1 전체 과목 (교과+비교과)
│ ├── 2 교과 과목만
│ └── 3 비교과 과목만 미제출 과제 · 미완료 차시. 0이 아니면 밝은 빨강
├── C ⚙️ 설정
│ ├── 1 캐시 비우고 다시 조회
│ ├── 2 로그아웃
│ ├── 3 TUI 테마 색
│ └── 4 메뉴 전환 시 화면 지우기
├── I 🔬 프로그램 정보 언어 · 화면 · 통신 · 로그인 상태
├── D 📚 문서 정리 (Dev) README · docs · 버그 수정 기록 위치
├── T 🧪 함수 전수 조사 (Dev) 개발용 함수 점검. 제출·로그아웃은 건너뜀
└── 0 🚪 종료
사이드바는 그 세션 위에서 이렇게 갈라집니다.
flowchart TD
side["사이드바"] --> login["1 로그인"]
side --> todo["2 지금 할 것"]
side --> asg["3 과제"]
side --> ntc["4 공지"]
side --> mat["5 강의실 자료"]
side --> les["6 이러닝"]
side --> tt["7 시간표"]
side --> score["8 성적"]
side --> sum["9 전체 현황"]
side --> cfg["C 설정"]
side --> info["I 프로그램 정보<br/>언어 · 화면 · 통신 · 로그인 상태"]
side --> docs["D 문서 정리 (Dev)<br/>README · docs · 버그 수정 기록 위치"]
side --> test["T 함수 전수 조사 (Dev)<br/>개발용 함수 점검. 제출·로그아웃은 건너뜀"]
side --> exit["0 종료"]
flowchart TD
login["1 로그인"] --> id["학번 로그인"]
login --> env[".env 로 로그인<br/>SEOWON_SID · SEOWON_PW"]
login --> out["로그아웃<br/>이 프로세스 세션만 지움"]
login --> jump["지금 할 것 보러 가기"]
todo["2 지금 할 것<br/>지금 기간의 미제출 과제 + 미학습 차시"] --> rowAsg["과제 행"]
todo --> rowLes["차시 행"]
rowAsg --> asgAct["과제 동작"]
rowLes --> pct["학습률만 표시"]
asg["3 과제"] --> all["전체 과제"]
asg --> due["지금 할 수 있는 과제<br/>제출 기간이 열린 미제출"]
asg --> miss["미제출 과제<br/>기간이 닫혀도 제출 파일이 없으면 포함"]
asg --> done["제출한 과제"]
all --> asgAct
due --> asgAct
miss --> asgAct
done --> asgAct
asgAct --> v["v 상세 다시 보기"]
asgAct --> a["a 참고첨부 다운로드"]
asgAct --> s["s 제출파일 다운로드"]
asgAct --> u["u 파일 제출 · 업로드"]
asgAct --> x["x 제출파일 삭제 후 반영"]
asgAct --> n["n 제출파일 이름 변경 후 반영"]
asgAct --> b["b 뒤로"]
flowchart TD
ntc["4 공지"] --> ntcBody["본문"]
ntcBody --> ntcFile["첨부 저장"]
mat["5 강의실 자료"] --> matFile["첨부 저장"]
les["6 이러닝"] --> allLes["전체 조회<br/>기간이 지난 차시도 포함. 퍼센트는 안 물음"]
les --> watch["들을 차시<br/>지금 학습 기간의 미학습·학습중만"]
les --> ratio["학습률<br/>전체 조회와 같은 차시. 퍼센트만 추가"]
allLes --> act["차시 동작"]
watch --> act
ratio --> act
act --> play["s 수강하기<br/>이캠퍼스 메인 열기"]
act --> video["d 영상 다운로드"]
act --> back["b 뒤로"]
tt["7 시간표"] --> subjects["과목 목록<br/>과목 · 시간 · 교수 · 학점 · 구분"]
tt --> png["PNG 저장<br/>폴더를 고른 뒤 timetable.png"]
score["8 성적"] --> cur["현재 성적 e-campus<br/>과목 · 등급 · 총점 · 조회 가능 여부"]
score --> past["지난 성적 ERP"]
past --> term["학기"]
term --> subj["과목<br/>구분 · 학점 · 등급 · 평점"]
sum["9 전체 현황<br/>미제출 과제 · 미완료 차시. 0이 아니면 밝은 빨강"] --> both["전체 과목 교과+비교과"]
sum --> curr["교과 과목만"]
sum --> extra["비교과 과목만"]
cfg["C 설정"] --> cache["캐시 비우고 다시 조회"]
cfg --> bye["로그아웃"]
cfg --> theme["TUI 테마 색"]
cfg --> clear["메뉴 전환 시 화면 지우기"]
파일을 받는 자리(참고첨부, 제출파일, 공지·자료 첨부, 영상, 시간표 PNG)는 모두 폴더를 고릅니다. 그 폴더에서 s 가 저장, Esc 가 취소입니다.
키보드만 씁니다. 마우스로 메뉴를 고르지 않습니다.
| 조작 | 동작 |
|---|---|
| 숫자 · 단축키 | 사이드바 이동 |
| ↑↓ Enter | 목록에서 고르기 |
| PageUp · PageDown | 표 목록과 공지 본문에서 페이지 이동 |
| Home · End | 공지 본문의 처음·마지막으로 이동 |
/ |
목록 검색 |
| Esc | 이전 화면. 메인에서 Esc 면 종료 |
q |
표 목록·공지 본문에서 이전 화면 |
| 비밀번호 | 학번 로그인에서 입력 중 *, Enter 뒤 입력완료 |
| 저장 | 폴더를 고른 뒤 s |
선택 줄은 배경을 끝까지 깔지 않습니다. 목록 칸은 그대로 그리고, 고른 줄의 글자만 테마 색으로 바꿉니다.
공지 상세는 기존 상자 틀 안에서 본문을 줄바꿈해 표시합니다. 긴 본문은 방향키나 PageUp·PageDown으로 끝까지 읽습니다. 제목과 정확히 같은 본문 첫 줄은 화면에서 제외하고, 나머지 내용은 그대로 표시합니다. Enter는 첨부가 있으면 파일 목록을 열고, 첨부가 없으면 공지 목록으로 돌아갑니다.
이러닝 전체 조회와 학습률은 같은 차시 범위이고, 지금 수강 기간이 아닌 차시도 포함합니다. 전체 조회는 수강하기·영상 받기이고, 학습률만 퍼센트를 묻습니다. 학습률은 그 과목 이러닝 목록의 학생 번호와 진도 방식으로 이력을 읽고, 표에 있는 값 중 가장 높은 퍼센트입니다. 목록 폼이나 특정 진도 방식이 실패해도 표준 진도 방식을 순서대로 재시도합니다. 이력이 없을 때만 0%입니다. 들을 차시만 지금 학습 기간의 미학습·학습중입니다.
출결이 비어 있거나 이미 다 들은 경우에는 차시 N건을 전부 수강하였습니다.처럼 그 상황을 보여 줍니다. 수강하기는 브라우저에서 이캠퍼스 메인(https://ecampus.seowon.ac.kr/home/mainHome/Form/main)을 엽니다.
시간표 과목 목록은 시간만 보여 줍니다. PNG 저장을 따로 고르면 폴더를 지정해 그림을 받습니다. SVG·HTML 파일은 만들지 않습니다.
프로그램 정보는 TypeScript, Node.js 22, 자체 터미널 메뉴, axios, cheerio 를 적습니다. 화면용 웹 프레임워크는 쓰지 않습니다.
C 설정 → 3 TUI 테마 색에서 테마를 미리 보고 저장합니다. 목록의 선택 글자와 표의 강조색을 취향에 맞게 바꿀 수 있습니다.
테마 22종을 미리 보고 취소하거나 선택한 테마를 저장할 수 있습니다.
각 테마의 색상 견본은 선택 여부와 관계없이 해당 팔레트로 표시됩니다. 작은 창에서는 선택 항목이 보이도록 목록이 스크롤되고, 표의 열 너비와 표시 행 수도 터미널 크기에 맞춥니다. NO_COLOR가 설정되어 있으면 색을 출력하지 않습니다.
seowon-cli/
├── lib/
│ ├── back/ 학교 연동과 조회
│ │ ├── campus.ts 세션 하나. 메뉴가 부르는 함수
│ │ ├── filters.ts 기간 · 미제출 · 미학습 · 학습률 판별
│ │ ├── engine/ 로그인 · 쿠키 · 원본 프로토콜
│ │ │ ├── ecampus/ 과제 · 공지 · 자료 · 이러닝 · 이번 성적
│ │ │ ├── erp/ 지난 성적
│ │ │ ├── course-registration/ 확정 수강 · 시간표
│ │ │ └── hope-basket/ 시간표 그림에 쓰는 공통 처리
│ │ ├── services/ 화면이 쓰는 목록·제출·성적
│ │ └── types/
│ └── front/
│ └── tui/ 터미널 메뉴
│ ├── cli.ts 진입점
│ ├── tui-kit.ts 표 · 색 · 폴더 선택
│ └── tui-actions.ts 저장 · 제출 · 다운로드
├── docs/
│ ├── media/ 가상 시간표 예시
│ ├── cases/ 문제 사례
│ └── BUGFIX_LOG.md 버그 수정 기록
├── scripts/copy-legacy.mjs 빌드 때 로그인 암호화 파일 복사
├── cli.bat
├── 외부저장소-강제최신화.bat 원격 main 상태로 강제 동기화
└── package.json
| 파일 | 담당 기능 |
|---|---|
lib/back/engine |
학교와 직접 통신 |
lib/back/services |
스냅샷 · 제출 · 성적 · 시간표 |
lib/back/campus.ts |
메뉴가 부르는 함수. 웹 API가 아님 |
lib/front/tui/cli.ts |
학생 메뉴 |
cli.bat |
Windows에서 설치 후 같은 메뉴 실행 |
외부저장소-강제최신화.bat |
원격 origin/main으로 강제 동기화. 배포·빌드는 수행하지 않음 |
모듈은 ESM ("type": "module") 입니다. 언어는 TypeScript 이고 Node.js 22 이상에서 실행합니다. 화면은 웹 프레임워크 없이 lib/front/tui 가 그립니다. 학교 페이지는 axios, HTML 은 cheerio, 시간표 PNG 는 @resvg/resvg-js 입니다. 공개 함수는 한국어 JSDoc(@param / @returns)을 씁니다.
| 환경 변수 | 기본 | 설명 |
|---|---|---|
SEOWON_SID |
없음 | 자동 로그인 학번 |
SEOWON_PW |
없음 | 자동 로그인 비밀번호 |
.env.example을 참고해 로컬 .env에 로그인 값을 설정합니다.
| 옵션 | 설명 |
|---|---|
| 로그인 | 마스킹 입력창 또는 .env 사용 |
--suite all |
함수 전수 조사를 바로 실행 |
--depth <n> |
상세·첨부 조사 건수. 기본 3, 정수 1~100 |
--heavy |
상세를 전체 행까지. --write 와 함께 영상도 받음 |
--write |
시간표와 첨부 하나를 저장. 폴더를 직접 고름 |
--timeout <ms> |
함수 제한 시간. 기본 90000, 1000~300000ms |
--verbose |
결과 종류·개수 등 메타정보만 출력 |
--list |
조사하는 함수 이름과 하는 일 |
--help |
도움말 |
필요 환경은 Node.js 22 이상입니다. seowon-client-web 을 띄울 필요가 없습니다.
cli.batnode_modules 가 없으면 잠금 파일 기준으로 npm ci 한 뒤 메뉴를 엽니다. 설치가 실패하면 메뉴를 실행하지 않고 실패 종료 코드를 반환합니다.
cli.bat은 UTF-8 코드 페이지를 설정하고 Windows 줄바꿈(CRLF)을 사용합니다. Git에서 받아도 같은 줄바꿈을 유지하도록 .gitattributes에 지정했습니다. 주석이 명령어로 실행되던 오류의 원인과 검증은 CASE-021에 기록했습니다.
cli.bat --help
rem .env에 로그인 값을 설정한 뒤 실행
cli.bat --suite allnpm install
npm run api-cli| 명령 | 하는 일 |
|---|---|
npm run api-cli |
tsx 로 lib/front/tui/cli.ts 실행 |
npm run dev |
같은 진입점 |
npm run typecheck |
타입만 검사 |
npm run build |
검증된 dist 정리 후 tsc 및 로그인 암호화 파일 복사 |
npm start |
node dist/front/tui/cli.js |
대화형 메뉴는 TTY 가 필요합니다. 조사가 끝나면 프로세스가 종료됩니다.
- 이러닝 시청 기록(
watchLesson)은 보내지 않습니다. 수강하기는 이캠퍼스 메인만 엽니다. - 함수 전수 조사 (Dev)는 과제를 제출하지 않고, 조사 끝에 로그아웃하지 않습니다.
--write와 메뉴의 저장은 고른 폴더에만 씁니다.
- ✅ 학교 서버 직접 접속. 웹 API 서버 없음
- ✅ e-campus 과제·공지·자료·이러닝·이번 학기 성적
- ✅ 미제출 과제는 기간이 닫혀 있어도 제출 파일이 없으면 미제출
- ✅ 확정 수강 시간표 PNG
- ✅ ERP 지난 성적 등급·평점
- ✅ 과제 제출과 제출 파일 삭제
- ✅ 저장할 때마다 폴더 선택
- ✅ 테마 색
- ✅ 조회 함수 전수 조사 (Dev). 함수가 하는 일과 service · engine 파일
- ✅
.env학번·비밀번호 로그인 - ✅ 학번 로그인 비밀번호 입력은
*로 가림 - ✅ 다운로드는 한 줄 진행 막대. 100% 뒤 그 줄은 지움
- ✅ 선택 줄은 글자색만 테마 색. 배경은 줄 끝까지 깔지 않음
- ✅ 학습률은 강의실의 학생 번호·진도 방식으로 조회
문서는 기능 설명, 실행 방법, 동작 범위, 문제 사례와 버그 수정 기록으로 나눠 관리합니다. 구현이 바뀌면 README의 메뉴·동작 설명과 docs/ 사례 색인을 함께 갱신합니다.
| 저장소 | 역할 |
|---|---|
| seowon-cli | 개발·확장 전 MVP. 한 대에서 학교 연동과 기능을 검증 |
| seowon-client-web | MVP에서 검증한 기능을 여러 학생용 브라우저 서비스로 확장 |
| seowon-client-api | 학교 연동 원본. 이 CLI 실행에는 필요 없음 |
MIT. 수업용 비공식 클라이언트입니다.
.env로그인에서otpLogin=N,otpUserYn=Y인 정상 응답을 추가 인증으로 잘못 판단하던 문제를 수정했습니다. 실제 OTP가 필요한 응답과 OTP 이동 경로는 계속 구분합니다. (CASE-015)- 테마 견본 색이 사라지고 작은 창에서 메뉴·표가 밀리던 문제를 수정했습니다. 숫자 팔레트로 견본을 그리고, 창 크기에 맞춰 목록 스크롤·표 너비·화면 지우기를 처리합니다. (CASE-023)
- 공지의 기존 상자 UI를 유지하면서 긴 본문 전체를 읽도록 했습니다. 제목과 같은 첫 줄은 화면에서만 제외하고, 별도 본문이 없으면 안내를 표시합니다. (CASE-022)
- 위 패치를 포함한 최종 검증은 테스트 99개, 타입 검사와 빌드 통과입니다. 실제 CLI의 로그인·조회·설정·파일 저장을 확인했으며, 같은 세션의 함수 조사에서 27건 성공·0건 실패였습니다. 상세 기록은 버그 수정 로그에 있습니다.
- 공지 상세에서 제목과 공유 메뉴가 본문에 섞이던 문제를 수정했습니다. 실제 본문 영역을 읽고, 짧거나 빈 본문과 중첩된 HTML을 올바르게 처리합니다. (CASE-022)
cli.bat의 한글 주석이 명령어처럼 실행되던 Windows 실행 오류를 수정했습니다. UTF-8 코드 페이지와 CRLF 줄바꿈을 적용하고, 의존성 설치 실패 시 종료 코드를 반환하도록 정리했습니다. (CASE-021)- 로그인 메뉴
1 학번 로그인의 비밀번호 입력을*로 가립니다. Enter 뒤에는 같은 줄이입력완료로 바뀌어 비밀번호가 화면에 남지 않습니다. (CASE-020) 외부저장소-강제최신화.bat를 추가했습니다. 원격origin/main을 로컬에 강제 동기화합니다. 의존성 설치·빌드는 수행하지 않습니다.- 개발 도구 메뉴에
문서 정리 (Dev)를 추가해 README·docs 색인·버그 수정 기록 위치를 CLI에서 확인할 수 있습니다. - 과목별 과제·이러닝 조회를 병렬화하고, 제출파일 스냅샷 갱신 인덱스를 재사용하도록 내부 조회 흐름을 최적화했습니다.
- 공통 동시성 제한 함수에 잘못된 제한값 보정과 관련 주석을 추가했습니다.
학습률 · 차시마다 퍼센트 조회는 퍼센트 필드가 없는 e-campus 응답도학습 인정 시간 ÷ 차시 길이로 계산합니다.- 빈 학습 이력 응답을 즉시
0%로 확정하지 않고 대체 조회를 계속합니다. - 개발용 메뉴는
함수 전수 조사 (Dev)로 표시하며, 문서 정리는docs/README.md와docs/BUGFIX_LOG.md에서 관리합니다. - 실제
.env로그인 세션으로 학습률 조회 차시를 검증했습니다.
