# 9-5 · 최종 보고서 (A4 세로 2쪽)

> **보는 사람**: 모두 (지난 세션 기록에서도)  
> **파일**: [index.html](index.html) (화면) · [screen.js](screen.js) (이 화면 동작)

## 이 화면은

확정된 배치로 만든 최종 보고서. PDF와 같은 A4 세로 2쪽으로 보여주고, 페이지를 누르면 크게 볼 수 있다. 링크 복사·PDF 저장(브라우저 인쇄)도 여기서 한다.

## 누르면 어떻게 되나

| 누르는 것 | 동작 | 이동 |
|---|---|---|
| PDF로 저장 (브라우저 인쇄) | `savePdf` | — |

## 프론트엔드

**이미 구현한 것**

- ✅ A4 페이지를 누르면 크게 보기 팝업(실제 크기 · 위아래 스크롤 · ✕·바깥·Esc로 닫기)
- ✅ PDF로 저장 = 브라우저 인쇄로 A4 2쪽 그대로 저장
- ✅ 링크 복사(참가자만 열 수 있는 주소)
- ✅ 실서버 모드: report.get으로 1쪽(요약·투표·파트)과 2쪽(워크플로우)을 다시 그리기
- ✅ 지난 세션 기록(A4)에서 `?sessionId=`로 들어오면 그 세션 보고서를 보여줌
- ✅ 보고서가 아직 준비 중이면(ready=false) 안내 후 report.ready 이벤트를 기다림

**남은 일**

- ⬜ 보고서 만드는 중 화면 디자인 (지금은 안내 문구만)
- ⬜ 팀장이 보고서에서 담당을 다시 고치는 화면 (API는 team.reassign으로 준비됨)
- ⬜ 로그인 없이 볼 수 있는 공개 링크를 만들지 정책 결정

## 백엔드가 해야 할 일 (쉽게)

- <b>보고서</b>는 배치 확정 때 AI가 만든다(요약 문장 + 팀 워크플로우 4단계). 만드는 동안에는 ready=false, 끝나면 report.ready 이벤트.
- 내용은 모두 <b>이미 저장된 데이터</b>에서 만든다: 투표 결과·AI 검증·익명 댓글 요약·숨은 공통점·확정된 파트 배치.
- <b>익명 규칙</b>: 아이디어 주인과 파트 담당 이름은 보여주지만, 댓글 쓴 사람·누가 어디에 투표했는지·인터뷰 답 원문·추가 질문 답은 절대 넣지 않는다.
- 세션이 끝난 뒤에도 <b>그 세션 참가자였던 회원</b>은 계속 볼 수 있다(지난 세션 기록 A4).
- PDF는 <b>서버에서 만들지 않는다</b>. 프론트가 브라우저 인쇄로 A4 2쪽을 그대로 저장한다.
- 팀장이 담당을 고치면(team.reassign) 보고서의 파트·워크플로우를 다시 만들고 version을 올린다.

## 이 화면이 쓰는 API

| 언제 | API | 요약 |
|---|---|---|
| 화면 열 때 | `GET /sessions/{sessionId}/report` | 최종 보고서 (9-5 · A4 보고서 보기) |

## 실시간 이벤트 (웹소켓으로 받는 것)

| 이벤트 | 받으면 |
|---|---|
| `report.ready` | 보고서 불러와서 A4 2쪽 그리기 |

형식은 [docs/02-API-공통-규칙.md](../../docs/02-API-공통-규칙.md#실시간-이벤트) 참고.

## API 상세

모든 경로 앞에 `/api/v1`가 붙어요. 공통 규칙(인증·에러 형식)은 [docs/02-API-공통-규칙.md](../../docs/02-API-공통-규칙.md).

### `GET /api/v1/sessions/{sessionId}/report` — 최종 보고서 (9-5 · A4 보고서 보기)

- **API id**: `report.get` (프론트: `api.call('report.get', …)`)
- **누가 부를 수 있나**: 세션 참가자 (회원)
- **하는 일**: A4 2쪽 보고서에 들어갈 내용 전부. 1쪽 = 왜 이 주제인지 · 현실성 · 투표 결과 · 파트와 맡은 사람, 2쪽 = 팀 워크플로우 4단계 · 내내 하는 일.

**응답** `200`

```json
{
  "ready": true,
  "reportId": "rep_7K2X9",
  "sessionId": "ses_7K2X9",
  "version": 1,
  "createdAt": "2026-09-18T16:10:00+09:00",
  "meta": {
    "date": "2026-09-18",
    "memberCount": 4,
    "durationMin": 70,
    "sessionTopic": "교내 해커톤 서비스 아이디어"
  },
  "topic": {
    "title": "과제 공지와 마감을 한곳에 모아 알려주는 웹",
    "summary": "메일·학교 사이트·단톡에 흩어진 과제 공지와 마감을 한 화면에 모아 알려줘요.",
    "owner": {
      "nickname": "노형원",
      "rank": 1
    }
  },
  "why": {
    "votes": {
      "total": 8,
      "top": 3,
      "gapToSecond": 1
    },
    "review": {
      "grade": "go",
      "summary": "일정 앱은 많지만 여러 곳의 학교 공지를 모아주는 건 드물어요",
      "searchUrl": "https://search.example.com/?q=..."
    },
    "praise": {
      "count": 2,
      "points": [
        "다들 겪는 문제라 공감이 커요",
        "발표하기 쉬워요"
      ]
    },
    "thread": "팀플에서 \"누가 무엇을 했는지\"가 한곳에 남지 않는 문제와 이어져요 (3위 아이디어도 같은 뿌리)"
  },
  "feasibility": {
    "level": "상",
    "summary": "웹 화면 2명 · 백엔드 1명으로 만들 수 있어요",
    "missingSkills": [
      {
        "name": "메일·LMS 자동 연동",
        "decision": "이번 범위에서 빼고 링크 붙여넣기로 대신"
      }
    ],
    "scope": "핵심 기능은 공지 모으기 · 마감 알림 두 가지로 시작해요"
  },
  "votes": {
    "maxVotesPerPerson": 2,
    "ranks": [
      {
        "rank": 1,
        "title": "과제 공지와 마감을 한곳에 모아 알려주는 웹",
        "owner": "노형원",
        "votes": 3
      },
      {
        "rank": 2,
        "title": "관심 있는 학교 행사·특강 소식만 골라 알려주는 웹",
        "owner": "김승희",
        "votes": 2
      },
      {
        "rank": 3,
        "title": "회의 후 할 일 정리 · 열람실 빈자리 제보판 · 학과 중고 전공책",
        "owner": null,
        "tieCount": 3,
        "votes": 1
      }
    ]
  },
  "parts": {
    "leader": "김승희",
    "core": [
      {
        "name": "화면 만들기",
        "assignee": "노형원"
      },
      {
        "name": "서버 · 공지 모으기",
        "assignee": "박상진"
      },
      {
        "name": "발표 · 시연",
        "assignee": "이세민"
      }
    ],
    "normal": [
      {
        "name": "화면 디자인",
        "assignee": "이세민"
      },
      {
        "name": "발표 자료",
        "assignee": "김승희"
      },
      {
        "name": "기획 · 범위 관리",
        "assignee": "노형원"
      }
    ],
    "small": [
      {
        "name": "경쟁 서비스 조사",
        "assignee": "이세민"
      },
      {
        "name": "시연용 예시 공지 만들기",
        "assignee": "노형원"
      },
      {
        "name": "기능 테스트 · 버그 기록",
        "assignee": "이세민"
      },
      {
        "name": "사용자 인터뷰 3명",
        "assignee": "김승희"
      },
      {
        "name": "제출 문서 · 보고서 정리",
        "assignee": "김승희"
      },
      {
        "name": "회의록 · 일정 챙기기",
        "assignee": "박상진"
      }
    ],
    "excluded": [
      {
        "name": "메일·LMS 자동 연동",
        "alternative": "링크 붙여넣기로 대신"
      }
    ]
  },
  "workflow": {
    "stages": [
      {
        "no": 1,
        "name": "범위와 설계 정하기",
        "current": true,
        "make": "핵심 기능 2개의 화면 흐름 · 공지를 가져올 게시판 3곳",
        "tasks": [
          {
            "nickname": "노형원",
            "text": "기능 범위와 화면 흐름 정리",
            "lead": "이끌기"
          },
          {
            "nickname": "박상진",
            "text": "게시판 3곳에서 글을 가져올 수 있는지 확인",
            "lead": null
          },
          {
            "nickname": "김승희",
            "text": "사용자 인터뷰 3명으로 불편 확인",
            "lead": null
          },
          {
            "nickname": "이세민",
            "text": "경쟁 서비스 조사해서 공유",
            "lead": null
          }
        ],
        "handoffs": [
          "화면 흐름 노형원 → 이세민",
          "가져올 수 있는 게시판 박상진 → 노형원"
        ]
      },
      {
        "no": 2,
        "name": "만들기",
        "current": false,
        "make": "공지 목록 · 마감 알림이 동작하는 웹",
        "tasks": [
          {
            "nickname": "노형원",
            "text": "공지 목록·마감 표시 화면 · 시연용 예시 공지",
            "lead": "이끌기 · 화면"
          },
          {
            "nickname": "박상진",
            "text": "공지 모으기 · 알림 보내기",
            "lead": "이끌기 · 서버"
          },
          {
            "nickname": "이세민",
            "text": "화면 디자인 · 발표 흐름 초안",
            "lead": null
          },
          {
            "nickname": "김승희",
            "text": "발표 자료 틀 · 서비스 이름 정하기",
            "lead": null
          }
        ],
        "handoffs": [
          "화면 디자인 이세민 → 노형원",
          "공지 데이터 형식 박상진 ↔ 노형원"
        ]
      },
      {
        "no": 3,
        "name": "합치고 확인하기",
        "current": false,
        "make": "처음부터 끝까지 시연되는 버전",
        "tasks": [
          {
            "nickname": "노형원",
            "text": "화면과 서버 연결 (박상진과 함께)",
            "lead": null
          },
          {
            "nickname": "박상진",
            "text": "서버 연결 · 시연 환경 준비",
            "lead": null
          },
          {
            "nickname": "이세민",
            "text": "기능 테스트 · 버그 기록",
            "lead": "이끌기"
          },
          {
            "nickname": "김승희",
            "text": "인터뷰 결과를 발표 자료에 반영",
            "lead": null
          }
        ],
        "handoffs": [
          "버그 목록 이세민 → 노형원 · 박상진"
        ]
      },
      {
        "no": 4,
        "name": "발표 준비",
        "current": false,
        "make": "발표 자료 · 시연 · 제출 문서",
        "tasks": [
          {
            "nickname": "이세민",
            "text": "발표 흐름 · 시연 연습",
            "lead": "이끌기 · 발표"
          },
          {
            "nickname": "김승희",
            "text": "발표 자료 완성 · 제출 문서 정리",
            "lead": "이끌기 · 자료"
          },
          {
            "nickname": "노형원",
            "text": "시연 화면 점검 · 리허설 피드백",
            "lead": null
          },
          {
            "nickname": "박상진",
            "text": "시연 환경 최종 점검",
            "lead": null
          }
        ],
        "handoffs": [
          "발표 자료 김승희 → 이세민"
        ]
      }
    ],
    "always": [
      {
        "text": "회의록 · 일정 챙기기",
        "nickname": "박상진"
      },
      {
        "text": "기능 범위 지키기",
        "nickname": "노형원"
      }
    ]
  },
  "anonymous": [
    "댓글 쓴 사람",
    "누가 어디에 투표했는지",
    "인터뷰 답 원문",
    "추가 질문의 답"
  ]
}
```

**에러**

| code | HTTP | 언제 |
|---|---|---|
| `NOT_PARTICIPANT` | 403 | 이 세션 참가자가 아님 |

**백엔드 메모**

- AI 작업 15가 끝나기 전에는 {"ready": false} → 끝나면 report.ready 이벤트.
- 세션이 끝난 뒤에도 그 세션 참가자였던 회원은 계속 볼 수 있다(지난 세션 기록 A4의 "보고서 보기").
- 공유 링크는 만들지 않는다(2026-09-18 결정) — 보고서는 참가자가 9-5 · A4에서 보거나 PDF로 저장해서 나눈다. 응답에 shareUrl 없음.
- "PDF로 저장"은 프론트가 브라우저 인쇄(A4)로 만든다 — 서버 PDF 생성은 필요 없음.
- 익명 규칙: 아이디어 주인·파트 담당 이름은 보여주지만 anonymous 목록의 정보(댓글 작성자·투표자·인터뷰 원문·추가 질문 답)는 절대 넣지 않는다.
- 워크플로우의 할 일·넘겨주기는 AI 초안이다. 검색 결과가 근거인 부분(searchUrl)만 링크를 단다.
