[
  {
    "id": "S0",
    "title": "시작",
    "role": "공통",
    "route": "/",
    "flow": {
      "prev": null,
      "next": "S1"
    },
    "goal": "속마음은 지키고, 결정은 함께.",
    "body": "팀 워크숍|친구 여행 · 확장 제안|팀 회식 · 확장 제안",
    "cta": "모임 만들기",
    "states": [
      "기본",
      "이어갈 방 없음"
    ],
    "back": "서비스 안 이전 화면 없음. 브라우저 백은 외부 이전 페이지로 이동한다.",
    "rule": "MVP는 팀 워크숍. 여행·회식은 후속 주제 제안으로 구분한다.",
    "source": "FR-01 / FR-21 / A안",
    "sprint": "공통",
    "priority": "P0",
    "docsFile": "FR-01 / FR-21 / A안",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "공통 · /",
        "rule": "속마음은 지키고, 결정은 함께.",
        "docs": "FR-01 / FR-21 / A안"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "MVP는 팀 워크숍. 여행·회식은 후속 주제 제안으로 구분한다.",
        "rule": "상태: 기본 / 이어갈 방 없음",
        "docs": "FR-01 / FR-21 / A안"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "서비스 안 이전 화면 없음. 브라우저 백은 외부 이전 페이지로 이동한다.",
        "rule": "주 행동: 모임 만들기",
        "docs": "FR-01 / FR-21 / A안"
      }
    ]
  },
  {
    "id": "S1",
    "title": "방 만들기",
    "role": "방장",
    "route": "/rooms/new",
    "flow": {
      "prev": "S0",
      "next": "S2"
    },
    "goal": "어떤 모임을 정할까요?",
    "body": "모임 이름: 9월 팀 워크숍|함께할 사람: 6명 (방장 포함)|답변 마감: 24시간|초대 방식: 공용 링크 + 코드",
    "cta": "초대방 만들기",
    "states": [
      "기본",
      "입력 오류",
      "만드는 중"
    ],
    "back": "변경 없음→S0. 입력 변경 있음→M1 확인. 생성 성공 후 이 폼은 히스토리에서 교체한다.",
    "rule": "인원 3~8명. 마감 3시간/오늘 자정/24시간/48시간. 생성 중 중복 클릭 금지; 오류는 값 유지. 초대 기본값은 미결.",
    "source": "FR-01 / P-01·02·07",
    "sprint": "방장",
    "priority": "P0",
    "docsFile": "FR-01 / P-01·02·07",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "방장 · /rooms/new",
        "rule": "어떤 모임을 정할까요?",
        "docs": "FR-01 / P-01·02·07"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "인원 3~8명. 마감 3시간/오늘 자정/24시간/48시간. 생성 중 중복 클릭 금지; 오류는 값 유지. 초대 기본값은 미결.",
        "rule": "상태: 기본 / 입력 오류 / 만드는 중",
        "docs": "FR-01 / P-01·02·07"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "변경 없음→S0. 입력 변경 있음→M1 확인. 생성 성공 후 이 폼은 히스토리에서 교체한다.",
        "rule": "주 행동: 초대방 만들기",
        "docs": "FR-01 / P-01·02·07"
      }
    ]
  },
  {
    "id": "S1Q",
    "title": "AI 질문 초안 검토",
    "role": "방장 · 확장",
    "route": "/rooms/new/questions",
    "flow": {
      "prev": "S1",
      "next": "S2"
    },
    "goal": "질문은 우리가 확인해요.",
    "body": "검토 전 AI 초안|우리 모임에서 피하고 싶은 것은?|질문 수정 · 추가 · 제외",
    "cta": "검토한 질문으로 만들기",
    "states": [
      "초안",
      "생성 오류",
      "검토 완료"
    ],
    "back": "S1로 돌아가 모임 설정 유지. 초안 재생성은 기존 편집을 덮기 전 확인.",
    "rule": "주제 확장 때만 적용하는 제안. MVP 고정 6문항 흐름에는 삽입하지 않는다. AI가 임의의 조건·발언을 만들지 않는다.",
    "source": "A안 / 쏠 스타일 가이드 AI 질문 흐름",
    "sprint": "방장 · 확장",
    "priority": "P1",
    "docsFile": "A안 / 쏠 스타일 가이드 AI 질문 흐름",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "방장 · 확장 · /rooms/new/questions",
        "rule": "질문은 우리가 확인해요.",
        "docs": "A안 / 쏠 스타일 가이드 AI 질문 흐름"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "주제 확장 때만 적용하는 제안. MVP 고정 6문항 흐름에는 삽입하지 않는다. AI가 임의의 조건·발언을 만들지 않는다.",
        "rule": "상태: 초안 / 생성 오류 / 검토 완료",
        "docs": "A안 / 쏠 스타일 가이드 AI 질문 흐름"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "S1로 돌아가 모임 설정 유지. 초안 재생성은 기존 편집을 덮기 전 확인.",
        "rule": "주 행동: 검토한 질문으로 만들기",
        "docs": "A안 / 쏠 스타일 가이드 AI 질문 흐름"
      }
    ]
  },
  {
    "id": "S2",
    "title": "초대하기",
    "role": "방장",
    "route": "/r/:room/invite",
    "flow": {
      "prev": "S5H",
      "next": "S3"
    },
    "goal": "우리끼리, 편하게 답해요.",
    "body": "9월 팀 워크숍 · 6명|공용 링크 + 입장 코드 482916 (예시)|답변 마감까지 24시간 (예시)",
    "cta": "내 답변 시작하기",
    "states": [
      "공용 링크",
      "개인 링크",
      "공유 취소"
    ],
    "back": "방 생성 직후에도 S1로 되돌리지 않고 S5H로 이동. 공유 시트 백은 시트만 닫는다.",
    "rule": "공유는 사용자가 대상과 내용을 확인해 실행. 개인 링크는 대상별로 구분; 참가자 토큰을 공개 링크에 포함하지 않는다.",
    "source": "FR-02 / P-07·08",
    "sprint": "방장",
    "priority": "P0",
    "docsFile": "FR-02 / P-07·08",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "방장 · /r/:room/invite",
        "rule": "우리끼리, 편하게 답해요.",
        "docs": "FR-02 / P-07·08"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "공유는 사용자가 대상과 내용을 확인해 실행. 개인 링크는 대상별로 구분; 참가자 토큰을 공개 링크에 포함하지 않는다.",
        "rule": "상태: 공용 링크 / 개인 링크 / 공유 취소",
        "docs": "FR-02 / P-07·08"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "방 생성 직후에도 S1로 되돌리지 않고 S5H로 이동. 공유 시트 백은 시트만 닫는다.",
        "rule": "주 행동: 내 답변 시작하기",
        "docs": "FR-02 / P-07·08"
      }
    ]
  },
  {
    "id": "S3",
    "title": "초대 입장 · 비공개 안내",
    "role": "공통",
    "route": "/r/:room/join",
    "flow": {
      "prev": "S0",
      "next": "S4-1"
    },
    "goal": "편하게 말해도 괜찮아요.",
    "body": "입장 코드: 482916|나를 부를 이름: 민지|내 답변은 다른 참가자와 방장에게 공개하지 않아요.",
    "cta": "내 의견 남기기",
    "states": [
      "첫 입장",
      "코드 오류",
      "이미 참여함"
    ],
    "back": "앱 상단 백→S0. 외부 초대 링크에서 브라우저 백→메신저/이전 페이지. 이름 변경 시 M1.",
    "rule": "코드·정원·기한 검증 후 참여 세션 발급. 동일 세션 재입장은 중복 인원 생성 없이 서버 상태로 복귀. 보관 기간은 아직 미결.",
    "source": "FR-03 / FR-19 / P-08·17",
    "sprint": "공통",
    "priority": "P0",
    "docsFile": "FR-03 / FR-19 / P-08·17",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "공통 · /r/:room/join",
        "rule": "편하게 말해도 괜찮아요.",
        "docs": "FR-03 / FR-19 / P-08·17"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "코드·정원·기한 검증 후 참여 세션 발급. 동일 세션 재입장은 중복 인원 생성 없이 서버 상태로 복귀. 보관 기간은 아직 미결.",
        "rule": "상태: 첫 입장 / 코드 오류 / 이미 참여함",
        "docs": "FR-03 / FR-19 / P-08·17"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "앱 상단 백→S0. 외부 초대 링크에서 브라우저 백→메신저/이전 페이지. 이름 변경 시 M1.",
        "rule": "주 행동: 내 의견 남기기",
        "docs": "FR-03 / FR-19 / P-08·17"
      }
    ]
  },
  {
    "id": "S4-1",
    "title": "내 답변 1 · 방식",
    "role": "본인",
    "route": "/r/:room/answer/1",
    "flow": {
      "prev": "S3",
      "next": "S4-2"
    },
    "goal": "어떤 분위기가 편해요?",
    "body": "실내 중심|야외 중심|반반이면 좋아요",
    "cta": "다음 질문",
    "states": [
      "기본",
      "입력 오류",
      "저장 실패"
    ],
    "back": "앞 문항으로 이동하고 입력·상한·순위를 유지한다. 첫 문항 백은 S3; 방 밖 이탈은 M1.",
    "rule": "필수 1개 선택. 이후 문항으로 이동해도 선택 유지. 본서비스 제안: 인증된 임시저장 성공/실패 표시; 실패 시 저장됐다고 말하지 않는다.",
    "source": "FR-04·05 / P-14·15·20",
    "sprint": "본인",
    "priority": "P0",
    "docsFile": "FR-04·05 / P-14·15·20",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "본인 · /r/:room/answer/1",
        "rule": "어떤 분위기가 편해요?",
        "docs": "FR-04·05 / P-14·15·20"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "필수 1개 선택. 이후 문항으로 이동해도 선택 유지. 본서비스 제안: 인증된 임시저장 성공/실패 표시; 실패 시 저장됐다고 말하지 않는다.",
        "rule": "상태: 기본 / 입력 오류 / 저장 실패",
        "docs": "FR-04·05 / P-14·15·20"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "앞 문항으로 이동하고 입력·상한·순위를 유지한다. 첫 문항 백은 S3; 방 밖 이탈은 M1.",
        "rule": "주 행동: 다음 질문",
        "docs": "FR-04·05 / P-14·15·20"
      }
    ]
  },
  {
    "id": "S4-2",
    "title": "내 답변 2 · 시간",
    "role": "본인",
    "route": "/r/:room/answer/2",
    "flow": {
      "prev": "S4-1",
      "next": "S4-3"
    },
    "goal": "어느 정도 시간이 편해요?",
    "body": "반나절|하루|1박 2일|꼭 지킬 상한: 하루",
    "cta": "다음 질문",
    "states": [
      "기본",
      "입력 오류",
      "저장 실패"
    ],
    "back": "앞 문항으로 이동하고 입력·상한·순위를 유지한다. 문항 사이 이동에는 이탈 확인을 띄우지 않는다.",
    "rule": "선호와 상한은 별도. 상한보다 긴 후보는 제외. 상한이 선호보다 짧으면 해당 필드에 오류. 본서비스 제안: 인증된 임시저장 성공/실패 표시; 실패 시 저장됐다고 말하지 않는다.",
    "source": "FR-04·05 / P-14·15·20",
    "sprint": "본인",
    "priority": "P0",
    "docsFile": "FR-04·05 / P-14·15·20",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "본인 · /r/:room/answer/2",
        "rule": "어느 정도 시간이 편해요?",
        "docs": "FR-04·05 / P-14·15·20"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "선호와 상한은 별도. 상한보다 긴 후보는 제외. 상한이 선호보다 짧으면 해당 필드에 오류. 본서비스 제안: 인증된 임시저장 성공/실패 표시; 실패 시 저장됐다고 말하지 않는다.",
        "rule": "상태: 기본 / 입력 오류 / 저장 실패",
        "docs": "FR-04·05 / P-14·15·20"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "앞 문항으로 이동하고 입력·상한·순위를 유지한다. 문항 사이 이동에는 이탈 확인을 띄우지 않는다.",
        "rule": "주 행동: 다음 질문",
        "docs": "FR-04·05 / P-14·15·20"
      }
    ]
  },
  {
    "id": "S4-3",
    "title": "내 답변 3 · 목적",
    "role": "본인",
    "route": "/r/:room/answer/3",
    "flow": {
      "prev": "S4-2",
      "next": "S4-4"
    },
    "goal": "무엇을 가장 얻고 싶나요?",
    "body": "1순위: 팀워크|2순위: 재충전|아이디어",
    "cta": "다음 질문",
    "states": [
      "기본",
      "입력 오류",
      "저장 실패"
    ],
    "back": "앞 문항으로 이동하고 입력·상한·순위를 유지한다. 문항 사이 이동에는 이탈 확인을 띄우지 않는다.",
    "rule": "1·2순위 중복 불가. 순위 교체 시 즉시 결과를 보여 준다. 본서비스 제안: 인증된 임시저장 성공/실패 표시; 실패 시 저장됐다고 말하지 않는다.",
    "source": "FR-04·05 / P-14·15·20",
    "sprint": "본인",
    "priority": "P0",
    "docsFile": "FR-04·05 / P-14·15·20",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "본인 · /r/:room/answer/3",
        "rule": "무엇을 가장 얻고 싶나요?",
        "docs": "FR-04·05 / P-14·15·20"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "1·2순위 중복 불가. 순위 교체 시 즉시 결과를 보여 준다. 본서비스 제안: 인증된 임시저장 성공/실패 표시; 실패 시 저장됐다고 말하지 않는다.",
        "rule": "상태: 기본 / 입력 오류 / 저장 실패",
        "docs": "FR-04·05 / P-14·15·20"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "앞 문항으로 이동하고 입력·상한·순위를 유지한다. 문항 사이 이동에는 이탈 확인을 띄우지 않는다.",
        "rule": "주 행동: 다음 질문",
        "docs": "FR-04·05 / P-14·15·20"
      }
    ]
  },
  {
    "id": "S4-4",
    "title": "내 답변 4 · 지역",
    "role": "본인",
    "route": "/r/:room/answer/4",
    "flow": {
      "prev": "S4-3",
      "next": "S4-5"
    },
    "goal": "어디에서 만나면 편할까요?",
    "body": "도심|근교|어디든 괜찮아요",
    "cta": "다음 질문",
    "states": [
      "기본",
      "입력 오류",
      "저장 실패"
    ],
    "back": "앞 문항으로 이동하고 입력·상한·순위를 유지한다. 문항 사이 이동에는 이탈 확인을 띄우지 않는다.",
    "rule": "무관은 빈 응답과 구별. 개인 위치·주소 입력을 요구하지 않는다. 본서비스 제안: 인증된 임시저장 성공/실패 표시; 실패 시 저장됐다고 말하지 않는다.",
    "source": "FR-04·05 / P-14·15·20",
    "sprint": "본인",
    "priority": "P0",
    "docsFile": "FR-04·05 / P-14·15·20",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "본인 · /r/:room/answer/4",
        "rule": "어디에서 만나면 편할까요?",
        "docs": "FR-04·05 / P-14·15·20"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "무관은 빈 응답과 구별. 개인 위치·주소 입력을 요구하지 않는다. 본서비스 제안: 인증된 임시저장 성공/실패 표시; 실패 시 저장됐다고 말하지 않는다.",
        "rule": "상태: 기본 / 입력 오류 / 저장 실패",
        "docs": "FR-04·05 / P-14·15·20"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "앞 문항으로 이동하고 입력·상한·순위를 유지한다. 문항 사이 이동에는 이탈 확인을 띄우지 않는다.",
        "rule": "주 행동: 다음 질문",
        "docs": "FR-04·05 / P-14·15·20"
      }
    ]
  },
  {
    "id": "S4-5",
    "title": "내 답변 5 · 예산",
    "role": "본인",
    "route": "/r/:room/answer/5",
    "flow": {
      "prev": "S4-4",
      "next": "S4-6"
    },
    "goal": "어느 정도가 부담 없나요?",
    "body": "선호 예산: 5만 원|꼭 지킬 상한: 10만 원|상한 없음",
    "cta": "다음 질문",
    "states": [
      "기본",
      "입력 오류",
      "저장 실패"
    ],
    "back": "앞 문항으로 이동하고 입력·상한·순위를 유지한다. 문항 사이 이동에는 이탈 확인을 띄우지 않는다.",
    "rule": "선호 초과는 선호 차이; 상한 초과만 제외. 선호보다 작은 상한은 오류. 선택 값을 URL에 넣지 않는다. 본서비스 제안: 인증된 임시저장 성공/실패 표시; 실패 시 저장됐다고 말하지 않는다.",
    "source": "FR-04·05 / P-14·15·20",
    "sprint": "본인",
    "priority": "P0",
    "docsFile": "FR-04·05 / P-14·15·20",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "본인 · /r/:room/answer/5",
        "rule": "어느 정도가 부담 없나요?",
        "docs": "FR-04·05 / P-14·15·20"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "선호 초과는 선호 차이; 상한 초과만 제외. 선호보다 작은 상한은 오류. 선택 값을 URL에 넣지 않는다. 본서비스 제안: 인증된 임시저장 성공/실패 표시; 실패 시 저장됐다고 말하지 않는다.",
        "rule": "상태: 기본 / 입력 오류 / 저장 실패",
        "docs": "FR-04·05 / P-14·15·20"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "앞 문항으로 이동하고 입력·상한·순위를 유지한다. 문항 사이 이동에는 이탈 확인을 띄우지 않는다.",
        "rule": "주 행동: 다음 질문",
        "docs": "FR-04·05 / P-14·15·20"
      }
    ]
  },
  {
    "id": "S4-6",
    "title": "내 답변 6 · 피할 것",
    "role": "본인",
    "route": "/r/:room/answer/6",
    "flow": {
      "prev": "S4-5",
      "next": "S4R"
    },
    "goal": "이것만은 피하고 싶어요.",
    "body": "술을 마시지 않는 일정이면 좋겠어요.|목록에서 고르기|입력하지 않고 넘어가기",
    "cta": "조건 확인하기",
    "states": [
      "기본",
      "입력 오류",
      "저장 실패"
    ],
    "back": "앞 문항으로 이동하고 입력·상한·순위를 유지한다. 문항 사이 이동에는 이탈 확인을 띄우지 않는다.",
    "rule": "선택 문항. 해석 실패 원문을 자동으로 버리지 않는다. 목록 선택 또는 명시적 비우기 뒤 진행. 본서비스 제안: 인증된 임시저장 성공/실패 표시; 실패 시 저장됐다고 말하지 않는다.",
    "source": "FR-04·05 / P-14·15·20",
    "sprint": "본인",
    "priority": "P0",
    "docsFile": "FR-04·05 / P-14·15·20",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "본인 · /r/:room/answer/6",
        "rule": "이것만은 피하고 싶어요.",
        "docs": "FR-04·05 / P-14·15·20"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "선택 문항. 해석 실패 원문을 자동으로 버리지 않는다. 목록 선택 또는 명시적 비우기 뒤 진행. 본서비스 제안: 인증된 임시저장 성공/실패 표시; 실패 시 저장됐다고 말하지 않는다.",
        "rule": "상태: 기본 / 입력 오류 / 저장 실패",
        "docs": "FR-04·05 / P-14·15·20"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "앞 문항으로 이동하고 입력·상한·순위를 유지한다. 문항 사이 이동에는 이탈 확인을 띄우지 않는다.",
        "rule": "주 행동: 조건 확인하기",
        "docs": "FR-04·05 / P-14·15·20"
      }
    ]
  },
  {
    "id": "S4R",
    "title": "구조화 확인 · 제출",
    "role": "본인",
    "route": "/r/:room/answer/review",
    "flow": {
      "prev": "S4-6",
      "next": "S5"
    },
    "goal": "내 조건, 이렇게 이해했어요.",
    "body": "술 없는 일정 · 꼭 지켜요|시간은 하루 이하|예산은 10만 원 이하|각 항목은 나만 확인할 수 있어요.",
    "cta": "이 조건으로 제출하기",
    "states": [
      "확인 필요",
      "해석 실패",
      "제출 중",
      "제출 오류"
    ],
    "back": "S4-6으로 복귀해 원문·태그 유지. 제출 성공 후 S5로 교체; 백으로 제출을 취소하지 않는다.",
    "rule": "해석 결과 수정/확인 필수. 실패 상태에서 제출 불가. 재시도는 같은 요청 식별자로 처리; 성공 여부 불명확하면 상태부터 조회.",
    "source": "FR-05·06 / NF-04",
    "sprint": "본인",
    "priority": "P0",
    "docsFile": "FR-05·06 / NF-04",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "본인 · /r/:room/answer/review",
        "rule": "내 조건, 이렇게 이해했어요.",
        "docs": "FR-05·06 / NF-04"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "해석 결과 수정/확인 필수. 실패 상태에서 제출 불가. 재시도는 같은 요청 식별자로 처리; 성공 여부 불명확하면 상태부터 조회.",
        "rule": "상태: 확인 필요 / 해석 실패 / 제출 중 / 제출 오류",
        "docs": "FR-05·06 / NF-04"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "S4-6으로 복귀해 원문·태그 유지. 제출 성공 후 S5로 교체; 백으로 제출을 취소하지 않는다.",
        "rule": "주 행동: 이 조건으로 제출하기",
        "docs": "FR-05·06 / NF-04"
      }
    ]
  },
  {
    "id": "S5",
    "title": "모임 홈 · 대기",
    "role": "공통",
    "route": "/r/:room",
    "flow": {
      "prev": "S0",
      "next": "S6"
    },
    "goal": "내 의견은 잘 도착했어요.",
    "body": "내 답변: 제출 완료|답변 4 / 6명 · 가상 예시|답변 마감까지 2시간 · 가상 예시",
    "cta": "내 답변 확인",
    "states": [
      "답변 대기",
      "조율 시작됨",
      "미응답 제외"
    ],
    "back": "상단 백→S0. 시스템 백은 유효한 직전 화면; 이미 제출한 입력 URL은 S5로 상태 보정한다.",
    "rule": "방장도 남의 답변을 볼 수 없다. 답변 수정은 수집 중에만. 조율 시작 이벤트 수신 시 읽기 전용과 상태 이동을 안내.",
    "source": "FR-06·07 / P-05",
    "sprint": "공통",
    "priority": "P0",
    "docsFile": "FR-06·07 / P-05",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "공통 · /r/:room",
        "rule": "내 의견은 잘 도착했어요.",
        "docs": "FR-06·07 / P-05"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "방장도 남의 답변을 볼 수 없다. 답변 수정은 수집 중에만. 조율 시작 이벤트 수신 시 읽기 전용과 상태 이동을 안내.",
        "rule": "상태: 답변 대기 / 조율 시작됨 / 미응답 제외",
        "docs": "FR-06·07 / P-05"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "상단 백→S0. 시스템 백은 유효한 직전 화면; 이미 제출한 입력 URL은 S5로 상태 보정한다.",
        "rule": "주 행동: 내 답변 확인",
        "docs": "FR-06·07 / P-05"
      }
    ]
  },
  {
    "id": "S5H",
    "title": "진행 관리",
    "role": "방장",
    "route": "/r/:room/manage",
    "flow": {
      "prev": "S5",
      "next": "S6"
    },
    "goal": "모두의 진행만 확인해요.",
    "body": "민지 · 답변 완료|준호 · 답변 완료|수연 · 작성 중|전체 4 / 6명 답변 · 예시",
    "cta": "조기 시작 검토",
    "states": [
      "수집 중",
      "시작 확인",
      "알림 대기시간"
    ],
    "back": "S5로 복귀. 조기 시작 확인창에서 백/ESC는 취소만 한다; 조율은 시작하지 않는다.",
    "rule": "3명 이상 답변해야 시작. 미응답자의 계산·리포트·재확인 제외를 확인창에 표시. 수동 알림 쿨다운 30분. 권한은 서버에서 검사.",
    "source": "FR-07~10 / P-05·06",
    "sprint": "방장",
    "priority": "P0",
    "docsFile": "FR-07~10 / P-05·06",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "방장 · /r/:room/manage",
        "rule": "모두의 진행만 확인해요.",
        "docs": "FR-07~10 / P-05·06"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "3명 이상 답변해야 시작. 미응답자의 계산·리포트·재확인 제외를 확인창에 표시. 수동 알림 쿨다운 30분. 권한은 서버에서 검사.",
        "rule": "상태: 수집 중 / 시작 확인 / 알림 대기시간",
        "docs": "FR-07~10 / P-05·06"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "S5로 복귀. 조기 시작 확인창에서 백/ESC는 취소만 한다; 조율은 시작하지 않는다.",
        "rule": "주 행동: 조기 시작 검토",
        "docs": "FR-07~10 / P-05·06"
      }
    ]
  },
  {
    "id": "S6",
    "title": "조율 진행",
    "role": "공통",
    "route": "/r/:room/progress",
    "flow": {
      "prev": "S5",
      "next": "S7"
    },
    "goal": "조건을 함께 맞추고 있어요.",
    "body": "1. 조건 모으기|2. 꼭 지킬 조건 확인|3. 후보 비교|4. 추천 이유 정리",
    "cta": "모임 홈으로",
    "states": [
      "계산 중",
      "설명 대체",
      "다시 연결 필요"
    ],
    "back": "S5로 나가도 서버 조율은 계속된다. 재입장은 새 계산을 시작하지 않고 현재 작업 상태를 조회한다.",
    "rule": "사람 단위 가짜 발언·가짜 진행률 금지. 설명만 30초 넘으면 템플릿. 계산 자체 실패는 E5; 결과가 없는데 성공처럼 넘어가지 않는다.",
    "source": "FR-11·12·14 / P-16",
    "sprint": "공통",
    "priority": "P0",
    "docsFile": "FR-11·12·14 / P-16",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "공통 · /r/:room/progress",
        "rule": "조건을 함께 맞추고 있어요.",
        "docs": "FR-11·12·14 / P-16"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "사람 단위 가짜 발언·가짜 진행률 금지. 설명만 30초 넘으면 템플릿. 계산 자체 실패는 E5; 결과가 없는데 성공처럼 넘어가지 않는다.",
        "rule": "상태: 계산 중 / 설명 대체 / 다시 연결 필요",
        "docs": "FR-11·12·14 / P-16"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "S5로 나가도 서버 조율은 계속된다. 재입장은 새 계산을 시작하지 않고 현재 작업 상태를 조회한다.",
        "rule": "주 행동: 모임 홈으로",
        "docs": "FR-11·12·14 / P-16"
      }
    ]
  },
  {
    "id": "S7",
    "title": "결과 · 후보 비교",
    "role": "공통",
    "route": "/r/:room/result",
    "flow": {
      "prev": "S5",
      "next": "S7B"
    },
    "goal": "함께 정할 안을 찾았어요.",
    "body": "양평 리트릿 워크숍 · 가상 추천|하루 · 1인 9만 원 · 가상 예시|공통 이유와 선호 차이|대안 두 개 더 보기",
    "cta": "내 최종 의견 남기기",
    "states": [
      "재확인 중",
      "전원 동의",
      "방장 확정",
      "조건 미반영"
    ],
    "back": "S5로 복귀. 대안 상세 시트가 열렸다면 시트만 닫고 결과 스크롤 위치를 복원한다.",
    "rule": "전원 동의=계산 대상 전원의 명시 동의. 미응답·기권·조건부를 자동 동의로 처리하지 않는다. 방장 확정은 중립 배지; 단독 조건 내용은 공개 금지.",
    "source": "FR-13 / P-05·09·12 / A안",
    "sprint": "공통",
    "priority": "P0",
    "docsFile": "FR-13 / P-05·09·12 / A안",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "공통 · /r/:room/result",
        "rule": "함께 정할 안을 찾았어요.",
        "docs": "FR-13 / P-05·09·12 / A안"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "전원 동의=계산 대상 전원의 명시 동의. 미응답·기권·조건부를 자동 동의로 처리하지 않는다. 방장 확정은 중립 배지; 단독 조건 내용은 공개 금지.",
        "rule": "상태: 재확인 중 / 전원 동의 / 방장 확정 / 조건 미반영",
        "docs": "FR-13 / P-05·09·12 / A안"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "S5로 복귀. 대안 상세 시트가 열렸다면 시트만 닫고 결과 스크롤 위치를 복원한다.",
        "rule": "주 행동: 내 최종 의견 남기기",
        "docs": "FR-13 / P-05·09·12 / A안"
      }
    ]
  },
  {
    "id": "S8",
    "title": "내 리포트",
    "role": "본인",
    "route": "/r/:room/me/report",
    "flow": {
      "prev": "S7",
      "next": "S7B"
    },
    "goal": "나의 조건은 이렇게 반영됐어요.",
    "body": "내 시간 상한은 지켜졌어요.|예산 상한은 지켜졌어요.|선호 예산보다 비용이 높아요.",
    "cta": "내 최종 의견 남기기",
    "states": [
      "본인 확인됨",
      "권한 만료"
    ],
    "back": "진입한 S7 또는 S9로 복귀. 외부 직접 진입 시 권한을 확인한 후 S7로 돌아가기 제공.",
    "rule": "방장에게도 본인 외 리포트 접근 금지. URL/공유 미리보기/방장 집계/로그에 개인 값 포함 금지. 세션 만료 시 화면을 가리고 E4.",
    "source": "FR-15·19 / P-12",
    "sprint": "본인",
    "priority": "P0",
    "docsFile": "FR-15·19 / P-12",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "본인 · /r/:room/me/report",
        "rule": "나의 조건은 이렇게 반영됐어요.",
        "docs": "FR-15·19 / P-12"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "방장에게도 본인 외 리포트 접근 금지. URL/공유 미리보기/방장 집계/로그에 개인 값 포함 금지. 세션 만료 시 화면을 가리고 E4.",
        "rule": "상태: 본인 확인됨 / 권한 만료",
        "docs": "FR-15·19 / P-12"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "진입한 S7 또는 S9로 복귀. 외부 직접 진입 시 권한을 확인한 후 S7로 돌아가기 제공.",
        "rule": "주 행동: 내 최종 의견 남기기",
        "docs": "FR-15·19 / P-12"
      }
    ]
  },
  {
    "id": "S7B",
    "title": "최종 의견",
    "role": "계산 대상 참가자",
    "route": "/r/:room/ratify",
    "flow": {
      "prev": "S7",
      "next": "S7"
    },
    "goal": "이 안으로 함께할 수 있나요?",
    "body": "동의해요|조건부로 동의해요|다시 조율해야 해요",
    "cta": "의견 보내기",
    "states": [
      "동의",
      "조건부 동의",
      "재조율 요청",
      "1회 사용함",
      "마감됨"
    ],
    "back": "입력 없음→진입한 S7/S8. 작성 중 조건이 있으면 M1. 제출 성공 후 결과로 교체; 백은 제출 취소가 아니다.",
    "rule": "조건부는 공개 가능한 실행 조건 필수 + 공개 미리보기. 재조율은 비공개 조건 구조화 성공 후 방당 1회 원자적 차감. 실패 시 권한 유지. 결과 버전이 바뀌면 이전 동의 재사용 금지(제안).",
    "source": "FR-16·17 / P-09·10",
    "sprint": "계산 대상 참가자",
    "priority": "P0",
    "docsFile": "FR-16·17 / P-09·10",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "계산 대상 참가자 · /r/:room/ratify",
        "rule": "이 안으로 함께할 수 있나요?",
        "docs": "FR-16·17 / P-09·10"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "조건부는 공개 가능한 실행 조건 필수 + 공개 미리보기. 재조율은 비공개 조건 구조화 성공 후 방당 1회 원자적 차감. 실패 시 권한 유지. 결과 버전이 바뀌면 이전 동의 재사용 금지(제안).",
        "rule": "상태: 동의 / 조건부 동의 / 재조율 요청 / 1회 사용함 / 마감됨",
        "docs": "FR-16·17 / P-09·10"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "입력 없음→진입한 S7/S8. 작성 중 조건이 있으면 M1. 제출 성공 후 결과로 교체; 백은 제출 취소가 아니다.",
        "rule": "주 행동: 의견 보내기",
        "docs": "FR-16·17 / P-09·10"
      }
    ]
  },
  {
    "id": "S7C",
    "title": "결정 확정 확인",
    "role": "방장",
    "route": "/r/:room/result?confirm",
    "flow": {
      "prev": "S7",
      "next": "S9"
    },
    "goal": "이 내용으로 확정할까요?",
    "body": "동의 3 · 조건부 1 · 기권 0 · 예시|공개 실행 조건: 저녁 8시 전에 종료|계산에 포함되지 않은 참가자 2명 · 예시",
    "cta": "결정 확정하기",
    "states": [
      "확정 가능",
      "재조율 처리 중",
      "조건 검토 필요"
    ],
    "back": "백/ESC/취소→S7. 확정 API 성공 전에는 완료 화면으로 이동하지 않는다.",
    "rule": "재조율 없음 AND (전원 응답 OR 24시간 마감) 조건. 공개 실행 조건 충돌이 있으면 확정 차단을 제안. 기권 존재 시 전원 동의 배지 금지.",
    "source": "FR-17 / P-09 / UX 제안",
    "sprint": "방장",
    "priority": "P0",
    "docsFile": "FR-17 / P-09 / UX 제안",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "방장 · /r/:room/result?confirm",
        "rule": "이 내용으로 확정할까요?",
        "docs": "FR-17 / P-09 / UX 제안"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "재조율 없음 AND (전원 응답 OR 24시간 마감) 조건. 공개 실행 조건 충돌이 있으면 확정 차단을 제안. 기권 존재 시 전원 동의 배지 금지.",
        "rule": "상태: 확정 가능 / 재조율 처리 중 / 조건 검토 필요",
        "docs": "FR-17 / P-09 / UX 제안"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "백/ESC/취소→S7. 확정 API 성공 전에는 완료 화면으로 이동하지 않는다.",
        "rule": "주 행동: 결정 확정하기",
        "docs": "FR-17 / P-09 / UX 제안"
      }
    ]
  },
  {
    "id": "S9",
    "title": "결정 완료",
    "role": "공통",
    "route": "/r/:room/done",
    "flow": {
      "prev": "S5",
      "next": "M2"
    },
    "goal": "이제 함께 실행해요.",
    "body": "양평 리트릿 워크숍 · 예시|방장 확정 · 전원 동의 미확인|실행 조건: 저녁 8시 전에 종료",
    "cta": "결정 공유하기",
    "states": [
      "전원 동의 후 확정",
      "방장 확정",
      "공유 취소"
    ],
    "back": "S5 읽기 전용 홈. 브라우저 백으로 재확인 폼이 열려도 서버 완료 상태에 따라 S9로 보정.",
    "rule": "공유는 공개 결정·실행 조건만. 캘린더 파일 생성은 외부 예약·일정 등록과 다름. 열람/삭제 기간 숫자는 정책 확정 전 약속하지 않는다.",
    "source": "FR-18 / P-17·18",
    "sprint": "공통",
    "priority": "P0",
    "docsFile": "FR-18 / P-17·18",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "공통 · /r/:room/done",
        "rule": "이제 함께 실행해요.",
        "docs": "FR-18 / P-17·18"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "공유는 공개 결정·실행 조건만. 캘린더 파일 생성은 외부 예약·일정 등록과 다름. 열람/삭제 기간 숫자는 정책 확정 전 약속하지 않는다.",
        "rule": "상태: 전원 동의 후 확정 / 방장 확정 / 공유 취소",
        "docs": "FR-18 / P-17·18"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "S5 읽기 전용 홈. 브라우저 백으로 재확인 폼이 열려도 서버 완료 상태에 따라 S9로 보정.",
        "rule": "주 행동: 결정 공유하기",
        "docs": "FR-18 / P-17·18"
      }
    ]
  },
  {
    "id": "E1",
    "title": "입장할 수 없음",
    "role": "공통",
    "route": "/r/:room/join?error",
    "flow": {
      "prev": "S0",
      "next": "S3"
    },
    "goal": "초대 내용을 확인해 주세요.",
    "body": "코드를 다시 확인해 주세요.|새 참가자 입장이 마감됐어요.|정원이 찼어요.",
    "cta": "코드 다시 입력",
    "states": [
      "코드 오류",
      "정원 초과",
      "초대 만료"
    ],
    "back": "S0 또는 외부 초대 원래 페이지. 기존 참가자는 세션 검증 후 S5/S7/S9로 복귀 가능(제안).",
    "rule": "신규 초대 만료와 기존 참가자 열람 권한을 분리한다는 제품 제안. 같은 이름만으로 기존 참가자를 식별하지 않는다.",
    "source": "P-08 / NF-03 / UX 제안",
    "sprint": "공통",
    "priority": "P0",
    "docsFile": "P-08 / NF-03 / UX 제안",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "공통 · /r/:room/join?error",
        "rule": "초대 내용을 확인해 주세요.",
        "docs": "P-08 / NF-03 / UX 제안"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "신규 초대 만료와 기존 참가자 열람 권한을 분리한다는 제품 제안. 같은 이름만으로 기존 참가자를 식별하지 않는다.",
        "rule": "상태: 코드 오류 / 정원 초과 / 초대 만료",
        "docs": "P-08 / NF-03 / UX 제안"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "S0 또는 외부 초대 원래 페이지. 기존 참가자는 세션 검증 후 S5/S7/S9로 복귀 가능(제안).",
        "rule": "주 행동: 코드 다시 입력",
        "docs": "P-08 / NF-03 / UX 제안"
      }
    ]
  },
  {
    "id": "E2",
    "title": "인원 미달 · 마감",
    "role": "방장",
    "route": "/r/:room/expired",
    "flow": {
      "prev": "S5H",
      "next": "S2"
    },
    "goal": "아직 조율을 시작할 수 없어요.",
    "body": "답변 2명 / 최소 3명 · 예시|24시간 연장 가능|이번 방을 닫을 수도 있어요.",
    "cta": "24시간 연장 검토",
    "states": [
      "연장 가능",
      "2회 사용함",
      "참가자 보기"
    ],
    "back": "S5H 또는 참가자는 S5. 백은 연장도 종료도 실행하지 않는다.",
    "rule": "24시간씩 최대 2회. 참가자에게 관리 버튼 숨김. 연장 성공 후 초대 시각 갱신; 기존 링크 재활성화 정책은 구현 확인 대상.",
    "source": "FR-09 / P-04",
    "sprint": "방장",
    "priority": "P0",
    "docsFile": "FR-09 / P-04",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "방장 · /r/:room/expired",
        "rule": "아직 조율을 시작할 수 없어요.",
        "docs": "FR-09 / P-04"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "24시간씩 최대 2회. 참가자에게 관리 버튼 숨김. 연장 성공 후 초대 시각 갱신; 기존 링크 재활성화 정책은 구현 확인 대상.",
        "rule": "상태: 연장 가능 / 2회 사용함 / 참가자 보기",
        "docs": "FR-09 / P-04"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "S5H 또는 참가자는 S5. 백은 연장도 종료도 실행하지 않는다.",
        "rule": "주 행동: 24시간 연장 검토",
        "docs": "FR-09 / P-04"
      }
    ]
  },
  {
    "id": "E3",
    "title": "후보 없음",
    "role": "공통",
    "route": "/r/:room/no-candidate",
    "flow": {
      "prev": "S5",
      "next": null
    },
    "goal": "모든 조건을 지키는 안이 없어요.",
    "body": "누군가의 조건을 임의로 낮추지 않아요.|공개 가능한 제외 사유만 보여요.|새 모임에서는 조건을 다시 확인해요.",
    "cta": "모임 홈으로",
    "states": [
      "후보 없음",
      "방장 보기",
      "참가자 보기"
    ],
    "back": "S5 상태 홈. 시스템 백으로 과거 추천이 보이더라도 현재 후보 없음 상태로 보정.",
    "rule": "현 범위: 방장은 확인 후 방 닫기/새 방. 참가자는 상태 열람. 상한 완화 동의 라운드는 NEXT이며 작동 버튼으로 제공하지 않는다.",
    "source": "FR-20·23 / AI 설계 §7",
    "sprint": "공통",
    "priority": "P0",
    "docsFile": "FR-20·23 / AI 설계 §7",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "공통 · /r/:room/no-candidate",
        "rule": "모든 조건을 지키는 안이 없어요.",
        "docs": "FR-20·23 / AI 설계 §7"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "현 범위: 방장은 확인 후 방 닫기/새 방. 참가자는 상태 열람. 상한 완화 동의 라운드는 NEXT이며 작동 버튼으로 제공하지 않는다.",
        "rule": "상태: 후보 없음 / 방장 보기 / 참가자 보기",
        "docs": "FR-20·23 / AI 설계 §7"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "S5 상태 홈. 시스템 백으로 과거 추천이 보이더라도 현재 후보 없음 상태로 보정.",
        "rule": "주 행동: 모임 홈으로",
        "docs": "FR-20·23 / AI 설계 §7"
      }
    ]
  },
  {
    "id": "E4",
    "title": "본인 확인 필요",
    "role": "공통",
    "route": "/r/:room/verify",
    "flow": {
      "prev": "S5",
      "next": "S8"
    },
    "goal": "내 정보는 확인 후 보여드려요.",
    "body": "개인 리포트 내용을 숨겼어요.|기존 개인 링크나 유효한 참여 세션으로 돌아오세요.|방장도 다른 사람의 리포트는 볼 수 없어요.",
    "cta": "모임 홈으로",
    "states": [
      "세션 만료",
      "다른 참가자",
      "복구 수단 없음"
    ],
    "back": "공개 가능한 S5로 이동. 재인증 성공 후 권한 허용된 요청 화면으로만 복귀.",
    "rule": "공용 링크/이름만으로 개인 리포트를 복구하지 않는다. 새 기기 복구 방식은 미결; 복구 성공을 보장하는 카피 금지.",
    "source": "FR-19 / NF-03",
    "sprint": "공통",
    "priority": "P0",
    "docsFile": "FR-19 / NF-03",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "공통 · /r/:room/verify",
        "rule": "내 정보는 확인 후 보여드려요.",
        "docs": "FR-19 / NF-03"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "공용 링크/이름만으로 개인 리포트를 복구하지 않는다. 새 기기 복구 방식은 미결; 복구 성공을 보장하는 카피 금지.",
        "rule": "상태: 세션 만료 / 다른 참가자 / 복구 수단 없음",
        "docs": "FR-19 / NF-03"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "공개 가능한 S5로 이동. 재인증 성공 후 권한 허용된 요청 화면으로만 복귀.",
        "rule": "주 행동: 모임 홈으로",
        "docs": "FR-19 / NF-03"
      }
    ]
  },
  {
    "id": "E5",
    "title": "연결 오류 · 재시도",
    "role": "공통",
    "route": "현재 화면의 오류 상태",
    "flow": {
      "prev": "S5",
      "next": null
    },
    "goal": "아직 처리 결과를 확인하지 못했어요.",
    "body": "입력은 현재 화면에 유지돼요.|저장 완료는 확인되지 않았어요.|연결 후 현재 상태부터 확인할게요.",
    "cta": "현재 상태 다시 확인",
    "states": [
      "오프라인",
      "처리 결과 불명",
      "다른 탭 변경"
    ],
    "back": "미저장 변경이 있으면 M1; 읽기 화면이면 이전 화면. 백이나 재시도로 생성·제출·차감을 반복하지 않는다.",
    "rule": "성공 여부 불명 시 조회 우선. 서버 버전 충돌이면 최신 상태 안내; 초안을 덮어쓰지 않고 별도 비교. 기기 종료 후 초안 복구 보장은 미결.",
    "source": "NF-04 / UX 제안",
    "sprint": "공통",
    "priority": "P0",
    "docsFile": "NF-04 / UX 제안",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "공통 · 현재 화면의 오류 상태",
        "rule": "아직 처리 결과를 확인하지 못했어요.",
        "docs": "NF-04 / UX 제안"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "성공 여부 불명 시 조회 우선. 서버 버전 충돌이면 최신 상태 안내; 초안을 덮어쓰지 않고 별도 비교. 기기 종료 후 초안 복구 보장은 미결.",
        "rule": "상태: 오프라인 / 처리 결과 불명 / 다른 탭 변경",
        "docs": "NF-04 / UX 제안"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "미저장 변경이 있으면 M1; 읽기 화면이면 이전 화면. 백이나 재시도로 생성·제출·차감을 반복하지 않는다.",
        "rule": "주 행동: 현재 상태 다시 확인",
        "docs": "NF-04 / UX 제안"
      }
    ]
  },
  {
    "id": "M1",
    "title": "작성 중 이탈 확인",
    "role": "공통",
    "route": "오버레이 · URL 없음",
    "flow": {
      "prev": "S4-1",
      "next": null
    },
    "goal": "작성 중인 내용이 있어요.",
    "body": "이 화면에 남아 계속 작성할 수 있어요.|나가면 저장되지 않은 수정은 사라져요.|이미 제출한 답변은 그대로예요.",
    "cta": "계속 작성하기",
    "states": [
      "미저장 수정",
      "저장 실패"
    ],
    "back": "백/ESC는 이 확인창만 닫고 작성 화면으로 복귀. 나가기 명시 선택 때만 보류한 이동을 실행.",
    "rule": "작성 중인 폼을 떠날 때만 표시. 문항 이전 이동은 제외. 취소에 초기 포커스; 포커스 가두기·복귀. 외부 브라우저 이탈에 커스텀 모달 보장 불가.",
    "source": "NF-01 / MDN beforeunload / UX 제안",
    "sprint": "공통",
    "priority": "P0",
    "docsFile": "NF-01 / MDN beforeunload / UX 제안",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "공통 · 오버레이 · URL 없음",
        "rule": "작성 중인 내용이 있어요.",
        "docs": "NF-01 / MDN beforeunload / UX 제안"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "작성 중인 폼을 떠날 때만 표시. 문항 이전 이동은 제외. 취소에 초기 포커스; 포커스 가두기·복귀. 외부 브라우저 이탈에 커스텀 모달 보장 불가.",
        "rule": "상태: 미저장 수정 / 저장 실패",
        "docs": "NF-01 / MDN beforeunload / UX 제안"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "백/ESC는 이 확인창만 닫고 작성 화면으로 복귀. 나가기 명시 선택 때만 보류한 이동을 실행.",
        "rule": "주 행동: 계속 작성하기",
        "docs": "NF-01 / MDN beforeunload / UX 제안"
      }
    ]
  },
  {
    "id": "M2",
    "title": "공유 · 캘린더",
    "role": "공통",
    "route": "네이티브 시트 / 대체 대화상자",
    "flow": {
      "prev": "S9",
      "next": "S9"
    },
    "goal": "함께 볼 결정만 공유해요.",
    "body": "공개 제목·일정·장소·실행 조건|개인 조건·리포트 링크 제외|링크 복사 / 캘린더 파일 내려받기",
    "cta": "공유 미리보기",
    "states": [
      "공유 준비",
      "시트 취소",
      "복사 실패"
    ],
    "back": "시트 백은 시트만 닫아 S9의 원래 스크롤·포커스로 복귀. 취소를 공유 성공으로 표시하지 않는다.",
    "rule": "공유 대상 선택은 사용자가 실행. Web Share 미지원→명시적 복사; 클립보드 거절→선택 가능한 텍스트. 예약·일정 등록 완료로 표기 금지.",
    "source": "FR-18 / A안",
    "sprint": "공통",
    "priority": "P0",
    "docsFile": "FR-18 / A안",
    "annotations": [
      {
        "n": 1,
        "element": "진입 · 상태 · 권한",
        "comp": "Header",
        "desc": "공통 · 네이티브 시트 / 대체 대화상자",
        "rule": "함께 볼 결정만 공유해요.",
        "docs": "FR-18 / A안"
      },
      {
        "n": 2,
        "element": "본문 · 검증 · 공개 경계",
        "comp": "Content",
        "desc": "공유 대상 선택은 사용자가 실행. Web Share 미지원→명시적 복사; 클립보드 거절→선택 가능한 텍스트. 예약·일정 등록 완료로 표기 금지.",
        "rule": "상태: 공유 준비 / 시트 취소 / 복사 실패",
        "docs": "FR-18 / A안"
      },
      {
        "n": 3,
        "element": "행동 · 백키 · 재진입",
        "comp": "Navigation",
        "desc": "시트 백은 시트만 닫아 S9의 원래 스크롤·포커스로 복귀. 취소를 공유 성공으로 표시하지 않는다.",
        "rule": "주 행동: 공유 미리보기",
        "docs": "FR-18 / A안"
      }
    ]
  }
]