7.2 KiB
7.2 KiB
Context: Server & API
1. 모듈별 상세 역할
server/index.js:- Fastify 서버 진입점입니다.
- 개발 모드에서는
@fastify/middie로 Vite 미들웨어를 붙이고,/api/*요청은 Vite SPA fallback이 가로채지 않도록 Fastify 라우트로 통과시킵니다. - 운영 모드(
npm start)에서는@fastify/static으로dist/를 서빙하고, HTML 요청은index.html로 fallback합니다.
server/config.js:config.json을 읽어 서버 포트, MongoDB host/port/db/user/pass, 쿠키 보안 옵션을 정규화합니다.MONGODB_URI가 직접 있으면 우선 사용하고, 없으면MONGODB_HOST/MONGODB_PORT기반으로 URI를 조립합니다.- 전투 사망 통계 컬렉션(
MONGODB_DAILY_DEATH_COLLECTION)과 집계 기준 타임존(DEATH_STATS_TIME_ZONE) 기본값을 제공합니다. - About 콘텐츠 컬렉션은
MONGODB_ABOUT_COLLECTION으로 조정하며 기본값은about_content입니다.
server/visitorCookie.js:arena_visitor_id쿠키 읽기/쓰기와 UUID 형식 검증을 담당합니다.- 방문자 쿠키 처리를 방문자 API와 일일 지표 API가 공유하도록 분리합니다.
server/db.js:MongoClient를 한 번 생성한 뒤 재사용하여 MongoDB 커넥션 풀을 유지합니다.- 종료 시
closeMongoConnection()으로 커넥션을 닫습니다.
server/about.js:- About 개발자정보와 개인정보처리방침 Markdown을 DB 기본 문서로 시드하고, 서버 메모리에 캐시합니다.
server/dailyMetrics.js:GET /api/daily-metrics/today:ANALYTICS_TIME_ZONE기준 오늘의 운영 지표를 반환합니다.POST /api/daily-metrics/match-started: 사용자가 실제 전투를 시작했을 때totalMatchStarts를 누적합니다.POST /api/daily-metrics/match-finished: 실제 전투가 끝났을 때totalMatchFinishes를 누적합니다.POST /api/daily-metrics/donation-clicked: 후원 버튼 클릭 수를 누적하기 위한 예약 API입니다.- 날짜별 합산 컬렉션(
daily_metrics)과 날짜+방문자 해시 기준 임시 카운터 컬렉션(daily_visitor_activity)을 사용합니다. - 임시 카운터는
expireAtTTL 인덱스로 기본 60일 뒤 자동 삭제됩니다.
server/deathStats.js:GET /api/death-stats/today:DEATH_STATS_TIME_ZONE기준 오늘 일자의 종족별 사망 집계와 총 사망 수를 반환합니다.POST /api/death-stats/today: 전투 종료 시 전달된deathsBySpecies를 오늘 일자별 누적 문서의deathsBySpecies,totalDeaths,battles에 바로 더합니다.- 집계 대상 종족은
human,orc,skeleton,slime,wolf,bear로 제한합니다.
server/visitors.js:POST /api/visitors/check:arena_visitor_idHttpOnly쿠키를 확인하고 없으면 UUID를 발급합니다.- MongoDB
visitors컬렉션에_id = visitorId로 upsert해 방문자 1명당 1개 문서를 유지합니다. GET /api/visitors/stats: 전체 유니크 방문자 수를 반환합니다.
2. 주요 로직 구현 세부 사항
유니크 방문자 체크
브라우저가 직접 MongoDB에 연결하지 않고, Fastify API가 MongoDB 커넥션 풀을 유지합니다.
- 프론트엔드가 앱 로드 시
POST /api/visitors/check를 호출합니다. - 서버가
arena_visitor_id쿠키를 검사합니다. - 쿠키가 없거나 유효하지 않으면
crypto.randomUUID()로 새 방문자 ID를 만들고HttpOnly쿠키로 내려줍니다. - MongoDB에는
_id,firstSeenAt,lastSeenAt,visits,firstUserAgent,lastUserAgent를 저장합니다. countDocuments()로 전체 유니크 방문자 수를 계산해 반환합니다.- 같은 요청에서 일일 지표의
totalVisits를 1 증가시키고, 해당 날짜에 처음 확인된 방문자면uniqueVisitors도 1 증가시킵니다.
일일 운영 지표
수익화 판단에 필요한 최소 지표만 저장하며, 입력 닉네임이나 매치 상세 로그는 저장하지 않습니다.
- 앱 로드 시 기존
POST /api/visitors/check흐름에서daily_metrics.totalVisits와daily_metrics.uniqueVisitors를 갱신합니다. - 사용자가 직접 시작한 전투만
POST /api/daily-metrics/match-started로totalMatchStarts에 누적합니다. - 프리뷰 전투는 제외하고, 실제 전투가 승리/무승부로 끝난 경우만
POST /api/daily-metrics/match-finished로totalMatchFinishes에 누적합니다. daily_visitor_activity는 날짜와 방문자 UUID를 함께 해시한_id를 사용해 당일 방문자별visits,matchStarts,matchFinishes,donationClicks만 임시 저장합니다.- 방문자의 당일
matchStarts가 1에서 2로 넘어가는 순간에만daily_metrics.visitorsWithTwoOrMoreMatches를 1 증가시킵니다. daily_visitor_activity는DAILY_ACTIVITY_RETENTION_DAYS설정값에 따라 TTL로 자동 삭제하고, 장기 보관 대상은 날짜별 합산 문서인daily_metrics입니다.
전투 사망 통계
프리뷰 전투는 통계에서 제외하고, 사용자가 시작한 실제 전투만 저장합니다.
fighterManifest.js의 모든 스킨은species를 가집니다.combat.js의 처치 흐름이ArenaScene.recordKill()을 호출하면,ArenaScene은 피처치자의skin.species를 현재 전투의battleDeathCounts에 누적합니다.- 전투가 5초 이상 이어지면
GET /api/death-stats/today로 가져온 오늘 집계와 현재 전투의 사망 수를 합산해#battle-notice에 표시합니다. - 전투 종료 시
POST /api/death-stats/today로deathsBySpecies만 보냅니다. - 서버는
daily_death_stats컬렉션에서 오늘 일자의battles,totalDeaths,deathsBySpecies.*값을$inc로 갱신합니다.
3. 설정 규칙
- 서버 설정:
.env대신config.json을 사용합니다. 로컬 전용 파일이며, 저장소에는config.json.sample만 공유합니다. - MongoDB 연결: 접속 정보는
config.json의MONGODB_HOST,MONGODB_PORT,MONGODB_DB등으로 관리합니다. - 일일 지표 설정:
MONGODB_DAILY_METRICS_COLLECTION,MONGODB_DAILY_VISITOR_ACTIVITY_COLLECTION,ANALYTICS_TIME_ZONE,DAILY_ACTIVITY_RETENTION_DAYS로 집계 컬렉션과 임시 카운터 보관 기간을 조정합니다. - API 변경:
/api/*경로는 Fastify 라우트가 담당하며, 개발 모드에서 Vite 미들웨어보다 우선순위를 가집니다.
4. About 콘텐츠
server/about.js:- 서버 시작 시
MONGODB_ABOUT_COLLECTION컬렉션(기본값about_content)에developer-info,privacy-policy기본 문서를 upsert합니다. - 개발자 정보 기본값은
alias: horoli,email: sunha321@gmail.com,github: https://github.com/Horoli입니다. - 개인정보처리방침은
privacy-policy.markdown문자열 필드에 Markdown 원문으로 저장합니다. 기본값은 빈 문자열이며, 운영자가 DB에서 직접 작성/수정합니다. - 서버가 MongoDB 연결에 성공하면 About 콘텐츠를 메모리에 캐시합니다. 브라우저 표시를 위해
GET /api/about읽기 전용 API만 제공하며, 수정 API는 만들지 않습니다.
- 서버 시작 시