10 Commits

Author SHA1 Message Date
eb44f50886 Index user votes by date for daily archive
- /userVotesByDate/{date}/{uid}/{gameId} fan-out 인덱스 추가 — RTDB에는 부분 노드 읽기가 없어서 dailyArchive가 하루치를 처리하려면 /userVotes 트리 전체(전 유저 x 전 보존 날짜)를 내려받아야 했다
- 투표를 쓰는 3곳(submitVote, changeVote, processGameEndWithGame의 판정 결과 주입)이 원자 update 하나로 원본과 미러를 함께 기록
- 삭제 경로도 동기화: deleteUserVoteGame은 양쪽에서, deleteUserVoteIndex는 유저의 날짜 목록을 먼저 읽어 해당 날짜 미러만 정리
- database.rules.json에 userVotesByDate·userVotesByDateMeta를 read/write false로 추가 — 교차 유저 데이터라 서버 전용
- 백필 스크립트 추가(npm run backfill:vote-index). dry-run 기본, --apply로 500건씩 청킹 기록, 멱등. 완료 시 /userVotesByDateMeta/backfilledAt 마커를 남겨 잡이 원본 스캔을 그만두는 근거로 쓴다
- 미러 정합성 테스트 8건 추가
2026-07-27 13:26:15 +09:00
ed573a81e0 Cache games by date and invalidate on writes
- gameRepository에 날짜 키 공유 캐시(MemCache, 15초) 추가 — 날짜별 경기 목록은 유저 독립 전역 데이터라 요청 간 공유할 수 있다. GET /prediction/games가 요청마다 range 쿼리를 재발행하던 것을 인스턴스당 분당 수 회로 수렴시킨다
- games 문서 쓰기 경로에 무효화 연결: syncGamesForMonth는 여러 날짜에 걸치므로 전량 폐기, forceSyncDay는 해당 날짜만
- createGameDayCache가 공유 캐시를 경유하도록 변경 — 요청마다 새로 만드는 짧은 수명 인스턴스도 실제 쿼리를 유발하지 않는다
- predictionHandlers의 games 분기에 Cache-Control public max-age=15 추가(무인증·전 유저 공통 응답이라 CDN·브라우저 중복 제거가 가능한데 그동안 헤더가 없었다)
- MemCache.getOrFetch가 truthy 대신 히트 여부로 판정하도록 수정 — 캐시된 null이 미스로 취급돼 fetcher가 매번 재실행되던 문제(존재하지 않는 상품 조회가 요청마다 Firestore read 유발)
- MemCache에 peek·clear 추가, 단위 테스트 6건 신설
2026-07-27 13:25:59 +09:00
85edc7c7e3 Simplify orders to immediate debit with single refund path
- 주문 생성 시 예약(홀드) 없이 즉시 차감하고 confirmed 로 시작 — 상태 흐름을 확정 → 배송중 → 배송완료(+어드민 환불)로 간소화
- 유저 취소 엔드포인트(POST /orders/:id/cancel)와 cancelOrder 제거 — 상태 전이는 어드민 전용, 되돌림은 환불 전이 하나로 통일 (차감 txId 를 reversalOf 로 링크)
- order_reserve/order_release 원장 타입과 reserve/capture/release op, 지갑 reservedBalance 제거 — 불변식을 available = earned - spent 로 단순화
- 이전 데이터 전면 삭제에 따라 2026-07 개편 이전 원장 문서용 레거시 정규화(StoredLedgerEntry, balanceAfter 역산, refMonth/refDay 합성)도 제거
- 주문/원장/지갑 테스트를 새 스키마로 갱신하고 orderService 에뮬레이터 테스트 6건 추가 (즉시 차감·잔액 부족·권한·전이 검증·환불 반환)
2026-07-21 16:06:13 +09:00
c635f16952 Add admin console read APIs, claim script, and CORS hedge
- 어드민 웹(fanit_admin) 지원: GET products/list(비노출 포함 전체 상품, AdminProductDto)·GET orders/list(전 유저 주문, createdAt desc 커서 페이지네이션) 추가 — Hosting rewrite·직접 호출 양쪽에서 일관되는 2세그먼트 라우트
- 지갑·원장 어드민 응답도 DTO로 감싸 Timestamp({_seconds}) 유출 제거
- admin 함수에 단일 origin CORS 헤지 추가(OPTIONS preflight를 requireAdmin보다 먼저 처리, 에러 응답에도 헤더 적용)
- scripts/set-admin-claim.ts로 운영자 admin 클레임 부여(부여 후 재로그인 필요)
- Storage 규칙: write만 admin 클레임으로 제한, read는 불변(앱 이미지 표시 계약 유지)
- 신규 조회·DTO vitest 테스트 추가
2026-07-21 13:57:42 +09:00
2e4d01f985 Normalize pre-migration ledger documents in the response
- 포인트 시스템 개편(2026-07-16) 이전 스키마 문서가 운영 Firestore에 그대로 남아 있어 포인트 내역이 실패하던 문제 수정
- 구 문서에는 txId/uid/op/available*/reserved*가 없고 balanceAfter/refMonth/refDay가 있다
- 읽기 타입을 StoredLedgerEntry로 넓히고, DTO에서 남은 값으로 복원한다
  - txId는 문서 id, uid는 요청 uid, op는 type에서, 거래 전 잔액은 balanceAfter에서 역산
  - refMonth + refDay를 relatedDate(YYYY-MM-DD)로 합침
- 실제 운영 문서 형태를 그대로 쓴 회귀 테스트 추가
2026-07-20 20:50:57 +09:00
8cb31b8122 Add end-to-end wire format test for point ledger
- Firestore에 저장된 Timestamp가 DTO를 거쳐 JSON으로 나갈 때까지 전 구간 검증
- 앱 포인트 내역 크래시(_seconds Map을 as String으로 캐스트)의 회귀 방지용
- relatedDate 같은 날짜 전용 필드의 YYYY-MM-DD 형식 유지도 함께 확인
2026-07-20 16:31:42 +09:00
9daba193e4 Add draw prediction support to vote pipeline
- selectedTeamCode에 무승부 예약 코드 'DRAW' 허용 (sideOf가 draw 진영 반환)
- RTDB /votes/{gameId}/counts에 drawCount 추가, 투표 요약 응답에 포함
- 채점 규칙 변경: 무승부 경기는 'DRAW' 투표만 적중, 팀 투표는 오답 (기존: 전원 적중 처리)
- 무승부 경기(completed + winningTeamCode 없음)도 onGameCompleted 트리거에서 즉시 채점 (기존: dailyArchive 리컨실까지 지연)
- 어드민 수동 종료(POST /admin/game/end)에 winningTeamCode: 'DRAW' 지원
- VOTE_FLOW.md 갱신, voteRepository 무승부 투표/카운트 재분배 테스트 추가
2026-07-10 16:51:56 +09:00
c94ce69e4f Remove redundant .js extensions from import paths.
- TypeScript 소스 파일 내 모든 import 구문에서 불필요한 `.js` 확장자를 제거하여 모듈 참조 방식을 표준화했습니다.
- 핸들러, 서비스, 리포지토리 및 테스트 코드를 포함한 프로젝트 전반의 import 경로를 일관성 있게 정리했습니다.
2026-05-06 16:17:51 +09:00
c7e4ed8c22 Standardize game status values and make favorite team optional.
- `GameStatus` 타입을 `scheduled`, `live`, `completed`, `cancelled`로 변경하여 상태 관리의 일관성을 높였습니다.
- 사용자 프로필의 `favoriteTeamCode`를 선택 사항으로 변경하고, null 또는 undefined 입력에 대한 처리를 추가했습니다.
- KBO 데이터 병합 과정에 상세 로그를 도입하여 실시간 데이터 매칭 및 외부 API 호출 실패 상황에 대한 가시성을 확보했습니다.
- 상태 값 변경에 따라 영향받는 서비스 로직과 테스트 코드를 일괄 업데이트했습니다.
2026-04-14 23:08:45 +09:00
7ff609022f init 2026-04-13 09:18:34 +09:00