Merged
Conversation
회원 승인 시스템 기반 작업. 기존 active/dormant/withdrawn에 pending_approval(승인대기), inactive(비활성), ob(OB) 상태를 추가. Co-Authored-By: Claude <noreply@anthropic.com>
pending_approval(승인대기/warning), inactive(비활성/destructive), ob(OB/outline) 상태 및 Badge variant 매핑 추가. Co-Authored-By: Claude <noreply@anthropic.com>
프론트엔드에서 멤버 상태(pending_approval, active, inactive 등)에 따라 리다이렉트 처리를 할 수 있도록 status 필드를 응답에 포함 Co-Authored-By: Claude <noreply@anthropic.com>
신규 유저가 온보딩을 완료하면 즉시 active가 아닌 pending_approval 상태로 설정하여 관리자 승인 후에만 대시보드에 접근할 수 있도록 함 기존 유저의 UPDATE 케이스는 변경하지 않음 Co-Authored-By: Claude <noreply@anthropic.com>
로그인 시 멤버 status를 조회하여 상태에 따라 적절한 페이지로 리다이렉트: - pending_approval → /pending (승인 대기 페이지) - inactive → /inactive (비활성 안내 페이지) - active → /dashboard (기존 동작 유지) Co-Authored-By: Claude <noreply@anthropic.com>
pending_approval, inactive 상태의 유저를 각각 /pending, /inactive 페이지로 리다이렉트. 차단 페이지 자체는 예외 처리하여 무한 루프 방지. Co-Authored-By: Claude <noreply@anthropic.com>
pending_approval 상태 유저가 보는 대기 화면. 스카이블루 Clock 아이콘, 안내 메시지, 로그아웃 버튼 포함. Co-Authored-By: Claude <noreply@anthropic.com>
inactive 상태 유저가 보는 차단 화면. 레드 ShieldX 아이콘, 안내 메시지, 로그아웃 버튼 포함. Co-Authored-By: Claude <noreply@anthropic.com>
- GET /api/admin/members: grouped/counts에 pending_approval, inactive, ob 추가 - GET /api/admin/members: 응답에 nickname, interests, resolution, onboardingCompleted 추가 - PUT /api/admin/members/[id]: validStatuses에 6개 상태 전체 포함 - 그룹핑 로직을 동적 키 방식으로 리팩토링 Co-Authored-By: Claude <noreply@anthropic.com>
- Task 11: 4개 통계 카드 → 6개 상태 필터 탭 (pill 버튼) 교체
- pending_approval, active, ob, dormant, inactive 탭 추가
- 승인대기 탭 선택 시 카드 그리드 뷰로 전환
- Member 인터페이스에 nickname, bio, interests, resolution,
onboardingCompleted 필드 추가
- MemberCounts/MembersData에 6개 상태 모두 포함
- handleApproveMember / handleRejectMember 핸들러 추가
- Task 12: PendingMemberCard 컴포넌트 신규 생성
- 프로필 이미지, 이름, 닉네임, 파트, 블로그 링크 표시
- bio, interests, resolution 선택적 렌더링
- 승인(활성/OB 선택) / 거절 2단계 액션
- Task 14: MemberFormDialog에 상태 편집 필드 추가
- 편집 모드에서만 상태 select 표시
- MEMBER_STATUS_CONFIG 기반 6개 상태 옵션
- PUT 요청 body에 status 포함
Co-Authored-By: Claude <noreply@anthropic.com>
Record<string, ...> 대신 개별 키를 as 타입 단언으로 선언하여 TypeScript strict 모드에서 undefined 가능성 제거. Co-Authored-By: Claude <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
리다이렉트 중에도 finally에서 onboardingChecked가 true로 설정되어 children이 잠깐 렌더링되던 문제 수정. 리다이렉트 시에는 로딩 화면을 유지하도록 setOnboardingChecked(true)를 성공 경로에서만 호출. Co-Authored-By: Claude <noreply@anthropic.com>
pathname 변경 시 onboardingChecked를 false로 리셋하여 API 체크 완료 전까지 로딩 화면 유지. Co-Authored-By: Claude <noreply@anthropic.com>
onboardingChecked boolean 대신 checkedPathname으로 변경하여 pathname 변경 시 자동으로 로딩 상태가 되도록 개선. react-hooks/set-state-in-effect 룰 위반 해결. Co-Authored-By: Claude <noreply@anthropic.com>
choihooo
added a commit
that referenced
this pull request
Mar 10, 2026
P1 #10 문제 해결: - 문제: 매일 10:00에 실행되므로 daysSinceCreation % 3 === 0 로직이 불안정 - 3일째 10:00에 3일 경과 (3 % 3 = 0) → 리마인드 발송 - 4일째 10:00에도 여전히 리마인드 발송 가능 해결 방법: 1. fines 테이블에 lastReminderAt 컬럼 추가 2. 리마인드 발송 후 lastReminderAt 업데이트 3. 마지막 리마인드로부터 정확히 3일 경과 시만 재발송 변경 사항: - schema.ts: fines 테이블에 lastReminderAt 컬럼 및 인덱스 추가 - fine-reminder.ts: 필터 로직을 lastReminderAt 기반으로 변경 - fine.service.ts: updateLastReminderAt() 메서드 추가 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
choihooo
added a commit
that referenced
this pull request
Mar 10, 2026
* fix: Fine Reminder 3일 간격 로직 수정 (P1 #10) P1 #10 문제 해결: - 문제: 매일 10:00에 실행되므로 daysSinceCreation % 3 === 0 로직이 불안정 - 3일째 10:00에 3일 경과 (3 % 3 = 0) → 리마인드 발송 - 4일째 10:00에도 여전히 리마인드 발송 가능 해결 방법: 1. fines 테이블에 lastReminderAt 컬럼 추가 2. 리마인드 발송 후 lastReminderAt 업데이트 3. 마지막 리마인드로부터 정확히 3일 경과 시만 재발송 변경 사항: - schema.ts: fines 테이블에 lastReminderAt 컬럼 및 인덱스 추가 - fine-reminder.ts: 필터 로직을 lastReminderAt 기반으로 변경 - fine.service.ts: updateLastReminderAt() 메서드 추가 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: 필터 로직 버그 수정 (코드 리뷰 사항 반영) Priority 1 문제 해결: 1. 필터 로직 버그 수정 - 이전: createdAt < threeDaysAgo (3일 이전 체크 - 로직 반대) - 수정: now < threeDaysSinceCreation (3일 미경과 제외) 2. NULL 처리 로직 개선 - 이전: !lastReminderAt → 무조건 true (3일 미경과해도 발송) - 수정: !lastReminderAt → 3일 경과 확인 후 return true 변경 사항: - threeDaysAgo 변수 제거 - threeDaysSinceCreation 변수 추가 (createdAt + 3일) - 주석 명확화 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
- ExternalLinkIcon 재사용 컴포넌트 생성 - 새 탭에서 열림을 나타내는 sr-only 텍스트 추가 - 랜딩 페이지, 게시판, 큐레이션 외부 링크에 적용 - aria-hidden으로 아이콘 숨김 처리 Refs: docs/26-03-11-web-accessibility-audit.md P1 #10
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
온보딩 완료 후 관리자 승인이 필요한 멤버 승인 워크플로우와 6단계 상태 관리 시스템을 구축합니다.
pending_approval상태로 설정, 관리자 승인 전까지 플랫폼 접근 차단pending_approval·active·inactive·dormant·ob·withdrawnChanges
packages/shared/src/db/schema.tspending_approval,inactive,ob추가packages/web/src/lib/member-config.tspackages/web/src/app/api/auth/me/route.tsstatus필드 추가packages/web/src/app/api/profile/onboarding/route.tspending_approval설정packages/web/src/app/auth/callback/route.tspackages/web/src/app/(user)/layout.tsxpackages/web/src/app/(user)/pending/page.tsxpackages/web/src/app/(user)/inactive/page.tsxpackages/web/src/app/api/admin/members/route.tspackages/web/src/app/api/admin/members/[id]/route.tspackages/web/src/app/(admin)/admin/members/page.tsxpackages/web/src/app/(admin)/admin/members/pending-member-card.tsxpackages/web/src/app/(admin)/admin/members/member-form-dialog.tsxDesign Decisions
pending_approval상태 시 완전 차단inactive도 완전 차단dormant,ob는 모든 기능 허용Test Plan
pending_approval상태 확인pnpm build성공 확인🤖 Generated with Claude Code