All checks were successful
Server CI/CD / deploy (push) Successful in 1m36s
- unsafe 타입 단언 → safe assertion (chain handler 11곳, auth Logout) - Repository 에러 시 nil 반환으로 통일 (chain, auth, announcement) - string ID → uint 파싱으로 타입 안전성 확보 (auth, announcement) - CORS AllowHeaders에 Idempotency-Key, X-API-Key 추가 - /verify 엔드포인트 rate limiter 적용 - Redis 호출에 context timeout 적용 (auth, idempotency 미들웨어) - chain handler 에러 응답에서 내부 정보 노출 방지 - f.Close() 에러 검사 추가 (download service 2곳) - 공지사항 Delete 404 응답 추가 - 회원가입 롤백 시 Delete 에러 로깅 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
120 lines
5.3 KiB
Markdown
120 lines
5.3 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Commands
|
|
|
|
```bash
|
|
go run . # 로컬 실행
|
|
go build -o server . # 빌드
|
|
docker build -t a301-server . # Docker 빌드
|
|
```
|
|
|
|
## Tech Stack
|
|
|
|
- **Go** + **Fiber v2** (StreamRequestBody: true — 대용량 업로드용, Body Limit 4GB)
|
|
- **GORM** + **MySQL** (AutoMigrate 사용)
|
|
- **Redis** — JWT 세션 저장(`session:{userID}`, `refresh:{userID}`) + 멱등성 캐시
|
|
- **JWT** — `golang-jwt/jwt v5`, Access + Refresh 토큰 로테이션
|
|
|
|
## Project Purpose
|
|
|
|
"One of the plans" 게임 플랫폼 백엔드.
|
|
인증 / 공지사항 / 게임 파일 업로드·서빙 / 블록체인(TOL Chain) 연동 담당.
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
internal/
|
|
├── auth/ # User 모델, JWT 발급·검증, 세션 관리(Redis)
|
|
├── announcement/ # Announcement CRUD
|
|
├── download/ # Info 조회, 파일 업로드(스트리밍), 파일 서빙
|
|
└── chain/ # 블록체인 지갑·거래·마켓·인벤토리 (5파일: handler, service, repository, model, client)
|
|
pkg/
|
|
├── config/ # 환경변수 → Config 구조체
|
|
├── database/ # ConnectMySQL(), ConnectRedis()
|
|
└── middleware/ # Auth, AdminOnly, ServerAuth, Idempotency
|
|
routes/routes.go # 모든 라우트 등록
|
|
```
|
|
|
|
## Key Patterns
|
|
|
|
- **계층 구조**: `Handler → Service → Repository`. 각 도메인 폴더에 4~5파일.
|
|
- **파일 업로드**: `Fiber StreamRequestBody: true` + `io.Copy`로 raw body를 직접 디스크에 스트리밍. 메모리에 파일 올리지 않음.
|
|
- **SHA256 자동 추출**: 게임 zip 업로드 시 zip 내 `A301.exe`를 스트리밍으로 읽어 해시 계산.
|
|
- **CORS**: `AllowMethods`에 `PATCH` 포함 필수 (유저 권한 변경 엔드포인트). `AllowOrigins`: `https://a301.tolelom.xyz`.
|
|
- **초기 admin 계정**: 서버 시작 시 `EnsureAdmin()`으로 존재 확인 후 없으면 생성.
|
|
- **DI 패턴**: `main.go`에서 생성자 함수로 Repo → Service → Handler 주입.
|
|
- **콜백 연결**: `authSvc.SetWalletCreator()` — 회원가입 시 자동 지갑 생성. `chainSvc.SetUserResolver()` — username → userID 변환.
|
|
|
|
## Middleware
|
|
|
|
- **Auth**: `Authorization: Bearer <jwt>` 검증 + Redis 세션 확인. `c.Locals("userID", "username", "role")` 설정.
|
|
- **AdminOnly**: `role == "admin"` 확인, 아니면 403.
|
|
- **ServerAuth**: `X-API-Key` 헤더 검증. 게임 서버 → API 서버 내부 통신용.
|
|
- **Idempotency**: `Idempotency-Key` 헤더로 중복 요청 방지. Redis 캐시 TTL 10분. 블록체인 트랜잭션 이중 지출 방지용.
|
|
|
|
## JWT 토큰 로테이션
|
|
|
|
- **Access Token**: `JWT_SECRET`으로 서명, 기본 24시간 만료, Redis `session:{userID}`에 저장.
|
|
- **Refresh Token**: `REFRESH_SECRET`으로 서명, 7일 만료, Redis `refresh:{userID}`에 저장.
|
|
- **Refresh 시**: 이전 토큰 무효화 + 새 Access/Refresh 쌍 발급 (로테이션).
|
|
- **Logout**: Redis에서 session + refresh 키 모두 삭제.
|
|
|
|
## Rate Limiting
|
|
|
|
- Auth 엔드포인트: IP당 10 req/min
|
|
- 일반 API: IP당 60 req/min
|
|
|
|
## 블록체인 연동 (internal/chain/)
|
|
|
|
TOL Chain 노드와 JSON-RPC 2.0 통신.
|
|
|
|
- **UserWallet 모델**: ed25519 키페어 생성, 개인키는 AES-256-GCM 암호화 후 DB 저장.
|
|
- **client.go**: Chain 노드 RPC 호출 (10초 타임아웃).
|
|
- **service.go**: 지갑 생성/암호화, 트랜잭션 서명, 마켓/인벤토리 로직.
|
|
- **내부 API**: 게임 서버가 username 기반으로 보상 지급 (`/api/internal/chain/*`).
|
|
|
|
## Routes
|
|
|
|
**인증**: `POST /api/auth/{register,login,refresh,logout,verify}` (register/login/refresh는 rate limit)
|
|
|
|
**유저 관리 (admin)**: `GET /api/users/`, `PATCH /api/users/:id/role`, `DELETE /api/users/:id`
|
|
|
|
**공지사항**: `GET /api/announcements/`, `POST|PUT|DELETE /api/announcements/:id` (CUD는 admin)
|
|
|
|
**다운로드**: `GET /api/download/{info,file,launcher}`, `POST /api/download/upload/{game,launcher}` (upload는 admin)
|
|
|
|
**체인 조회 (JWT)**: `GET /api/chain/{wallet,balance,assets,asset/:id,inventory,market,market/:id}`
|
|
|
|
**체인 트랜잭션 (JWT + Idempotency)**: `POST /api/chain/{transfer,asset/transfer,market/list,market/buy,market/cancel,inventory/equip,inventory/unequip}`
|
|
|
|
**체인 관리자 (JWT + Admin + Idempotency)**: `POST /api/chain/admin/{mint,reward,template}`
|
|
|
|
**내부 API (X-API-Key + Idempotency)**: `POST /api/internal/chain/{reward,mint}`, `GET /api/internal/chain/{balance,assets,inventory}` (username 쿼리 파라미터)
|
|
|
|
## Environment Variables
|
|
|
|
```
|
|
APP_PORT=8080
|
|
DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME
|
|
REDIS_ADDR, REDIS_PASSWORD
|
|
JWT_SECRET, REFRESH_SECRET, JWT_EXPIRY_HOURS(기본24)
|
|
ADMIN_USERNAME, ADMIN_PASSWORD
|
|
BASE_URL=https://a301.api.tolelom.xyz
|
|
GAME_DIR=/data/game
|
|
CHAIN_NODE_URL=http://localhost:8545
|
|
CHAIN_ID=tolchain-dev
|
|
OPERATOR_KEY_HEX # 오퍼레이터 개인키 (블록체인 트랜잭션 서명용)
|
|
WALLET_ENCRYPTION_KEY # 64자 hex = 32바이트 AES-256 키 (지갑 암호화)
|
|
INTERNAL_API_KEY # 게임 서버 인증용 API 키
|
|
```
|
|
|
|
## File Storage
|
|
|
|
게임 파일은 `GAME_DIR`(`/data/game`)에 저장:
|
|
- `/data/game/game.zip` — 게임 본체
|
|
- `/data/game/launcher.exe` — 런처
|
|
|
|
Docker 볼륨 `game_data:/data/game` 마운트로 컨테이너 재시작 후에도 유지.
|