팀 스프린트 플래닝 포커 - 실시간 스토리 포인트 투표
sprint-planning-poker-inertia
문제 설명
프로젝트 개요
애자일 스프린트 플래닝 시 팀원들이 실시간으로 스토리 포인트를 투표하고 결과를 집계하는 플래닝 포커 웹 애플리케이션입니다. Laravel 13.x + Inertia.js + React 19 모노리스 풀스택 아키텍처로 구현하며, 방 생성/참가, 카드 투표, 결과 공개 등의 기능을 제공합니다.
필수 기능
- 방 생성 및 관리: 방장이 플래닝 포커 세션 방을 생성하고 고유 코드 발급
- 참가자 입장: 방 코드로 다른 팀원들이 입장 (닉네임 입력)
- 스토리 카드 관리: 방장이 투표할 스토리(이슈) 추가/수정/삭제
- 포인트 투표: 각 참가자가 피보나치 수열(1, 2, 3, 5, 8, 13, 21) 또는 커스텀 카드로 투표
- 투표 현황 표시: 누가 투표했는지 실시간으로 표시 (카드는 뒤집힌 상태)
- 결과 공개: 방장이 '공개' 버튼을 누르면 모든 카드가 동시에 오픈되고 평균/중앙값 표시
- 재투표 기능: 논의 후 다시 투표할 수 있도록 리셋
- 세션 대시보드: 방장이 현재 방 상태, 참가자 목록, 투표 히스토리 확인
보너스 기능
- 투표 결과 히스토리 저장 및 CSV 내보내기
- 타이머 기능 (투표 제한 시간 설정)
- 다크 모드 지원
- 방 비밀번호 설정 (선택적)
- 투표 통계 차트 (막대 그래프로 분포 시각화)
기술 스택
- Backend: Laravel 13.x (라우트, 컨트롤러, Eloquent ORM, SQLite)
- Frontend: React 19 (컴포넌트, Hooks)
- Bridge: Inertia.js (Laravel과 React 연결, SPA 경험 제공)
- Styling: Tailwind CSS
- Database: SQLite (로컬 개발용)
데이터베이스 구조
- rooms: id, code(unique), name, created_by, status, created_at
- participants: id, room_id, nickname, is_host, joined_at
- stories: id, room_id, title, description, status(pending/voting/revealed), order
- votes: id, story_id, participant_id, point, created_at
제약 조건
- • Laravel 13.x + Inertia.js + React 19 모노리스 풀스택 구조 (별도 API 라우트 없음)
- • Laravel Breeze (React + Inertia) starter kit 사용 권장
- • SQLite 데이터베이스 사용
- • Tailwind CSS로 스타일링
- • Inertia::render()로 Laravel 컨트롤러에서 React 컴포넌트에 데이터 전달
- • 방 코드는 6자리 영숫자 랜덤 생성 (unique)
- • 투표 카드는 피보나치 수열 기본 제공 (1, 2, 3, 5, 8, 13, 21, ?, ☕)
- • 방장만 스토리 추가/삭제 및 결과 공개 권한
- • 모든 참가자가 투표해야 '모두 투표 완료' 상태 표시
- • 투표 결과는 평균과 중앙값 모두 표시
- • React 컴포넌트는 Pages 폴더에 구성 (Inertia 페이지 컴포넌트)
- • useState, useEffect 등 React Hooks 활용
- • Laravel 마이그레이션으로 테이블 스키마 정의
- • Eloquent 관계(hasMany, belongsTo) 적극 활용
프롬프트 레시피
아래 프롬프트를 순서대로 AI에게 보내면 됩니다. 복사 버튼을 눌러 바로 사용하세요.
mkdir sprint-planning-poker-inertia && cd sprint-planning-poker-inertia 이 폴더에서 Laravel 13.x + Inertia.js + React 19 프로젝트를 시작합니다. 다음 작업을 수행해주세요: 1. Laravel Breeze (React + Inertia) starter kit으로 프로젝트 초기화 - `composer create-project laravel/laravel . "^13.0"` - `composer require laravel/breeze --dev` - `php artisan breeze:install react --inertia` - `npm install && npm run build` 2. SQLite 데이터베이스 설정 - .env 파일에서 DB_CONNECTION=sqlite로 변경 - database/database.sqlite 파일 생성 3. 필요한 마이그레이션 파일 4개 생성: - rooms 테이블: id, code(string, unique), name(string), created_by(string), status(enum: active, closed), timestamps - participants 테이블: id, room_id(foreign), nickname(string), is_host(boolean), joined_at(timestamp) - stories 테이블: id, room_id(foreign), title(string), description(text, nullable), status(enum: pending, voting, revealed), order(integer), timestamps - votes 테이블: id, story_id(foreign), participant_id(foreign), point(string), timestamps 4. 마이그레이션 실행: `php artisan migrate` 5. 기본 레이아웃 확인 및 Tailwind CSS 설정 점검 완료 후 프로젝트 구조와 마이그레이션 파일 내용을 보여주세요.
기대 결과: Laravel 13.x + Breeze + Inertia + React 19 프로젝트가 초기화되고, SQLite 데이터베이스에 rooms, participants, stories, votes 테이블이 생성됩니다. 마이그레이션 파일에 외래키 제약조건과 인덱스가 올바르게 설정되어 있어야 합니다.
Eloquent 모델 4개와 기본 컨트롤러 2개를 생성해주세요.
1. **모델 생성 (app/Models):**
- Room 모델: participants, stories 관계 정의 (hasMany)
- Participant 모델: room, votes 관계 정의 (belongsTo, hasMany)
- Story 모델: room, votes 관계 정의 (belongsTo, hasMany)
- Vote 모델: story, participant 관계 정의 (belongsTo)
2. **컨트롤러 생성:**
- RoomController: 방 생성(store), 방 입장(join), 방 정보 조회(show) 메서드
- StoryController: 스토리 CRUD 메서드 (index, store, update, destroy)
3. **라우트 설정 (routes/web.php):**
```php
Route::get('/', [RoomController::class, 'index'])->name('home');
Route::post('/rooms', [RoomController::class, 'store'])->name('rooms.store');
Route::get('/rooms/{code}', [RoomController::class, 'show'])->name('rooms.show');
Route::post('/rooms/{code}/join', [RoomController::class, 'join'])->name('rooms.join');
Route::post('/rooms/{code}/stories', [StoryController::class, 'store'])->name('stories.store');
Route::patch('/stories/{story}', [StoryController::class, 'update'])->name('stories.update');
Route::delete('/stories/{story}', [StoryController::class, 'destroy'])->name('stories.destroy');
```
4. **RoomController 로직 구현:**
- index: 홈 페이지 (Inertia::render('Home'))
- store: 방 생성 로직 (6자리 랜덤 코드 생성, 방장 정보 저장, 방 코드 반환)
- show: 방 정보 + 참가자 목록 + 스토리 목록 반환 (Inertia::render('Room/Show', [...]))
- join: 참가자 추가 로직 (닉네임 중복 체크, participant 레코드 생성)
완료 후 모델 관계 설정과 컨트롤러 코드를 보여주세요.
기대 결과: Room, Participant, Story, Vote 모델에 Eloquent 관계가 정의되고, RoomController와 StoryController에 기본 CRUD 로직이 구현됩니다. 방 생성 시 6자리 고유 코드가 자동 생성되며, 방장 정보가 participants 테이블에 저장됩니다.
React 페이지 컴포넌트 2개를 생성해주세요 (resources/js/Pages). 1. **Home.jsx (홈 페이지):** - 방 생성 폼: 방 이름 입력, 방장 닉네임 입력, '방 만들기' 버튼 - 방 참가 폼: 방 코드 입력, 닉네임 입력, '참가하기' 버튼 - Inertia의 useForm hook 사용하여 폼 데이터 관리 - router.post()로 방 생성/참가 요청 - Tailwind CSS로 깔끔한 카드 레이아웃 (중앙 정렬, 그림자 효과) 2. **Room/Show.jsx (방 페이지):** - Props로 room, participants, stories, currentParticipant 데이터 받기 - 상단: 방 이름, 방 코드 표시, 참가자 목록 (아바타 또는 이름 배지) - 중앙: 현재 투표 중인 스토리 제목/설명 표시 - 하단: 투표 카드 버튼 그리드 (1, 2, 3, 5, 8, 13, 21, ?, ☕) - 피보나치 수열 - 방장인 경우: '스토리 추가' 버튼, '결과 공개' 버튼 표시 - 투표 현황: 각 참가자의 투표 여부 표시 (카드 뒤집힌 아이콘 또는 체크 표시) 3. **컴포넌트 스타일링:** - 투표 카드는 큰 버튼 형태 (hover 효과, 선택 시 색상 변경) - 참가자 배지는 둥근 아바타 스타일 - 반응형 디자인 (모바일에서도 사용 가능) 완료 후 Home.jsx와 Room/Show.jsx 코드를 보여주세요.
기대 결과: Home.jsx에서 방 생성/참가 폼이 작동하며, Room/Show.jsx에서 방 정보, 참가자 목록, 투표 카드 UI가 표시됩니다. Inertia의 useForm과 router를 활용하여 SPA처럼 페이지 전환 없이 데이터 전송이 이루어집니다.
투표 기능을 구현해주세요.
1. **VoteController 생성 (app/Http/Controllers):**
- store 메서드: 투표 저장 로직
- story_id, participant_id, point 받기
- 중복 투표 체크 (같은 participant가 같은 story에 이미 투표했는지)
- 중복이면 기존 투표 업데이트, 아니면 새로 생성
- 투표 후 방 페이지로 리다이렉트 (Inertia 응답)
2. **라우트 추가 (routes/web.php):**
```php
Route::post('/stories/{story}/vote', [VoteController::class, 'store'])->name('votes.store');
```
3. **Room/Show.jsx 업데이트:**
- 투표 카드 클릭 시 router.post()로 투표 전송
- 현재 참가자가 투표한 카드는 하이라이트 표시
- 투표 현황 섹션에 각 참가자의 투표 상태 표시 (투표 완료 시 체크 아이콘)
4. **RoomController show 메서드 업데이트:**
- 각 스토리에 대한 투표 데이터 포함 (votes 관계 로드)
- 현재 참가자의 투표 여부 확인 로직 추가
- Inertia::render('Room/Show', [ 'room' => $room, 'participants' => $participants, 'stories' => $stories, 'currentStory' => $currentStory, 'votes' => $votes, 'currentParticipant' => $currentParticipant ])
완료 후 VoteController 코드와 업데이트된 Room/Show.jsx를 보여주세요.
기대 결과: 투표 카드를 클릭하면 votes 테이블에 투표 데이터가 저장되고, 투표 현황이 실시간으로 업데이트됩니다. 중복 투표 시 기존 투표가 업데이트되며, 모든 참가자의 투표 상태가 UI에 반영됩니다.
스토리 관리 및 결과 공개 기능을 구현해주세요.
1. **StoryController 업데이트:**
- store 메서드: 새 스토리 추가 (방장만 가능하도록 검증)
- update 메서드: 스토리 상태 변경 (pending → voting → revealed)
- reveal 메서드 추가: 스토리 상태를 'revealed'로 변경하고 투표 결과 집계
2. **라우트 추가:**
```php
Route::post('/stories/{story}/reveal', [StoryController::class, 'reveal'])->name('stories.reveal');
Route::post('/stories/{story}/reset', [StoryController::class, 'reset'])->name('stories.reset');
```
3. **Room/Show.jsx 업데이트:**
- 방장인 경우 '스토리 추가' 모달 또는 폼 표시
- 스토리 목록 사이드바 추가 (pending/voting/revealed 상태별 구분)
- 현재 투표 중인 스토리에 '결과 공개' 버튼 (방장만 표시)
- 결과 공개 시 모든 투표 카드 오픈 + 평균/중앙값 표시
- '재투표' 버튼으로 스토리 상태를 다시 'voting'으로 변경하고 투표 초기화
4. **투표 결과 집계 로직:**
- StoryController reveal 메서드에서 해당 스토리의 모든 투표 집계
- 숫자 카드만 평균/중앙값 계산 (?, ☕는 제외)
- 결과를 Inertia 응답에 포함
5. **ResultCard 컴포넌트 생성 (resources/js/Components):**
- 투표 결과를 카드 형태로 표시 (참가자별 투표 포인트)
- 평균, 중앙값, 최빈값 표시
- 막대 그래프로 분포 시각화 (선택)
완료 후 StoryController reveal 메서드와 업데이트된 Room/Show.jsx, ResultCard 컴포넌트를 보여주세요.
기대 결과: 방장이 '결과 공개' 버튼을 누르면 모든 투표 카드가 공개되고, 평균과 중앙값이 계산되어 표시됩니다. 스토리 목록에서 상태별로 스토리를 확인할 수 있으며, 재투표 기능으로 다시 투표할 수 있습니다.
실시간 업데이트 및 최종 UX 개선을 해주세요.
1. **폴링 또는 자동 새로고침 구현:**
- Room/Show.jsx에서 useEffect로 5초마다 방 데이터 자동 새로고침
- Inertia의 router.reload() 또는 router.visit() 활용
- 투표/결과 공개 시 자동으로 다른 참가자 화면도 업데이트되도록
2. **UI/UX 개선:**
- 투표 완료 참가자 수 / 전체 참가자 수 표시 (예: "3/5 투표 완료")
- 모든 참가자가 투표 완료 시 자동으로 알림 표시 또는 효과음 (선택)
- 로딩 스피너 추가 (투표 제출 중, 결과 공개 중)
- 토스트 알림 (투표 완료, 스토리 추가, 결과 공개 등)
3. **방 코드 공유 기능:**
- 방 코드 옆에 '복사' 버튼 추가 (클립보드 복사)
- 공유 링크 생성 (예: http://localhost:8000/rooms/{code})
4. **히스토리 기능 (보너스):**
- 완료된 스토리 목록 하단에 표시
- 각 스토리의 최종 투표 결과 요약 표시
5. **다크 모드 토글 (보너스):**
- 헤더에 다크 모드 토글 버튼 추가
- Tailwind CSS의 dark: 클래스 활용
- localStorage에 테마 설정 저장
6. **테스트 및 최종 검증:**
- 방 생성 → 참가자 입장 → 스토리 추가 → 투표 → 결과 공개 → 재투표 전체 플로우 테스트
- 에러 핸들링 (방 코드 없음, 닉네임 중복, 권한 없음 등)
완료 후 최종 Room/Show.jsx 코드와 추가된 기능들을 보여주세요. 전체 애플리케이션이 매끄럽게 작동하는지 확인하고, 스크린샷이나 데모 영상을 제공하면 더 좋습니다.
기대 결과: 방 페이지가 5초마다 자동으로 새로고침되어 다른 참가자의 투표 현황이 실시간으로 반영됩니다. 투표 완료 비율이 표시되고, 방 코드 복사 버튼으로 쉽게 팀원을 초대할 수 있습니다. 최종적으로 완전히 작동하는 플래닝 포커 애플리케이션이 완성됩니다.
제출된 작품 (2)
로그인 후 제출실시간 의사결정 플랫폼
실시간 협업으로 빠르게 추정하고 합의까지 끝내는 저마찰 플래닝 포커 플랫폼, for 'agile-teams'
스프린트 플래닝 포커 - 실시간 협업 도구
애자일 팀을 위한 실시간 스토리 포인트 투표 시스템. 원격 팀도 효율적으로 스프린트 계획을 수립할 수 있습니다.