Skip to content

플레이 링크를 코드로도 공유 #1013

Description

@sevineleven

왜

완주 후 공유 수단이 링크 하나

  • 토너먼트 생성 시점에 6자리 코드(ABC123) 발급. 이후 불변
  • 그 코드는 대기실 합류에만 쓰임
    • 원인: checkJoinable 이 isPending() 을 요구
  • 결과: 완주 후 코드가 죽어 공유 수단이 URL 하나로 좁아짐
  • 결과: 오프라인 구두 전달·손 입력 지원 없음

링크 주소의 추측 가능성

  • /play/{tournamentId} 의 주소가 순번 id
    • 결과: 공유를 켠 토너먼트에 번호만 바꿔 진입 가능
  • 6자리 코드는 약 1,750만 조합
    • 결과: 이 축으로는 코드가 나음
  • 범위: 링크 자체의 추측 가능성은 이 작업 밖

무엇을

완주한 토너먼트에 코드로 입장

  • POST /api/v1/tournaments/from-play-code 신설. body 는 { "code": "ABC123" }
  • 기존 코드에 "완주 상태에서는 플레이 입장 주소" 의미를 하나 더 얹음
  • 새 컬럼·새 코드 발급 없음
  • 조건: uk_tournaments_active_invite_code 가 활성 토너먼트 전체에서 코드 유일성 보장
    • 삭제 행은 generated 컬럼이 NULL 이 되어 코드 재활용
    • 결과: 코드 하나가 활성 토너먼트 하나를 가리키는 것이 이미 성립

상태가 정하는 게이트

대상 상태 코드로 열리는 문 게이트
대기실 참여자로 합류 (기존) 초대 유효 · 30분
주최자 완주 플레이 생성 (신규) 공유 링크 유효 · 14일
  • 코드는 주소. 열리는 문은 상태가 결정
  • 공유를 켜지 않았으면 playLinkExpiresAt 이 비어 코드로도 막힘
  • 주최자 탈퇴로 링크가 무효화된 경우도 같은 게이트를 타 함께 막힘

결정

항목 결정
미리보기 by-invite-code 에 상태별 분기. 완주면 409 대신 플레이 가능 정보
정원 8명. 초대·링크·코드 동일. 초과 시 TOURNAMENT-030
알림 ROOT 주최자 (TournamentPlayedFromLink 유지)
만료 playLinkExpiresAt 을 그대로 게이트로 사용. 링크와 자동 동일

검증

시나리오 기대
완주한 토너먼트 코드로 입장 플레이 생성. 원본 아이템 그대로
공유를 켜지 않은 완주 토너먼트 코드 거부
만료된 플레이 링크의 코드 거부. 재발급(#980) 후 다시 입장 가능
대기실 토너먼트 코드 종전대로 합류 (회귀 가드)
주최자 탈퇴로 무효화된 토너먼트 코드 거부
이미 참여 중인 사람의 재입장 기존 참여 행 (멱등)
정원 초과 TOURNAMENT-030

범위

클론 재공유와 source 평탄화 소멸

참고

관련 이슈

이슈 관계
#980 플레이 링크 멱등화·만료 후 재발급
#1044 클론 제거 (#1027 Phase 1-3)

Activity

  1. self-assigned this
    on Aug 31, 2026
  2. sevineleven commented on Sep 15, 2026

    @sevineleven
    CollaboratorAuthor

    미결정 항목 정리 - 착수 가능

    본문의 "함께 정할 것" 을 정했습니다.

    결정
    미리보기 by-invite-code 에 상태별 분기를 둔다. COMPLETED 면 409 대신 플레이 가능 정보를 내린다
    정원 8명. 초대·링크·코드 전부 동일. 초과 시 TOURNAMENT-030
    알림 지금처럼 ROOT 주최자에게 (TournamentPlayedFromLink 유지)
    만료 코드가 playLinkExpiresAt 을 그대로 게이트로 쓴다 → 링크와 자동으로 같아진다

    "링크 경로도 클론을 받게 할지" 는 사라졌습니다

    #1027 Phase 1-3(#1044)으로 클론 개념 자체가 없어져서 이 질문이 성립하지 않습니다. 진행 상태가 참여 행(tournament_users.status)으로 옮겨졌고, 누가 어느 주소로 들어오든 그 토너먼트의 참여 행이 하나 생깁니다.

    같은 이유로 본문의 "source 를 ROOT 로 평탄화" 도 필요 없어졌습니다. 이 이슈는 코드로 입장하는 경로 하나만 남습니다.

    정원을 링크에도 거는 이유

    지금은 초대 합류만 8명 제한이고 플레이 링크는 무제한입니다. 코드 입장만 막으면 "코드로는 막히는데 링크 달라고 하면 들어가지는" 상태가 되어 제한이 이름뿐이 됩니다. 같은 동작이므로 주소와 무관하게 같은 제한을 건다.

    기존 사용은 안 깨집니다. prod 실측상 공유된 토너먼트 37개의 입장자 분포가 이렇습니다.

    1명 27건 · 2명 5건 · 3명 3건 · 4명 2건   ← 최대 4명
    

    8명에 근접한 사례가 없어, 제한을 걸어도 막히는 사용자가 없습니다.

    곁가지 - 문서가 코드와 어긋나 있습니다

    #370 본문엔 "소유자 포함 최대 9명" 으로 적혀 있는데 실제 코드는 이렇습니다.

    internal const val TOURNAMENT_MAX_PARTICIPANT_COUNT = 8
    if (tournamentUserRepository.countByTournamentId(tournamentId) >= TOURNAMENT_MAX_PARTICIPANT_COUNT)

    참여 행 기준이라 주최자 포함 8명입니다. 이 작업에서 API 문서도 8로 맞춥니다.

    만료가 자동으로 맞는 이유

    코드는 주소일 뿐이고 무엇이 열려 있는지는 상태가 정합니다.

    대상 상태 코드로 무엇이 되나 게이트
    PENDING 참여자로 합류 (기존) isPending() + isInviteValid() (30분)
    COMPLETED 플레이 생성 (신규) isPlayLinkValid() (14일)

    playLinkExpiresAt 이 비어 있으면(주최자가 공유를 안 켰으면) 코드로도 막힙니다. 주최자가 나가 링크가 무효화된 경우도 같은 게이트를 타므로 함께 막히고, #980 으로 만료 후 재발급하면 코드도 같이 살아납니다.

  3. linked a pull request that will close this issue플레이 링크를 코드로도 공유 #1101on Sep 15, 2026
  4. changed the title [-]완료된 토너먼트를 코드로도 입장 + 클론 재공유 (source 는 ROOT 로 평탄화)[/-] [+]플레이 링크를 코드로도 공유[/+] on Sep 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

feat외부 가시적 새 기능

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions