Skip to content

feat: 마이페이지 Discord 계정 연동 기능 구현 #77

@Sunja-An

Description

@Sunja-An

개요

기존 회원가입을 완료한 사용자가 마이페이지에서 자신의 Discord 계정을 서비스 계정과 연동하는 기능을 구현한다.

배경

현재 Discord OAuth2 인증 플로우(/api/oauth2/discord/login)는 신규 유저 가입 전용으로 동작하며, 이미 이메일/비밀번호로 가입한 기존 유저가 Discord 계정을 연결할 수 있는 수단이 없다. 이를 해결하기 위해 계정 연동 전용 OAuth2 플로우를 별도로 추가한다.

  • Discord 봇 서비스(GAMERS)와의 데이터 동기화(길드 검증, 채널 알림 등)를 위해 사용자의 Discord ID가 필요하다.
  • 프런트엔드와 병렬 개발이 가능하도록 API Contract를 우선 확정한다.

구현 범위

In Scope

  • OAuth2 인증 리다이렉트 & 콜백 처리
  • CSRF 방어를 위한 Redis 기반 state 토큰 관리 (userID 바인딩)
  • discord_accounts 테이블 upsert (신규 연동 / 동일 계정 재연동 / 다른 계정으로 교체)
  • JWT 기반 인증 연동 (연동 시작 엔드포인트는 로그인 필수)

Out of Scope

  • Discord 봇 명령어 처리 로직
  • 프런트엔드 UI 구현

API Contract

Endpoint 1 — 연동 시작

항목 내용
Method GET
Path /api/user/connect/discord
Auth Required (JWT Bearer)
Response 302 Found → Discord OAuth2 인증 페이지로 리다이렉트

Endpoint 2 — 콜백 처리

항목 내용
Method GET
Path /api/user/connect/discord/callback
Auth Not required (Discord가 직접 호출)
Query Params code, state, error(선택)
Response (성공) 302 Found/mypage?connect=success
Response (실패) 302 Found/mypage?connect=error&reason={reason}

주요 로직 흐름 (콜백)

state 검증 (Redis GetDel) → userID 획득
  ↓
code 교환 → Discord 사용자 정보 획득
  ↓
discord_id가 다른 유저에 이미 연동 → 409 ErrDiscordAlreadyLinked (OA005)
  ↓
현재 유저의 discord_accounts 조회
  ├── 없음              → CreateDiscordAccount
  ├── 동일 discord_id  → UpdateDiscordAccount (avatar/verified 갱신)
  └── 다른 discord_id  → DeleteByUserId + CreateDiscordAccount (계정 교체)
  ↓
Discord OAuth2 token → Redis 저장 (봇 API 연동용)

변경 파일 목록

신규

  • internal/oauth2/application/port/connect_state_port.go — ConnectStatePort 인터페이스
  • internal/oauth2/infra/state/connect_state_redis_adapter.go — Redis 기반 state 어댑터

수정

  • internal/global/exception/oauth2_error_status.goErrDiscordAlreadyLinked (OA005) 추가
  • internal/oauth2/application/port/oauth2_database_port.goDeleteDiscordAccountByUserId 추가
  • internal/oauth2/infra/persistence/adapter/oauth2_database_adapter.go — 위 메서드 구현
  • internal/oauth2/application/discord_service.goGetDiscordConnectURL / HandleDiscordConnectCallback 추가
  • internal/oauth2/presentation/discord_controller.go — 신규 라우트 및 핸들러 추가
  • internal/oauth2/provider.goConnectStateRedisAdapter DI 주입

완료 조건

  • GET /api/user/connect/discord — JWT 인증 후 Discord OAuth2 URL로 302 리다이렉트
  • GET /api/user/connect/discord/callback — code/state 처리 후 마이페이지로 302 리다이렉트
  • Redis에 connect:state:{token} 키로 userID가 저장되고 콜백 후 삭제됨 (TTL 10분)
  • discord_accounts 테이블에 연동 정보가 정확히 저장/갱신됨
  • 동일 Discord ID를 다른 유저가 재연동 시도 시 409 에러 처리
  • 인증 취소, 유효하지 않은 state, code 누락 등 에러 케이스 처리
  • 기존 Discord 로그인 플로우(/api/oauth2/discord/login) 정상 동작 유지

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions