콘텐츠로 이동

Worked example: report & block flow design

Generated by the flow-design route (skills/ux-audit, skills/design-critique). Demonstrates the canonical feature-flow spec format — entry points, step sequence, state transitions, edge/error paths, completion criteria, and the Korean trust & safety regulatory floor. Adapted from the dogfood brief in docs/DOGFOOD-SDK-FINDINGS.md (F-1).

Brief: 커뮤니티 앱의 게시물 신고 및 사용자 차단 플로우 설계 — 신고 사유 선택, 처리 상태 안내, 차단 후 상호작용 차단 범위.

Cite knowledge/patterns/ui-reasoning.md (task-shape reasoning for interaction flows), knowledge/patterns/async-control.md (in-flight submit states), and knowledge/patterns/trust-safety-moderation.md (report/block domain rules) as the grounding for this spec.


# 게시물 신고 및 사용자 차단 플로우

> 플랫폼: 모바일 웹 (iOS Safari + Android Chrome) + 데스크톱
> 대상: 커뮤니티 앱 — 게시물, 댓글, 프로필 대상 신고/차단
> 근거: knowledge/patterns/ui-reasoning.md, knowledge/patterns/async-control.md, knowledge/patterns/trust-safety-moderation.md, knowledge/PRINCIPLES.md

## 진입점 (Entry points)

- **신고**: 게시물/댓글/프로필의 오버플로 메뉴(⋯) → "신고" 항목. 목적성 있는 트리거이며 삭제 계열 액션이 아니므로 destructive red로 스타일링하지 않는다.
- **차단**: 사용자 프로필 화면의 "차단" 메뉴, 또는 신고 완료 확인 화면에서 옵션으로 제공(신고와 차단은 독립 액션 — 자동 번들 금지).
- 두 진입점 모두 키보드로 Tab 이동 후 Enter/Space로 활성화 가능해야 한다.

## 신고 플로우 — 단계 (Steps)

| 단계 | 상태 | 설명 |
| --- | --- | --- |
| 1. 사유 선택 | `idle``selecting` | 바텀시트(모바일)/모달(데스크톱)에서 라디오 그룹으로 사유 6종 중 1개 선택 |
| 2. 상세 입력 (선택 시) | `selecting``detailing` | "기타" 선택 시에만 텍스트 영역 노출 (최대 500자) |
| 3. 제출 | `detailing`/`selecting``submitting` | 제출 버튼은 사유 미선택 상태에서 비활성화 |
| 4. 접수 확인 | `submitting``received` | 토스트/확인 뷰 "신고가 접수되었어요" 즉시 표시 |
| 5. 처리 상태 추적 | `received``in_review``actioned` \| `declined` | "신고 내역"에서 상태 뱃지로 추적, 전환마다 알림 발송 |

전체 신고 사유 목록 (마이너 태그, 모더레이션 백오피스는 더 세분화):

1. 스팸/광고
2. 욕설·혐오
3. 성적 콘텐츠
4. 사기·사칭
5. 개인정보 노출
6. 기타 (자유 텍스트)

## 처리 상태 커뮤니케이션
접수됨 ──▶ 검토 중 ──▶ 조치 완료 └──▶ 기각 └──▶ 임시조치됨 (권리침해 주장 시, 최대 30일)
- 상태는 색상 + 텍스트 뱃지로 표시한다 (색상 단독 금지).
- 조치 완료 시 조치 여부만 안내하고 구체적 제재 내용은 밝히지 않는다 (보복 방지) — "커뮤니티 가이드라인 위반으로 조치했어요".
- 기각 시 재신고 경로를 제공한다(추가 근거 첨부 가능).

### 한국 정보통신망법 준수 — 임시조치 (제44조의2)

- 게시물이 타인의 권리(명예훼손, 사생활 침해)를 침해한다는 주장이 접수되면, 운영자는 **최대 30일간 임시조치**(콘텐츠 비공개)를 취할 수 있다.
- 임시조치 상태는 접수/검토/조치 완료와 구분되는 별도 상태로 UI에 노출한다 ("임시조치됨").
- 작성자에게는 조치 사유(법적 근거)와 이의제기 경로(30일 이내 처리 예정 명시)를 함께 안내한다. 신고자 신원은 공개하지 않는다.
- 청소년유해매체물 카테고리는 별도 라벨/연령 게이트 처리 대상이며 "삭제됨"으로 뭉뚱그리지 않는다.

## 차단 플로우 — 단계 (Steps)

| 단계 | 상태 | 설명 |
| --- | --- | --- |
| 1. 차단 트리거 | `idle` → `confirming` | 프로필/게시물 메뉴에서 "차단" 선택 → 확인 다이얼로그 |
| 2. 확인 | `confirming` → `blocking` | 다이얼로그에 범위를 한 줄로 명시: "서로의 게시물이 보이지 않고 DM을 보낼 수 없어요" |
| 3. 완료 | `blocking` → `blocked` | 완료 즉시 상호작용 범위 적용, 성공 토스트 없이 조용히 반영(과시적 확인 지양) |

### 차단 범위 (블라스트 반경)

| 상호작용 | A가 B를 차단한 후 |
| --- | --- |
| B가 A의 프로필/게시물 조회 | 숨김 또는 최소 정보만("게시물이 없어요") — "차단되었습니다" 노출 금지 |
| B가 A에게 댓글/DM 시도 | 작성창에서 조용히 차단, 일반적인 실패 문구 |
| A가 B의 콘텐츠 조회 | 피드/검색/알림에서 모두 숨김 |
| 기존 팔로우 관계 | 양방향 자동 해제 |
| 공유 스레드/그룹 콘텐츠 | A에게 "차단한 사용자의 댓글이에요" + 펼치기로 접힘 표시 |

- **비통지 원칙**: 차단 사실은 상대방에게 절대 알리지 않는다. 상대가 추론하는 것은 허용하되 확인해주지 않는다.
- 차단 해제는 설정 > 차단 목록에서 1회 확인 후 진행하며, 해제해도 끊긴 팔로우는 복구되지 않음을 안내한다.

## 엣지 케이스와 오류 경로 (Edge cases & error paths)

- **제출 실패(네트워크 에러)**: 제출 버튼이 `submitting` 상태에서 실패로 전환되면 "신고 접수에 실패했어요. 다시 시도해주세요" 인라인 에러 + 재시도 버튼. 입력한 사유/텍스트는 보존한다.
- **취소/이탈**: 사유 선택 시트에서 바깥 영역 클릭 또는 Escape로 취소 가능. 취소 시 어떤 서버 호출도 발생하지 않는다.
- **신고 남용(레이트 리밋)**: 사용자당 시간당 신고 횟수를 제한하되, 한도 초과 시 "신고 한도 초과" 같은 명시적 에러 대신 조용히 큐잉("접수되었어요"로 동일 표시)한다 — 악용자에게 임계값을 노출하지 않기 위함.
- **브리게이딩 방지**: 신고 수가 자동으로 콘텐츠를 조치하지 않으며, 신고 카운트를 UI에 노출하지 않는다("n명이 신고했어요" 금지).
- **차단 확인 중 이탈**: 다이얼로그를 닫으면(Escape/바깥 클릭) `confirming` → `idle`로 되돌아가고 아무 상태도 변경되지 않는다.
- **중복 차단 시도**: 이미 차단된 사용자에 대해 차단 메뉴는 "차단 해제"로 전환되어 표시된다(중복 액션 방지).

## 완료 기준과 이탈 지점 (Completion & exit criteria)

- **신고 완료 기준**: 사유 선택 + (조건부) 상세 텍스트 + 제출 성공 응답 수신 시 완료로 간주하며, 리포터 측 화면에서 신고 콘텐츠는 즉시 블러/축소 처리한다(모더레이션 판정이 아닌 클라이언트 배려로 명시).
- **차단 완료 기준**: 확인 다이얼로그에서 명시적 확인 클릭 + 서버 응답 수신 시 완료. 실패 시 `confirming` 상태로 롤백하고 에러를 표시한다.
- **이탈(dropoff) 지점**: 사유 선택 화면에서의 이탈이 가장 흔하다 — 사유 미선택 상태에서 시트를 닫아도 데이터 손실 경고는 표시하지 않는다(신고는 낮은 리스크 작업).

## 반응형 동작

- Mobile (360–430px): 전체 폭 바텀시트, 사유 리스트는 세로 스택.
- Tablet (768px): 모바일과 동일한 시트 레이아웃 유지(모달로 전환하지 않음).
- Desktop (1024px+): 중앙 정렬 모달, 최대 너비 480px, 배경 스크림 적용.

## 접근성

- 사유 리스트: `role="radiogroup"`, 각 항목 `aria-checked`, 시트 오픈 시 첫 라디오에 초기 포커스, 화살표 키로 이동.
- 다이얼로그/시트: 포커스 트랩, `aria-modal="true"`, `Escape`로 닫힘, 닫힐 때 트리거(⋯ 메뉴)로 포커스 복귀.
- 상태 전환(접수 확인, 처리 상태 변경)은 `aria-live="polite"`로 스크린 리더에 안내.
- 터치 타깃은 사유 행/차단 확인 버튼 모두 44×44px 이상, 8px 그리드 간격 준수.
- 상태 뱃지 및 블러 오버레이 텍스트는 최소 **4.5:1 contrast ratio** (WCAG AA) 확보 — 경고/오류 텍스트도 동일 기준 적용.

## 하지 말아야 할 것 (Don't)

- Don't: 차단 시 상대방에게 알림을 보내지 마세요 — 비통지 원칙 위반이며 보복 위험을 키운다.
- Don't: 신고 사유를 하나의 자유 텍스트 필드로만 받지 마세요 — 분류/집계가 불가능해진다.
- Don't: 신고 수를 콘텐츠에 노출하지 마세요 — 브리게이딩을 유발한다.
- Don't: 임시조치를 작성자에게 설명 없이 적용하지 마세요 — 법적 근거와 이의제기 경로는 필수 요소다.
- Avoid: 조치 완료 사유를 구체적으로("게시물 삭제 처리") 드러내는 문구 — 재신고 대상에게 회피 학습을 제공한다.


Why this is a good flow-design example

  • Entry points are explicit — where the flow starts, for both report and block, including keyboard trigger.
  • Steps and states are tabular — every step names its before/after state, matching route --check flow-design's "states/steps" requirement.
  • Edge cases and error paths get their own section — network failure, abuse rate-limiting, cancellation, duplicate actions.
  • Completion and exit criteria are explicit — what counts as "done" for each flow, and where users drop off.
  • The Korean regulatory floor is load-bearing, not a footnote — 정보통신망법 제44조의2 임시조치 gets its own subsection with the 30-day window, notice-and-objection duty, and youth-protection carve-out.
  • Accessibility is concreterole="radiogroup", focus trap, aria-live, explicit 4.5:1 contrast ratio, 44×44px touch targets.
  • A Don't section closes the spec — five concrete anti-patterns, each tied back to a rule stated earlier (non-notification, abuse prevention, legal disclosure).

Cross-reference