콘텐츠로 이동

행사방 위치별 영상 탐색 및 아카이브

티켓: MSG-436(상위) · 세부 MSG-438~443 (2026-08-20 발행) · 원본: Codex 세션 2026-08-19 작성 상태: 확정 (2026-08-20 팀원 K 승인) — 행사방 정본. 기존 event-room.md의 제보·참여 모델을 대체한다. 뷰포트 기준 행사 칩 노출과 시 칩 묶음(구 PRD FR-1), 수동 시드 등재, 미션 축 연계 비목표 결정은 그대로 승계된다. 2026-09-09 개정(MSG-586): 상태 표에 지도 칩 노출 열을 추가하고 업로드 유예 회차를 칩에 노출하기로 확정했다. FR-23~25 신설.

1. 개요

행사방은 초대형 행사와 행사에서 파생된 여러 장소를 지도 격자 위에서 탐색하고, 장소별 현장 영상을 촬영하거나 갤러리에서 업로드하는 기능이다. 등재 대상은 정말 큰 행사만이다(눈높이 기준은 BTS 부산 콘서트급, 2026-08-20 팀원 K 확정). 도시 하나가 들썩이는 규모라야 파생 장소와 현장 영상 수요가 성립하기 때문이다.

사용자는 지역 → 행사 → 행사 위치 → 위치별 영상 순서로 탐색한다. 영상은 행사 영역 전체에 복제하지 않고 대표 격자 하나에만 저장한다. 다만 행사 위치에 연결된 어느 격자를 눌러도 같은 위치별 영상 피드를 조회할 수 있다.

행사가 끝난 뒤에도 기록은 유지한다. 종료 후 30일까지는 지난 영상을 추가로 올릴 수 있고 댓글과 도움돼요도 그대로 남길 수 있다. 30일이 지나면 영상 업로드와 댓글·도움돼요 변경이 함께 차단되고 완전한 읽기 전용 아카이브로 전환한다.

관련 디자인

  • Figma 파일: Fill Map
  • 행사방 섹션: 행사방 시안 - 포켓몬 메가페스타 부산
  • 기준 화면: 행사 개요, 알림 상태, 위치별 영상, 빈 위치, 업로드, 영상 상세, 종료 아카이브
  • Figma URL: https://www.figma.com/design/CpqOlgayviFOG0WXTBUfpp/Fill-Map?node-id=14599-10560

2. 목표

  • 사용자가 행사에 포함된 팝업, 체험존, 퍼레이드, 포토존을 위치 단위로 탐색할 수 있게 한다.
  • 현장에 있지 않아도 촬영 또는 갤러리 선택으로 행사 영상을 올릴 수 있게 한다.
  • 영상 파일과 DB 레코드를 중복 생성하지 않고 대표 격자 한 곳에만 저장한다.
  • 행사 위치 영역의 어느 격자를 눌러도 위치별 영상 기록에 접근할 수 있게 한다.
  • 행사 종료 후 30일간 누락된 영상을 보완할 수 있게 한다.
  • 아카이브로 넘어간 행사의 영상, 댓글, 도움돼요 수를 변경 불가능한 기록으로 보존한다.
  • 현재 행사방 열람 인원을 heartbeat와 캐시로 근실시간 표시한다.
  • 같은 행사가 다시 열릴 때 이전 회차 기록과 새 회차 데이터를 분리한다.

3. 핵심 용어와 데이터 관계

EventSeries (행사 시리즈)
└─ EventOccurrence (행사 회차)
   ├─ EventLocation (행사 위치)
   │  ├─ EventLocationGrid[] (영역을 구성하는 격자)
   │  └─ representativeGridId (영상 저장 대표 격자)
   └─ EventVideo[]
      ├─ eventOccurrenceId
      ├─ eventLocationId
      └─ gridId = representativeGridId
  • EventSeries: 포켓몬 메가페스타처럼 반복 개최될 수 있는 행사의 공통 단위
  • EventOccurrence: 특정 기간에 열린 행사 회차
  • EventLocation: 부산역 팝업, 광안리 퍼레이드처럼 회차에 속한 실제 장소
  • EventLocationGrid: 행사 위치가 지도에서 차지하는 전체 격자 영역
  • representativeGridId: 영상 레코드가 실제로 연결되는 격자 하나
  • EventVideo: 영상 파일과 행사 회차·위치·대표 격자 연결 정보

4. 확정 정책

4.1 대표 격자 지정

  1. 행사 위치 영역이 9×9처럼 홀수 행·열의 직사각형이면 정중앙 격자를 대표 격자로 지정한다.
  2. 영역이 직사각형이 아니거나 중앙 격자를 계산할 수 없으면 운영자가 지정한 representativeGridId를 사용한다.
  3. 운영자가 대표 격자를 지정하지 않은 예외 상황에서는 영역 중심점과 가장 가까운 포함 격자를 선택하고 그 결과를 저장한다.
  4. 한 행사 위치의 모든 영상은 해당 위치의 대표 격자 하나에만 연결한다.
  5. 영상 파일이나 영상 레코드를 9×9 전체 격자에 복제하지 않는다.
  6. 행사 영역의 다른 격자를 클릭하면 EventLocationGrid 연결을 통해 같은 위치별 영상 피드를 조회한다.

4.2 행사 상태

상태 기간 영상 조회 영상 업로드 댓글 작성·수정 도움돼요 변경 알림 지도 칩 노출
예정 시작 전 가능 불가 (2026-08-21 확정) 가능 가능 사용자 선택 시작 2주 전부터
진행 중 시작~종료 가능 가능 가능 가능 사용자 선택 노출
업로드 유예 종료 후 30일 가능 가능 가능 가능 자동 OFF 노출 (2026-09-09 확정)
아카이브 종료 30일 이후 가능 불가 불가 불가 OFF 미노출
  • 아카이브 전환(종료 + 30일) 시 댓글 입력창과 도움돼요 버튼을 비활성화한다.
  • 기존 댓글과 도움돼요 수는 아카이브에서도 계속 표시한다.
  • 종료 후 30일 동안 업로드한 영상에도 댓글과 도움돼요를 남길 수 있다.
  • 2026-08-21 확정(번복): 댓글·도움돼요 잠금 시점을 행사 종료에서 아카이브 전환(종료 + 30일)으로 옮겼다. 유예 기간을 둔 목적이 "행사 다녀와서 나중에 올리기"인데 그 영상이 처음부터 아무도 반응할 수 없는 상태로 올라가면 유예의 목적과 결과가 서로 깎이기 때문이다. 기존 근거였던 "종료 = 기록 확정"은 "아카이브 전환 = 기록 확정"으로 옮겨갔고, 이로써 업로드 창과 반응 창이 시작 ~ 종료 + 30일로 정렬된다.
  • 2026-09-09 확정(번복): 업로드 유예 상태의 회차도 지도 칩에 노출한다. 기존에는 종료 정각에 칩에서 빠져 사용자가 그 행사로 들어갈 입구가 사라졌고, 그 상태로 업로드와 댓글과 도움돼요만 열려 있었다. 2026-08-21에 반응 잠금 시점을 옮길 때 쓴 근거가 그대로 적용된다. 유예 기간을 둔 목적이 "행사 다녀와서 나중에 올리기"인데 들어갈 경로가 없으면 유예의 목적과 결과가 서로 깎인다. 아카이브 회차는 계속 칩에서 빼는데, 읽기 전용 기록이라 지난 행사 아카이브 화면이 그 접근을 맡기 때문이다.
  • 칩 목록의 순서 기준은 이번 변경으로 바뀌지 않는다. 시 이름을 1차 기준으로 유지해 화면이 시 단위로 칩을 묶는 구조를 그대로 쓴다. 진행 중인 행사를 끝난 행사보다 앞으로 당기는 별도 정렬은 도입하지 않는다.
  • 업로드 마감 시각은 eventEndAt + 30일이다.
  • 마감 시각 비교는 서버 시간을 기준으로 한다.
  • 2026-08-21 확정: 행사 경유 업로드는 행사 시작부터 개방한다(구 표기 "정책상 허용 시 가능" 미결의 해소). 시작 전 시도는 EVENT_UPLOAD_NOT_STARTED로 거부하고(FE는 버튼 비활성화), 일반 격자 업로드는 행사와 무관하게 언제나 자유다.

4.3 업로드 방식

  • 사용자는 현재 행사 위치에 있지 않아도 업로드할 수 있다.
  • 업로드 화면은 촬영하기영상 선택을 같은 단계에서 제공한다.
  • 제목과 영상 설명은 입력받지 않는다.
  • 사용자가 행사 위치 화면에서 업로드하면 행사 회차와 행사 위치를 자동 지정한다.
  • gridId는 서버가 행사 위치의 대표 격자로 결정한다.
  • 기기의 현재 위치나 영상 GPS 메타데이터는 필수 조건으로 사용하지 않는다.
  • 업로드 완료 후 해당 행사 위치의 최신 영상 피드로 돌아간다.

4.4 현재 열람 인원

  • 프론트엔드는 행사방을 보고 있는 동안 주기적으로 heartbeat를 전송한다.
  • 기본 전송 주기는 30초다.
  • 서버는 마지막 heartbeat가 90초 이내인 고유 세션을 현재 열람자로 집계한다.
  • 로그인 사용자는 사용자 ID, 비로그인 사용자는 익명 세션 ID로 중복 제거한다.
  • 활성 세션은 Redis 등 TTL을 지원하는 캐시에 저장한다.
  • UI 문구는 120명 보는 중 형식으로 행사명 인접 영역에 표시한다.
  • 행사 알림 영역 아래에는 열람 인원을 중복 표시하지 않는다.

5. 사용자 스토리

US-001: 지역 행사 칩 탐색

Description: 사용자는 지역 칩을 펼쳐 현재 지역의 대표 행사를 선택하고 싶다.

Acceptance Criteria: - [ ] 접힌 상태에는 부산 ›만 표시된다. - [ ] 펼친 상태에는 📍 부산, 활성 행사, 추천 행사가 한 행에 표시된다. - [ ] 활성 행사 칩 포켓몬 부산 D-7은 파란색으로 표시된다. - [ ] 지역축제 기본 칩은 제거되지 않는다. - [ ] 칩이 서로 겹치거나 중복 표시되지 않는다. - [ ] 종료 뒤에도 종료 시각 + 30일 정각 전까지는 칩에 계속 표시된다(2026-09-09 확정). - [ ] 종료 시각 + 30일 정각부터는 칩에서 사라진다(그 순간이 아카이브 전환 시각이다). - [ ] Typecheck와 lint가 통과한다. - [ ] 브라우저에서 실제 화면을 검증한다.

US-002: 행사 개요와 위치 목록 조회

Description: 사용자는 행사에 들어간 뒤 관련 장소와 영상 현황을 먼저 보고 싶다.

Acceptance Criteria: - [ ] 행사 이미지, 행사명, 기간, D-day, 열람 인원, 작은 알림 토글이 표시된다. - [ ] 행사 위치 목록에 위치명, 유형, 운영 시간, 영상 수가 표시된다. - [ ] 지도에서 각 행사 위치 영역이 서로 떨어진 실제 위치에 표시된다. - [ ] 각 격자 색상은 셀 경계 전체를 정확히 채운다. - [ ] 위치 카드 선택 시 해당 위치별 영상 피드로 이동한다. - [ ] Typecheck와 lint가 통과한다. - [ ] 브라우저에서 실제 화면을 검증한다.

US-003: 행사 위치 격자 조회

Description: 사용자는 지도에서 행사 위치에 속한 격자를 눌러 그 위치의 영상을 보고 싶다.

Acceptance Criteria: - [ ] 행사 위치의 모든 격자는 EventLocationGrid로 연결된다. - [ ] 영역 내 어느 격자를 선택해도 동일한 eventLocationId가 해석된다. - [ ] 선택 위치는 진한 파란색, 다른 행사 위치는 낮은 강도의 행사색으로 표시된다. - [ ] 선택된 색상 영역은 실제 지도 격자의 X/Y 및 크기와 일치한다. - [ ] 영상 데이터를 다른 격자에 복제하지 않는다. - [ ] Typecheck와 lint가 통과한다. - [ ] 브라우저에서 실제 화면을 검증한다.

US-004: 위치별 영상 피드 조회

Description: 사용자는 선택한 행사 위치에 올라온 영상을 한 행에 하나씩 보고 싶다.

Acceptance Criteria: - [ ] 위치별 영상 API는 eventOccurrenceIdeventLocationId로 조회한다. - [ ] 각 카드는 전체 너비 16:9 썸네일, 재생 버튼, 길이를 표시한다. - [ ] 카드 하단에는 하트 수, 댓글 수, 업로드 시간이 표시된다. - [ ] 카드 목록에는 사용자가 입력하지 않은 제목이나 설명을 표시하지 않는다. - [ ] 업로드 시간은 가장 오른쪽에 표시된다. - [ ] 결과가 없으면 아직 이 위치에 올라온 영상이 없어요와 업로드 CTA를 표시한다. - [ ] Typecheck와 lint가 통과한다. - [ ] 브라우저에서 실제 화면을 검증한다.

US-005: 영상 촬영 및 갤러리 업로드

Description: 사용자는 현장에서 바로 촬영하거나 나중에 갤러리 영상을 선택해 올리고 싶다.

Acceptance Criteria: - [ ] 업로드 카드에 촬영하기영상 선택 버튼이 함께 표시된다. - [ ] 업로드는 사용자의 현재 위치와 무관하게 가능하다. - [ ] 업로드 요청에 eventOccurrenceIdeventLocationId가 포함된다. - [ ] 서버가 eventLocationId의 대표 격자를 조회해 gridId를 지정한다. - [ ] 제목과 설명 입력 필드가 존재하지 않는다. - [ ] 성공 시 위치별 피드 최상단에 새 영상이 표시된다. - [ ] 마감 이후 요청은 명확한 마감 오류로 거절된다. - [ ] Typecheck와 lint가 통과한다. - [ ] 브라우저에서 촬영·갤러리 두 흐름을 검증한다.

US-006: 영상 상세와 댓글

Description: 사용자는 영상을 재생하고 반응 및 댓글 기록을 확인하고 싶다.

Acceptance Criteria: - [ ] 상세에는 영상, 대표 격자, 업로드 시각, 작성자 정보가 표시된다. - [ ] 진행 중인 행사에서는 도움돼요와 댓글 작성이 가능하다. - [ ] 댓글마다 작성자, 내용, 작성 시간이 표시된다. - [ ] 아카이브된 행사에서는 기존 댓글과 도움돼요 수가 표시된다. - [ ] 아카이브된 행사에서는 댓글 입력과 도움돼요 변경이 서버와 UI 모두에서 차단된다. - [ ] 유예 기간(종료 후 30일)에는 댓글 입력과 도움돼요 변경이 계속 가능하다. - [ ] 목록의 하트 표기와 상세의 도움돼요 수는 동일한 반응 데이터를 사용한다. - [ ] Typecheck와 lint가 통과한다. - [ ] 브라우저에서 진행 중·유예·아카이브 상태를 각각 검증한다.

US-007: 행사 알림

Description: 사용자는 행사 시작과 일정 변경 알림을 작게 켜거나 끄고 싶다.

Acceptance Criteria: - [ ] 행사명 인접 영역에 작은 알림 토글이 표시된다. - [ ] 알림은 행사 시작과 일정 변경에 사용된다. - [ ] 행사 종료 시 서버가 알림 구독을 자동 비활성화한다. - [ ] 별도의 행사 참여하기나 행사방 나가기 과정이 없다. - [ ] Typecheck와 lint가 통과한다. - [ ] 브라우저에서 ON/OFF/자동 종료 상태를 검증한다.

US-008: 현재 열람 인원 표시

Description: 사용자는 현재 같은 행사방을 보고 있는 사람 수를 확인하고 싶다.

Acceptance Criteria: - [ ] 행사방 진입 시 익명 또는 로그인 세션 ID로 heartbeat를 시작한다. - [ ] 화면 이탈 또는 탭 비활성화 시 불필요한 heartbeat를 중단하거나 낮춘다. - [ ] 마지막 신호가 90초를 넘긴 세션은 집계에서 제외된다. - [ ] 동일 세션의 중복 탭 처리 정책에 따라 중복 집계되지 않는다. - [ ] UI는 행사명 옆에 N명 보는 중을 표시한다. - [ ] 캐시 장애 시 숫자를 숨기고 핵심 행사방 기능은 계속 동작한다. - [ ] Typecheck와 lint가 통과한다. - [ ] 브라우저에서 진입·이탈·만료 상황을 검증한다.

US-009: 종료 후 30일 업로드 유예

Description: 사용자는 행사 당일 놓친 영상을 다음 날 또는 종료 후 일정 기간 안에 올리고 싶다.

Acceptance Criteria: - [ ] 종료 후 30일까지 지난 영상 올리기를 제공한다. - [ ] 유예 기간 업로드에도 대표 격자 지정 규칙을 동일하게 적용한다. - [ ] 유예 기간에 생성된 영상에도 댓글·도움돼요 변경이 가능하다(2026-08-21 번복). - [ ] 종료 30일 이후 업로드 CTA가 사라진다. - [ ] 경계 시각의 허용 여부는 서버 시간으로 일관되게 판정한다. - [ ] Typecheck와 lint가 통과한다. - [ ] 브라우저에서 종료 직전, 종료 후, 마감 직전, 마감 후 상태를 검증한다.

US-010: 지난 행사 회차 아카이브

Description: 사용자는 같은 행사가 다시 열려도 이전 회차의 장소와 영상을 구분해 보고 싶다.

Acceptance Criteria: - [ ] 새 개최 기간에는 새 EventOccurrence를 생성한다. - [ ] 기본 화면은 현재 회차를 표시한다. - [ ] 지난 행사 영상에서 이전 회차를 선택할 수 있다. - [ ] 이전 회차의 위치, 영상, 댓글, 도움돼요 수를 그대로 조회할 수 있다. - [ ] 서로 다른 회차의 영상 수와 열람 인원이 섞이지 않는다. - [ ] Typecheck와 lint가 통과한다. - [ ] 브라우저에서 현재·이전 회차 전환을 검증한다.

6. 기능 요구사항

  • FR-1: 시스템은 행사 시리즈와 행사 회차를 분리해 저장해야 한다.
  • FR-2: 행사 위치는 행사 회차에 속해야 하며 하나 이상의 격자와 연결되어야 한다.
  • FR-3: 행사 위치는 반드시 유효한 대표 격자 하나를 가져야 한다.
  • FR-4: 9×9 영역의 대표 격자는 5번째 행·5번째 열의 중앙 격자여야 한다.
  • FR-5: 중앙 계산 실패 시 설정된 대표 격자를 사용해야 한다.
  • FR-6: 대표 격자 설정도 없으면 영역 중심에 가장 가까운 포함 격자를 계산하고 저장해야 한다.
  • FR-7: 영상은 행사 회차, 행사 위치, 대표 격자에 각각 한 번만 연결되어야 한다.
  • FR-8: 행사 영역의 어느 격자에서 진입해도 위치별 피드를 조회할 수 있어야 한다.
  • FR-9: 업로드는 현재 위치 권한 없이도 동작해야 한다.
  • FR-10: 업로드는 촬영과 갤러리 선택을 모두 지원해야 한다.
  • FR-11: 업로드는 영상 제목과 설명을 요구하지 않아야 한다.
  • FR-12: 종료 후 30일까지 영상 업로드를 허용해야 한다.
  • FR-13: 아카이브 전환(종료 + 30일) 시 댓글 생성·수정·삭제와 도움돼요 추가·취소를 차단해야 한다(2026-08-21 번복 — 유예 기간은 허용).
  • FR-14: 아카이브 후에도 댓글과 도움돼요 집계는 조회할 수 있어야 한다.
  • FR-15: 종료 30일 이후 모든 영상 업로드를 차단해야 한다.
  • FR-16: 종료 시 알림 구독을 자동으로 비활성화해야 한다.
  • FR-17: 행사방 열람자는 heartbeat 기반으로 중복 제거해 집계해야 한다.
  • FR-18: 캐시에서 90초 이상 갱신되지 않은 세션은 자동 제외해야 한다.
  • FR-19: 열람자 집계 장애는 영상 조회·업로드 API에 영향을 주지 않아야 한다.
  • FR-20: 영상 목록은 최신 업로드 순으로 정렬해야 한다.
  • FR-21: 댓글 목록은 댓글 작성 시간을 제공해야 한다.
  • FR-22: 종료 상태와 업로드 마감은 클라이언트 값이 아니라 서버 시각으로 판정해야 한다.
  • FR-23: 지도 뷰포트 행사 칩 목록에는 노출 기간에 든 예정 회차, 진행 중 회차, 업로드 유예 회차를 담아야 한다(2026-09-09 확정, SRS FR-EVENT-01 개정).
  • FR-24: 지도 뷰포트 행사 칩 목록에서 아카이브 회차(종료 시각 + 30일 정각 이후)는 제외해야 한다(SRS FR-EVENT-01).
  • FR-25: 칩 목록은 시 이름을 1차 정렬 기준으로 유지해, 화면이 시 단위로 칩을 묶는 구조가 깨지지 않아야 한다(SRS FR-EVENT-01의 시 칩 묶음 계약).

7. 제안 API

조회

  • GET /event-occurrences/{occurrenceId}: 행사 헤더, 상태, 기간, 알림 상태
  • GET /event-occurrences/{occurrenceId}/locations: 위치 목록, 영역 격자, 대표 격자, 영상 수
  • GET /event-occurrences/{occurrenceId}/locations/{locationId}/videos?cursor=: 위치별 영상 피드
  • GET /grids/{gridId}/event-locations: 선택 격자가 속한 현재·지난 행사 위치
  • GET /event-videos/{videoId}: 영상 상세, 댓글, 도움돼요 수, 읽기 전용 여부
  • GET /event-videos/{videoId}/comments?cursor=: 댓글 목록 둘째 페이지부터 (커서 기반. 첫 페이지는 위 영상 상세 응답에 실려 온다. US-006·FR-21의 댓글 목록을 전달하는 API이며 2026-08-21 MSG-441 스펙 작성 중 등재했다)
  • GET /event-occurrences/{occurrenceId}/viewer-count: 현재 열람 인원

변경

  • POST /event-occurrences/{occurrenceId}/heartbeat: 열람 세션 갱신
  • POST /event-occurrences/{occurrenceId}/locations/{locationId}/videos: 영상 업로드 생성
  • POST /event-videos/{videoId}/comments: 아카이브 전 행사 댓글 작성
  • PATCH /event-videos/{videoId}/comments/{commentId}: 아카이브 전 행사 댓글 수정
  • DELETE /event-videos/{videoId}/comments/{commentId}: 아카이브 전 행사 댓글 삭제
  • PUT /event-videos/{videoId}/helpful: 아카이브 전 행사 도움돼요 추가
  • DELETE /event-videos/{videoId}/helpful: 아카이브 전 행사 도움돼요 취소
  • PUT /event-occurrences/{occurrenceId}/notification: 사용자 알림 ON/OFF

공통 오류 코드

  • EVENT_NOT_FOUND: 행사 회차가 없음
  • EVENT_LOCATION_NOT_FOUND: 행사 위치가 없음
  • EVENT_UPLOAD_CLOSED: 종료 후 30일 업로드 마감
  • EVENT_INTERACTION_LOCKED: 아카이브된 행사 댓글·도움돼요 변경 시도
  • REPRESENTATIVE_GRID_MISSING: 대표 격자 결정 실패
  • INVALID_VIDEO: 지원하지 않는 영상 또는 업로드 제한 위반

8. 데이터 필드 제안

EventOccurrence

  • id
  • eventSeriesId
  • title
  • startsAt
  • endsAt
  • uploadClosesAt = endsAt + 30일
  • status: UPCOMING | LIVE | UPLOAD_GRACE | ARCHIVED

EventLocation

  • id
  • eventOccurrenceId
  • name
  • type
  • operatingHours
  • representativeGridId

EventLocationGrid

  • eventLocationId
  • gridId
  • rowIndexcolumnIndex 또는 공간 좌표

EventVideo

  • id
  • eventOccurrenceId
  • eventLocationId
  • gridId
  • uploaderId
  • videoUrl
  • thumbnailUrl
  • durationSeconds
  • capturedAt (선택)
  • createdAt
  • interactionLocked

ViewerPresence

  • 캐시 키: 행사 회차 ID
  • 멤버: 사용자 ID 또는 익명 세션 ID
  • 값: 마지막 heartbeat 시각
  • 활성 기준: 현재 시각 기준 90초 이내

9. UI·UX 요구사항

  • 배경은 밝은 회청색, 카드는 흰색, 주요 행동과 선택 상태는 파란색을 사용한다.
  • 행사 칩은 부산 불꽃축제 시안과 같은 구성으로 통일한다.
  • 📍 부산: 연한 파란색
  • 포켓몬 부산 D-7: 파란색 활성
  • 🎬 부산국제영화제: 흰색 추천
  • 행사 위치는 지도에 실제로 떨어진 위치로 분산해 표시한다.
  • 행사 위치가 차지하는 셀은 일부 도형이 아니라 완전한 격자 단위로 채운다.
  • 위치별 영상은 한 행에 하나씩 표시한다.
  • 업로드 카드에는 촬영하기영상 선택을 나란히 표시한다.
  • 상세 댓글에는 상대 작성 시간을 오른쪽에 표시한다.
  • 아카이브 상태에서는 댓글 입력창을 숨기거나 비활성 상태와 사유를 명확히 표시한다.
  • 아카이브 상태의 도움돼요 버튼은 현재 수만 표시하고 클릭할 수 없어야 한다.

10. 비기능 요구사항

  • 위치별 영상 첫 페이지 응답 목표는 p95 1.5초 이하다.
  • 영상 목록은 커서 기반 페이지네이션을 사용한다. 댓글 목록도 같은 규칙을 따른다(상세 응답이 첫 페이지를 담고, 그다음은 커서로 이어 받는다).
  • 동일 영상 업로드 요청의 재시도는 중복 레코드를 만들지 않도록 멱등 키를 지원한다. 보장 범위는 해당 영상이 교체되거나 삭제되기 전까지다(2026-08-21 확정 — 교체와 삭제는 확정 응답을 받은 클라이언트만 할 수 있어, 이 보장이 겨누는 응답 유실 재시도와 실행 순서가 겹치지 않는다).
  • 대표 격자 연결과 영상 생성은 하나의 트랜잭션으로 처리한다.
  • 댓글·도움돼요 잠금은 UI뿐 아니라 변경 API에서 반드시 검증한다.
  • 업로드 마감 시각과 행사 상태 전환 작업은 재실행해도 안전해야 한다.
  • heartbeat 캐시 장애 시 열람 인원만 숨기고 행사 핵심 기능은 정상 제공한다.
  • 영상 접근 권한, 신고, 삭제 등 기존 공통 영상 정책을 그대로 적용한다.
  • 영상 파일의 최대 길이(30초)·용량·지원 코덱도 기존 공통 업로드 정책을 재사용한다(2026-08-21 확정 — 행사 전용 파일 규격을 두지 않는다).

11. 비목표

  • 별도 행사 참여하기 및 행사방 나가기
  • 참여 인원 수 집계
  • 제보 작성·목록·상세 기능
  • 영상 제목 및 설명 입력
  • 영상 레코드를 행사 위치의 모든 격자에 복제 저장
  • 현재 위치와 업로드 위치의 강제 일치
  • 아카이브된 행사에서 댓글이나 도움돼요 변경
  • 행사 전용 채팅방 또는 영상 외 질문 창구

12. 성공 지표

  • 위치 카드 선택 후 영상 재생까지의 중앙값이 3단계 이내다.
  • 영상 업로드 시작 사용자의 70% 이상이 업로드를 완료한다.
  • 행사 종료 후 업로드된 영상 비율을 측정해 유예 기간 사용성을 확인한다.
  • 대표 격자 누락으로 실패하는 업로드 비율이 0.1% 미만이다.
  • 하나의 영상 ID가 여러 격자에 중복 생성되는 사례가 0건이다.
  • heartbeat 만료 후 90초 이내에 열람 인원에서 제거된다.
  • 아카이브된 행사에서 댓글·도움돼요 변경 성공 사례가 0건이다.

13. 테스트 시나리오

  1. 9×9 행사 위치를 생성하면 중앙 격자가 대표로 결정된다.
  2. 불규칙 영역에서 설정된 대표 격자가 사용된다.
  3. 대표 격자 설정이 없으면 중심점에서 가장 가까운 포함 격자가 저장된다.
  4. 행사 영역의 서로 다른 두 격자를 눌러도 같은 위치별 피드가 반환된다.
  5. 영상 업로드 후 대표 격자 한 곳에만 영상 관계가 생성된다.
  6. 현재 행사 지역 밖에서도 촬영 및 갤러리 업로드가 성공한다.
  7. 행사 진행 중 댓글과 도움돼요 변경이 성공한다.
  8. 종료 직후 영상 업로드와 댓글·도움돼요 변경이 모두 성공하고, 아카이브 전환 후에는 둘 다 거절된다.
  9. 종료 후 30일 마감 직전 업로드는 성공한다.
  10. 마감 이후 업로드는 EVENT_UPLOAD_CLOSED로 실패한다.
  11. 같은 행사의 새 회차를 생성해도 이전 영상이 현재 회차에 섞이지 않는다.
  12. heartbeat 전송 중인 세션만 집계되고 90초가 지나면 제거된다.
  13. 댓글 작성 시간이 목록과 상세에 올바르게 표시된다.
  14. 캐시 장애 시 열람 인원은 숨겨지지만 영상 조회와 업로드는 동작한다.

14. 구현 순서 제안

  1. 행사 시리즈·회차·위치·위치 격자·대표 격자 데이터 모델
  2. 대표 격자 계산 및 운영자 대체값 검증
  3. 행사 위치 및 격자 역조회 API
  4. 위치별 영상 조회 API와 커서 페이지네이션
  5. 촬영·갤러리 공통 업로드 API 및 멱등 처리
  6. 행사 상태와 종료 후 30일 업로드 유예 정책
  7. 아카이브된 행사 댓글·도움돼요 변경 잠금
  8. heartbeat와 열람 인원 캐시 집계
  9. 지역·행사 칩과 행사 개요 UI
  10. 위치별 영상·빈 상태·업로드·상세 UI
  11. 종료 아카이브와 이전 회차 전환 UI
  12. 브라우저 E2E 및 서버 경계 시각 테스트

15. 남은 확인 사항

  • 운영자가 행사 위치 영역과 대표 격자를 등록하는 어드민 화면의 범위를 별도로 정해야 한다.
  • 예정 상태 영상 업로드 허용 여부: 2026-08-21 차단으로 확정돼 종결(§4.2 확정 기록 참조).
  • 영상 신고 및 운영자 삭제 시 아카이브 카운트 처리 정책을 기존 영상 정책과 맞춰야 한다.
  • 비로그인 사용자의 영상 업로드·댓글·도움돼요 허용 여부: 조회는 GET 한정으로 비로그인 허용, 업로드·댓글·도움돼요 변경은 로그인 필수로 MSG-439·440에서 확정돼 종결(MSG-441이 댓글·도움돼요 변경에 같은 정책을 승계한다). 익명 세션 ID는 §4.4 열람 인원 집계 전용이라 쓰기 주체가 아니다.