대진대학교 개설과목을 검색하고, 수동으로 시간표를 편집하거나 조건에 맞는 시간표 후보를 만드는 비공식 수강 계획 도구입니다. 과목 선택부터 공강·학점 조정, 이수내역과 졸업요건 확인까지 한 화면 흐름으로 연결합니다.
2026-09-30 공개 서비스에서 캡처한 비로그인 초기 화면입니다. 개인 시간표나 이수내역은 포함하지 않았습니다.
학교 공식 서비스가 아닙니다. 개설과목과 졸업요건 결과는 참고용이며, 실제 수강신청 전 학교 포털·최신 교육과정편람·소속 학과 안내를 확인해야 합니다.
시간이 겹치지 않는 분반을 찾는 것만으로 수강 계획이 끝나지는 않습니다. 필요한 학점, 공강 요일, 하루 수업 배치와 전공필수 이수 여부도 함께 살펴야 합니다. timeTabler는 직접 고른 과목을 우선하면서, 나머지 조합을 자동완성으로 비교할 수 있게 구성했습니다.
- 과목명·교수·과목코드·이수구분·요일로 개설과목을 검색합니다.
- 바로 듣고 싶은 분반은 현재 시간표에, 조합을 비교할 과목은 자동완성 후보에 담습니다.
- 학점·공강 요일·수업 시간대 조건을 정하고 후보 3개를 비교합니다. 반영되지 못한 선호 조건도 함께 확인합니다.
- 시간표를 브라우저에 저장하거나 URL로 공유하고, PNG·인쇄/PDF로 내보냅니다.
로그인 없이 시간표 작성·자동완성·저장·공유·내보내기를 사용할 수 있습니다. 학교 이메일 OTP 로그인은 운영 환경에 메일 발송 자격 증명이 구성된 경우에만 표시됩니다.
| 영역 | 할 수 있는 일 |
|---|---|
| 시간표 편집 | 분반 추가·교체·삭제, 드래그 앤 드롭, 필수·희망·예비·제외 역할 설정, 실행 취소·다시 실행 |
| 조건별 자동완성 | 목표·최소·최대 학점, 공강·제외 요일, 이른/늦은 수업, 점심 여유, 하루 수업시간·공강 길이·현재 선택 유지 선호 반영 |
| 충돌과 대안 | 시간 충돌 경고, 교체 가능한 분반 제안, 후보별 등교일·첫/마지막 수업·미반영 조건 설명 |
| 학업과 강의 기록 | 학과·입학연도별 전공필수와 졸업요건 점검, 과거 강의계획서 검색, 내 학업에서 이수내역·저장 시간표·계정 관리 |
| 모바일과 접근성 | 건너뛸 수 있는 학과·학년 온보딩, 바텀시트, 키보드 조작, 라이트·다크 테마, PWA와 오프라인 직접 경로 fallback |
- 편집과 탐색의 분리: 현재 시간표와 자동완성 후보를 별도로 관리합니다. 후보는 분반이 아닌 과목 단위로 담아 여러 조합을 탐색합니다.
- 제약 조건으로 시간표 모델링: OR-Tools CP-SAT가 충돌·필수과목·학점을 제약으로 다루고, 공강과 수업 시간대 선호를 반영한 결정론적 후보를 만듭니다. 계산은 API와 분리된 worker에서 처리합니다.
- 데이터 버전 일치: API와 브라우저 정적 fallback은 같은
datasetVersion을 사용합니다. 오래된 브라우저 데이터와 새 카탈로그가 섞이지 않도록 요청 시 버전을 확인합니다. - 판정 근거 보존: 교육과정 자료의 출처·학과명·입학연도와 원문 위치를 보존합니다. 공식 근거만으로 확정할 수 없는 예외는 자동 충족으로 처리하지 않습니다.
- 공개 최적화 API의 작업 관리: 요청별 rate limit, 활성 작업 상한, lease 복구·취소·만료 정리로 최적화 작업의 수명과 부하를 관리합니다.
| 자료 | 저장소에 포함된 범위 |
|---|---|
| 활성 개설과목 | 2026-1 학기 1,576개 분반 |
| 교육과정 | 2016~2026 입학연도별 712개 단위, 전공기초·전공필수 2,944과목 |
| 졸업요건 | 2020~2026 학과·입학연도·전공경로별 789개 최저학점 프로필, 교양필수 52개 연도별 레코드 |
| 과거 강의 | 2020~2026 정규·계절학기 20,031개 분반과 강의계획서 원본 |
활성 카탈로그의 기준 학기는 2026-1이며, 최신 학기의 개설 현황을 보장하지 않습니다. 입학연도·학과별 전공필수 점검은 이 카탈로그의 실제 개설 분반과 연결합니다. 데이터 출처와 판정 한계는 아래에 별도로 정리했습니다.
browser → Nginx/React web → FastAPI → PostgreSQL ← OR-Tools worker
├── versioned active catalog files
└── lossless DREAMS history archive
프론트, API/optimizer, DB는 한 이미지에 섞지 않습니다. compose.yaml이 다음 서비스를 같은 방식으로 재현합니다.
| 서비스 | 역할 |
|---|---|
web |
React 정적 앱과 Nginx reverse proxy |
api |
FastAPI 카탈로그·인증·최적화 API |
optimizer |
OR-Tools CP-SAT 작업 처리 |
db |
PostgreSQL 영속 저장소 |
migrate |
Alembic 스키마 마이그레이션 |
ingest |
DREAMS 전체 원본과 2016~2026 교육과정·졸업요건 정규화 자료를 checksum 검증 후 DB에 무손실·멱등 적재 |
기술 선택과 경계는 docs/ARCHITECTURE.md, PostgreSQL 구조는
docs/ERD.md, 저장소별 데이터 흐름과 HTTP 계약은
docs/API_SPEC.md에 정리되어 있습니다.
- Docker Engine
- Docker Compose v2
- 외부 reverse proxy를 연결하려는 경우 Compose에서 사용하는 Docker network
git clone https://github.com/kdhoon723/timeTabler.git
cd timeTabler
cp .env.example .env
# .env의 POSTGRES_PASSWORD를 긴 무작위 값으로 교체
docker network create kdhoon-public 2>/dev/null || true
docker compose up -d --build
curl http://127.0.0.1:18080/api/v1/health/ready기본 웹 주소는 http://127.0.0.1:18080입니다. PostgreSQL 포트는 호스트에 공개하지
않습니다. 실제 스키마의 테이블·관계·제약조건은 docs/ERD.md에 문서화되어
있습니다. 다른 서버에서도 저장소, .env, Docker와 Compose만 있으면 같은 스택을 실행할
수 있습니다.
주요 환경 변수는 .env.example에 있습니다. .env와 운영 자격 증명은 Git에서 제외됩니다.
로그인은 시간표 편집의 선행 조건이 아닙니다. 활성화하려면 소유한 발신 도메인을 Resend에서 검증하고 .env에 다음 값을 설정합니다. API 키와 HMAC secret은 저장소에 커밋하지 않습니다.
TIMETABLER_AUTH_ENABLED=true
TIMETABLER_AUTH_HMAC_SECRET=<32바이트 이상의 무작위 비밀값>
TIMETABLER_AUTH_EMAIL_PROVIDER=resend
TIMETABLER_AUTH_RESEND_API_KEY=<Resend API key>
TIMETABLER_AUTH_RESEND_FROM=PL-timeTabler <login@검증한-발신-도메인>서버는 입력한 학번으로 학번@daejin.ac.kr을 생성하고 6자리 코드를 보냅니다. 코드는 5분 후 만료되고 5회 실패 시 폐기되며, 재전송은 60초로 제한합니다. 세션은 원문 토큰을 저장하지 않는 Secure·HttpOnly·SameSite=Lax 쿠키를 사용합니다.
현재 Compose는 kdhoon-public 외부 네트워크를 사용합니다. cloudflared를 같은 네트워크에 연결하고 다음처럼 origin을 지정할 수 있습니다.
- hostname: timetable.example.com
service: http://timetabler-web:80DNS CNAME 대상은 Cloudflare가 해당 계정에 발급한 <tunnel-id>.cfargotunnel.com을 사용합니다. 터널 토큰과 계정 자격 증명은 저장소에 넣지 않습니다.
- 과목·강의실 snapshot과 졸업요건 정규화 결과는 공개된 학교 자료를 기반으로 합니다.
- 학생 계정, 쿠키, 개인 이수내역과 내부 교번은 데이터셋에 포함하지 않습니다.
- 교수명·강의시간·강의실처럼 공개 강의정보에 포함된 항목만 시간표 생성에 사용합니다.
- 데이터 수집 시점과 학교 시스템의 최신 상태가 다를 수 있습니다. 이 저장소의 판정은 공식 수강신청·졸업 판정을 대체하지 않습니다.
- 원문 자료의 권리는 각 원저작자·제공기관에 있으며, 재사용 시 원문 사이트의 이용 조건을 확인해야 합니다.
상세 출처, 변환 과정, checksum과 현재 제한은 data/README.md와 data/requirements/README.md를 참고하세요.
새 강의계획서나 개설과목 snapshot은 기존 파일을 직접 덮어쓰지 않고 별도 staging에서 준비합니다.
data/courses,data/classrooms,data/requirements에 새 학기 원본과 정규화 결과를 둡니다.data/manifest.json의 레코드 수와 SHA-256 checksum을 갱신합니다.- canonical API snapshot에서 브라우저 fallback을 다시 생성합니다.
- DREAMS 아카이브는
data/dreams/manifest.jsonchecksum과 레코드 수를 검증합니다. - 교육과정편람은 입학연도별 통합 정규화 파일을 다시 생성하고 기존 2026 검수 snapshot과 교차 검증합니다.
- 아래 release gate가 통과한 뒤 새 이미지를 빌드합니다.
uv --directory apps/backend run timetabler-validate-data
uv --directory apps/backend run timetabler-export-static-catalog
uv --directory apps/backend run timetabler-normalize-requirements
uv --directory apps/backend run timetabler-normalize-graduation-requirements
docker compose run --rm --build ingestAPI와 정적 fallback은 과목·강의실 checksum을 합친 같은 datasetVersion과 1,576개 분반의 동일한 세션 의미를 사용합니다. API는 이 버전을 최적화 요청과 함께 검증하므로 브라우저의 오래된 데이터와 새 카탈로그가 섞이지 않습니다.
통합 교육과정 자료는 2016 HWP의 표 셀과 20172026 PDF의 세로 병합 좌표를 복원합니다. 입학연도·원문 학과명과 별칭·전공기초/전공필수·학년/학기·출처 위치를 보존하고 PostgreSQL에 적재합니다. 20202026은 편람의 졸업소요 최저학점 표도 학과·학번·전공경로별로 구조화해 총학점·교양·전공 영역과 교양필수 과목을 자동 점검합니다. 외국인·편입학 예외, 개인별 승인과 자유서술형 졸업심사 조건은 자동 충족으로 단정하지 않고 수동 확인 상태로 유지합니다.
개발 도구가 필요한 경로입니다. CI는 Python 3.12, uv 0.8.x, Node.js 22를 사용합니다. Docker 실행만 할 경우 위의 요구 사항을 따르세요.
# backend
uv --directory apps/backend sync --frozen
uv --directory apps/backend run ruff format --check src tests ../../scripts/extract-major-required.py
uv --directory apps/backend run ruff check src tests ../../scripts/extract-major-required.py
uv --directory apps/backend run mypy src
uv --directory apps/backend run pytest -q
uv --directory apps/backend run timetabler-validate-data
# web
npm ci --prefix apps/web
npm run api:generate --prefix apps/web
npm run typecheck --prefix apps/web
npm run lint --prefix apps/web
npm test --prefix apps/web
npm run build --prefix apps/web
# browser E2E: mobile, desktop, accessibility
npm ci --prefix e2e
npx --prefix e2e playwright install --with-deps chromium
npm test --prefix e2eGitHub Actions는 GitHub가 제공하는 ubuntu-latest runner에서 백엔드, OpenAPI·정적 카탈로그 snapshot, 데이터 검증, 프론트 타입·lint·unit·build, Playwright, Docker Compose 기동과 실제 OR-Tools E2E를 검사합니다. 운영 서버를 Actions runner로 사용하지 않습니다.
./scripts/backup-db.sh
./scripts/restore-db.sh backups/timetabler-YYYYMMDDTHHMMSSZ.dump
docker compose logs -f api optimizer web db로그인 사용자가 저장한 프로필·시간표·이수내역은 계정 소유 데이터로 PostgreSQL에 저장되며 회원 탈퇴 시 함께 삭제됩니다. 공유 URL과 공개 강의 아카이브에는 개인 이수내역을 포함하지 않습니다.
보안 문제는 공개 이슈에 민감한 내용을 남기지 말고 GitHub의 Security → Report a vulnerability를 이용해 주세요. 자세한 정책은 SECURITY.md에 있습니다.
- 변경 범위를 작게 유지하고 관련 테스트를 추가합니다.
- 위의 backend, web, E2E 검증 중 변경 범위에 해당하는 명령을 실행합니다.
- 데이터 변경은 출처, 변환 방식, 레코드 수와 checksum을 함께 갱신합니다.
- 공식 근거로 확정할 수 없는 규칙은 자동 충족으로 단정하지 않고
UNKNOWN또는 수동 확인 상태로 둡니다.
이 저장소에는 아직 별도의 오픈소스 라이선스가 부여되지 않았습니다. 공개 열람과 이슈·기여 검토가 가능하지만, 코드와 데이터의 재배포·상업적 이용 권한이 자동으로 부여되지는 않습니다. 포함된 학교 원문 자료와 공개 데이터의 권리는 각 제공기관에 있습니다.
DESIGN.md— 모바일 우선 제품·UI/UX 규칙docs/ARCHITECTURE.md— 기술·배포·최적화 경계docs/ERD.md·핵심 ERD HTML— 실제 PostgreSQL 테이블·관계·제약조건docs/API_SPEC.md— 파일·PostgreSQL 저장 경계와 HTTP API 계약docs/PRODUCT_PLAN.md— 기능과 출시 기준docs/IMPLEMENTATION_READINESS.md— OR-Tools 검증 기준docs/UX_ITERATION_3.md— 현재 시간표와 자동완성 후보 분리docs/UX_ITERATION_4.md— 과목 진입 역할과 모바일 바텀시트 스와이프docs/UX_ITERATION_5.md— 초기 시간표 배색 실험docs/UX_ITERATION_6.md— 필수과목 도구 역할, 20색 시간순 배정, 브라우저 자동 다크 방지docs/research/DAEJIN_GRADUATION_RULES.md— 공식 졸업요건 출처와 자동 판정 경계
