# 끼리(KKIRI) 화면 시나리오

작성일: 2026-09-04  
기준: 모바일 우선, 팀 워크숍 MVP  
표기: `현재`는 배포된 데모, `목표`는 제안하는 실제 MVP

## 1. 설계 원칙

1. **결정 전에 프라이버시 계약을 먼저 보여준다.** “비공개”를 하단 문구가 아니라 입력 전 약속으로 만든다.
2. **한 화면에는 한 판단만 둔다.** 선택, 제출, 동의가 섞이지 않게 한다.
3. **협상 연출보다 계산 근거가 먼저다.** 로딩 애니메이션 뒤에는 실제 충돌 조건과 선택 규칙이 있어야 한다.
4. **합의는 추천 생성으로 끝나지 않는다.** 참가자의 재확인을 받아야 `완료`다.
5. **공개 화면과 개인 화면을 나눈다.** 집단은 결론과 공통 이유를 보고, 개인은 자기 조건의 반영·양보 내역을 본다.

## 2. 정보구조

```text
/                         주제 선택
/rooms/new                방 만들기
/r/:roomId/invite         초대·참여 현황
/r/:roomId/join           닉네임·프라이버시 약속
/r/:roomId/preferences    비공개 조건 입력
/r/:roomId/waiting        제출 대기
/r/:roomId/negotiating    합의 계산 진행
/r/:roomId/result         집단 합의안
/r/:roomId/my-receipt     개인 합의 영수증
/r/:roomId/ratify         최종 재확인
/r/:roomId/done           결정 완료
```

방장만 방 설정을 바꿀 수 있다. 참가자는 자기 입력과 자기 합의 영수증만 볼 수 있다. 집단 결과에는 개인 이름과 원문 답변을 넣지 않는다.

## 3. 전체 화면 목록

| ID | 화면 | 주 사용자 | 화면의 단일 질문 | 성공 신호 |
|---|---|---|---|---|
| S00 | 주제 선택 | 방장 | 무엇을 정할 것인가? | 팀 워크숍 선택 |
| S01 | 방 만들기 | 방장 | 결정의 경계는 무엇인가? | 방 생성 |
| S02 | 초대·참여 현황 | 방장 | 필요한 사람이 모두 들어왔나? | 참가 인원 충족 |
| S03 | 닉네임·프라이버시 | 참가자 | 무엇이 공개되고 숨겨지는가? | 약속 확인 후 시작 |
| S04 | 비공개 조건 입력 | 참가자 | 절대 조건과 양보 조건은 무엇인가? | 제출 완료 |
| S05 | 제출 대기 | 모두 | 누가 답을 마쳤나? | 전원 제출 또는 방장 마감 |
| S06 | 합의 계산 | 모두 | 무엇을 비교하고 있나? | 후보안 생성 |
| S07 | 집단 합의안 | 모두 | 무엇을, 왜 골랐나? | 결과 이해 |
| S08 | 개인 합의 영수증 | 참가자 | 내 조건은 어떻게 반영됐나? | 개인 검토 완료 |
| S09 | 최종 재확인 | 모두 | 이 안으로 진행해도 되는가? | 전원 응답 |
| S10 | 완료·실행 인계 | 방장 | 누가 무엇을 실행할 것인가? | 결정 기록 저장 |

## 4. 상세 시나리오

### S00. 주제 선택 `/`

**목적:** 처음 5초 안에 “속마음은 숨기고 결정은 함께한다”는 가치를 이해시키고, 지원 주제만 선택하게 한다.

**구성**

- 로고 `끼리`
- 헤드라인 `말하기 어려운 조건은 숨기고, 결정은 함께.`
- 사용 가능 카드 `팀 워크숍`
- 보조 카드 `여행`, `회식` — 현재 데모 보기용, MVP 방 생성은 비활성
- 주요 CTA `팀 워크숍 정하기`

**현재와의 차이:** 현재는 여행·워크숍·회식 3개가 모두 활성이다. 목표 MVP에서는 워크숍만 실제 다자간 방을 만들게 한다.

**예외**

- 오프라인: 데모 보기만 허용하고 방 생성 버튼에 `인터넷 연결 후 방을 만들 수 있어요` 표시
- 로딩 실패: 카드 대신 `주제를 불러오지 못했어요 · 다시 시도` 표시

### S01. 방 만들기 `/rooms/new`

**목적:** 합의 엔진이 비교할 수 있는 최소 경계를 방장이 정한다.

**입력**

- 워크숍 이름
- 참가 예정 인원
- 후보 날짜 또는 시간 범위
- 반나절 / 하루 / 1박 2일
- 출발 기준 지역
- 1인 예산 상한

**행동**

- 입력 즉시 임시 저장
- CTA `초대방 만들기`
- 생성 전에 요약 확인: `6명 · 반나절 · 서울 출발 · 1인 예산 상한 입력됨`

**검증**

- 참가 예정 인원은 최소 2명이어야 한다.
- 예산 상한과 일정 범위가 비어 있으면 어떤 후보도 하드 제약을 검사할 수 없으므로 생성하지 않는다.
- 뒤로 가도 입력은 유지한다.

### S02. 초대·참여 현황 `/r/:roomId/invite`

**목적:** 링크 공유와 참가 상태 확인을 같은 화면에서 끝낸다.

**구성**

- 방 요약
- 초대 링크와 `링크 복사`
- 상태 목록: `입장 전`, `작성 중`, `제출 완료`
- 주요 CTA `내 조건 입력하기`
- 방장 보조 행동 `응답 마감`

**프라이버시 카피**

> 방장은 누가 제출했는지만 봅니다. 누구의 답인지, 무엇을 골랐는지는 볼 수 없습니다.

**예외**

- 링크 만료: `이 방은 마감됐어요. 방장에게 새 링크를 요청하세요.`
- 정원 초과: 방에 들어가지 못하게 하고 방장에게 정원 변경 요청 안내
- 부분 상태: 일부 참가자가 작성 중이어도 제출 완료 인원만 숫자로 표시

### S03. 닉네임·프라이버시 약속 `/r/:roomId/join`

**목적:** 답을 받기 전에 공개 범위와 삭제 시점을 이해시키고 명시적 동의를 받는다.

**화면 카피**

- `당신의 원문 답변은 다른 참가자와 방장에게 보이지 않습니다.`
- `공개 결과에는 개인을 특정할 수 없는 공통 조건만 나옵니다.`
- `방이 끝나면 원문 답변을 정해진 기간 뒤 삭제합니다.`

보관 기간은 서버 정책이 정해진 뒤 숫자를 넣는다. 지금 임의의 기간을 약속하지 않는다.

**입력:** 닉네임 1개. 실명은 요구하지 않는다.  
**CTA:** `약속을 확인하고 시작하기`

### S04. 비공개 조건 입력 `/r/:roomId/preferences`

한 화면에 한 질문만 보여준다. 진행률은 `2 / 7`처럼 현재 위치를 표시한다. 질문 수 7개는 **※ 가정 기반 — 확인 필요**이며 파일럿에서 이탈률을 보고 줄인다.

**질문 구조**

1. 참여할 수 없는 날짜·시간
2. 이동 가능 범위
3. 1인 예산 상한
4. 피해야 하는 활동 또는 환경
5. 가장 중요한 목적
6. 선호 활동 유형
7. 내가 양보할 수 있는 것

**응답 수준**

- `절대 안 됨` — 하드 제약
- `중요` — 높은 가중치
- `있으면 좋음` — 낮은 가중치
- `상관없음` — 점수에 영향 없음

**마이크로카피**

- `이유는 적지 않아도 됩니다.`
- `자유 입력은 끼리가 조건으로 바꾸며, 제출 전 당신이 다시 확인합니다.`

**에러 예방**

- 자유 입력에서 이름, 연락처, 진단명 같은 민감정보로 보이는 표현을 감지하면 `조건만 남기고 사유는 지워도 합의할 수 있어요`라고 제안한다.
- 제출 전 구조화 결과를 `서울 안에서`, `반나절`, `격한 야외 활동 제외`처럼 보여주고 사용자가 수정한다.

### S05. 제출 대기 `/r/:roomId/waiting`

**목적:** 답변 내용 없이 진행 상태만 공유한다.

**구성**

- `4명 중 3명이 답했어요`
- 참가자별 상태 아이콘
- 내 답 `수정하기`
- 방장에게만 `현재 응답으로 마감` 표시

**마감 규칙**

- 예정 인원보다 적게 마감하면 누락된 사람을 명시한다.
- 방장은 누락 참가자를 대신해 답하지 못한다.
- 마감 뒤 새 참가자는 들어오지 못한다.

### S06. 합의 계산 `/r/:roomId/negotiating`

**목적:** 3초가 넘는 계산은 무엇을 하고 있는지 단계로 설명한다.

**단계**

1. `개인 조건을 익명 구조로 바꾸는 중`
2. `하드 제약을 어기는 후보를 제외하는 중`
3. `가장 불리한 사람의 만족도를 비교하는 중`
4. `공개 가능한 이유를 만드는 중`

현재 데모의 고정 2.2초 애니메이션은 단계 연출일 뿐이다. 목표 MVP에서는 실제 작업 상태와 연결한다.

**실패**

- 조건을 만족하는 후보 0개: 결과를 꾸미지 않고 `모든 조건을 동시에 지키는 안이 없습니다`로 이동
- 설명 생성 실패: 계산 결과는 보존하고 규칙 기반 문장으로 대체
- 네트워크 실패: 재시도해도 중복 계산되지 않도록 동일 작업 ID 사용

### S07. 집단 합의안 `/r/:roomId/result`

**목적:** 결론, 근거, 제외된 대안의 차이를 공개하되 개인은 특정하지 않는다.

**구성 순서**

1. 결과 배지 `합의 제안 · 아직 확정 전`
2. 안의 제목, 시간, 장소, 예산 범위
3. `지킨 조건` — 하드 제약 집단 요약
4. `왜 이 안인가` — 최저 만족도와 평균 만족도를 이용한 비교 설명
5. `가장 가까운 대안` — 무엇이 달랐는지 한 줄
6. CTA `내 조건 반영 확인하기`

**금지 카피:** `AI가 최적의 답을 찾았습니다.`  
**권장 카피:** `하드 제약을 모두 지킨 후보 중, 가장 불리한 사람의 만족도가 가장 높은 안입니다.`

### S08. 개인 합의 영수증 `/r/:roomId/my-receipt`

**목적:** 다른 사람의 답을 보지 않고도 “내 말이 반영됐다”는 근거를 준다.

**구성**

- `지킨 조건`: 서울, 반나절, 예산 상한
- `반영한 선호`: 팀워크 중심
- `양보한 선호`: 야외 활동
- `끼리가 공개한 내용`: 개인 식별 없는 집단 문장
- CTA `최종 의견 보내기`

이 화면은 참가자별 인증 토큰으로 보호한다. URL만 아는 다른 참가자가 접근할 수 없어야 한다.

### S09. 최종 재확인 `/r/:roomId/ratify`

**선택지**

- `동의해요`
- `조건부로 동의해요` — 공개 가능한 조건 한 줄 선택
- `다시 조정해야 해요` — 새 하드 제약 또는 누락 조건을 비공개 입력

선택은 제출 전 바꿀 수 있다. 제출 뒤에는 집단 화면에 이름이 아닌 상태 합계만 보인다. 전원이 `동의` 또는 `조건부 동의`이면 완료된다.

### S10. 완료·실행 인계 `/r/:roomId/done`

**목적:** 합의를 실제 실행으로 넘긴다.

**구성**

- 최종안 요약
- 재확인 상태 `6명 전원 확인`
- 결정 기록 링크
- 방장용 실행 체크: 장소 문의, 일정 공유, 비용 확인
- 원문 답변 삭제 예정 안내

외부 예약·결제 버튼은 MVP에 넣지 않는다. 합의와 거래를 섞으면 사용자 동의와 책임 범위가 흐려진다.

## 5. 인터랙션 상태 매트릭스

| 상태 | 공통 처리 | 대표 화면 |
|---|---|---|
| Default | 현재 해야 할 한 가지 행동만 강조 | 전 화면 |
| Loading | 스켈레톤 또는 실제 계산 단계 표시 | S02, S06, S07 |
| Empty | 원인과 다음 CTA를 함께 표시 | S02 참가자 0명, S07 후보 0개 |
| Error | 실패 지점과 재시도 범위를 구체적으로 표시 | S01 방 생성, S04 제출, S06 계산 |
| Success | 토스트와 상태 변경을 함께 표시 | 링크 복사, 답 제출, 재확인 |
| Partial | 완료된 데이터는 유지하고 빠진 것만 알림 | S02, S05 |
| Forbidden | 방장/참가자 권한 차이를 설명 | S08 다른 사람 접근, 방 설정 |
| Offline | 임시 저장 여부와 연결 뒤 행동을 명시 | S04 응답 작성 |

## 6. 권한과 공개 범위

| 데이터 | 본인 | 다른 참가자 | 방장 | 합의 엔진 |
|---|---:|---:|---:|---:|
| 원문 답변 | 보기·수정 | 불가 | 불가 | 처리 가능 |
| 구조화한 개인 조건 | 보기·확인 | 불가 | 불가 | 처리 가능 |
| 제출 상태 | 보기 | 보기 | 보기 | 보기 |
| 집단 합의 이유 | 보기 | 보기 | 보기 | 생성 |
| 개인 합의 영수증 | 보기 | 불가 | 불가 | 생성 |
| 최종 재확인 합계 | 보기 | 보기 | 보기 | 집계 |

## 7. 분석 이벤트

개인 답변 원문은 분석 이벤트에 넣지 않는다.

| 이벤트 | 시점 | 최소 속성 |
|---|---|---|
| `room_created` | 방 생성 | room_id, participant_target |
| `participant_joined` | 입장 | room_id, anonymous_participant_id |
| `preference_submitted` | 조건 제출 | room_id, question_version |
| `consensus_ready` | 계산 완료 | room_id, candidate_count, hard_constraint_conflicts |
| `receipt_viewed` | 개인 영수증 확인 | room_id |
| `ratification_submitted` | 최종 의견 제출 | room_id, decision_type |
| `decision_completed` | 전원 확인 | room_id, revision_count |
| `renegotiation_requested` | 재조정 | room_id, reason_category |

## 8. 인수 조건

- Given 참가자 4명이 서로 다른 기기에서 같은 방에 들어왔을 때, When 각자 조건을 제출하면, Then 다른 참가자와 방장은 원문과 구조화 조건을 볼 수 없다.
- Given 한 후보가 참가자 한 명의 하드 제약을 위반할 때, When 합의 계산을 실행하면, Then 그 후보는 추천 결과에 포함되지 않는다.
- Given 가능한 후보가 여러 개일 때, When 순위를 계산하면, Then 최저 개인 만족도가 높은 후보가 평균 만족도만 높은 후보보다 앞선다.
- Given 공개 결과를 볼 때, Then 특정 참가자의 이름과 민감한 사유가 노출되지 않는다.
- Given 결과가 생성됐지만 재확인이 끝나지 않았을 때, Then 상태는 `합의 제안`이며 `결정 완료`가 아니다.
- Given 한 명이 재조정을 요청했을 때, Then 누가 요청했는지 공개하지 않고 새 조건으로 다시 계산한다.
- Given 네트워크가 끊겼을 때, When 참가자가 답을 작성하면, Then 기기에 임시 저장하고 연결 뒤 제출 여부를 다시 묻는다.

## 9. 현재 데모를 발표에 쓸 때의 화면 수정 우선순위

1. 결과 배지를 `합의 완료`가 아니라 `합의 제안 · 규칙 기반 데모`로 바꾼다.
2. 협상 화면에 4단계 계산 문구를 넣는다.
3. 결과 뒤에 `내 조건 반영 확인`과 `최종 동의` 화면을 추가한다.
4. 초대 화면에서 실제 동기화가 없다는 문구를 유지한다.
5. 발표자는 “현재는 흐름 검증용 시뮬레이션”이라고 먼저 밝힌다.

## 10. 근거

- [배포된 데모](https://kkiri-consensus-demo.pages.dev/)
- [현재 화면 상태와 저장 로직](../REPOS/consensus-demo/app.js)
- [현재 질문·결과 데이터](../REPOS/consensus-demo/consensus.js)
- [현재 도메인 테스트](../REPOS/consensus-demo/tests/consensus.test.js)

