# Portforwarding-Free Connection Plan

이 문서는 “포트포워딩 없이 런처만으로 접속” 기능을 나중에 구현하기 위한 설계 초안이다. 현재는 구현하지 않았고, `server-pack` 프로필의 `tunnelCommand` 자리에 외부 도구를 연결할 수 있는 수준까지만 준비되어 있다.

## 목표

- 호스트 사용자가 공유기 포트포워딩을 직접 설정하지 않아도 됨
- 접속 사용자는 런처에서 세션 주소 또는 세션 코드를 받아 바로 접속 가능
- 가능하면 버튼 몇 번으로 `서버 실행 -> 세션 공개 -> 다른 사용자 접속` 흐름이 끝나야 함
- 관리자가 런처와 백엔드를 함께 운영할 수 있어야 함

## 원하는 사용자 흐름

### 호스트

1. 라이브러리에서 `server-pack` 프로필 선택
2. `서버 실행` 클릭
3. 런처가 서버 프로세스를 시작
4. 런처가 백엔드에 세션 생성 요청
5. 백엔드가 공개 접속 주소 또는 세션 코드를 발급
6. 호스트는 그 주소/코드를 다른 사용자에게 전달

### 접속자

1. 같은 프로필을 라이브러리에 추가
2. 호스트가 보낸 주소 또는 세션 코드를 입력
3. 런처가 실제 접속 주소를 해석
4. 마인크래프트를 자동 실행하고 해당 서버로 바로 접속

## 필요한 구성요소

### 1. Session API

역할:

- 세션 생성
- 세션 갱신
- 세션 종료
- 세션 조회
- 세션 코드와 실제 릴레이 주소 매핑

예상 엔드포인트:

- `POST /api/sessions`
- `PATCH /api/sessions/:id`
- `DELETE /api/sessions/:id`
- `GET /api/sessions/:code`

세션 데이터 예시:

```json
{
  "id": "sess_123",
  "profileId": "my-server-pack",
  "hostUserId": "uuid-or-account-id",
  "relayAddress": "relay.example.com:34192",
  "accessCode": "ABCD-EFGH",
  "status": "active",
  "createdAt": "2026-05-04T10:00:00Z",
  "lastHeartbeatAt": "2026-05-04T10:01:00Z"
}
```

### 2. Relay or Tunnel Layer

실제로 포트포워딩 없는 접속을 가능하게 하는 핵심이다.

선택지:

- 자체 Relay 서버 운영
- 기존 터널링 솔루션 연동
- TURN 비슷한 중계 방식
- 전용 게임 프록시 운영

이 프로젝트에서는 우선 아래 두 단계 접근이 현실적이다.

1. 외부 터널링 도구 연동
2. 자체 세션/중계 서버로 점진적 전환

### 3. Launcher Host Agent

호스트 측 런처가 해야 하는 일:

- 로컬 서버 실행 상태 확인
- 백엔드에 세션 생성
- 터널 또는 릴레이 프로세스 시작
- 공개 주소 수신
- 주기적 heartbeat 전송
- 서버 종료 시 세션 종료

### 4. Launcher Join Resolver

접속자 측 런처가 해야 하는 일:

- 세션 코드 입력 UI 제공
- 코드로 세션 조회
- 실제 접속 주소 해석
- 선택 프로필과 세션 프로필 일치 여부 확인
- 게임 실행 시 자동 접속 파라미터 전달

## 권장 1차 구현 방향

가장 빠른 방향은 “전용 Relay”를 바로 만드는 것이 아니라, “Session API + 터널 도구 연동”부터 시작하는 것이다.

### 이유

- 현재 런처에 `server-pack`, `tunnelCommand`, 공개 주소 표시 흐름이 이미 들어가 있음
- 가장 적은 변경으로 실사용 가능 여부를 먼저 검증할 수 있음
- 이후 자체 릴레이로 갈아탈 때 UI와 라이브러리 모델을 그대로 유지할 수 있음

### 1차 구성

- 런처:
  - 서버 실행
  - 터널 명령 실행
  - 터널 출력에서 공개 주소 파싱
  - Session API에 주소 등록
- 백엔드:
  - 세션 코드 발급
  - 코드 -> 주소 매핑
  - heartbeat 만료 처리
- 접속자 런처:
  - 세션 코드 입력
  - 코드 조회
  - 자동 접속

## 이후 2차 구현 방향

터널 명령에 외부 도구를 직접 의존하지 않고, 전용 서비스로 이동한다.

### 추가되는 것

- 릴레이 노드
- 호스트 인증 토큰
- 세션별 임시 접속 권한
- 트래픽/세션 제한
- 관리자 대시보드

### 기대 효과

- 터널 도구 설치 부담 감소
- 사용자 경험 단순화
- 접속 로그와 세션 통계 수집 가능
- 악용 방지 정책 적용 가능

## 런처 쪽에 나중에 추가할 UI

### 라이브러리

- `세션 만들기`
- `세션 코드 복사`
- `세션 종료`
- `세션 상태 보기`

### 설치/실행

- `세션 코드로 접속`
- 최근 접속 세션 기록
- 세션 만료 안내

### 설정

- 세션 API 주소
- 릴레이 지역 선택
- 호스트 세션 자동 재등록 여부

## 프로필 스키마 확장 예정

나중에 `catalog.json` 또는 분리된 관리자 설정에 아래 필드가 추가될 수 있다.

```json
{
  "sessionBackendUrl": "https://session.example.com",
  "sessionJoinMode": "code",
  "sessionCodeLength": 8,
  "relayMode": "external-tunnel",
  "relayRegion": "ap-northeast-2"
}
```

## 보안 고려사항

필수 항목:

- 세션 생성은 인증된 사용자만 가능해야 함
- 호스트 heartbeat가 끊기면 세션 자동 만료
- 세션 코드는 충분히 예측 불가능해야 함
- 동일 계정의 세션 수 제한 필요
- 악의적 트래픽에 대한 rate limit 필요
- 프로필 ID 불일치 세션 차단 또는 경고 필요

추가 고려:

- 세션 코드에 만료 시간 포함
- 백엔드 서명 토큰 사용
- 서버 로그 업로드 여부
- 접속자 IP/세션 기록 보관 정책

## 장애 대응

### 호스트 측

- 서버는 켜졌는데 릴레이 주소 발급 실패
- 터널은 살아있는데 heartbeat 실패
- 서버 프로세스 종료 후 세션 정리 누락

대응:

- 런처가 재시도 정책 보유
- 종료 이벤트에서 세션 삭제 호출
- stale session 정리 배치 작업 필요

### 접속자 측

- 세션 코드는 맞는데 만료됨
- 주소는 받았는데 릴레이가 이미 죽음
- 잘못된 프로필로 접속 시도

대응:

- 사용자에게 구체적인 실패 메시지 제공
- 세션 재조회 버튼
- 프로필 불일치 시 설치 페이지 이동 유도

## 구현 순서 제안

### 1단계

- Session API 설계
- 세션 코드 발급/조회/만료 로직 구현
- 런처에 세션 코드 입력 UI 추가

### 2단계

- 현재 `tunnelCommand` 기반 흐름과 Session API 연결
- 호스트 세션 등록/heartbeat/종료 처리
- 접속자 자동 접속 완료

### 3단계

- 자체 Relay 서비스 검토
- 전용 호스트 인증 및 운영 정책 도입
- 외부 터널 도구 의존도 축소

## 현재 코드와 연결되는 지점

- `app/assets/js/serverruntime.js`
  - 서버 실행 후 공개 주소 확보 지점
- `app/assets/js/scripts/library.js`
  - 호스트 공개 주소 표시 및 수동 주소 입력 UI
- `app/assets/js/processbuilder.js`
  - 자동 접속 인자 전달 지점
- `app/assets/js/catalogmanager.js`
  - 프로필 메타데이터 확장 지점

## 결론

“포트포워딩 없이 접속”은 런처 버튼 하나로 끝나는 기능처럼 보여도, 실제로는 런처만의 문제가 아니라 세션 백엔드와 릴레이 계층이 함께 있어야 성립한다.

따라서 다음 구현 목표는 아래가 적절하다.

1. `Session API` 설계
2. `server-pack + tunnelCommand` 흐름을 세션 코드 모델과 연결
3. 이후 전용 Relay 서비스로 확장
