Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
165 commits
Select commit Hold shift + click to select a range
78a6b14
feat: 프로젝트 개발 환경 세팅 (#2)
rkdcodus Jan 26, 2025
b76f24c
feat: 디자인 시스템 및 스타일링 셋업 (#5)
rkdcodus Feb 2, 2025
4f0c631
chore: Qodana ci 파이프라인 구축 (#7)
qodana-cloud[bot] Feb 4, 2025
18685b2
chore: 스토리북 환경 구축 및 CI 설정 (#10)
WonJuneKim Feb 4, 2025
087210c
feat: 폴더 구조 세팅 및 절대 경로 처리 (#13)
rkdcodus Feb 5, 2025
d10671b
chore: Qodana 스크립트 수정 (#15)
WonJuneKim Feb 5, 2025
f527738
feat: Interaction 컴포넌트 구현 (#17)
rkdcodus Feb 7, 2025
99049f1
feat: Label 및 Badge 컴포넌트 구현 (#20)
rkdcodus Feb 7, 2025
9d9df55
fix: 인터렉션 컴포넌트 수정 및 storybook 설정 (#22)
rkdcodus Feb 9, 2025
9a56475
feat: Title, Callout, Hero 컴포넌트 구현 (#23)
rkdcodus Feb 9, 2025
29fcda8
feat: progress 컴포넌트 구현 (#29)
rkdcodus Feb 11, 2025
3a3e398
feat: 범용성있는 버튼 컴포넌트 구현 (#30)
WonJuneKim Feb 12, 2025
4da8065
feat: 아이코노그래피를 기반으로 아이콘 컴포넌트 구현 (#32)
rkdcodus Feb 12, 2025
e6ca171
fix: 인터랙션 컴포넌트 재구현 및 semantic 컬러 토큰 업데이트 (#35)
rkdcodus Feb 14, 2025
42b1cad
feat: Input 컴포넌트 구현 (#36)
rkdcodus Feb 14, 2025
f4cf305
feat: 지원하기 페이지 UI 구현 (#40)
rkdcodus Feb 16, 2025
7ff3ee4
feat: Card와 Post 컴포넌트 구현 (#37)
WonJuneKim Feb 16, 2025
6c5031e
feat: 탭 컴포넌트 구현 (#39)
WonJuneKim Feb 16, 2025
c09104c
feat: FAQ 페이지 UI 구현 및 아코디언 컴포넌트 구현 (#53)
rkdcodus Feb 21, 2025
81c173e
feat: Select 컴포넌트 구현 (#44)
WonJuneKim Feb 25, 2025
60baf85
feat: SnackBar 컴포넌트 구현 (#45)
WonJuneKim Feb 25, 2025
3488c42
Fix: 인터렉션 재구현 3차 (#60)
rkdcodus Feb 28, 2025
aae8118
feat: Header, Footer 관련 컴포넌트 구현 및 Layout 적용 (#56)
rkdcodus Mar 2, 2025
dcfa976
refactor: Card 및 Post 컴포넌트 Interaction 주입 (#55)
WonJuneKim Mar 2, 2025
ed5cbec
feat: Role 컴포넌트 구현 (#63)
WonJuneKim Mar 2, 2025
b66c71f
feat: dialog 컴포넌트 구현 (#61)
rkdcodus Mar 3, 2025
1a6c14b
chore: favicon 설정 (#58)
rkdcodus Mar 5, 2025
b1352ba
feat: 아이콘 추가 (#74)
rkdcodus Mar 5, 2025
97733ed
fix: HeroIndex 컴포넌트 수정 (#80)
rkdcodus Mar 5, 2025
43deb4a
feat: 활동 페이지 UI 구현 (#77)
rkdcodus Mar 5, 2025
5924adc
feat: Toast 구현 (#67)
rkdcodus Mar 5, 2025
a140f97
feat: 메인페이지 UI 구현 (#78)
WonJuneKim Mar 7, 2025
df970a1
feat: apply-3 페이지 및 지원 완료 페이지 UI 구현 (#81)
rkdcodus Mar 7, 2025
c78ff19
feat: File, Uploader 컴포넌트 구현 (#76)
rkdcodus Mar 8, 2025
de05aae
feat: 프로젝트, 프로젝트 상세페이지 구현 (#84)
WonJuneKim Mar 8, 2025
28169f2
fix: 인터렉션 focus-visible 효과 나타날 때 border가 보이지 않는 버그 해결 (#89)
rkdcodus Mar 9, 2025
20133f0
bug: 빌드 파일 생성 과정에서 발생한 에러 수정 (#88)
WonJuneKim Mar 10, 2025
d54b50b
feat: apply-2 페이지 UI 구현 (#82)
rkdcodus Mar 11, 2025
12ed75e
feat: 지원서 작성 페이지 UI 구현(apply-4) (#85)
rkdcodus Mar 11, 2025
7167c8d
feat: 리팩토링 이슈 템플릿 추가 (#92)
rkdcodus Mar 11, 2025
807d44e
chore: api 연동을 위한 axios, tanstack query 세팅 및 테스트 (#90)
rkdcodus Mar 11, 2025
8882a24
refactor: requestHandler 제네릭 타입 수정 (#102)
rkdcodus Mar 12, 2025
e7b2c16
feat: CheckBox 컴포넌트 구현 (#86)
WonJuneKim Mar 12, 2025
4614d88
refactor: 스타일 폴더 리팩토링 (#100)
rkdcodus Mar 14, 2025
acc470a
refactor: 직군명, 이메일 변경 및 데브옵스 애니메이션 비활성화 (#104)
rkdcodus Mar 14, 2025
912a778
feat: 젝톡 조회 기능 및 EmptyData 컴포넌트 구현 (#99)
rkdcodus Mar 16, 2025
cafb053
feat: 젝톡 summary 표시 및 EmptyData 조건부 수정 (#111)
rkdcodus Mar 24, 2025
cdb0d82
feat: 파일 업로드 기능 구현 (#109)
rkdcodus Mar 26, 2025
6a7d68f
feat: 지원서 플로우 기능 구현 (#112)
rkdcodus Mar 31, 2025
98bb34b
feat: 페이지 하단 지원 스낵바 구현 (#120)
rkdcodus Apr 7, 2025
10872ed
feat: 로컬스토리지 자동 임시 저장 기능 구현 (#122)
rkdcodus Apr 7, 2025
a964c90
feat: 회원 비회원 인증 및 회원정보 등록 기능 (#114)
WonJuneKim Apr 8, 2025
ead70c9
bug: workflow runner 버전 업데이트 (#133)
WonJuneKim Apr 8, 2025
316fb25
refactor: 다이얼로그 함수 호출식으로 재구현 (#127)
rkdcodus Apr 8, 2025
d19d48e
chore: 배포 스크립트 및 환경 설정 (#135)
WonJuneKim Apr 9, 2025
66e944e
fix: Uploader 스토리북 에러 해결 (#138)
rkdcodus Apr 9, 2025
f1fe156
feat: 답변 SELECT 필드 추가 (#130)
rkdcodus Apr 10, 2025
c989bc6
feat: 임시저장 불러오기 다이얼로그 표시 및 임시지원서 제거 api 연동 (+지원서 관련 함수 및 타입 리팩토링) (#134)
rkdcodus Apr 13, 2025
6a0fe79
feat: FAQ 페이지 기능 변경 및 개선 (#144)
WonJuneKim Apr 15, 2025
97d9cca
feat: PIN 재설정 기능 구현 (#146)
WonJuneKim Apr 15, 2025
cffc433
feat: 에러 핸들링 (#143)
rkdcodus Apr 15, 2025
2048a2a
fix: QuestionResponse 타입 수정 및 적용 (#151)
rkdcodus Apr 16, 2025
353183a
feat: 프로젝트 탭 API 연동 (#147)
WonJuneKim Apr 16, 2025
7a5e02e
bug: 임시 회원가입 시 토큰 핸들링이 정상적으로 처리되지 않는 문제 해결 (#153)
WonJuneKim Apr 16, 2025
e268404
chore: sentry 에러 모니터링 도구 도입 (#145)
rkdcodus Apr 16, 2025
e6afa70
fix: 배포 전 발견된 수정 및 추가 사항 작업 (#154)
rkdcodus Apr 16, 2025
553c836
bug: 임시 회원가입 버튼 클릭 이벤트가 전송안되는 버그 해결 (#157)
WonJuneKim Apr 16, 2025
7be1e20
bug: 지원서 제출 버튼 활성화 버그 및 지원서 문항 에러 토스트 버그 해결 (#158)
rkdcodus Apr 16, 2025
a5608d0
fix: 스크롤 최상단 이동 기능 추가, 지원서 임시 저장 조회 및 파일 업로드 버그 수정 (#161)
rkdcodus Apr 17, 2025
186e413
fix: 지원 페이지 전반적인 내용과 UI 수정 (#166)
rkdcodus Apr 17, 2025
5122807
bug: Faq 페이지 내 탭 이동 시 히스토리가 유지되는 문제 해결 (#164)
WonJuneKim Apr 17, 2025
a4555b9
bug: 프로젝트 목록, 상세 페이지 관련 이슈 해결 (#162)
WonJuneKim Apr 17, 2025
b9df721
chore: QA 용 환경 구축 시 배포 설정 (#168)
WonJuneKim Apr 17, 2025
e250bf4
fix: 지원서 작성 페이지 벗어날 경우 다이얼로그 표시 (#171)
rkdcodus Apr 17, 2025
10eaf90
bug: 지원 플로우 중 인증 과정 중에 발견한 이슈 해결 (#173)
WonJuneKim Apr 17, 2025
950b1de
fix: 임시 모바일 UI 구현 (#172)
rkdcodus Apr 17, 2025
7093a43
bug: 작성페이지 접근 실패 버그 원인 확인을 위한 콘솔 로그 (#175)
rkdcodus Apr 17, 2025
b67f2e4
bug: 인증 과정에서 추가로 발생한 이슈 대응 (#177)
WonJuneKim Apr 17, 2025
ee075ff
fix: 지원서 제출 및 임시 저장 조회 버그 해결 (#176)
rkdcodus Apr 17, 2025
4e6a1dc
fix: 지원서 문항 조회 토스트, 지원서 제출자 검증 로직 추가 등 이슈 해결 (#178)
rkdcodus Apr 17, 2025
e8b9066
bug: 토큰 재발급 후 기존 api 호출이 수행되지 않는 문제 해결 (#181)
WonJuneKim Apr 17, 2025
d4eee48
fix: 지원자 정보 작성 페이지에서 지원서 제출 여부 판단 (#183)
rkdcodus Apr 18, 2025
00047ff
feat: 불필요한 로그를 제거하고 모니터링 로그로 대체 (#184)
WonJuneKim Apr 18, 2025
36da0f9
Bug: 임시 회원 최초 프로필 등록 여부 확인 api 연결 (#189)
rkdcodus Apr 18, 2025
1a823e6
chore: Amplitude 기본 설정 (#194)
WonJuneKim Apr 19, 2025
2da8934
feat: 매일 오전 5시~7시 점검 페이지 전환 기능 구현 (#192)
rkdcodus Apr 19, 2025
1e3647d
refactor: 점검 시간 기준을 KST으로 수정 (#197)
rkdcodus May 5, 2025
39c21dc
chore: gtm 이벤트 트래킹을 위한 전역 설정 (#206)
WonJuneKim May 5, 2025
acab938
chore: seo 개선 작업 (#198)
rkdcodus May 5, 2025
c912a86
feat: 지원 마감 UI 처리 (#209)
rkdcodus May 7, 2025
95bb1a3
fix: applyProcedureList startDate ISO 8601 형식으로 변경 (#211)
rkdcodus May 7, 2025
86bbbad
feat: 지원하기 페이지에서 모집 마감 페이지로 변경 (#213)
rkdcodus Jun 24, 2025
e0435c8
chore: 모노레포 사용을 위한 아키택쳐 변경 (#216)
WonJuneKim Aug 14, 2025
2260e6b
feat: emotion 기반 디자인 토큰 정의 (#218)
rkdcodus Aug 20, 2025
b40a29f
refactor: 디자인 토큰 업데이트 (#220)
rkdcodus Aug 22, 2025
ecc709e
bug: CI 파이프라인에서 발견되는 이슈들 해결 (#226)
WonJuneKim Aug 29, 2025
34ffb21
refactor: 디자인 토큰 업데이트 (#228)
rkdcodus Aug 30, 2025
1d61449
feat: 인터랙션 레이어 구현 (#222)
rkdcodus Sep 9, 2025
e6c9e26
feat: Hero 컴포넌트 구현 (#223)
rkdcodus Sep 10, 2025
2e7c154
feat: Icon 컴포넌트 구현 및 젝트 심볼 이미지 추가 (#224)
rkdcodus Sep 15, 2025
e0ae155
feat: Label 컴포넌트 구현 (#230)
rkdcodus Sep 18, 2025
c4107ca
feat: badge 컴포넌트 구현 (#232)
rkdcodus Oct 13, 2025
9a862d8
feat: Title 컴포넌트 구현 (#233)
rkdcodus Oct 13, 2025
f4b92bd
feat: 버튼 컴포넌트 - 디자인 시스템을 구현 (#238)
WonJuneKim Oct 14, 2025
c7ca820
feat: 버튼 없는 Callout 컴포넌트 구현 (#234)
rkdcodus Oct 14, 2025
663d1da
feat: Callout 컴포넌트에 버튼 기능 추가 (#241)
rkdcodus Oct 24, 2025
caf92bf
feat: 이미지 컴포넌트 구현 (#237)
rkdcodus Oct 24, 2025
2724925
refactor: 디자인 토큰 업데이트 (#243)
rkdcodus Oct 24, 2025
ed3b132
chore: 스토리북 다크/라이트 모드 기능 설정 (#244)
rkdcodus Oct 24, 2025
ff3f750
토큰 변경 (#260)
whdgur5717 Nov 14, 2025
6309d01
chore: radix-ui 패키지 설치 (#262)
whdgur5717 Nov 14, 2025
304e8e3
feat: FileItem 컴포넌트 구현 (#246)
rkdcodus Nov 17, 2025
b813d72
feat: 토스트, 스낵바 컴포넌트를 구현합니다 (#245)
rkdcodus Nov 18, 2025
77e4bda
feat: Uploader 업로더 컴포넌트 구현 (#247)
rkdcodus Nov 19, 2025
9723897
feat: 디자인 시스템 - Divider 컴포넌트 구현 (#250)
WonJuneKim Nov 20, 2025
1f53df3
feat: 디자인 시스템 - Input 컴포넌트 구현 (#248)
WonJuneKim Nov 20, 2025
d453425
feat: 디자인 시스템 - Logo 컴포넌트 구현 (#255)
WonJuneKim Nov 20, 2025
3b325e8
feat: 디자인 시스템 - Checkbox 컴포넌트 구현 (#259)
WonJuneKim Nov 20, 2025
58e3646
feat: 세그먼티드 컨트롤 컴포넌트 구현 (#272)
rkdcodus Nov 23, 2025
aca9f3f
chore: github actions를 통한 리뷰어 자동할당 프로세스 구현 (#254)
whdgur5717 Nov 23, 2025
de2df63
feat: 디자인 시스템 - Footer 컴포넌트 구현 (#268)
kimdonggu42 Nov 23, 2025
759bedc
feat: Tab 컴포넌트 구현 (#273)
whdgur5717 Nov 24, 2025
7767ca4
feat: 디자인 시스템 - Tooltip(툴팁) 컴포넌트 구현 (#276)
WonJuneKim Nov 25, 2025
fb3330e
feat: 포맷 정리 및 의존성 관련 정리 (#284)
whdgur5717 Nov 26, 2025
5db2ecf
feat: jds 패키지 storybook 버전 업데이트 (#286)
whdgur5717 Nov 27, 2025
a972c74
feat: 디자인 시스템 - Banner 컴포넌트 구현 (#277)
kimdonggu42 Nov 28, 2025
410bb1a
feat: 디자인 시스템 - emptyState 컴포넌트 구현 (#282)
ccconac Nov 30, 2025
9ff0cd1
feat: 디자인 시스템 - Navigation 컴포넌트 구현 (#285)
rkdcodus Nov 30, 2025
31ccdf8
feat: 디자인 시스템 - Step 컴포넌트 구현 (#288)
WonJuneKim Dec 8, 2025
efc1fd3
feat: API 처리 구조 및 API 검증 프로세스 구현 (#292)
WonJuneKim Dec 8, 2025
1525e65
feat: Badge, Navigation 디자인 토큰값 변경 사항 반영 (#295)
rkdcodus Dec 11, 2025
5a49ab0
feat: 디자인 시스템 - Menu 관련 컴포넌트 구현 (#297)
rkdcodus Dec 14, 2025
7b6d605
feat: 디자인 시스템 - Card 컴포넌트 구현 (#266)
WonJuneKim Dec 17, 2025
a6c73f0
feat: GNB 구현 (#301)
rkdcodus Dec 19, 2025
38da25d
feat: 랜딩 페이지 디자인 리뉴얼 (#304)
kimdonggu42 Dec 20, 2025
40dd590
feat: FAQ 페이지 구현 (#310)
rkdcodus Dec 24, 2025
9f5f391
feat: 비전 페이지 구현 (#305)
kimdonggu42 Dec 25, 2025
7783112
feat: 디자인 시스템 - Dialog 컴포넌트 구현 (#291)
ccconac Dec 26, 2025
7ecf20e
feat: 팀 프로젝트, 프로젝트 상세 페이지 구현 (#306)
rkdcodus Dec 27, 2025
26e0ea4
feat: 미니 스터디, 라이브 세션 페이지 구현 (#309)
kimdonggu42 Dec 28, 2025
cfdf247
feat: 지원하기 플로우 리뉴얼 (#314)
WonJuneKim Dec 28, 2025
f4e683d
feat: 랜딩, 비전과 스토리, 미니 스터디, 라이브 세션 페이지 QA 피드백 반영 (1차) (#315)
kimdonggu42 Dec 28, 2025
6bb284b
feat: 에러 페이지 구현 (#313)
rkdcodus Dec 28, 2025
0eb66ae
fix: GNB, FAQ, 파비콘 QA 수정 (#318)
rkdcodus Dec 28, 2025
2dab2ca
fix: 누락된 멤버 이미지 적용 (#316)
kimdonggu42 Dec 28, 2025
b9f87f6
fix: QA 이슈 해결 - GNB, 지원안내 및 지원하기, 팀 프로젝트, (#322)
rkdcodus Dec 29, 2025
16af4b0
fix: QA 이슈 해결 - 지원하기 플로우 (#323)
WonJuneKim Dec 29, 2025
30c254d
feat: 지원서 작성 중 페이지 이탈 시 확인 모달 추가 (#325)
kimdonggu42 Dec 29, 2025
5b72c91
fix: draft의 jobFamily와 현재 선택한 jobFamily가 다르면 draft 무시하도록 변경합니다. (#326)
WonJuneKim Dec 29, 2025
5b7ae1a
feat: 젝트 비전 스토리 버튼 클릭 시 /vision 이동 기능 추가 (#327)
kimdonggu42 Dec 29, 2025
f29c413
chore: 빌드 스크립트 수정 (#332)
WonJuneKim Dec 29, 2025
3574ab8
Chore/sync main to dev (#344)
WonJuneKim Dec 29, 2025
6d33dc5
chore: GTM 메타 픽셀, 커스텀 이벤트 추가 (#346)
WonJuneKim Jan 1, 2026
cde0a64
chore: Discord용 Sentry 웹 훅 생성 (#350)
WonJuneKim Jan 4, 2026
bd4beed
fix: 임시 저장 플로우 데이터 흐름 개선 (#353)
WonJuneKim Jan 6, 2026
1e62987
fix: 푸터 인스타 링크 수정 (#352)
rkdcodus Jan 6, 2026
4f549a4
fix: Button, Card 구조 및 기타 UI 구조 변경 (#356)
WonJuneKim Jan 6, 2026
128c211
chore: 버전 관리를 담당하는 workflow를 생성합니다. (#357)
WonJuneKim Jan 6, 2026
e56cf57
chore: changelog에서 제외하는 prefix를 추가합니다. (#359)
WonJuneKim Jan 6, 2026
7a8af2c
chore: sync main to dev (#360)
WonJuneKim Jan 6, 2026
a6d1c83
Chore/merge main to dev (#361)
WonJuneKim Jan 6, 2026
e944647
chore: merge main to dev
WonJuneKim Jan 6, 2026
2bfb586
release: 디자인 시스템 리뉴얼 및 지원 플로우 개선 (#362) (#363)
WonJuneKim Jan 6, 2026
3ea0310
fix: GNB 모바일 뷰 지원하기 cta 추가 및 레이아웃 구조 변경 (#364)
rkdcodus Jan 8, 2026
01fa79e
fix: 미니 스터디 레이아웃 수정 (#366)
kimdonggu42 Jan 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 148 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
name: Create Release

on:
push:
branches:
- main

jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Get latest tag
id: get_latest_tag
run: |
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
echo "latest_tag=$LATEST_TAG" >> $GITHUB_OUTPUT
echo "Latest tag: $LATEST_TAG"

- name: Check for changes
id: check_changes
run: |
LATEST_TAG=${{ steps.get_latest_tag.outputs.latest_tag }}

if [ "$LATEST_TAG" = "v0.0.0" ]; then
COMMIT_COUNT=$(git rev-list --count HEAD)
else
COMMIT_COUNT=$(git rev-list --count $LATEST_TAG..HEAD)
fi

if [ "$COMMIT_COUNT" -eq 0 ]; then
echo "has_changes=false" >> $GITHUB_OUTPUT
echo "No changes since last tag"
else
echo "has_changes=true" >> $GITHUB_OUTPUT
echo "Found $COMMIT_COUNT commits since last tag"
fi

- name: Calculate next version
id: next_version
if: steps.check_changes.outputs.has_changes == 'true'
run: |
LATEST_TAG=${{ steps.get_latest_tag.outputs.latest_tag }}

VERSION=${LATEST_TAG#v}
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"

# 커밋 메시지 분석 (release, deploy, merge 커밋 제외)
COMMITS=$(git log $LATEST_TAG..HEAD --pretty=format:"%s" 2>/dev/null | grep -viE "^(release|deploy|Merge)" || echo "")

if echo "$COMMITS" | grep -qiE "^(feat|feature)(\(.+\))?!:|BREAKING CHANGE"; then
MAJOR=$((MAJOR + 1))
MINOR=0
PATCH=0
elif echo "$COMMITS" | grep -qiE "^(feat|feature)(\(.+\))?:"; then
MINOR=$((MINOR + 1))
PATCH=0
else
PATCH=$((PATCH + 1))
fi

NEW_VERSION="v${MAJOR}.${MINOR}.${PATCH}"

# 중복 태그 확인
if git tag -l | grep -q "^${NEW_VERSION}$"; then
echo "Tag $NEW_VERSION already exists, skipping"
echo "skip_release=true" >> $GITHUB_OUTPUT
else
echo "skip_release=false" >> $GITHUB_OUTPUT
fi

echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "New version: $NEW_VERSION"

- name: Generate changelog
id: changelog
if: steps.check_changes.outputs.has_changes == 'true' && steps.next_version.outputs.skip_release != 'true'
run: |
LATEST_TAG=${{ steps.get_latest_tag.outputs.latest_tag }}

if [ "$LATEST_TAG" = "v0.0.0" ]; then
COMMITS=$(git log --pretty=format:"- %s (%h)" --reverse)
else
COMMITS=$(git log $LATEST_TAG..HEAD --pretty=format:"- %s (%h)" --reverse)
fi

FEATURES=""
FIXES=""
CHORES=""
OTHERS=""

while IFS= read -r line; do
# release, deploy, merge 커밋 제외
if echo "$line" | grep -qiE "^- (release|deploy)(\(.+\))?:|^- Merge "; then
continue
elif echo "$line" | grep -qiE "^- (feat|feature)(\(.+\))?:"; then
FEATURES="$FEATURES$line"$'\n'
elif echo "$line" | grep -qiE "^- (fix|hotfix)(\(.+\))?:"; then
FIXES="$FIXES$line"$'\n'
elif echo "$line" | grep -qiE "^- (chore|docs|style|refactor|perf|test|ci)(\(.+\))?:"; then
CHORES="$CHORES$line"$'\n'
else
OTHERS="$OTHERS$line"$'\n'
fi
done <<< "$COMMITS"

CHANGELOG=""

if [ -n "$FEATURES" ]; then
CHANGELOG="$CHANGELOG## Features"$'\n'"$FEATURES"$'\n'
fi

if [ -n "$FIXES" ]; then
CHANGELOG="$CHANGELOG## Bug Fixes"$'\n'"$FIXES"$'\n'
fi

if [ -n "$CHORES" ]; then
CHANGELOG="$CHANGELOG## Chores"$'\n'"$CHORES"$'\n'
fi

if [ -n "$OTHERS" ]; then
CHANGELOG="$CHANGELOG## Other Changes"$'\n'"$OTHERS"$'\n'
fi

EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
echo "changelog<<$EOF" >> $GITHUB_OUTPUT
echo "$CHANGELOG" >> $GITHUB_OUTPUT
echo "$EOF" >> $GITHUB_OUTPUT

- name: Create Release
if: steps.check_changes.outputs.has_changes == 'true' && steps.next_version.outputs.skip_release != 'true'
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.next_version.outputs.new_version }}
name: Release ${{ steps.next_version.outputs.new_version }}
body: ${{ steps.changelog.outputs.changelog }}
draft: false
prerelease: false
generate_release_notes: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3 changes: 3 additions & 0 deletions api/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
173 changes: 173 additions & 0 deletions api/sentry-discord.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import type { VercelRequest, VercelResponse } from "@vercel/node";

// Sentry Webhook Payload 타입
interface SentryIssue {
title: string;
culprit: string;
shortId: string;
metadata: {
type?: string;
value?: string;
};
web_url?: string;
}

interface SentryEvent {
title: string;
environment?: string;
tags: Array<[string, string]>;
web_url?: string;
}

interface SentryWebhookPayload {
action: string;
data: {
issue?: SentryIssue;
event?: SentryEvent;
};
actor?: {
name?: string;
};
triggered_rule?: string;
}

// 타입 가드
const hasIssue = (payload: SentryWebhookPayload): boolean =>
payload.data.issue !== undefined;

const hasEvent = (payload: SentryWebhookPayload): boolean =>
payload.data.event !== undefined;

// 필터링 - production 환경의 중요한 알림만 허용
const ALLOWED_ACTIONS = new Set(["created", "regressed", "triggered"]);

function shouldSkip(payload: SentryWebhookPayload): boolean {
if (!ALLOWED_ACTIONS.has(payload.action)) {
return true;
}

if (hasEvent(payload)) {
return payload.data.event?.environment !== "production";
}

return false;
}

// Discord Embed 생성
function createIssueEmbed(issue: SentryIssue, action: string, actorName: string) {
return {
embeds: [
{
title: `[${action.toUpperCase()}] ${issue.title}`,
description: issue.culprit || "No culprit information",
color: getColorByAction(action),
...(issue.web_url && { url: issue.web_url }),
fields: [
{ name: "Issue", value: issue.shortId, inline: true },
{ name: "Type", value: issue.metadata.type ?? "Unknown", inline: true },
{ name: "Triggered by", value: actorName, inline: true },
{ name: "Message", value: truncate(issue.metadata.value ?? "N/A", 200), inline: false },
],
timestamp: new Date().toISOString(),
footer: { text: "Sentry" },
},
],
};
}

function createEventEmbed(event: SentryEvent, triggeredRule: string) {
const tags = Object.fromEntries(event.tags);

return {
embeds: [
{
title: `[ERROR] ${event.title}`,
description: triggeredRule ? `Rule: ${triggeredRule}` : "Sentry Alert",
color: 0xff0000,
...(event.web_url && { url: event.web_url }),
fields: [
{ name: "Environment", value: event.environment ?? "Unknown", inline: true },
{ name: "Browser", value: tags.browser ?? "-", inline: true },
{ name: "OS", value: tags.os ?? "-", inline: true },
],
timestamp: new Date().toISOString(),
footer: { text: "Sentry" },
},
],
};
}

function createDiscordPayload(payload: SentryWebhookPayload) {
if (hasIssue(payload) && payload.data.issue) {
return createIssueEmbed(payload.data.issue, payload.action, payload.actor?.name ?? "System");
}

if (hasEvent(payload) && payload.data.event) {
return createEventEmbed(payload.data.event, payload.triggered_rule ?? "");
}

// fallback
return {
embeds: [
{
title: "[ALERT] Sentry Notification",
description: "Unknown payload type",
color: 0x9e9e9e,
timestamp: new Date().toISOString(),
},
],
};
}

//색상 유틸리티
function getColorByAction(action: string): number {
const map: Record<string, number> = {
created: 0xff0000,
regressed: 0xff6f00,
resolved: 0x00c853,
};
return map[action] ?? 0x9e9e9e;
}

function truncate(value: string, max: number) {
return value.length > max ? value.slice(0, max - 3) + "..." : value;
}

// 핸들러 - Vercel이 Sentry로 부터 HTTP 요청을 받으면 수행됨
export default async function handler(req: VercelRequest, res: VercelResponse) {
if (req.method !== "POST") {
return res.status(405).end();
}

if (!req.headers["sentry-hook-signature"]) {
return res.status(401).json({ error: "Invalid source" });
}

const webhookUrl = process.env.DISCORD_WEBHOOK_URL;
if (!webhookUrl) {
return res.status(500).json({ error: "Webhook not configured" });
}

const payload = req.body as unknown as SentryWebhookPayload;
if (!payload?.data) {
return res.status(400).json({ error: "Invalid payload" });
}

if (shouldSkip(payload)) {
return res.status(200).json({ skipped: true });
}

try {
const discordPayload = createDiscordPayload(payload);

await fetch(webhookUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(discordPayload),
});
} catch (error) {
console.error("Discord webhook failed:", error);
}

return res.status(200).json({ ok: true });
}
12 changes: 12 additions & 0 deletions api/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true,
"noEmit": true
},
"include": ["."]
}
1 change: 1 addition & 0 deletions apps/web/src/apis/apply/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export const interestedDomainSchema = z.enum([
export const memberMeResponseSchema = z.object({
id: z.number(),
name: z.string(),
phoneNumber: z.string(),
careerDetails: careerDetailsSchema,
region: regionSchema,
experiencePeriod: experiencePeriodSchema,
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/common/footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function Footer() {
</FooterJds.LogoDiv>
<FooterJds.Social
github='https://github.com/JECT-Study'
instagram='https://www.instagram.com/ject_official'
instagram='https://www.instagram.com/ject.official'
/>
</FooterJds.Header>
<FooterJds.Divider />
Expand Down
Loading