DOCS/journey/troubleshooting/251216_bayesian_presentation_ballquiz_redesign.md

155 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 베이지안 프레젠테이션 BallQuiz 페이지 리디자인
**날짜**: 2025-12-16
**작성자**: happybell80
**관련 파일**:
- `bayesian-presentation/frontend/src/pages/BallQuizPage.tsx`
- `bayesian-presentation/backend/app/services/state_service.py`
- `bayesian-presentation/backend/main.py`
---
## 문제 상황
### 1. Section 구조 복잡성
- Section 1(초기 확률 입력)과 Section 2(공 꺼내기)가 분리되어 불필요한 단계 추가
- 발표자가 두 번에 나눠 입력해야 하는 불편함
### 2. 셀 수정 불가 문제
- 초기 확률과 회차별 확률이 읽기 전용으로 표시되는 경우 발생
- `isRoundCompleted` 조건으로 인해 일부 셀만 수정 가능
### 3. 포트 충돌
- 백엔드를 포트 8000에서 실행하려고 시도
- 포트 8000은 다른 서비스(goosefarminvestment)가 사용 중
- nginx 설정은 포트 3001로 프록시 설정되어 있음
### 4. 기본 section 설정 오류
- Section 1 제거 후에도 백엔드 기본 section이 1로 유지
- 프론트엔드에서 section 2로 시작하도록 변경했으나 백엔드와 불일치
### 5. 입력 필드 UX 문제 (2025-12-17 추가)
- **입력값 유실**: 페이지 새로고침/재연결 시 입력한 확률이 사라짐 (서버에는 저장되지만 화면에 표시 안 됨)
- **입력 중 덮어쓰기**: 입력 중 서버 `state_update`가 오면 아직 저장되지 않은 입력값이 사라짐
- **리셋 버튼 미작동**: 리셋 후에도 테이블의 입력값이 그대로 남아있어 초기화되지 않음
### 6. 베이지안 업데이트 로직 문제 (2025-12-17 추가)
- **독립적 확률 변환**: 각 회차마다 확률(%)을 독립적으로 베타분포로 변환하여 이전 회차 정보가 누적되지 않음
- **그래프 색상 구분 부족**: 초기와 회차별 그래프 색상이 동일하여 변화 추이 파악 어려움
- **피크 값 미표시**: 5회차까지 입력 완료 후 최종 확률 추정값(피크)이 표시되지 않음
- **하이라이트 테두리 과도**: 공을 꺼낸 후 활성화된 셀의 테두리가 과도하게 강조됨
- **종합 행 미표시**: 종합 행의 회차별 값이 "-"로만 표시되어 평균 확률을 확인할 수 없음
---
## 해결 방안
### Section 1 제거 및 통합
- `BallQuizPage.tsx`: Section 1 렌더링 코드 제거 (141-259줄)
- Section 2에 초기 확률과 회차별 확률 입력 통합
- "시뮬레이션 시작" 버튼 제거
### 모든 셀 수정 가능하도록 변경
- `BallQuizPage.tsx:174-219`: `isRoundCompleted` 조건 제거, 모든 회차 셀을 항상 input 필드로 표시
- `BallQuizPage.tsx:120-164`: 초기 확률도 항상 input 필드로 표시
- 사용자 입력값 우선 반영 로직 개선
### 포트 충돌 해결
- `main.py`: 백엔드 실행 포트를 3001로 변경
- nginx 설정 확인: `/bayesian-api/``http://localhost:3001/`
- 포트 8000은 다른 서비스 사용 중이므로 사용 불가
### 기본 section 설정
- `state_service.py:26`: 기본 section을 1 → 2로 변경
- `state_service.py:207`: `reset_state`에서도 section 2로 초기화
- 프론트엔드와 백엔드 일치
### 입력 필드 UX 개선 (2025-12-17)
- **서버 상태로 로컬 상태 동기화**: `BallQuizPage.tsx:25-86` - `useEffect`로 서버 `state_update` 수신 시 `participantInputs` 동기화
- **입력 중 필드 보호**: `BallQuizPage.tsx:22` - `focusedInputRef`로 포커스 중인 필드는 서버 업데이트로 덮어쓰지 않음
- **자동 저장**: `BallQuizPage.tsx:94-120` - `useEffect` + debounce(300ms)로 입력값 자동 저장
- **리셋 시 로컬 상태 초기화**: `BallQuizPage.tsx:26-29` - `estimates`가 빈 객체일 때 `participantInputs`도 빈 객체로 초기화
### 베이지안 업데이트 로직 개선 (2025-12-17)
- **누적 odds 변환**: 각 회차마다 입력한 확률(%)을 odds로 변환하여 이전 alpha, beta에 누적
- 예: 초기 50% → alpha=1, beta=1 → 1회차 60% → alpha=2.5, beta=2 → 2회차 65% → alpha=4.36, beta=3
- 5회차까지 진행 시 alpha + beta > 10
- **그래프 색상 점진적 변화**: 초기 연보라(`rgba(200, 180, 255, 0.8)`)에서 5회차 진한 보라(`rgba(92, 0, 230, 0.9)`)로 점진적 변화
- **5회차 피크 값 표시**: 5회차까지 입력 완료 시 Beta 분포 피크 공식 `(alpha - 1) / (alpha + beta - 2)`로 계산하여 그래프 하단에 표시
- **하이라이트 테두리 제거**: 활성화된 셀의 테두리 제거, 배경색(`bg-primary/5`)과 그림자(`shadow-sm`)만 유지
- **종합 행 회차별 값 표시**: 각 회차별 참가자들의 평균 확률 계산하여 확률(%)과 odds(x:1) 형식으로 표시
- **초기 그래프 항상 표시**: 초기값이 없어도 기본값 50%로 그래프 표시
- **입력하지 않은 회차 그래프 미표시**: 해당 회차에 입력이 없으면 그래프를 그리지 않음
---
## 구현 완료
- Section 1 제거 완료
- 42개 셀(7명 × 6컬럼) 모두 수정 가능
- 포트 3001로 백엔드 실행
- 기본 section 2로 통일
- 입력 필드 UX 개선 완료 (2025-12-17)
- 새로고침/재연결 시 입력값 유지
- 입력 중 서버 업데이트로 덮어쓰기 방지
- 자동 저장으로 입력값 유실 방지
- 리셋 버튼 정상 작동
- 베이지안 업데이트 로직 개선 완료 (2025-12-17)
- 누적 odds 변환으로 이전 회차 정보 누적
- 그래프 색상 점진적 변화 (연보라 → 진한 보라)
- 5회차 피크 값 표시 (그래프 하단)
- 하이라이트 테두리 제거
- 종합 행 회차별 평균 확률 표시
- 초기 그래프 항상 표시 (기본값 50%)
- 입력하지 않은 회차 그래프 미표시
---
## 교훈
### 포트 사용 전 확인 필수
- **원인**: nginx 설정과 백엔드 포트를 확인하지 않고 포트 8000 사용 시도
- **교훈**:
- 포트 사용 전 `netstat` 또는 `ss` 명령어로 사용 중인 포트 확인
- nginx 설정 파일에서 프록시 포트 확인 (`/etc/nginx/sites-enabled/default`)
- 다른 서비스와 충돌하지 않는 포트 사용
- **원칙**: `312_writing-principles.md` - 확인된 사실만 기록
### 프론트엔드/백엔드 기본값 일치 확인
- **원인**: Section 1 제거 후 프론트엔드만 section 2로 변경, 백엔드는 section 1 유지
- **교훈**:
- 상태 관련 기본값 변경 시 프론트엔드와 백엔드 모두 확인
- `state_service.py`의 초기값과 프론트엔드 기본값 일치 확인
- **원칙**: `311_FastAPI_구조_원칙.md` - 상태 관리 일관성
### 사용자 요구사항 명확히 이해
- **원인**: "엑셀처럼 수정 가능하게" 요구사항을 여러 번 반복 요청
- **교훈**:
- 읽기 전용 셀(`isRoundCompleted` 조건)을 제거하고 모든 셀을 항상 input 필드로 표시
- 사용자가 "엑셀처럼"이라고 표현할 때는 모든 셀을 클릭해서 바로 수정 가능해야 함
- **원칙**: 사용자 의도 파악 후 구현
### 브라우저 직접 확인 습관화
- **원인**: 코드 수정 후 브라우저에서 직접 확인하지 않고 가정으로 진행
- **교훈**:
- Playwright를 사용한 자동화 테스트로 브라우저 상태 확인
- 코드 변경 후 반드시 실제 브라우저에서 동작 확인
- **원칙**: `AGENTS.md` - 직접 확인 후 진행
### 서버 상태 리셋 시 로컬 상태도 초기화 필수
- **원인**: `reset_state`로 서버 `estimates``{}`로 초기화되지만, 프론트엔드 `useEffect` 동기화 로직에서 빈 객체일 때 early return하여 `participantInputs`가 초기화되지 않음
- **교훈**:
- 서버 상태가 빈 객체로 리셋될 때는 로컬 상태도 명시적으로 초기화해야 함
- `useEffect`에서 early return 전에 빈 객체 체크 후 로컬 상태 초기화 로직 추가
- **원칙**: `313_React_구조_원칙.md:100-104` - 프론트엔드/백엔드 상태 동기화
### 베이지안 업데이트는 누적 방식으로 구현
- **원인**: 각 회차마다 확률을 독립적으로 베타분포로 변환하여 이전 회차 정보가 누적되지 않음
- **교훈**:
- 베이지안 업데이트는 이전 정보를 누적하는 방식이므로, 각 회차 입력값을 odds로 변환하여 alpha, beta에 누적
- 확률(%)을 odds로 변환: `odds = prob / (100 - prob)`, `alpha = odds`, `beta = 1`
- 누적: `cumulativeAlpha += odds.alpha`, `cumulativeBeta += odds.beta`
- 5회차까지 진행 시 alpha + beta > 10이 되어 그래프가 더 뾰족해짐
- **원칙**: 베이지안 추론의 본질은 사전 정보와 관찰 정보를 결합하는 것