신한대학교 시간표 마법사
2026.07 - 2026.09 · 기획, 프론트엔드 및 백엔드 개발, 인프라 운영
- Next.js
- TypeScript
- Tailwind CSS
- Express
- Playwright
- Zod
- Docker
개요
매 학기 학교 SAP에서 강좌를 하나씩 찾아가며 시간표를 맞추는 일이 번거로워서 직접 만든 서비스입니다. 듣고 싶은 과목을 바구니에 담고 공강일과 시간대, 학점 조건만 정하면, 시간이 겹치지 않는 시간표 조합을 자동으로 찾아 줍니다. 설계 단계에서 가장 먼저 정한 원칙은 사용자가 늘어나도 학교 서버에는 부담을 주지 않는 것이었습니다. 그래서 강좌 데이터는 빌드 시점에만 수집해 검증하고, 운영 중인 서버는 메모리에 올려 둔 데이터만 제공하도록 구성했습니다. 기획부터 데이터 수집, 프론트엔드와 백엔드, 배포와 운영까지 모든 과정을 혼자 진행했습니다.
기여도
프론트엔드 개발
100%강좌 찾기, 시간표 만들기, 내 시간표 화면부터 PNG와 PDF 내보내기까지, 사용자가 거치는 화면을 모두 개발했습니다.
백엔드 개발
100%강좌 검색 API와 시간표 조합 생성 API를 Express로 설계하고 개발했습니다.
데이터 수집
100%Playwright로 SAP 강좌 페이지를 수집하고 Zod로 검증해, 검증을 통과한 데이터만 서비스에 반영하는 카탈로그 생성 과정을 만들었습니다.
배포 및 운영
100%Docker, Jenkins와 Nginx로 프론트엔드와 백엔드를 각각 무중단 배포하도록 구성하고, 직접 운영하고 있습니다.
주요 작업
SAP 강좌 수집
Playwright로 SAP에 로그인한 뒤 학과와 마이크로디그리별 강좌를 병렬로 수집합니다. 수집한 데이터는 Zod로 검증한 뒤 JSON으로 저장하고, 수집이나 검증에 실패하면 기존의 정상 데이터를 그대로 유지해 잘못된 데이터가 서비스되지 않도록 했습니다.
강좌 검색 API
강좌명, 과목코드, 교수, 학과, 전공, 요일, 시간대, 학점을 조합해 원하는 강좌를 찾을 수 있는 검색 API를 만들었습니다. 조회 응답에는 Express의 ETag 설정과 Cache-Control을 적용해, 데이터가 바뀌지 않았다면 304로 응답하도록 했습니다.
시간표 조합 생성
바구니마다 분반 하나를 골라 시간이 겹치지 않는 조합을 찾는 탐색 알고리즘을 직접 설계했습니다. 공강일, 피하고 싶은 시간대, 학점 범위 조건을 탐색 과정에 함께 반영합니다.
강좌 찾기 화면
검색 조건을 URL 쿼리로 관리해, 새로고침하거나 링크를 공유해도 같은 검색 결과를 그대로 볼 수 있도록 만들었습니다. 해석할 수 없는 조건은 결과에서 제외하고 사용자에게 따로 안내합니다.
시간표 편집과 저장
자동으로 만든 조합을 보드에서 분반 단위로 직접 넣고 빼며 다듬을 수 있습니다. 확정한 시간표는 브라우저에 저장되고, 다른 탭에서 바뀐 내용도 곧바로 반영됩니다.
시간표 내보내기
시간표를 캔버스에 직접 그려 PNG와 PDF 파일로 저장할 수 있도록 만들었습니다. 화면과 내보낸 파일이 같은 칸 병합 규칙을 쓰도록 분리해, 두 결과가 서로 어긋나지 않게 했습니다.
담당 업무
- 서비스 기획과 화면 구성
- Next.js 기반 프론트엔드 개발
- Express 기반 강좌 검색, 시간표 조합 API 개발
- Playwright SAP 강좌 수집기 개발
- Zod 스키마 기반 데이터 검증
- Vitest 단위, 통합 테스트 작성
- Docker 실행 환경 구성
- Jenkins 배포 자동화
- Nginx 무중단 배포 및 서버 운영
문제 해결 과정
SAP 인증 화면 전환으로 강좌가 수집되지 않는 문제
문제학교 SAP의 개설과목 조회 화면이 로그인을 요구하도록 바뀌면서, 수집기가 로그인 화면에서 멈춰 강좌가 0건으로 수집되었습니다.
해결Playwright에 SAP 로그온 절차를 추가하고, 인증 후 달라지는 열 구성과 조회 조건 선택 방식에 맞춰 수집기를 수정했습니다. 또한 계정 정보가 없으면 수집을 시작하기 전에 설정 검증 단계에서 바로 중단하도록 만들어, 같은 원인으로 빈 데이터가 만들어지지 않게 했습니다.
병렬 수집 중 조회 결과가 섞이는 문제
문제수집 시간을 줄이려고 여러 페이지에서 병렬로 수집하자, 조회 조건이 반영되기 전의 표를 읽어 다른 학과의 강좌가 섞이거나 빈 결과가 저장되는 문제가 생겼습니다.
해결SAP 화면이 조회 후 표를 비동기로 다시 그린다는 점이 원인이었습니다. 조회 조건이 화면에 반영되고 표가 갱신된 것을 확인한 뒤에만 결과를 읽고, 갱신되지 않은 결과는 사용하지 않도록 막았습니다. 일시적인 오류는 재시도하고, 학교 서버에 부담을 주지 않도록 동시 수집 수를 1에서 8 사이로 제한했습니다.
시간표 조합 수 폭발
문제분반이 많은 과목을 여러 개 담으면 가능한 조합의 수가 기하급수적으로 늘어나, 응답이 끝나지 않을 수 있었습니다.
해결요일과 시간대처럼 강좌 하나만으로 판단할 수 있는 조건은 탐색 전에 걸러내고, 학점 초과와 시간 충돌은 탐색 중에 즉시 가지치기했습니다. 그리고 탐색 횟수에 상한을 두어, 상한에 도달하면 탐색을 멈추고 결과가 일부만 반환되었다는 사실을 함께 알리도록 만들었습니다.
iOS에서 요일 선택이 잘못 눌리는 문제
문제iOS에서 요일 칩을 빠르게 연달아 누르면, 방금 누른 칩이 아니라 직전에 누른 칩이 다시 눌리는 문제가 있었습니다.
해결iOS가 터치가 끝난 뒤 합성해 보내는 클릭 이벤트가 원인이었습니다. 합성된 클릭은 무시하고, 터치하는 시점에 바로 칩을 토글하도록 수정했습니다.
백엔드 재배포 후 연결이 끊기는 문제
문제백엔드 컨테이너를 다시 배포할 때마다 컨테이너 IP가 바뀌어, 프론트엔드가 백엔드에 연결하지 못했습니다.
해결두 컨테이너를 같은 Docker 네트워크에 연결하고, IP 대신 컨테이너 이름으로 백엔드에 접근하도록 바꿨습니다. 지정한 네트워크가 없으면 배포를 중단하도록 해서, 연결되지 않은 상태로 배포가 끝나는 상황도 막았습니다.
결과
- 2026학년도 2학기 강좌 1,676개를 수집해 서비스 중
- 운영 중에는 학교 서버에 요청하지 않는 읽기 전용 API 구성
- 백엔드 테스트 166개로 수집, 검색, 조합 규칙 검증
- 강좌 검색부터 조합 생성, 편집, 저장, 내보내기까지 한 흐름으로 완성
- Jenkins와 Nginx로 프론트엔드와 백엔드의 무중단 배포 자동화
AI 활용
- 개발 과정에서 AI 에이전트를 설계와 구현에 함께 활용했습니다. 저는 학교 강좌 정보를 시간표 서비스에서 활용하기 위한 요구사항을 정리하고, 데이터 수집 시점과 제공 방식, 개발 도구와 작업 범위를 직접 정했습니다.
- 예를 들어 DB 없이 빌드 시점에 강좌 데이터를 수집해 JSON으로 제공하는 구조는 AI와 함께 설계했습니다. AI가 데이터 모델과 API 구조, 구현 방안을 제안하면, 저는 요구사항에 맞춰 방향을 조정했습니다. 또한 작업을 하나의 큰 변경으로 처리하지 않고, 이슈와 PR, 작은 커밋 단위로 나누어 진행하도록 구성했습니다.
스크린샷

강좌 찾기 화면

시간표 자동 조합 화면

시간표 편집 화면

내 시간표 화면