블로그로 돌아가기
Product

차단·신고·가이드라인 — 데이팅 앱 신뢰 시스템의 기술 설계

회원 차단이 매칭과 채팅에 미치는 파급 효과, 6가지 신고 사유와 4단계 제재 시스템, 그리고 커뮤니티 가이드라인이 안전한 만남을 만드는 기술적 설계를 공유합니다.

Team Somebling ·
#신뢰 시스템 #차단 #신고 #커뮤니티 가이드라인 #안전

“안전하지 않으면 아무도 안 써요”

데이팅 앱을 설계할 때 가장 먼저 마주하는 현실이 있습니다. 아무리 정교한 매칭 알고리즘을 만들어도, 단 한 번의 불쾌한 경험이 사용자를 영원히 잃게 만들 수 있다는 것입니다.

사용자 이탈의 가장 큰 이유를 분석해보면 매칭 품질 문제보다 안전과 관련된 경험이 훨씬 더 큰 비중을 차지합니다. 부적절한 메시지, 가짜 프로필, 상대방의 집요한 연락, 개인정보 요구 등은 단순히 불편함을 넘어 이용자로 하여금 서비스 자체에 대한 신뢰를 잃게 만듭니다.

기존 데이팅 앱들이 자주 받는 비판 중 하나가 바로 이것입니다. “신고는 할 수 있는데, 아무 일도 안 일어난다.” 신고 버튼이 존재하지만 실제로 제재가 이뤄지는지 알 수 없고, 차단을 해도 다른 경로로 연락이 오거나 다시 매칭될 수 있습니다. 이런 경험이 반복될수록 사용자의 신뢰는 빠르게 무너집니다.

썸블링은 이 문제를 처음부터 진지하게 다루기로 했습니다. 신뢰 시스템은 부가 기능이 아니라 제품의 핵심 인프라입니다. 이번 글에서는 썸블링이 설계한 차단, 신고, 커뮤니티 가이드라인의 기술적 구조를 상세히 공유합니다.


3중 방어선: 예방 → 대응 → 제재

썸블링의 신뢰 시스템은 단순히 문제가 발생했을 때 처리하는 것을 넘어, 문제가 발생하기 전부터 시작하는 3중 방어선 구조를 채택하고 있습니다.

flowchart TD
    subgraph 예방["1단계: 예방"]
        A[커뮤니티 가이드라인 안내]
        B[채팅 시작 전 가이드라인 모달]
        C[개인정보 공유 경고]
    end
    subgraph 대응["2단계: 대응"]
        D[회원 차단 기능]
        E[회원 신고 기능]
        F[매칭 해제]
    end
    subgraph 제재["3단계: 제재"]
        G[관리자 신고 검토]
        H[경고 / 일시정지 / 영구정지]
        I[노쇼 카드 몰수]
    end
    A --> D
    B --> D
    C --> E
    D --> G
    E --> G
    G --> H

1단계 예방은 사용자가 처음 채팅을 시작하는 순간부터 작동합니다. 썸블링은 매칭 후 첫 채팅방에 입장할 때 커뮤니티 가이드라인 모달을 자동으로 표시합니다. 이 모달은 단순한 약관 안내가 아니라 구체적인 금지 행동과 권장 행동을 명시하여, 사용자 스스로 어떤 행동이 허용되지 않는지를 명확히 인식하게 합니다.

2단계 대응은 불쾌한 경험이 발생했을 때 사용자가 즉각적으로 취할 수 있는 자기 보호 도구를 제공합니다. 차단과 신고는 별개의 기능이며, 각각 다른 목적과 효과를 가집니다.

3단계 제재는 신고된 내용을 관리자가 검토하고 실제 제재를 집행하는 단계입니다. 경고부터 영구 정지까지 4단계로 세분화하여, 행동의 심각성에 비례한 제재가 이뤄지도록 설계했습니다.


차단 시스템: 즉각적인 자기 보호

차단은 사용자가 스스로를 보호할 수 있는 가장 즉각적인 도구입니다. 버튼 하나로 불쾌한 상대와의 모든 접점을 차단합니다. 그런데 기술적으로 “차단”이란 정확히 무엇을 의미할까요?

차단의 파급 효과

썸블링에서 차단을 실행하면 단순히 메시지만 막히는 것이 아닙니다. 차단은 시스템 전체에 걸쳐 즉각적인 파급 효과를 만들어냅니다.

flowchart LR
    A[차단 요청 POST /members/block] --> B[member_blocks 레코드 생성<br/>UNIQUE blocker_id + blocked_id]
    B --> C[채팅방 BLOCKED 처리<br/>ChatRoomStatus.BLOCKED]
    B --> D[매칭 후보 제외<br/>일일 배치 QueryDSL 필터]
    B --> E[프로필 조회 차단<br/>403 ACCESS_DENIED]
    C --> F[메시지 전송 불가<br/>CHAT_ROOM_NOT_ACTIVE 에러]
    D --> G[일일 매칭 배치에서 영구 제외]

채팅방 상태 전환: 차단이 발생하는 순간, 두 사람이 공유하던 채팅방은 ACTIVE에서 BLOCKED 상태로 전환됩니다. 이후 차단된 사용자가 메시지를 전송하려 하면 CHAT_ROOM_NOT_ACTIVE 에러가 반환됩니다. 사용자는 자신이 차단됐다는 사실을 메시지 전송 실패로 간접적으로 알게 됩니다.

매칭 후보 제외: 일일 매칭 배치가 실행될 때, QueryDSL로 작성된 매칭 후보 쿼리는 차단 관계를 가진 회원 쌍을 필터링합니다. 차단자(blocker)와 피차단자(blocked) 모두 서로의 매칭 후보에서 제외됩니다.

// 차단 관계 제외 서브쿼리 (QueryDSL)
BooleanExpression notBlocked = JPAExpressions
    .selectFrom(memberBlock)
    .where(
        memberBlock.blockerId.eq(memberId)
            .and(memberBlock.blockedId.eq(candidate.id))
        .or(
        memberBlock.blockerId.eq(candidate.id)
            .and(memberBlock.blockedId.eq(memberId))
        )
    )
    .notExists();

중복 차단 방지: member_blocks 테이블에는 UNIQUE(blocker_id, blocked_id) 제약이 걸려 있습니다. 같은 대상을 중복으로 차단하려 하면 ALREADY_BLOCKED 에러가 반환됩니다.

차단 해제 후 채팅방 복구 여부

차단을 해제하면 어떻게 될까요? 썸블링은 의도적으로 채팅방을 복구하지 않습니다. 차단 해제 이후 다시 소통하려면 새로운 매칭을 통해서만 가능합니다. 이는 안전 우선 원칙에 따른 설계 결정입니다. 차단은 두 사람의 관계를 완전히 초기화하는 행위이며, 이전 대화 내역이 노출되지 않아야 사용자가 안심하고 차단을 활용할 수 있습니다.

차단 목록 관리

프로필 설정에서 차단 목록을 확인하고 해제할 수 있습니다. /profile/blocked 페이지는 차단한 회원의 닉네임, 프로필 이미지(블러 처리), 차단 날짜를 표시합니다. 차단 해제는 낙관적 업데이트(optimistic update)로 즉시 UI에 반영되며, 서버 오류 시 롤백합니다.


신고 시스템: 6가지 사유와 처리 흐름

차단이 자기 보호라면, 신고는 커뮤니티 보호입니다. 나는 이미 차단했지만, 같은 행동이 다른 이용자에게도 반복될 수 있기 때문입니다. 신고는 플랫폼이 문제 있는 행동을 인지하고 제재할 수 있는 유일한 창구입니다.

6가지 신고 사유

신고 사유코드설명예시
부적절한 메시지INAPPROPRIATE_MESSAGE성적이거나 폭력적인 메시지원치 않는 성적 표현, 위협적 언어
괴롭힘HARASSMENT반복적이고 집요한 연락차단 후 새 계정 생성, 지속적 압박
가짜 프로필FAKE_PROFILE본인이 아닌 사진 또는 허위 정보타인 사진 도용, 나이·성별 허위 기재
불쾌한 콘텐츠OFFENSIVE_CONTENT혐오·차별적 발언외모 비하, 특정 집단 혐오 표현
스팸SPAM광고, 홍보, 피싱외부 링크 유도, 금전 요구, 상업적 홍보
기타OTHER위 항목에 해당하지 않는 문제자세한 설명 필수

신고 사유를 6가지로 세분화한 이유가 있습니다. 관리자가 신고를 처리할 때 사유별로 다른 제재 기준을 적용할 수 있고, 사유별 신고 통계를 분석하면 어떤 유형의 문제가 가장 많이 발생하는지 파악하여 예방 정책을 강화할 수 있습니다.

신고 처리 흐름

flowchart TD
    A[회원이 신고 제출<br/>POST /members/report] --> B[member_reports 레코드 생성<br/>status: PENDING]
    B --> C[관리자 대시보드<br/>신고 대기 카운트 +1]
    C --> D{관리자 검토<br/>신고 내용 확인}
    D -->|증거 충분| E[REVIEWED 처리<br/>제재 단계 결정]
    D -->|근거 불충분| F[DISMISSED 처리<br/>신고자에게 기각 통보]
    E --> G{제재 수준 결정}
    G -->|1회 경미한 위반| H[경고 알림 발송<br/>MemberNotification]
    G -->|반복 또는 중간 위반| I[일시 정지<br/>MemberStatus.DORMANT]
    G -->|심각한 위반| J[영구 정지<br/>MemberStatus.WITHDRAWN]
    J --> K[모든 매칭·채팅 비활성화]
    I --> L[일정 기간 후 ACTIVE 복구 가능]

신고가 접수되는 순간 member_reports 테이블에 PENDING 상태로 레코드가 생성됩니다. 관리자 대시보드에는 대기 중인 신고 건수가 강조 표시되어, 처리되지 않은 신고가 쌓이는 것을 방지합니다.

중복 신고 방지

같은 신고자가 같은 대상을 반복해서 신고하는 것은 허용하지 않습니다. 악의적인 신고 도구 남용을 막기 위한 설계입니다.

// 중복 신고 검증
boolean alreadyReported = memberReportRepository
    .existsByReporterIdAndReportedMemberId(reporterId, reportedMemberId);

if (alreadyReported) {
    throw new AroException(ErrorCode.DUPLICATE_REPORT);
}

다만 이전 신고가 REVIEWED 또는 DISMISSED 처리된 이후 새로운 문제가 발생했다면 재신고가 가능하도록 설계할 예정입니다. 현재는 단순 중복 방지 로직을 우선 적용했습니다.


4단계 제재 시스템

신고 검토 후 제재 수준을 결정할 때, 행동의 심각성과 반복 여부를 함께 고려합니다. 썸블링의 제재 시스템은 4단계로 구성됩니다.

단계이름MemberStatus제한 내용기간
1단계경고ACTIVE상태 변경 없음, 알림 발송-
2단계기능 제한ACTIVE신규 매칭 생성 중단7일
3단계일시 정지DORMANT모든 서비스 이용 불가30일
4단계영구 정지WITHDRAWN계정 비활성화, 재가입 불가영구
stateDiagram-v2
    [*] --> ACTIVE: 회원가입
    ACTIVE --> ACTIVE: 1단계 경고<br/>(알림 발송)
    ACTIVE --> ACTIVE: 2단계 기능 제한<br/>(신규 매칭 중단 7일)
    ACTIVE --> DORMANT: 3단계 일시 정지<br/>(30일)
    DORMANT --> ACTIVE: 정지 기간 만료
    ACTIVE --> WITHDRAWN: 4단계 영구 정지
    WITHDRAWN --> [*]: 계정 비활성화<br/>재가입 불가

    note right of ACTIVE
        매칭 배치 대상
        모든 서비스 이용 가능
    end note
    note right of DORMANT
        로그인 차단
        매칭 배치 제외
    end note
    note right of WITHDRAWN
        모든 매칭·채팅 비활성화
        API 접근 차단
    end note

MemberStatus는 썸블링 시스템 전반에서 활용되는 핵심 enum입니다. 매칭 배치는 ACTIVE 상태 회원만 후보로 선별하고, API 인증 과정에서 WITHDRAWN 상태의 회원은 로그인 자체가 차단됩니다.

// 로그인 시 회원 상태 검증
if (member.getStatus() == MemberStatus.WITHDRAWN) {
    throw new AroException(ErrorCode.MEMBER_WITHDRAWN);
}
if (member.getStatus() == MemberStatus.DORMANT) {
    throw new AroException(ErrorCode.MEMBER_DORMANT);
}

만남 노쇼(No-Show) 제재

만남 신청·수락 시스템에는 별도의 제재 메커니즘이 있습니다. 썸블링의 만남 기능은 쌍방이 예약금(카드 5장)을 걸고 만남을 확정합니다. 만남 당일 한쪽이 나타나지 않아 NO_SHOW 상태가 되면, 노쇼를 한 쪽의 예약금 카드가 자동으로 몰수됩니다. 단순한 금전적 불이익을 넘어, 반복 노쇼 기록은 신뢰 점수에 반영되어 향후 매칭 우선순위에도 영향을 줄 예정입니다.


커뮤니티 가이드라인: 예방이 최선

처벌보다 예방이 더 효과적입니다. 썸블링은 이 원칙을 UI 설계에 직접 반영했습니다.

ChatGuidelineModal: 첫 채팅의 게이트키퍼

매칭 후 채팅방에 처음 입장하는 순간, ChatGuidelineModal이 자동으로 표시됩니다. 이 모달은 매번 표시되지 않습니다. localStorage에 해당 채팅방 ID를 기록하여 첫 입장에만 노출됩니다.

// ChatGuidelineModal: 첫 채팅방 입장 시 자동 표시
const hasSeenGuideline = localStorage.getItem(`guideline_${roomId}`);

useEffect(() => {
  if (!hasSeenGuideline) {
    setShowGuideline(true);
  }
}, [roomId]);

const handleAcknowledge = () => {
  localStorage.setItem(`guideline_${roomId}`, 'true');
  setShowGuideline(false);
};

가이드라인 모달의 내용은 두 섹션으로 나뉩니다.

금지 사항 (하지 말아야 할 것)

권장 사항 (이렇게 대화하세요)

가이드라인의 법적 효력

가이드라인 모달을 통한 확인은 단순한 UX 요소가 아닙니다. 사용자가 명시적으로 “확인했습니다”를 누르는 행위는 서비스 이용 규칙에 동의했음을 기록하는 행위이기도 합니다. 향후 분쟁 발생 시 관련 기록이 법적 근거로 활용될 수 있습니다.


프론트엔드 UX: 안전을 위한 인터페이스

신뢰 시스템이 아무리 탄탄해도, 사용자가 쉽게 접근할 수 없다면 무용지물입니다. 썸블링은 차단과 신고 기능을 자연스럽게 접근할 수 있는 위치에 배치했습니다.

접근 경로

기능접근 경로 1접근 경로 2
차단채팅방 헤더 우측 메뉴 (⋮)프로필 모달 하단
신고채팅방 헤더 우측 메뉴 (⋮)홈 매칭 카드 롱프레스
차단 목록프로필 → 계정 설정 → 차단 관리-

BlockDialog: 차단 확인 다이얼로그

// BlockDialog 핵심 흐름
const BlockDialog = ({ targetMember, onConfirm, onCancel }) => {
  const [reason, setReason] = useState('');

  return (
    <Dialog>
      <DialogTitle>{targetMember.nickname}님을 차단하시겠어요?</DialogTitle>
      <DialogDescription>
        차단하면 서로의 매칭 목록에서 제외되고,
        채팅을 더 이상 주고받을 수 없게 됩니다.
      </DialogDescription>
      <TextArea
        placeholder="차단 사유를 입력해주세요 (선택)"
        value={reason}
        onChange={(e) => setReason(e.target.value)}
        maxLength={200}
      />
      <Button variant="danger" onClick={() => onConfirm(reason)}>
        차단하기
      </Button>
      <Button variant="ghost" onClick={onCancel}>
        취소
      </Button>
    </Dialog>
  );
};

차단 사유 입력은 선택 사항입니다. 사용자가 굳이 이유를 설명하지 않아도 차단할 수 있어야 합니다. 차단이라는 자기 보호 행위에 심리적 장벽을 낮추는 것이 중요하기 때문입니다.

ReportDialog: 신고 다이얼로그

신고 다이얼로그는 6가지 사유를 선택지 형태로 제공합니다. OTHER를 선택한 경우에만 상세 설명 입력이 필수 항목이 됩니다.

const REPORT_REASONS = [
  { code: 'INAPPROPRIATE_MESSAGE', label: '부적절한 메시지' },
  { code: 'HARASSMENT',           label: '괴롭힘 또는 집요한 연락' },
  { code: 'FAKE_PROFILE',         label: '가짜 프로필 또는 허위 정보' },
  { code: 'OFFENSIVE_CONTENT',    label: '욕설 또는 혐오 표현' },
  { code: 'SPAM',                 label: '스팸 또는 광고' },
  { code: 'OTHER',                label: '기타 (직접 입력)' },
];

신고 제출 후에는 “신고가 접수되었습니다. 검토 후 조치하겠습니다.”라는 확인 메시지를 표시합니다. 과거 데이팅 앱들이 받은 비판 “신고해도 아무 일도 안 일어나는 것 같다”를 의식한 설계입니다. 실제 처리 결과를 관리자가 빠르게 검토하고, 중대한 제재가 결정되면 신고자에게 처리 완료 알림이 발송됩니다.


관리자 도구: 효율적인 신고 처리

신뢰 시스템의 3단계인 제재가 실제로 작동하려면, 관리자가 신고를 빠르고 일관성 있게 처리할 수 있어야 합니다. 썸블링의 관리자 대시보드는 신고 처리를 위한 전용 도구를 제공합니다.

관리자 대시보드 신고 현황

대시보드 첫 화면의 주요 KPI 카드 중 하나가 대기 신고 건수입니다. 이 숫자가 0이 아닌 경우 강조 색상(경고 오렌지)으로 표시되어, 관리자가 처리해야 할 작업이 있음을 즉각 인지할 수 있습니다.

신고 관리 페이지

신고 목록은 접기/펼치기 가능한 카드 형식으로 표시됩니다. 접힌 상태에서는 신고자 ID, 피신고자 닉네임, 신고 사유, 상태 인디케이터만 보이고, 펼치면 상세 내용이 노출됩니다.

신고 카드 (접힌 상태)
┌────────────────────────────────────────────┐
│ 🟡 PENDING  신고자: #1234  대상: 가나다  부적절한 메시지  2026-02-07  [펼치기 ▼] │
└────────────────────────────────────────────┘

신고 카드 (펼친 상태)
┌────────────────────────────────────────────┐
│ 🟡 PENDING  신고자: #1234  대상: 가나다  부적절한 메시지  2026-02-07  [접기 ▲]  │
│                                                                                  │
│ 신고 상세 내용:                                                                   │
│ "원치 않는 성적 메시지를 반복적으로 전송했습니다. 차단했지만 신고도 남깁니다."          │
│                                                                                  │
│ 신고자 ID: 1234  피신고자 ID: 5678  신고일: 2026-02-07 14:23                      │
│                                                                                  │
│          [처리 완료 ✓]    [기각 ✗]                                                │
└────────────────────────────────────────────┘

상태 인디케이터는 색상으로 직관적으로 구분됩니다.

회원 상태 변경

신고 처리 후 제재가 필요한 경우, 관리자 회원 관리 페이지에서 드롭다운으로 즉시 상태를 변경할 수 있습니다.

회원 상태 변경 드롭다운
┌──────────────┐
│ ● ACTIVE     │
│ ◐ DORMANT    │  ← 선택 시 즉시 일시 정지
│ ○ WITHDRAWN  │  ← 선택 시 영구 정지
└──────────────┘

상태 변경은 낙관적 업데이트로 즉시 UI에 반영되며, 서버 오류 시 이전 상태로 롤백됩니다. 변경된 회원은 다음 API 요청 시 상태 검증에서 차단됩니다.


데이터로 개선하기

신뢰 시스템은 구축한 뒤 방치해서는 안 됩니다. 지속적인 모니터링과 데이터 분석을 통해 시스템을 개선해야 합니다.

핵심 모니터링 지표

지표설명목표
신고율총 채팅 수 대비 신고 건수낮을수록 좋음
차단율총 매칭 수 대비 차단 건수트렌드 모니터링
신고 처리 시간PENDING → REVIEWED/DISMISSED 평균 시간24시간 이내
재신고율제재 후 동일 회원 재신고 비율낮을수록 좋음
이탈 상관관계신고/차단 경험 후 이탈율이탈 방지 목표

차단·신고 패턴 분석

특정 회원에게 신고나 차단이 집중되는 경우, 이를 선제적으로 모니터링할 수 있습니다. 단기간에 다수의 신고를 받은 회원은 자동으로 관리자 검토 대상으로 분류하는 시스템을 도입할 계획입니다.

-- 최근 7일간 신고를 3건 이상 받은 회원
SELECT reported_member_id, COUNT(*) as report_count
FROM member_reports
WHERE created_at >= NOW() - INTERVAL '7 days'
  AND status = 'PENDING'
GROUP BY reported_member_id
HAVING COUNT(*) >= 3
ORDER BY report_count DESC;

향후 계획: AI 기반 자동 감지

현재는 신고 후 관리자 수동 검토 방식으로 운영합니다. 장기적으로는 채팅 메시지의 패턴을 분석하여 잠재적으로 부적절한 내용을 자동 감지하는 AI 모듈 도입을 검토하고 있습니다.

다만 이 기능은 개인정보 보호와 표현의 자유 사이의 균형을 신중하게 고려해야 합니다. 무분별한 자동 차단은 억울한 피해자를 만들 수 있고, 오히려 서비스에 대한 신뢰를 무너뜨릴 수 있습니다. 썸블링은 자동 감지 결과를 참고 정보로만 활용하고, 최종 제재 결정은 반드시 사람이 내리는 원칙을 유지할 것입니다.


만남 후기: 신뢰 시스템의 완성

신뢰 시스템의 마지막 퍼즐은 만남 후기입니다. 온라인에서의 대화를 넘어 실제 오프라인 만남이 이뤄진 이후, 두 사람은 서로에 대한 후기를 남길 수 있습니다.

후기는 1~5점 별점과 함께 8가지 태그 중 선택할 수 있습니다.

태그설명
PUNCTUAL시간을 잘 지켜요
KIND친절하고 배려심이 깊어요
FUN_CONVERSATION대화가 잘 통해요
LOOKS_LIKE_PHOTO프로필 사진과 비슷해요
GOOD_MANNERS예의가 바르고 매너가 좋아요
COMFORTABLE편안한 분위기를 만들어줘요
THOUGHTFUL세심하게 배려해줬어요
GOOD_LISTENER잘 들어줘요

이 후기는 매칭 카드에 ReviewSummaryBadge 형태로 집약 표시됩니다. 평균 별점, 총 리뷰 수, 상위 3개 태그가 노출됩니다. 이는 온라인 프로필만으로 판단하기 어려운 실제 만남에서의 신뢰도를 수치화하는 장치입니다. 좋은 매너를 가진 사람은 자연스럽게 더 많은 매칭 기회를 얻게 됩니다.


마무리: 안전이 곧 제품 가치

신뢰 시스템을 설계하며 가장 많이 들은 질문은 이것이었습니다. “이런 시스템을 만드는 데 그만한 비용을 쓸 가치가 있나요?”

저희의 답은 명확합니다. 안전이 곧 제품의 핵심 가치입니다.

데이팅 앱에서 사람들이 진솔하게 자신을 드러내고 상대방을 신뢰하려면, 그 공간이 안전하다는 믿음이 먼저 있어야 합니다. 아무리 정교한 AI 매칭이 있어도, 아무리 세련된 UI가 있어도, 사용자가 안전하지 않다고 느끼는 순간 모든 것이 무의미해집니다.

잘 작동하는 신뢰 시스템의 아이러니한 특성이 있습니다. 보이지 않을수록 잘 작동하는 것입니다. 사용자가 차단 버튼을 찾을 필요도 없고, 신고를 고민할 일도 없고, 가이드라인 모달을 읽지 않아도 되는 상태. 그 상태가 우리가 궁극적으로 만들고 싶은 썸블링의 모습입니다.

안전한 공간에서만 진솔한 대화가 피어납니다. 그리고 진솔한 대화에서만 진짜 연결이 시작됩니다.


썸블링은 성격과 가치관 기반 AI 매칭 데이팅 앱입니다. 외모가 아닌 내면으로 연결되는 만남을 지향합니다.

댓글

GitHub 계정으로 로그인하여 댓글을 남길 수 있습니다. 허위사실, 욕설, 사칭 등의 댓글은 통보 없이 삭제될 수 있습니다.

블로그로 돌아가기