feat: About 다이얼로그 추가, UI 최적화 및 서버 캐싱 강화
- About 다이얼로그 추가 (개발자 정보 및 개인정보처리방침) - Markdown 렌더러 구현 (Bold, Italic, Code, Blockquote 지원) - 전투 화면 하단 'About' 및 방문자 카운팅 UI 재배치 및 디자인 통일 - 프로덕션 환경에서 정적 파일 강력 캐싱 설정 (7일 유지) - 파비콘 404 오류 해결을 위한 이모지 데이터 URI 추가 - 모바일 전투 화면 레이아웃 최적화 및 승리 연출 개선 - 일일 운영 지표(Daily Metrics) 수집 API 및 로직 추가
This commit is contained in:
+13
-2
@@ -8,6 +8,7 @@
|
||||
|
||||
### UI 컴포넌트 (`src/ui/`)
|
||||
- **`matchForm.js`**: 설정 폼 제어 및 `localStorage` 설정 유지.
|
||||
- **`aboutDialog.js`**: About 버튼/다이얼로그, 개발자정보, 개인정보처리방침 Markdown 표시.
|
||||
- **`arenaScoreboard.js`**: 좌측 HUD 레일의 팀 badge 업데이트 및 관전 시점 전환.
|
||||
- **`arenaKillLog.js`**: 좌측 하단 킬로그 표시 및 관리.
|
||||
- **`battleDeathNotice.js`**: 상단 사망 통계 공지 UI.
|
||||
@@ -23,8 +24,18 @@
|
||||
### 전투 화면 레이아웃 (HUD)
|
||||
- **팀 Badge**: 좌측 HUD 레일에 배치되며, 클릭 시 해당 팀의 생존 유닛 중 무작위 1명으로 시점을 고정합니다.
|
||||
- **킬로그**: 처치자와 피처치자를 좌우로 배치하고, 피처치자 아이콘에 빨간 X를 겹쳐 사망 관계를 명확히 표시합니다.
|
||||
- **승리 연출**: 승리 시 Web Audio 기반 팡파르와 CSS 애니메이션(광선, 컨페티)을 결합해 화려하게 연출합니다. 무승부는 더 차분한 톤을 사용합니다.
|
||||
- **모바일 레이아웃**: 실제 전투 시작 시 모바일에서는 옵션 drawer를 자동으로 접고, 상단 팀 HUD는 옵션 버튼 폭을 제외한 영역에 두 줄 4열로 맞춰 4개 이후 팀도 잘리지 않게 합니다. 모바일 팀 카드 선택 표시는 내부 테두리로 처리해 외곽선이 잘려 보이지 않게 합니다. 킬로그는 전투 캔버스 바로 아래에 배치하되 방문자 카운터 안전 여백을 남겨 하단 카운터와 충돌하지 않게 합니다.
|
||||
- **모바일 옵션 drawer**: 전투 중 펼친 옵션 drawer는 닉네임 입력 높이와 컨트롤 간격을 줄여 전투 시작/재시작/일시정지 버튼이 작은 화면에서도 한 번에 보이도록 합니다.
|
||||
- **승리 연출**: 승리 시 Web Audio 기반 팡파르와 CSS 애니메이션(광선, 컨페티)을 결합해 화려하게 연출합니다. 전투 종료 시 옵션 drawer를 접어 결과 배너가 설정 폼과 충돌하지 않게 하며, 결과 배너는 일정 시간 후 자동으로 사라지거나 클릭 시 즉시 닫힙니다. 무승부는 더 차분한 톤을 사용합니다.
|
||||
|
||||
## 3. UI 개발 규칙
|
||||
- **DOM 접근 최소화**: 성능 최적화를 위해 필요한 시점에만 최소한으로 DOM을 업데이트합니다.
|
||||
- **반응형 상태**: `#app`의 클래스(`match-live`, `options-open`, `drawer-collapsed`, `match-paused`)를 통해 전반적인 UI 상태를 제어합니다.
|
||||
- **반응형 상태**: `#app`의 클래스(`match-live`, `options-open`, `drawer-collapsed`, `match-paused`, `match-ended`)를 통해 전반적인 UI 상태를 제어합니다.
|
||||
|
||||
## 4. About 다이얼로그
|
||||
|
||||
- **`src/ui/aboutDialog.js`**:
|
||||
- 메인 대기 화면과 전투 화면에서 공통으로 노출되는 `#about-button`을 제어합니다.
|
||||
- About 다이얼로그는 기본으로 개발자정보 탭을 보여주고, 개인정보처리방침 탭에서 DB에 저장된 Markdown 원문을 안전한 DOM 노드로 렌더링합니다.
|
||||
- 브라우저는 `GET /api/about` 읽기 전용 API로 서버 시작 시 캐시된 About 콘텐츠를 가져오며, API 실패 시 개발자 기본값과 빈 정책 안내 문구로 폴백합니다.
|
||||
- 전투 화면 모바일 레이아웃에서는 About 버튼과 방문자 카운터가 하단에서 겹치지 않도록 kill log 여백 계산에 포함합니다.
|
||||
|
||||
@@ -10,9 +10,22 @@
|
||||
- `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`에 바로 더합니다.
|
||||
@@ -31,6 +44,16 @@
|
||||
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.totalVisits`와 `daily_metrics.uniqueVisitors`를 갱신합니다.
|
||||
2. 사용자가 직접 시작한 전투만 `POST /api/daily-metrics/match-started`로 `totalMatchStarts`에 누적합니다.
|
||||
3. 프리뷰 전투는 제외하고, 실제 전투가 승리/무승부로 끝난 경우만 `POST /api/daily-metrics/match-finished`로 `totalMatchFinishes`에 누적합니다.
|
||||
4. `daily_visitor_activity`는 날짜와 방문자 UUID를 함께 해시한 `_id`를 사용해 당일 방문자별 `visits`, `matchStarts`, `matchFinishes`, `donationClicks`만 임시 저장합니다.
|
||||
5. 방문자의 당일 `matchStarts`가 1에서 2로 넘어가는 순간에만 `daily_metrics.visitorsWithTwoOrMoreMatches`를 1 증가시킵니다.
|
||||
6. `daily_visitor_activity`는 `DAILY_ACTIVITY_RETENTION_DAYS` 설정값에 따라 TTL로 자동 삭제하고, 장기 보관 대상은 날짜별 합산 문서인 `daily_metrics`입니다.
|
||||
|
||||
### 전투 사망 통계
|
||||
프리뷰 전투는 통계에서 제외하고, 사용자가 시작한 실제 전투만 저장합니다.
|
||||
@@ -43,4 +66,13 @@
|
||||
## 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는 만들지 않습니다.
|
||||
|
||||
Reference in New Issue
Block a user