AI 예측 - 생성 시점을 킥오프 22시간 전으로 변경(선발투수 예고 이후), 잡 매시간 실행 - 경기 시작 후 생성 금지(사후 예측 방지), 경기 단위 커밋으로 중단 시 진행분 보존 일정·라이브 UI - 야구 일정에 순위 탭 추가 (KBO 단일 순위표 · MLB 6개 디비전, /api/standings 신설) - 경기중 카드에 현재 이닝·실시간 스코어 표시 (30s 폴링, 서버 15s 캐시) - MLB 선발 누락 수정: statsapi 날짜 파라미터 미국 날짜 기준 보정(-1일) - 라이브 대기타석 스크롤바 다크 테마 처리 운영 견고성 - 우천취소: 경기 삭제 → cancelled 상태 보존 (투표·예측 기록 유지, 정산/투표/AI 제외) - 더블헤더: 시작시각순 seq로 1·2차전 분리 등록 (match_id _2, 정산·라이브·프리뷰 매핑) - 축구 데이터 수집을 wc 리그로 한정 (야구 팀을 축구 API에 검색하던 쿼터 낭비 수정) 점수제 - 야구 판정 완화: 근접=득실차 ±1, 부분=한 팀 득점 ±1 (등급·배점은 리그 공통 유지) - 채점 판정을 _grade_of() 단일 함수로 통합, 종료된 야구 경기 재채점 - 배점 안내 모달 야구 문구 분리, docs/SCORING.md 갱신 기타 - 야구 전용 댓글 닉네임 풀 (종목별 세션 캐시 분리) - 리더보드 리그별 조회 연동 (?league=) |
||
|---|---|---|
| .claude | ||
| backend | ||
| docs | ||
| frontend | ||
| .gitignore | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| HANDOFF.md | ||
| README.md | ||
| docker-compose.yml | ||
README.md
TriplePick 2026
"AI(GPT · Claude · Gemini) vs 너" — 글로벌 축구 승부예측 서비스. 3개 AI 모델이 매 경기를 서로 다르게 예측하고, 유저는 픽을 찍어 AI와 겨룬다. 끝까지 가장 정확하게 맞힌 1인에게 100만원 챌린지.
아키텍처
o2o-triple-pick/
├── docker-compose.yml # db · api · worker · frontend 한 번에 실행
├── backend/ # FastAPI + SQLAlchemy(async) + PostgreSQL
│ ├── app/ # API · 워커(APScheduler) · AI/이메일 실연동
│ └── .env.example
└── frontend/ # React + Vite + TypeScript + Tailwind v4
├── src/ # pages · components · lib(api 연동)
└── .env.example
- frontend — React SPA. nginx 가 정적 파일 서빙 +
/api를 백엔드로 프록시. - backend (api) — FastAPI. 경기/AI예측/crowd 읽기, 픽 제출, 채점, 리더보드, 관리자.
- backend (worker) — APScheduler 별도 프로세스. 아래 "시간 기반 작업" 자동 처리.
- db — PostgreSQL.
빠른 시작 (Docker)
cp backend/.env.example backend/.env # 키(선택) 채우기
docker compose up --build
# 프론트: http://localhost:8080
# API 문서: http://localhost:8000/docs
DB 는 최초 기동 시 6경기 + AI 예측(부트스트랩) + crowd baseline 으로 자동 시드된다. AI/이메일 키가 없어도 전체 플로우(예측·제출·채점·리더보드)는 즉시 동작한다.
시간 기반 작업 (워커가 자동 처리)
조사된 "필요한 시간들"을 워커 단일 프로세스가 모두 담당한다:
| 작업 | 시점 | 설정 |
|---|---|---|
| 투표 오픈 | 킥오프 − 48h (D-2) | VOTE_OPEN_HOURS_BEFORE |
| 투표 마감 | 킥오프 − 5분 | VOTE_LOCK_MINUTES_BEFORE |
| 상태 전이 (scheduled→open→locked→finished) | 주기 틱 | STATUS_TICK_SECONDS (기본 60s) |
| AI 예측 생성 (3모델 실 API 호출) | 매일 KST 00:05 | AI_GENERATE_HOUR / _MINUTE |
| 결과 메일 발송 (구독자) | 경기 종료 +3h | RESULT_EMAIL_DELAY_MINUTES |
데모에서는
DEMO_FORCE_OPEN=true로 마감 전까지 항상 투표 가능. 운영 배포 시 false.
외부 연동 (실연동 — 키 없으면 해당 기능만 생략)
- AI 3모델 — OpenAI(GPT) · Anthropic(Claude,
claude-opus-4-8) · Google(Gemini).OPENAI_API_KEY/ANTHROPIC_API_KEY/GOOGLE_API_KEY. - 이메일 — SMTP.
SMTP_HOST외backend/.env참조.
API 요약
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /api/matches?lang=ko |
전체 경기 (예측·crowd 포함) |
| GET | /api/matches/{id} |
경기 상세 |
| POST | /api/predictions |
픽 제출 (1회 수정·crowd 증분·매칭 모델) |
| GET | /api/leaderboard |
누적 포인트 랭킹 |
| POST | /api/admin/result |
(Bearer) 결과 입력 → 채점 |
| POST | /api/admin/ai-predictions |
(Bearer) AI 예측 수동 upsert |
로컬 개발 (Docker 없이)
# 백엔드
cd backend && python3.12 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# Postgres 띄우고 DATABASE_URL 지정 후:
uvicorn app.main:app --reload # API
python -m app.worker # 워커
# 프론트
cd frontend && npm install && npm run dev # http://localhost:5173 (/api → :8000 프록시)
채점 규칙
docs/SCORING.md (SSOT). 정확 스코어 5 · 근접 3 · 승패 2 · 부분 1 · 빗나감 0.
누적 포인트 1위에게 최종 상금. 임직원/운영진 배제.
문서
docs/SCORING.md— 채점·심사 SSOTdocs/DESIGN.md— 디자인 토큰 SSOTdocs/BACKEND.md— 초기 백엔드 설계 메모(Firebase 기준 → 현 구현은 FastAPI)