feat: 인프라 개선 — 헬스체크, 로깅, 보안, CI 검증
- /health + /ready 엔드포인트 추가 (DB/Redis 상태 확인) - RequestID 미들웨어 + 구조화 JSON 로깅 - 체인 트랜잭션 per-user rate limit (20 req/min) - DB 커넥션 풀 설정 (MaxOpen 25, MaxIdle 10, MaxLifetime 5m) - Graceful Shutdown 시 Redis/MySQL 연결 정리 - Dockerfile HEALTHCHECK 추가 - CI에 go vet + 빌드 검증 단계 추가 (deploy 전 실행) - 보스 레이드 클라이언트 입장 API (JWT 인증) - Player 프로필 모듈 추가 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
84
internal/player/handler.go
Normal file
84
internal/player/handler.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package player
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
svc *Service
|
||||
}
|
||||
|
||||
func NewHandler(svc *Service) *Handler {
|
||||
return &Handler{svc: svc}
|
||||
}
|
||||
|
||||
// GetProfile 자신의 프로필 조회 (JWT 인증)
|
||||
func (h *Handler) GetProfile(c *fiber.Ctx) error {
|
||||
userID, ok := c.Locals("userID").(uint)
|
||||
if !ok {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "인증 정보가 올바르지 않습니다"})
|
||||
}
|
||||
|
||||
profile, err := h.svc.GetProfile(userID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
|
||||
return c.JSON(profile)
|
||||
}
|
||||
|
||||
// UpdateProfile 자신의 프로필 수정 (JWT 인증)
|
||||
func (h *Handler) UpdateProfile(c *fiber.Ctx) error {
|
||||
userID, ok := c.Locals("userID").(uint)
|
||||
if !ok {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "인증 정보가 올바르지 않습니다"})
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Nickname string `json:"nickname"`
|
||||
}
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "잘못된 요청입니다"})
|
||||
}
|
||||
|
||||
profile, err := h.svc.UpdateProfile(userID, req.Nickname)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
|
||||
return c.JSON(profile)
|
||||
}
|
||||
|
||||
// InternalGetProfile 내부 API: username 쿼리 파라미터로 프로필 조회
|
||||
func (h *Handler) InternalGetProfile(c *fiber.Ctx) error {
|
||||
username := c.Query("username")
|
||||
if username == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "username 파라미터가 필요합니다"})
|
||||
}
|
||||
|
||||
profile, err := h.svc.GetProfileByUsername(username)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
|
||||
return c.JSON(profile)
|
||||
}
|
||||
|
||||
// InternalSaveGameData 내부 API: username 쿼리 파라미터로 게임 데이터 저장
|
||||
func (h *Handler) InternalSaveGameData(c *fiber.Ctx) error {
|
||||
username := c.Query("username")
|
||||
if username == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "username 파라미터가 필요합니다"})
|
||||
}
|
||||
|
||||
var req GameDataRequest
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "잘못된 요청입니다"})
|
||||
}
|
||||
|
||||
if err := h.svc.SaveGameDataByUsername(username, &req); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{"message": "게임 데이터가 저장되었습니다"})
|
||||
}
|
||||
Reference in New Issue
Block a user