← 이력서로

CHUP

교내 채용 공고와 지원자 정보를 통합 관리하는 웹 서비스

기간
2025.06 – 2026.08
역할
프론트엔드 개발
팀
프론트엔드 4 · 백엔드 2
기술
  • Next.js 16
  • React 19
  • TypeScript
  • Turborepo
  • Tailwind CSS
  • TanStack Query
  • React Hook Form
  • Zod
  • Zustand

배경

CHUP은 광주소프트웨어마이스터고등학교의 채용 공고와 지원자 정보를 한 곳에서 조회·관리하도록 만든 웹 서비스입니다. 학생은 채용 공고 확인부터 지원 현황 조회까지 한 화면에서 처리하고, 교사는 공고 등록·지원자 관리·마감 상태 확인을 한 곳에서 합니다. 교내 채용 공고와 지원 자료가 여러 곳에 흩어져 있어, 학생은 공고를 찾기 어렵고 교사는 같은 관리 업무를 반복해야 했습니다. 2025년에 AI를 적극 활용해 약 7일 만에 v1을 기획·개발·배포했고, 실제 채용 안내·지원 과정에 바로 도입했습니다. 2026년에는 학생과 교사의 화면을 각자에 맞게 키우기 위해 v2를 새로 만들었습니다.

맡은 일

v1에서는 학생용 채용 공고·회사 상세·지원 흐름과 이력서·포트폴리오 링크 제출, 관리자 지원자 정보 화면을 맡았습니다. v2에서는 모노레포 구조를 설계하고, 학생 앱과 관리자 앱의 채용·지원·교통비 지원 기능을 API와 연결했습니다. v2 커밋의 절반 이상을 작성했습니다.

한 일

v2: Turborepo 모노레포 전환과 학생·관리자 앱 분리

  • 문제: 학생과 교사(관리자)는 쓰는 화면과 권한이 완전히 달랐습니다. 한 앱 안에서 역할을 전환하는 구조로는 두 화면을 따로 키우기 어려웠습니다.
  • 해결: 기능 개발 전 스캐폴드 단계, 즉 옮길 코드가 가장 적은 시점에 단일 Next.js 앱을 Turborepo + pnpm workspace 모노레포로 바꿨습니다. 앱은 client(학생)와 admin(선생님)으로 나누고, 공유 코드는 @chup/core, @chup/ui, @chup/tailwind-config, @chup/eslint-config, @chup/typescript-config 5개 패키지로 뽑았습니다. #2
  • 결정: 패키지마다 빌드 방식을 다르게 했습니다. @chup/core는 'use client'와 server-only 지시문을 지키기 위해 빌드하지 않고 소스 그대로 가져다 쓰게 했습니다(transpilePackages). 순수 UI인 @chup/ui는 미리 빌드해 JS와 CSS 산출물을 냈습니다. 서버 전용 코드는 @chup/core/shared/server 서브패스로만 노출해 클라이언트 번들에 섞이지 않게 했습니다.
  • 결과: 두 앱이 서브도메인으로 나뉘어 쿠키도 앱별로 따로 관리됩니다. 학생 화면(홈·채용 공고·지원 현황·내 정보)과 관리자 화면(대시보드·공고 관리·지원자 관리)을 각각 구성했습니다. #14

v2: 채용 공고·지원 화면을 실제 API로 전환

  • 문제: 목업 데이터로 만든 학생·관리자 화면을 실제 서버와 연결해야 했습니다.
  • 해결: 학생 앱의 공고 목록·상세에 검색·고용 형태·마감일 정렬 파라미터를 연결하고 로딩·빈 결과·오류 상태를 넣었습니다. 관리자 앱에는 공고 등록·수정·모집 상태 변경 API를 연결하고, zod와 React Hook Form으로 요청을 검증했습니다. 서버 검증 오류는 해당 폼 필드나 폼 전체 오류로 보여 주고, 성공하면 공고 목록과 대시보드 캐시를 무효화합니다. #25 #28 #38
  • 결과: 여러 이력서를 골라 한 번에 지원할 수 있게 했고, 이력서와 전화번호가 모두 있어야 지원 버튼이 켜지도록 했습니다. 중복 지원과 파일 용량 초과(413)에는 각각 맞는 안내를 보여 줍니다. #66 #69 #71 #95

v2: 면접 교통비 지원과 외부 지원 등록

  • 문제: 3학년 학생의 면접 교통비 지원 신청과 처리를 서비스 안에서 할 수 있어야 했습니다. CHUP 밖에서 지원한 내역과 면접 일정도 함께 관리할 필요가 있었습니다.
  • 해결: 학생 앱에 교통비 신청·내역 화면을 만들었습니다. 회사명, 면접 일시, 증빙 파일 1~5개를 보내고 이미지·PDF 형식과 용량을 검증합니다. 관리자 앱에는 학생별 신청 내역, 증빙 ZIP 다운로드, 승인·거절 처리를 넣었습니다. 외부 지원 내역 등록과 면접 일시 입력·표시도 추가하고 회귀 테스트를 붙였습니다. #80 #99
  • 결과: 처리 후에는 TanStack Query 캐시를 갱신해 학생 요약과 신청 목록이 바로 바뀝니다.

트러블슈팅

모집 중인 공고가 ’마감’으로 보이던 문제 (v2)

  • 상황: 학생 공고 목록에서 모집 중인 공고가 모두 마감으로 표시됐습니다.
  • 원인: /api/jobs 목록 응답은 모집 중인 공고만 돌려주기 때문에 status 필드가 없습니다. 프론트는 목록과 상세가 같은 타입을 쓰고 있었고, 비어 있는 status를 마감으로 해석했습니다.
  • 해결: 목록 응답 타입과 상세 응답 타입을 나눴습니다. 목록 카드는 API 계약대로 모집중을 표시하고, 상세와 관리자 화면은 기존 상태 처리를 유지했습니다. 같은 시기에 지원 응답의 중첩·평탄 구조 불일치와 이력서 업로드 필드명도 OpenAPI 명세에 맞췄습니다. #62 #63 #64