Skip to content

chore: 프레임워크 업그레이드 (Next.js 16 + React 19 + Tailwind v4)#5

Merged
bbbang105 merged 3 commits intodevfrom
feat/phase1-framework-upgrade
Feb 24, 2026
Merged

chore: 프레임워크 업그레이드 (Next.js 16 + React 19 + Tailwind v4)#5
bbbang105 merged 3 commits intodevfrom
feat/phase1-framework-upgrade

Conversation

@bbbang105
Copy link
Copy Markdown
Owner

🎯 Summary

Next.js 14 → 16.1, React 18 → 19.2, Tailwind CSS v3 → v4.2 프레임워크 메이저 업그레이드


🔴 AS-IS

  • Next.js 14.2 + React 18.3 + Tailwind CSS v3.4
  • middleware.ts 컨벤션, next lint 사용
  • tailwind.config.ts JS 설정 기반

🟢 TO-BE

  • Next.js 16.1.6 + React 19.2.4 + Tailwind CSS 4.2.1
  • proxy.ts 컨벤션 (Next.js 16), ESLint flat config 직접 사용
  • CSS-first 설정 (globals.css @theme 지시어), Turbopack 기본 빌드

💬 참고사항

커밋 구성 (2단계 분리)

커밋 범위
chore: Next.js 16.1 + React 19.2 업그레이드 프레임워크 코어
chore: Tailwind CSS v3 → v4.2 업그레이드 스타일 시스템
chore: next-env.d.ts 경로 업데이트 자동 생성 파일

주요 변경 사항

결정 이유
middleware.tsproxy.ts Next.js 16 공식 컨벤션 변경
next linteslint . Next.js 16에서 next lint 제거됨
useSyncExternalStore mounted 패턴 React 19 set-state-in-effect 규칙 대응
SidebarContent 외부 추출 React 19 static-components 규칙 대응
tailwindcss-animatetw-animate-css Tailwind v4 호환 패키지 교체
data-scroll-behavior="smooth" 추가 Next.js 16 스크롤 동작 변경 호환

검증 결과

  • pnpm typecheck 통과
  • pnpm --filter @blog-study/web build 통과 (Turbopack)
  • pnpm --filter @blog-study/web lint 에러 0
  • 로컬 dev 실행 후 시각적 확인 완료

🤖 Generated with Claude Code

bbbang105 and others added 3 commits February 24, 2026 14:23
- next 14.2 → 16.1.6, react 18.3 → 19.2.4
- middleware.ts → proxy.ts 리네임 (Next.js 16 컨벤션)
- next lint → eslint CLI 마이그레이션 (eslint.config.mjs 추가)
- React 19 ESLint 규칙 대응:
  - header: useSyncExternalStore로 mounted 패턴 교체
  - sidebar: SidebarContent 컴포넌트 외부 추출
  - input: 빈 인터페이스 → type alias
- layout.tsx에 data-scroll-behavior="smooth" 추가

Co-Authored-By: Claude <noreply@anthropic.com>
- tailwindcss v3.4 → v4.2.1, postcss 플러그인 → @tailwindcss/postcss
- tailwindcss-animate → tw-animate-css 교체
- tailwind.config.ts 삭제 → globals.css @theme 지시어로 마이그레이션
- @tailwind 지시어 → @import "tailwindcss" 변경
- autoprefixer 제거 (v4에 내장)
- 컴포넌트 Tailwind v4 클래스명 마이그레이션 (outline-none → outline-hidden 등)
- components.json tailwind config 경로 비우기

Co-Authored-By: Claude <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Feb 24, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
study-admin-web Ready Ready Preview, Comment Feb 24, 2026 5:36am

@bbbang105 bbbang105 added ⚒️ chore 빌드 부분 혹은 패키지 매니저 수정 사항 🚨 fix 버그 수정 / 에러 해결 labels Feb 24, 2026
@bbbang105 bbbang105 merged commit aebcb16 into dev Feb 24, 2026
8 checks passed
@bbbang105 bbbang105 deleted the feat/phase1-framework-upgrade branch February 24, 2026 05:38
choihooo added a commit that referenced this pull request Mar 10, 2026
P0 #5: 주간 랭킹 날짜 필터 추가
- 문제: activityScores 테이블에서 모든 기간의 점수를 합산
- 해결: 이번 주 시작일(~ 00:00:00 KST)부터 종료일(~ 23:59:59.999 KST)까지의 점수만 필터링
- 파일: weekly-ranking.ts

P0 #6: 회차 시작 알림 타임존 수정
- 문제: UTC 기준으로 날짜 비교해서 KST에서 실행 시 날짜 불일치
- 해결: KST (UTC+9) 기준으로 오늘 날짜 구해서 비교
- 파일: round-reporter.ts (sendRoundStartAnnouncement)

P0 #7: 회차 종료 후 isCurrent 플래그 업데이트
- 문제: 회차 리포트 전송 후 isCurrent 플래그가 업데이트되지 않음
- 해결: 다음 회차가 있으면 해당 회차를 current로 설정, 없으면 현재 회차의 isCurrent를 false로 변경
- 파일: round-reporter.ts (sendRoundReport)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
choihooo added a commit that referenced this pull request Mar 10, 2026
* fix: 회차 스케줄러 버그 수정 (P0 #5, #6, #7)

P0 #5: 주간 랭킹 날짜 필터 추가
- 문제: activityScores 테이블에서 모든 기간의 점수를 합산
- 해결: 이번 주 시작일(~ 00:00:00 KST)부터 종료일(~ 23:59:59.999 KST)까지의 점수만 필터링
- 파일: weekly-ranking.ts

P0 #6: 회차 시작 알림 타임존 수정
- 문제: UTC 기준으로 날짜 비교해서 KST에서 실행 시 날짜 불일치
- 해결: KST (UTC+9) 기준으로 오늘 날짜 구해서 비교
- 파일: round-reporter.ts (sendRoundStartAnnouncement)

P0 #7: 회차 종료 후 isCurrent 플래그 업데이트
- 문제: 회차 리포트 전송 후 isCurrent 플래그가 업데이트되지 않음
- 해결: 다음 회차가 있으면 해당 회차를 current로 설정, 없으면 현재 회차의 isCurrent를 false로 변경
- 파일: round-reporter.ts (sendRoundReport)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: 타임존 처리를 formatKSTDate 헬퍼 함수로 분리

코드 리뷰 사항 반영:
- P0 #6 타임존 처리 로직을 formatKSTDate() 헬퍼 함수로 분리
- 코드 재사용성과 명확성 향상
- KST 오프셋 계산 로직을 함수 내부로 캡슐화

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
choihooo added a commit that referenced this pull request Mar 11, 2026
- 에러 메시지에 role="alert", aria-live="assertive" 추가
- 입력 필드에 aria-invalid, aria-describedby 속성 추가
- 필드별 에러를 동적으로 연결하여 스크린 리더에 정확히 전달
- 게시판 작성, 멤버 폼에 적용

Refs: docs/26-03-11-web-accessibility-audit.md P1 #5
choihooo added a commit that referenced this pull request Mar 11, 2026
* feat: 큐레이션 데이터 품질 개선 (description, thumbnailUrl 추출)

P1 #8: 큐레이션 봇 크롤러 데이터 품질 개선

주요 변경사항:
- RSS 피드에서 description, thumbnailUrl 필드 추출
- feed-parser 공유 유틸리티 생성 (extractFeedItems, sanitizeDescription, extractOgImage)
- SSRF 보호 강화 (isSafeUrl를 url-validator로 이동)
- HTML 엔티티 디코딩 추가 (html-entities 패키지)
- 제어 문자/유니코드 익스플로잇 제거 로직 개선
- 웹 API와 봇 간 코드 중복 제거

보안 개선:
- extractOgImage 함수에 isSafeUrl SSRF 체크 추가
- sanitizeDescription에 제어 문자/유니코드 익스플로잇 제거 추가
- 내부 URL (localhost, 127.0.0.1, 169.254.169.254 등) 차단

테스트:
- feed-parser.property.test.ts 추가 (20개 테스트 케이스)
- SSRF 보호, XSS 방지, 한글/이모지 처리 등 검증

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* perf: OG 이미지 추출 병렬 처리로 성능 개선

- 봇 스케줄러: Promise.allSettled로 OG 이미지 동시 추출
- 웹 API: OG 이미지 병렬 추출 후 DB 삽입 (순차 유지)
- 순차 처리(최대 250초) → 병렬 처리(최대 5초)로 대기 시간 단축
- Promise.allSettled로 개별 실패시 전체 프로세스 보호

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: 타입 안전성 개선 (NormalizedFeedItem 타입 명시)

- 웹 API: NormalizedFeedItem 타입 import 추가
- filter/map 콜백에 명시적 타입 어노테이션 추가
- Promise.allSettled 결과에 타입 가드 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: PR 빌드 에러 수정 (utils export, isSafeUrl re-export)

- shared/utils: utils namespace export 추가 (import { utils } 패턴 지원)
- rss-detect.ts: isSafeUrl re-export 추가
- 타입 안전성 개선: Promise.allSettled result 변수 분리

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: P2 #15 핸들러 및 스케줄러 테스트 추가

- Handlers 통합 테스트 5개 추가 (모듈 로드, 함수 export 확인)
- Round Service 통합 테스트 15개 추가
  * isDeadlinePassed, isGracePeriod, isGracePeriodEnded 함수 테스트
  * 날짜 파싱 정확성 테스트
  * 일관성 테스트
- 총 145개 테스트 통과

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: handlers.test.ts mock export 추가로 테스트 수정

- sendFineNotification, sendFineReminder export를 mock에 추가
- 모든 테스트 통과 (153개)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: 린트 에러 수정 (unused imports 제거)

- getConfigValue import 제거 (round-integration.test.ts)
- Client import 제거 (handlers.test.ts)
- 에러 0개, warnings 56개 (console.log 관련)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: PR #29 코드 리뷰 피드백 반영

## 개선사항

### 1. 핸들러 테스트 실제 동작 검증으로 강화
- Mock만 사용하던 테스트를 실제 이벤트 리스너 등록 검증으로 개선
- setupActivityHandler: MessageCreate, MessageReactionAdd 이벤트 등록 확인
- setupDMHandler: InteractionCreate 이벤트 등록 확인
- Property-Based Testing 패턴 유지

### 2. feed-parser 보안 강화 (SSRF)
- extractOgImage()에서 OG 이미지 URL 자체도 안전한지 검증
- 이중 SSRF 보호: 페이지 URL + OG 이미지 URL 모두 검증
- 공격자가 og:image에 내부 URL을 넣는 방어

### 3. 에러 핸들링 개선
- extractOgImage() 에러를 타입별로 분류하여 로그
- timeout, network error, unexpected error 각각 다른 레벨로 처리
- 디버깅 및 운영 모니터링 개선

### 4. 테스트 커버리지 확대
- extractFeedItems() 포맷별 동작 테스트 추가 (RSS, Atom, JSON, RDF)
- Property 17-20: 각 포맷의 파싱 로직 검증
- 총 24개 테스트 통과

### 5. 타입 안정성 개선
- API 라우트에서 불필요한 타입 단언 제거
- 타입 가드를 사용하여 안전하게 필터링

### 6. next-env.d.ts 복구
- 개발 전용 변경을 원래대로 복구
- 프로덕션 빌드 호환성 유지

## 테스트 결과
- 154개 테스트 전체 통과
- 핸들러 테스트: 9개 (이벤트 리스너 등록 검증)
- feed-parser 테스트: 24개 (보안 + 포맷별 동작)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(a11y): 테이블 헤더에 scope 속성 추가

- TableHead 컴포넌트에 기본값 scope="col" 추가
- 모든 테이블 헤더의 의미 체계를 스크린 리더에 명확히 전달
- WCAG 2.1 AA 준수

Refs: docs/26-03-11-web-accessibility-audit.md P1 #9

* feat(a11y): 활성 내비게이션에 aria-current 속성 추가

- BottomNav 컴포넌트에 aria-current="page" 추가
- 현재 페이지 여부를 스크린 리더에 명확히 전달
- 모바일 하단 내비게이션 접근성 개선

Refs: docs/26-03-11-web-accessibility-audit.md P1 #4

* feat(a11y): 외부 링크에 스크린 리더용 보조 텍스트 추가

- ExternalLinkIcon 재사용 컴포넌트 생성
- 새 탭에서 열림을 나타내는 sr-only 텍스트 추가
- 랜딩 페이지, 게시판, 큐레이션 외부 링크에 적용
- aria-hidden으로 아이콘 숨김 처리

Refs: docs/26-03-11-web-accessibility-audit.md P1 #10

* feat(a11y): 검색 입력 필드에 접근 가능한 라벨 추가

- sr-only 클래스로 화면에는 보이지 않는 라벨 추가
- htmlFor와 id로 명시적 연결
- 검색 아이콘에 aria-hidden 적용
- 큐레이션, 멤버, 벌금 페이지 검색창 개선

Refs: docs/26-03-11-web-accessibility-audit.md P1 #6

* feat(a11y): 폼 에러 메시지를 입력 필드와 연결

- 에러 메시지에 role="alert", aria-live="assertive" 추가
- 입력 필드에 aria-invalid, aria-describedby 속성 추가
- 필드별 에러를 동적으로 연결하여 스크린 리더에 정확히 전달
- 게시판 작성, 멤버 폼에 적용

Refs: docs/26-03-11-web-accessibility-audit.md P1 #5

* fix(a11y): 사용하지 않는 ExternalLinkIcon import 제거

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
bbbang105 added a commit that referenced this pull request Mar 13, 2026
라우트 보호 미들웨어가 프레임워크 업그레이드(#5)에서 누락 삭제됨.
비관리자 /admin 접근 시 /dashboard 리다이렉트, 미인증 시 /login 리다이렉트 복원.

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚒️ chore 빌드 부분 혹은 패키지 매니저 수정 사항 🚨 fix 버그 수정 / 에러 해결

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant