arena/context/server.md

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)을 사용합니다.
    • 임시 카운터는 expireAt TTL 인덱스로 기본 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_id HttpOnly 쿠키를 확인하고 없으면 UUID를 발급합니다.
    • MongoDB visitors 컬렉션에 _id = visitorId로 upsert해 방문자 1명당 1개 문서를 유지합니다.
    • GET /api/visitors/stats: 전체 유니크 방문자 수를 반환합니다.

2. 주요 로직 구현 세부 사항

유니크 방문자 체크

브라우저가 직접 MongoDB에 연결하지 않고, Fastify API가 MongoDB 커넥션 풀을 유지합니다.

  1. 프론트엔드가 앱 로드 시 POST /api/visitors/check를 호출합니다.
  2. 서버가 arena_visitor_id 쿠키를 검사합니다.
  3. 쿠키가 없거나 유효하지 않으면 crypto.randomUUID()로 새 방문자 ID를 만들고 HttpOnly 쿠키로 내려줍니다.
  4. MongoDB에는 _id, firstSeenAt, lastSeenAt, visits, firstUserAgent, lastUserAgent를 저장합니다.
  5. countDocuments()로 전체 유니크 방문자 수를 계산해 반환합니다.
  6. 같은 요청에서 일일 지표의 totalVisits를 1 증가시키고, 해당 날짜에 처음 확인된 방문자면 uniqueVisitors도 1 증가시킵니다.

일일 운영 지표

수익화 판단에 필요한 최소 지표만 저장하며, 입력 닉네임이나 매치 상세 로그는 저장하지 않습니다.

  1. 앱 로드 시 기존 POST /api/visitors/check 흐름에서 daily_metrics.totalVisitsdaily_metrics.uniqueVisitors를 갱신합니다.
  2. 사용자가 직접 시작한 전투만 POST /api/daily-metrics/match-startedtotalMatchStarts에 누적합니다.
  3. 프리뷰 전투는 제외하고, 실제 전투가 승리/무승부로 끝난 경우만 POST /api/daily-metrics/match-finishedtotalMatchFinishes에 누적합니다.
  4. daily_visitor_activity는 날짜와 방문자 UUID를 함께 해시한 _id를 사용해 당일 방문자별 visits, matchStarts, matchFinishes, donationClicks만 임시 저장합니다.
  5. 방문자의 당일 matchStarts가 1에서 2로 넘어가는 순간에만 daily_metrics.visitorsWithTwoOrMoreMatches를 1 증가시킵니다.
  6. daily_visitor_activityDAILY_ACTIVITY_RETENTION_DAYS 설정값에 따라 TTL로 자동 삭제하고, 장기 보관 대상은 날짜별 합산 문서인 daily_metrics입니다.

전투 사망 통계

프리뷰 전투는 통계에서 제외하고, 사용자가 시작한 실제 전투만 저장합니다.

  1. fighterManifest.js의 모든 스킨은 species를 가집니다.
  2. combat.js의 처치 흐름이 ArenaScene.recordKill()을 호출하면, ArenaScene은 피처치자의 skin.species를 현재 전투의 battleDeathCounts에 누적합니다.
  3. 전투가 5초 이상 이어지면 GET /api/death-stats/today로 가져온 오늘 집계와 현재 전투의 사망 수를 합산해 #battle-notice에 표시합니다.
  4. 전투 종료 시 POST /api/death-stats/todaydeathsBySpecies만 보냅니다.
  5. 서버는 daily_death_stats 컬렉션에서 오늘 일자의 battles, totalDeaths, deathsBySpecies.* 값을 $inc로 갱신합니다.

3. 설정 규칙

  • 서버 설정: .env 대신 config.json을 사용합니다. 로컬 전용 파일이며, 저장소에는 config.json.sample만 공유합니다.
  • MongoDB 연결: 접속 정보는 config.jsonMONGODB_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는 만들지 않습니다.