d3h1 Blog

2023.04 - 진행 중 · 기획, 프론트엔드 개발 및 인프라 운영

  • Next.js
  • TypeScript
  • Tailwind CSS
  • Docker
  • Jenkins
  • Nginx

개요

개발하면서 알게 된 내용과 직접 겪은 경험을 기록하기 위해 만든 블로그입니다. 처음에는 Jekyll로 시작했지만, 코드를 수정하거나 기능을 추가하기가 불편해서 Next.js로 다시 만들었습니다. 지금은 글 작성과 검색, 댓글, SEO, 성능 개선부터 서버 배포까지 필요한 기능을 모두 직접 개발하고, 3년 넘게 운영하고 있습니다.

기여도

  • 프론트엔드 개발

    100%

    블로그 화면과 게시글, 검색, 카테고리, 댓글 기능을 직접 개발했습니다.

  • 성능 및 SEO 개선

    100%

    Lighthouse 결과를 근거로 성능을 개선하고, 검색엔진과 외부 서비스에 필요한 기능을 적용했습니다.

  • 배포 및 운영

    100%

    Docker, Jenkins와 Nginx로 직접 배포하고, 서버를 운영하고 있습니다.

주요 작업

  • MDX 기반 게시글 관리

    글과 이미지를 한곳에서 관리하려고 MDX를 도입했습니다. 게시글 정보가 잘못 입력되면 빌드 단계에서 바로 걸러지도록 메타데이터 검증 기능도 추가했습니다.

  • 게시글 검색 및 탐색

    제목과 본문으로 글을 검색할 수 있도록 만들고, 카테고리 분류와 이전·다음 글, 연관 글 기능을 함께 구현했습니다.

  • SEO 적용

    검색엔진과 외부 서비스에서 글이 올바르게 표시되도록 Open Graph, JSON-LD, Sitemap, robots.txt와 RSS 피드를 적용했습니다.

  • 이미지 및 로딩 성능 개선

    화면에 실제로 표시되는 크기에 맞는 이미지를 제공하고, 먼저 보이는 이미지와 나중에 불러올 이미지의 우선순위를 나눴습니다.

  • 배포 자동화

    코드를 변경하면 Jenkins가 검사와 빌드, Docker 이미지 생성, 실행 확인, 운영 배포까지 차례로 진행하도록 구성했습니다.

  • Blue/Green 배포

    새 버전을 별도의 포트에서 먼저 실행해 확인한 뒤, Nginx가 요청을 보내는 대상을 바꾸도록 만들었습니다. 새 버전에 문제가 있으면 기존 버전이 그대로 서비스를 이어 갑니다.

담당 업무

  • 블로그 화면과 콘텐츠 구조 설계
  • Next.js 기반 프론트엔드 개발
  • MDX 게시글 관리 기능 구현
  • 검색, 카테고리 및 댓글 기능 구현
  • 웹 성능과 SEO 개선
  • Docker 실행 환경 구성
  • Jenkins 배포 자동화
  • Nginx Blue/Green 배포 및 서버 운영

문제 해결 과정

  • 유지보수가 어려운 기존 구조

    문제

    처음 사용한 Jekyll 블로그는 스타일과 기능이 한곳에 섞여 있어서, 코드를 수정하거나 새 기능을 추가하기 어려웠습니다.

    해결

    Next.js와 MDX로 블로그를 다시 만들고, 게시글 처리와 화면 구성, 데이터 관련 코드를 역할에 따라 분리했습니다.

  • 외부 호스팅 서비스 의존

    문제

    Vercel에서는 빌드 시간이 길어지고 간헐적으로 빌드가 실패했으며, Cloudflare Workers에서는 국내 접속 요청이 해외 리전으로 전달되는 문제가 있었습니다.

    해결

    이미 운영하고 있던 OCI 춘천 리전 서버에 블로그를 직접 배포하고, Docker로 실행 환경을 일정하게 유지했습니다.

  • 배포 중 서비스 중단

    문제

    기존 컨테이너를 새 컨테이너로 교체하는 동안, 짧게는 1초에서 길게는 7초까지 블로그에 접속할 수 없었습니다.

    해결

    두 포트를 번갈아 사용하는 Blue/Green 배포를 적용해, 새 컨테이너가 Health Check를 통과한 경우에만 Nginx가 새 버전으로 요청을 보내도록 구성했습니다.

  • Nginx 전환 직후 발생한 요청 실패

    문제

    Nginx upstream을 바꾼 직후 기존 컨테이너를 제거하자, 처리 중이던 연결에서 HTTP 502 오류가 발생했습니다.

    해결

    reload 이후에도 이전 워커가 기존 연결을 처리하고 있다는 점이 원인이었습니다. 이전 워커가 남은 연결을 처리할 수 있도록 10초의 유예 시간을 둔 뒤, 이전 컨테이너를 제거하도록 수정했습니다.

결과

  • Lighthouse 성능 점수 87점에서 100점으로 개선
  • LCP 2.4초에서 0.4초로 단축
  • 배포 중 2,016번의 연속 요청에서 실패 0건 확인
  • 새 버전 실행에 실패해도 기존 블로그가 계속 서비스되도록 개선
  • 코드 검사부터 빌드, 실행 확인, 운영 배포까지 자동화
  • 배포 결과를 Telegram으로 받아 볼 수 있도록 구성

스크린샷

  • 블로그 메인 화면

    블로그 메인 화면

  • 게시글 화면

    게시글 화면

  • 검색 결과 화면

    검색 결과 화면

신한Q&A

2025.07 - 2026.04 · UI 디자인, 프론트엔드 개발

  • Next.js
  • TypeScript
  • Tailwind CSS
  • Turborepo
  • TanStack Query

개요

학과 학생들이 수업과 학과 운영에 대한 의견을 남기고 답변을 받는 서비스로 시작해, 자유게시판과 Q&A, 프로젝트와 스터디 모집 게시판을 갖춘 학과 커뮤니티로 발전했습니다. 방향이 바뀌면서 프론트엔드를 새로 만들었고, 새 버전은 학생용 앱과 관리자용 앱을 Turborepo 모노레포로 나누어 UI와 API, 타입을 공통 패키지로 함께 쓰도록 구성했습니다. 기획 1명, 안드로이드 1명, 백엔드 1명, 디자인과 프론트엔드 1명으로 구성된 팀에서 서비스 디자인과 웹 프론트엔드를 맡았습니다.

기여도

  • UI 디자인

    100%

    학생용과 관리자용 화면, 공통 컴포넌트, 다크모드까지 포함한 디자인 시스템을 설계했습니다.

  • 프론트엔드 개발

    100%

    레거시 버전과 새 버전에서 학생용, 관리자용 웹 프론트엔드를 모두 개발했습니다.

  • 인증 및 BFF 구성

    100%

    학생과 관리자 인증, 사이버캠퍼스 학생 검증, Route Handler 기반 API 프록시를 구현했습니다.

주요 작업

  • Turborepo 모노레포 구성

    학생용 앱과 관리자용 앱을 분리하고, UI 컴포넌트와 API 클라이언트, 타입을 공통 패키지로 만들어 두 앱이 함께 쓰도록 구성했습니다.

  • 커뮤니티 기능

    자유게시판, Q&A, 프로젝트 모집, 스터디 모집 게시판과 게시글 및 댓글 작성, 좋아요, 신고 기능을 구현했습니다. 서버 상태는 TanStack Query로 관리하고, 데이터가 바뀐 뒤에는 필요한 목록만 다시 불러오도록 했습니다.

  • 사이버캠퍼스 학생 검증

    회원가입 시 사이버캠퍼스 계정으로 로그인해 학적 정보를 확인하고, 소프트웨어융합학과 학생만 가입할 수 있도록 만들었습니다.

  • BFF와 쿠키 기반 인증

    브라우저가 백엔드를 직접 호출하지 않도록 Route Handler가 요청을 대신 전달하고, 토큰은 HttpOnly 쿠키로 관리했습니다. 로그인과 로그아웃, 토큰 갱신도 Route Handler로 처리했습니다.

  • 관리자 대시보드

    신고된 게시글과 댓글을 확인하고 삭제할 수 있는 관리자 화면을 만들었습니다. 모바일에서는 사이드바를 드로어로 바꾸고, 신고 표는 가로로 스크롤되도록 했습니다.

  • 접근성과 다크모드

    Modal, Tabs, Dropdown 같은 공통 컴포넌트에 ARIA 속성과 키보드 조작을 추가했습니다. 색상을 시맨틱 토큰으로 정리해 모든 화면에 다크모드를 적용했습니다.

담당 업무

  • 서비스 UI 디자인과 디자인 시스템 설계
  • 레거시 Next.js 프론트엔드 개발
  • Turborepo 기반 새 프론트엔드 설계와 개발
  • 학생용 커뮤니티 화면 개발
  • 관리자 대시보드 개발
  • 카카오 로그인, JWT 인증과 사이버캠퍼스 학생 검증 구현
  • Route Handler 기반 BFF 구성과 API 연동
  • 접근성, 반응형, 다크모드 대응

문제 해결 과정

  • 한 앱에 섞여 있던 학생 기능과 관리자 기능

    문제

    레거시 버전은 학생 화면과 관리자 화면이 한 앱에 함께 있어서, 페이지마다 관리자인지 판별하는 코드와 미들웨어의 리다이렉트 조건이 계속 늘어났습니다.

    해결

    새 버전에서는 Turborepo로 학생용 앱과 관리자용 앱을 완전히 분리했습니다. 공통 UI와 API 클라이언트, 타입은 패키지로 나누어 두 앱이 같은 코드를 쓰면서도, 인증과 라우트 보호는 각 앱이 따로 관리하도록 만들었습니다.

  • 수동으로 진행하던 학생 인증

    문제

    레거시 버전은 학생증 사진을 올리면 관리자가 직접 확인해 승인하는 방식이라, 가입까지 시간이 걸리고 관리자가 요청을 매번 처리해야 했습니다.

    해결

    회원가입 과정에서 사이버캠퍼스에 로그인해 학적 정보를 바로 확인하도록 바꿨습니다. 로그인 실패와 다른 학과, 학적 정보 확인 실패를 구분해 안내하고, 확인을 마친 학생만 다음 단계로 넘어가도록 회원가입을 2단계로 나눴습니다.

  • 학생과 관리자 로그인 상태 충돌

    문제

    학생용 앱과 관리자용 앱이 같은 이름의 인증 쿠키를 쓰고 있어서, 한쪽에 로그인하면 다른 쪽의 로그인 상태에 영향을 줄 수 있었습니다.

    해결

    학생용 앱은 student_, 관리자용 앱은 admin_ 접두사를 붙여 인증 쿠키를 완전히 분리했습니다.

  • 로그인 후 리다이렉트를 악용한 외부 이동

    문제

    로그인 후 원래 보던 페이지로 돌아가도록 경로를 쿼리로 받다 보니, 외부 주소를 넣어 사용자를 다른 사이트로 보낼 수 있었습니다.

    해결

    리다이렉트 경로가 서비스 내부 경로인지 확인한 뒤에만 이동하도록 Open Redirect 방어를 추가했습니다.

결과

  • 학생용과 관리자용 앱을 하나의 모노레포에서 공통 패키지로 함께 관리
  • 학생증 사진 확인을 사이버캠퍼스 자동 검증으로 바꿔 관리자 승인 과정 제거
  • 공통 UI 컴포넌트에 키보드 조작과 ARIA 속성 적용
  • 학생용과 관리자용 전체 화면에 다크모드와 반응형 적용

스크린샷

  • 학생용 로그인 전 화면

    학생용 로그인 전 화면

  • 학생용 프로젝트 모집 작성 화면

    학생용 프로젝트 모집 작성 화면

  • 학생용 스터디 모집 게시글 화면

    학생용 스터디 모집 게시글 화면

  • 관리자용 메인 화면

    관리자용 메인 화면

  • 관리자용 신고 관리 화면

    관리자용 신고 관리 화면

  • 관리자용 게시글 관리 화면

    관리자용 게시글 관리 화면

Voice Home Secure

2025.08 - 2025.09 · UI 디자인, 프론트엔드 개발

  • Next.js
  • TypeScript
  • CSS Modules

개요

배달원이나 예상하지 못한 방문자에게 '누구세요?'라고 직접 묻기 불안한 사람을 위해, 익숙한 목소리로 현관문 너머의 방문자에게 대신 응대하는 캡스톤 프로젝트입니다. 사용자가 자신의 음성 파일을 올리면, 그 목소리로 상황별 응대 문구를 만들어 재생하거나 저장할 수 있습니다. 기획/AI 1명, 안드로이드 1명, 백엔드 1명, 디자인/프론트엔드 1명으로 구성된 팀에서 서비스 디자인과 웹 프론트엔드를 맡았습니다.

기여도

  • UI 디자인

    100%

    서비스 화면과 색상, 폰트, 공통 컴포넌트까지 포함한 디자인 시스템을 설계했습니다.

  • 프론트엔드 개발

    100%

    로그인, 음성 생성과 재생 화면을 개발하고, 백엔드 API를 연동했습니다.

  • 인증 구현

    100%

    카카오 로그인과 JWT 발급, 재발급 흐름을 구현했습니다.

주요 작업

  • 카카오 로그인

    카카오에서 받은 인가 코드로 토큰을 발급받고, 이를 백엔드에 전달해 서비스 JWT를 발급받는 흐름을 Route Handler로 구현했습니다.

  • 토큰 자동 재발급

    Middleware에서 요청마다 Refresh Token으로 Access Token을 재발급하고, 재발급에 실패하면 쿠키를 모두 지운 뒤 로그인 화면으로 보내도록 만들었습니다.

  • 상황별 음성 생성

    배달, 스토킹, 모르는 사람 세 가지 상황마다 응대 문구 5개를 사용자의 목소리로 한 번에 만들고, 문구별로 재생하거나 저장할 수 있도록 만들었습니다.

  • 사용자 지정 문구와 음성 테스트

    직접 입력한 문구를 사용자의 목소리로 읽어 주는 기능과, 업로드한 음성이 잘 적용되는지 미리 들어 보는 테스트 기능을 구현했습니다.

  • 디자인 시스템

    CSS 변수로 색상과 폰트를 정의하고, Button, TextField, TextArea, Modal, Icon, Logo, Header 같은 공통 컴포넌트를 만들었습니다.

  • 모달과 반응형 UI

    모달을 Portal로 띄우고, 모달이 열려 있는 동안 배경 스크롤을 막았으며, ESC 키로 닫을 수 있게 했습니다. 모바일에서도 화면과 모달이 넘치지 않도록 크기를 조정했습니다.

담당 업무

  • 서비스 UI 디자인과 디자인 시스템 설계
  • Next.js 기반 웹 프론트엔드 개발
  • 카카오 로그인과 JWT 인증 흐름 구현
  • 음성 생성, 재생, 저장 기능 구현
  • Server Action 기반 백엔드 API 연동
  • 공통 컴포넌트와 반응형 화면 구성

문제 해결 과정

  • 로그인 과정의 CSRF 위험

    문제

    카카오 로그인 콜백으로 돌아오는 요청이 실제로 우리 서비스에서 시작된 로그인인지 확인할 방법이 없었습니다.

    해결

    로그인을 시작할 때 무작위 state 값을 만들어 쿠키에 저장하고, 콜백에서 돌아온 state와 쿠키 값이 같을 때만 로그인을 진행하도록 Double Submit Cookie 방식을 적용했습니다.

  • 토큰 보관과 만료 처리

    문제

    JWT를 브라우저 스크립트가 접근할 수 있는 곳에 두면 탈취될 위험이 있었고, Access Token이 만료될 때마다 사용자가 다시 로그인해야 했습니다.

    해결

    토큰을 HttpOnly 쿠키에 저장하고, Middleware에서 Refresh Token으로 재발급하도록 만들었습니다. 재발급에 실패하면 페이지 요청은 로그인 화면으로 보내고, API 요청에는 401로 응답하도록 구분해 처리했습니다.

  • 음성 파일 업로드 용량 제한

    문제

    사용자의 음성 파일을 Server Action으로 백엔드에 넘기는 과정에서, 기본 요청 크기 제한 때문에 업로드가 실패했습니다.

    해결

    Server Action의 요청 본문 크기 제한을 음성 파일 크기에 맞게 늘려, 업로드가 정상적으로 이뤄지도록 수정했습니다.

  • 여러 음성을 묶어 보내는 ZIP 응답

    문제

    상황별 음성 생성 API는 음성 5개를 ZIP 파일 하나로 묶어 응답했기 때문에, 화면에서 문구별로 바로 재생하기 어려웠습니다.

    해결

    Server Action에서 ZIP을 풀어 WAV 파일만 골라내고, 5개가 모두 있는지 확인한 뒤 화면에 넘기도록 만들었습니다. 화면에서는 파일마다 재생 주소를 만들어 문구별로 재생하고 저장할 수 있습니다.

결과

  • 로그인부터 음성 업로드, 상황별 음성 생성, 재생과 저장까지 이어지는 웹 서비스 완성
  • HttpOnly 쿠키와 자동 재발급으로 로그인 상태 유지
  • 세 가지 상황의 응대 문구 15개를 사용자의 목소리로 생성

스크린샷

  • 로그인 화면

    로그인 화면

  • 음성 업로드 화면

    음성 업로드 화면

Comentor

2025.11 - 2026.04 · 프론트엔드 개발

  • Next.js
  • TypeScript
  • Tailwind CSS
  • Recharts

개요

청소년이 온라인에서 접하는 댓글을 스스로 비판적으로 바라볼 수 있도록 돕는 AI 가이드 서비스입니다. 댓글을 입력하면 먼저 문제가 있는 표현인지 확인하고, 필요한 경우에만 순화된 문장을 제안합니다. 이어서 욕설/모욕, 성차별, 기타 차별, 혐오 네 가지 항목의 점수를 차트로 보여 주어, 어떤 부분이 문제인지 한눈에 알 수 있습니다. 프론트엔드 1명, 백엔드와 AI 1명, 디자이너 2명으로 구성된 팀에서 프론트엔드를 혼자 맡았습니다. 댓글을 분석하고 교정하는 AI는 백엔드와 AI 담당 팀원이 개발했고, 저는 그 API를 사용자 흐름에 연결하고 디자이너의 Figma 디자인을 화면으로 구현했습니다.

기여도

  • 프론트엔드 개발

    100%

    홈, 댓글 교정, 편향 분석 화면과 공통 레이아웃을 개발했습니다.

  • API 연동

    100%

    Server Action으로 백엔드의 검토, 교정, 분석 API를 연동하고, 오류 상황을 한곳에서 처리했습니다.

  • 데이터 시각화

    100%

    Recharts로 편향 분석 결과를 레이더 차트와 방사형 차트로 보여 주는 컴포넌트를 만들었습니다.

주요 작업

  • 댓글 교정 흐름

    입력한 댓글을 검토 API로 먼저 확인하고, 문제가 있는 경우에만 교정 API를 호출해 순화된 문장을 보여 주도록 만들었습니다. 교정 결과에는 그라데이션 애니메이션을 적용했습니다.

  • 편향 분석 차트

    네 가지 편향 항목의 점수를 레이더 차트 하나와 항목별 방사형 차트로 함께 보여 줍니다. 항목마다 이름과 설명, 색상을 한곳에서 관리하도록 라벨 맵을 두었습니다.

  • 차트 컴포넌트 설계

    차트를 Header, Title, Legend, Content 같은 작은 컴포넌트로 나누어 조합하는 구조로 만들었습니다. 덕분에 화면마다 필요한 요소만 골라 배치할 수 있습니다.

  • 입력 편의 기능

    댓글 입력창에 되돌리기와 다시 실행, 음성으로 읽기, 복사, 글자 수 표시 기능을 추가했습니다.

  • 디자인 시스템 구성

    Figma 디자인을 기준으로 색상과 텍스트 테마, 폰트를 먼저 정의하고, Button, Logo, Icon 같은 공통 컴포넌트를 만들었습니다.

  • 공통 레이아웃과 반응형

    Route Group으로 교정 화면과 분석 화면에 공통 사이드바를 적용하고, 모바일부터 데스크톱까지 화면 크기에 맞게 배치가 바뀌도록 구성했습니다.

담당 업무

  • Figma 디자인 기반 화면 구현
  • 색상, 텍스트 테마와 공통 컴포넌트 구성
  • 댓글 교정 화면 개발
  • 편향 분석 화면과 차트 컴포넌트 개발
  • Server Action 기반 백엔드 API 연동
  • 로딩, 오류 상태 처리
  • 반응형 레이아웃과 사이드바 구성

문제 해결 과정

  • 백엔드 주소 노출과 오류 처리

    문제

    브라우저에서 백엔드 API를 직접 호출하면 서버 주소가 그대로 드러나고, 요청 제한이나 서버 오류가 발생할 때 화면마다 다르게 대응해야 했습니다.

    해결

    API 호출을 Server Action으로 옮겨 서버 주소를 환경 변수로만 관리했습니다. 요청 제한, 검토 실패, 교정 실패처럼 상황별로 오류 코드와 안내 문구를 정해, 같은 형태로 반환하도록 만들었습니다.

  • 불필요한 교정 요청

    문제

    모든 댓글에 교정 요청을 보내면 문제가 없는 문장까지 교정 API를 거치게 되어, 응답이 느려지고 서버에 부담이 생겼습니다.

    해결

    검토 API로 문제가 있는 댓글인지 먼저 확인하고, 문제가 있는 경우에만 교정 API를 호출하도록 요청 순서를 나눴습니다. 문제가 없는 댓글에는 수정이 필요하지 않다는 안내만 보여 줍니다.

  • 화면 간 결과 전달

    문제

    교정 화면에서 받은 결과를 분석 화면으로 넘길 때, 새로고침하거나 링크를 공유하면 결과가 사라졌습니다.

    해결

    원문과 교정 결과, 돌아갈 경로를 URL 쿼리로 전달하도록 바꿨습니다. 쿼리만으로 화면을 다시 구성할 수 있어서, 새로고침해도 결과가 유지됩니다.

  • 분석 결과 대기 중 빈 화면

    문제

    분석 API의 응답을 기다리는 동안 차트 영역이 비어 있어 화면이 멈춘 것처럼 보였고, 0과 1 사이의 소수 점수는 읽기 어려웠습니다.

    해결

    응답이 오기 전에는 스켈레톤을 보여 주고, 점수는 100점 기준으로 반올림해 표시하도록 수정했습니다.

결과

  • 댓글 입력부터 교정, 편향 분석까지 이어지는 화면 흐름 완성
  • 네 가지 편향 항목의 점수를 레이더 차트와 방사형 차트로 시각화
  • 문제가 있는 댓글에만 교정 API를 호출하도록 요청 흐름 개선
  • 모바일부터 데스크톱까지 반응형 화면 대응

AI 활용

  • Figma MCP를 활용해 디자이너가 만든 Figma 디자인의 정보를 가져와, 화면을 구현할 때 참고했습니다.
  • 처음 사용하는 Recharts의 사용 방법을 이해하기 위해 Context7 MCP로 공식 문서를 찾아보며, 레이더 차트와 방사형 차트를 구현했습니다.

스크린샷

  • 댓글 교정 화면

    댓글 교정 화면

  • 편향 분석 화면

    편향 분석 화면

신한대학교 시간표 마법사

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, 작은 커밋 단위로 나누어 진행하도록 구성했습니다.

스크린샷

  • 강좌 찾기 화면

    강좌 찾기 화면

  • 시간표 자동 조합 화면

    시간표 자동 조합 화면

  • 시간표 편집 화면

    시간표 편집 화면

  • 내 시간표 화면

    내 시간표 화면