Skip to content

feat(web): 게시판 날짜 투표 및 투표 변경 기능 구현#46

Merged
choihooo merged 21 commits intodevfrom
feature/board-poll-voting
Mar 16, 2026
Merged

feat(web): 게시판 날짜 투표 및 투표 변경 기능 구현#46
choihooo merged 21 commits intodevfrom
feature/board-poll-voting

Conversation

@choihooo
Copy link
Collaborator

📋 변경 사항

게시판 투표 시스템을 개선하여 날짜 투표와 투표 변경 기능을 구현했습니다.

✨ 주요 기능

  1. 날짜 투표 (다중 선택)

    • 멀티 캘린더로 여러 날짜 선택 가능
    • 날짜 형식 자동 변환 (2026-03-1703/17 (화))
    • 날짜 투표도 복수 선택과 동일하게 여러 날짜 투표 가능
  2. 투표 변경 허용

    • 단일/복수/날짜 투표: 재투표 시 기존 투표 자동 삭제 및 변경
    • 투표 후에도 계속 "투표 변경" 버튼 표시
    • 중복 투표 방지 로직 강화
  3. 게시글당 투표 1개 제한

    • 이미 투표가 있으면 추가 폼 숨김
    • 투표 삭제 시 다시 폼 표시
  4. 성능 개선

    • 투표 API 캐시 제거로 즉시 반영
    • 중복 클릭 방지로 불필요한 API 호출 감소

🛠️ 기술적 변경

Frontend

  • poll-editor.tsx: 날짜 투표 1개 제한 로직 추가
  • poll-vote-modal.tsx: 날짜 투표 다중 선택 지원, 요일 표시
  • poll-display.tsx: 투표 변경 가능, 날짜 요일 표시, 캐시 제거
  • write/page.tsx: 투표 데이터 디버깅 로그 추가

Backend

  • vote/route.ts: 날짜 투표 변경 가능하도록 수정
  • polls/route.ts: 캐시 제거로 즉시 반영

🐛 수정된 이슈

  • ✅ 날짜 투표가 생성되지 않는 문제 해결
  • ✅ 투표 후 3개가 들어가는 중복 투표 문제 해결
  • ✅ 투표 후 변경이 불가능한 문제 해결
  • ✅ 투표 반영이 늦는 문제 해결

📸 스크린샷

게시글 작성 시 투표 추가 (날짜 선택)
투표 작성

투표 결과 (요일 표시)
투표 결과

🧪 테스트 계획

  • 날짜 투표 생성 (여러 날짜 선택)
  • 투표 변경 (기존 투표 삭제 후 재투표)
  • 날짜 요일 표시 확인
  • 중복 투표 방지 확인
  • 게시글당 투표 1개 제한 확인
  • dev 브랜치와 충돌 없는지 확인

🔍 리뷰 요청사항

특별히 리뷰가 필요한 부분:

  • 투표 변경 로직的安全性
  • 캐시 제거에 따른 성능 영향
  • 날짜 투표 UI/UX 개선 가능성

🤖 Generated with Claude Code

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

choihooo and others added 10 commits March 13, 2026 15:58
게시글 작성 시 카카오톡 스타일의 투표 기능을 추가하여
멤버들의 참여도를 높이고 의견을 수렴할 수 있게 합니다.

## 기능

### 투표 유형
- 단일 선택 (라디오)
- 복수 선택 (체크박스)
- 날짜 투표
- 익명 투표

### 주요 기능
- 게시글 작성 시 투표 추가 가능
- 최소 2개 선택지, 추가/삭제 가능
- 마감시간 설정 (1시간/6시간/1일/3일/1주)
- 투표 현황 실시간 표시 (진행바 + 투표자 목록)
- 익명 투표 시 투표자 비공개
- 단일/복수 투표 변경 허용 (재투표)

## DB 스키마

### 추가 테이블
- board_polls: 투표 메타데이터
- board_poll_options: 투표 선택지
- board_poll_votes: 투표 참여 기록

### Enum
- poll_type: single, multiple, date, anonymous

## API

### 추가 엔드포인트
- GET /api/board/[postId]/polls - 투표 조회
- POST /api/board/[postId]/polls/[pollId]/vote - 투표 참여
- POST /api/board/[postId]/polls/[pollId]/options - 선택지 추가

### 수정 엔드포인트
- POST /api/board - 투표 생성 로직 추가

## UI 컴포넌트

### 추가 컴포넌트
- PollEditor: 투표 생성 에디터
- PollDisplay: 투표 표시 (진행바 + 투표자 목록)
- PollVoteModal: 투표 참여 모달

### 수정 페이지
- /board/write - 투표 추가 기능
- /board/[id] - 투표 표시 + 참여

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 게시글 수정 페이지에서 투표 수정/삭제 기능 추가
- 투표 참여자가 0명일 때만 수정 가능
- 질문, 유형, 마감시간, 선택지 수정 가능
- 선택지 추가/삭제 기능 (최소 2개 유지)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- API에서 게시글별 투표 개수 반환 (pollCount 필드)
- 게시판 목록에 투표 아이콘(BarChart3)과 개수 표시
- 인디고색(indigo-500)으로 댓글 아이콘과 구분
- 데스크톱/모바일, 일반/고정 게시글 모두 지원

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 게시글 상세: 투표 현황 표시, 투표자 상세 모달
- 게시글 수정: 투표 관리 버튼 및 모달 연동
- 투표 참여 후 실시간 갱신
- 익명 투표는 투표자 목록 비공개

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- [postId] 폴더 구조를 [id]로 통합
- 중복된 polls API 라우트 삭제
- 기존 게시글 상세 경로와 일관성 유지

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 기능 개요 및 투표 유형 설명
- 사용자 흐름 및 화면 구성
- DB 스키마 및 API 명세
- 제한 사항 및 변경 사항 기록

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- shadcn/ui Calendar 및 Popover 컴포넌트 추가
- 날짜 선택 달력으로 직관적인 날짜 설정
- 시간 선택 피커로 정확한 시간 설정
- date-fns로 한국어 날짜 형식 지원
- 기존 빠른 선택 버튼 (1시간/1일 등) 유지

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- +1시간, +1일 등 빠른 선택 버튼 삭제
- 달력과 시간 피커로만 마감시간 설정

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 캘린더 셀 크기 증가 (h-9 w-9)
- 더 큰 패딩과 여백 추가
- nav 버튼 크기 조정 (h-7 w-7)
- 전체적으로 더 읽기 쉬운 UI로 개선

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 투표 유형이 '날짜 투표'일 때 날짜 선택기 표시
- 여러 날짜 선택 가능 (최소 2개)
- 선택된 날짜를 태그 형태로 표시
- 개별 날짜 삭제 버튼 제공
- 날짜 형식: MM월 dd일 (요일)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@choihooo choihooo requested a review from bbbang105 as a code owner March 16, 2026 01:40
@vercel
Copy link

vercel bot commented Mar 16, 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 Mar 16, 2026 6:19am

@bbbang105 bbbang105 added 📄 docs 문서 추가 및 수정 🔄 refactor 코드 리팩토링 🚀 feat 새로운 기능 추가 / 일부 코드 추가 / 일부 코드 수정 (리팩토링과 구분) / 디자인 요소 수정 labels Mar 16, 2026
choihooo and others added 2 commits March 16, 2026 10:50
- CRITICAL: 투표 변경 시 레이스 컨디션 수정
  - 단일/복수/날짜 투표의 트랜잭션으로 원자성 보장
  - 기존 투표 삭제 + 새 투표 추가를 하나의 트랜잭션으로 처리
  - 익명 투표는 별도 처리 (기존 투표 유지)

- HIGH: 프로젝트 가이드라인 준수
  - 모든 alert()를 toast.error()로 변경 (7곳)
  - sonner 라이브러리 사용으로 UI 일관성 확보

- MEDIUM: 캐시 정책 최적화
  - 투표 조회 API 캐시를 30초에서 5초로 축소
  - 투표 후 빠른 반영 + 성능 확보

- LOW: 디버그 파일 제거
  - check-polls.ts, check-post-polls.ts 삭제

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- TypeScript 에러 13개 수정 (voteCount 타입 캐스팅, 트랜잭션 반환값, options 타입)
- 사용하지 않는 import/변수 제거 (X, AlertCircle, EXPIRY_OPTIONS, setExpiry, datePickerOpen)
- React 순수성 경고 수정 (Date.now()를 useState 초기화 함수로 래핑)
- 투표 완료 후 즉시 캐시 무효화 (revalidatePath 추가)
- DB 스키마에 유니크 인덱스 문서 추가 (게시글당 활성 투표 1개 제한)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@bbbang105 bbbang105 added 🔧 ci CI/CD 파이프라인 변경 🚨 fix 버그 수정 / 에러 해결 labels Mar 16, 2026
- 투표 추가 후 수정 버튼 표시 (Edit2 아이콘)
- 수정 모드에서 투표 질문, 유형, 마감시간, 선택지 변경 가능
- 수정/취소 버튼 추가로 UX 개선
- 기존 투표 폼을 수정 모드에서 재사용하여 코드 중복 최소화

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 닉네임(members.nickname) → 실명(members.name) 변경
- 투표자 목록 모달에서 실명이 보이도록 수정

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- memberNickname 필드 추가로 닉네임도 가져오기
- 투표자 목록 모달에서 실명 + 닉네임(@Nickname) 표시
- 미리보기 아바타 툴팁에 닉네임 포함
- 실명과 닉네임이 다를 경우에만 닉네임 표시

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
문제: 브라우저 캐시(5초)로 인해 투표 후 반영이 지연됨

해결:
1. 캐시 버스팅 추가: polls 요청에 ?t={timestamp} 쿼리 파라미터 추가
2. 낙관적 업데이트: 투표 전/후에 onRefresh() 호출로 즉시 UI 갱신
3. 에러 시 재갱신: 실패해도 최신 데이터 유지

원인: revalidatePath()는 서버 캐시만 무효화하고 브라우저 캐시는 건드리지 못함

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
문제: 익명 투표에서 votesByOption에 투표를 추가하지 않아서 voteCount가 0이 됨

원인:
- votesByOption에 익명 투표를 추가하지 않는 조건문 존재
- totalVotes는 모든 투표를 카운트하지만 voteCount는 0이 됨

해결:
- 익명 투표도 votesByOption에 추가 (voters 배열만 비워둠)
- anonymous_id 필드 추가로 익명 투표 추적 준비

참고: hasVoted 추적을 위해서는 클라이언트에서 anonymous_id 저장 필요

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
투표 시스템을 4개 유형에서 2개 유형으로 단순화하고 복수/익명 옵션을 별도로 분리

**주요 변경사항:**
- 투표 유형: single/multiple/date/anonymous → text/date (2개 유형)
- 복수 선택: allowMultiple boolean 필드로 분리
- 익명 투표: isAnonymous boolean 필드로 분리
- DB 스키마: allow_add_option → allow_multiple, is_anonymous 추가
- 투표 취소: 익명 투표 포함 모든 투표 취소 가능
- 단일 투표: 1개만 선택되도록 개선 (최신 클릭 유지)

**API 변경:**
- polls/route.ts: allowMultiple, isAnonymous 필드 추가
- vote/route.ts: 익명 체크 제거, 항상 memberId 저장
- options/route.ts: 미사용 API 제거 (allowAddOption 기능 삭제)

**UI 변경:**
- poll-editor.tsx: 텍스트/날짜 버튼으로 변경, 복수/익명 토글 버튼 추가
- poll-vote-modal.tsx: allowMultiple 필드 사용하도록 수정
- poll-display.tsx: 중첩 링크 문제 해결 (MemberAvatar에 noLink prop)

**기술 개선:**
- shared 패키지 재빌드로 Drizzle ORM 타입 오류 해결
- Hydration 에러 해결 (<a> 태그 중첩 문제)
- errorResponse 함수에 스택 트레이스 로깅 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
투표 수정 모달을 생성 모달과 동일한 스타일로 변경하고 타입 안전성 강화

**UI 변경:**
- 투표 유형 선택: Select 박스 → 텍스트/날짜 버튼 (변경 불가)
- 투표 옵션: 복수 선택/익명 토글 버튼 추가
- 뱃지 라벨: "텍스트/날짜 · 복수 · 익명" 형식으로 통일

**기능 개선:**
- 익명 투표 수정: allowMultiple, isAnonymous 필드 업데이트 지원
- 투표 유형 변경 방지: 생성 후 유형 변경 불가 (disabled)
- undefined 체크 강화: 날짜 파싱 시 null/undefined 처리

**타입 안전성:**
- pollType: 'single'|'multiple'|'date'|'anonymous' → 'text'|'date'
- 익명 체크: poll.pollType !== 'anonymous' → !poll.isAnonymous
- 미사용 import/변수 제거: Switch, withCache, request → _request
- Next.js 캐시 삭제로 validator 타입 에러 해결

**API 수정:**
- polls/[pollId]/route.ts PATCH: allowMultiple, isAnonymous 업데이트 로직 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
리뷰 코멘트를 반영한 코드 품질 개선

**프로젝트 가이드라인 준수:**
- window.confirm() → 커스텀 AlertDialog 사용 (CancelVoteDialog)
- CLAUDE.md 가이드라인 준수로 기존 DeletePostDialog 패턴 따름

**성능 개선:**
- 캐시 전략 재도입: 5초 캐시로 빠른 반영 + 성능 확보
- withCache() 함수로 일관된 캐싱 적용
- 투표 후 revalidatePath()로 즉시 갱신 유지

**코드 재사용성:**
- 날짜 포맷팅 유틸리티 함수 추출 (lib/date-utils.ts)
- formatPollDate(): YYYY-MM-DD → MM/DD (요일) 변환
- formatExpiresAt(): 마감시간 포맷팅 로직 통합
- poll-display.tsx, poll-vote-modal.tsx에서 공유 사용

**코드 정리:**
- date-fns 의존성 제거 (poll-vote-modal.tsx)
- 중복된 날짜 포맷팅 로직 제거
- 미사용 핸들러 정리 (handleCancelVote → handleConfirmCancel)
- 임포트 정리 및 타입 안전성 강화

**새로운 컴포넌트:**
- cancel-vote-dialog.tsx: 투표 취소 확인 다이얼로그
- AlertDialog 패턴으로 일관된 UI/UX 제공
- 에러 핸들링 및 로딩 상태 표시

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
익명 투표에서 1명이 여러 선택지에 투표해도 1명으로 카운트

**문제:**
- 기존 로직: votes.length로 모든 투표 기록 수를 카운트
- 결과: 1명이 2개 선택지 투표 시 2명 참여로 표시됨

**해결:**
- 고유 memberId를 Set으로 중복 제거 후 카운트
- const totalVotes = votes.length
- const totalVotes = new Set(votes.map(v => v.memberId)).size

**특징:**
- 익명/실명 투표 모두 동일하게 적용
- 복수 선택 투표에서도 정확한 참여자 수 계산
- memberId 기반으로 중복 제거 (신원 ID)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@choihooo choihooo merged commit e4317fb into dev Mar 16, 2026
7 checks passed
@choihooo choihooo deleted the feature/board-poll-voting branch March 16, 2026 06:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔧 ci CI/CD 파이프라인 변경 📄 docs 문서 추가 및 수정 🚀 feat 새로운 기능 추가 / 일부 코드 추가 / 일부 코드 수정 (리팩토링과 구분) / 디자인 요소 수정 🚨 fix 버그 수정 / 에러 해결 🔄 refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants