Skip to content

feat: 차단/신고 API, 암호화 모델 결정, 스케줄러 정리 #30

Description

@cfcromn

Describe

API 명세서(34개 엔드포인트)는 #28 로 모두 구현되었다. 이 이슈는 명세서에 없지만 CLAUDE.md 와 암호화 설계 문서에 정의되어 있는, MVP 마감 전 남은 세 가지를 함께 처리한다.


1. 차단 / 신고 API

Block, Report 는 엔티티와 레포지토리만 있고 API가 없다.

문제는 차단 로직이 이미 서버 전반에서 동작 중이라는 점이다. CapsuleAccessPolicy, SendFriendRequestService, RespondFriendRequestService, CreateCapsuleService, SearchFriendService 가 모두 BlockRepository 를 호출한다. 즉 차단을 전제로 동작하는데 정작 차단할 수단이 없는 상태다.

  • POST /api/v1/blocks 차단, DELETE /api/v1/blocks/{memberId} 차단 해제, GET /api/v1/blocks 차단 목록
  • POST /api/v1/reports 신고 (uq_report_reporter_target 으로 중복 신고 차단)
  • 차단 시 기존 친구 관계와 대기 중인 친구 요청을 어떻게 처리할지 결정 필요
  • Report.targetTypeReport.reason 이 raw String 이다. CLAUDE.md 의 표현적 도메인 모델링 원칙에 따라 enum 으로 교체한다(마이그레이션 불필요, 컬럼은 이미 VARCHAR).
  • 두 API 모두 명세서에 없으므로 Notion 반영이 필요하다.

2. 암호화 모델 결정 — Shamir's Secret Sharing

이건 구현 작업 전에 결정이 필요한 항목이다.

「🔐 암호화 설계」 문서와 현재 구현이 서로 다른 모델이다.

설계 문서 (클라이언트 사이드 E2E)

  • CEK 를 클라이언트에서 생성하고, 서버에 평문으로 전달하지 않는다
  • CEK 를 Shamir's Secret Sharing 으로 N개 조각 분할 → tbl_key_share 에 저장 (2-of-3 기본, 3-of-5 강화)
  • 열람 시 서버는 위치·비밀번호 검증 후 키 조각만 반환하고, 복호화는 클라이언트가 수행한다
  • 서버는 캡슐 내용을 절대 볼 수 없다

현재 구현 (#23, 서버 사이드 봉투 암호화)

  • 서버가 보유한 MUDDA_MASTER_KEY 를 KEK 로 사용한다
  • EncryptedStringConverter (JPA AttributeConverter) 가 TimeCapsule.content 를 투명하게 암·복호화한다
  • OpenCapsuleService 가 평문 내용을 응답에 담아 반환한다 → 서버가 평문을 볼 수 있다
  • tbl_key_share 는 존재하지 않는다

현재 구현은 저장소 유출에 대한 at-rest 암호화로는 유효하지만, CLAUDE.md 의 "서버는 캡슐 내용을 절대 평문으로 볼 수 없다" 는 만족하지 못한다.

결정할 것

  • (A) 설계 문서대로 클라이언트 사이드 E2E 로 전환한다. tbl_key_share 추가, Shamir GF(256) 직접 구현, 캡슐 생성/열람 API 의 요청·응답 계약 변경, 클라이언트 작업 동반. 범위가 크므로 별도 이슈로 분리하는 편이 낫다.
  • (B) 현재 서버 사이드 모델을 유지하기로 확정하고, CLAUDE.md 와 암호화 설계 문서를 실제 구현에 맞게 수정한다. Shamir 는 스택에서 제외한다.

어느 쪽이든 문서와 코드 중 하나는 고쳐야 한다. 지금은 둘이 어긋난 상태다. 결정 전까지 이 항목은 구현하지 않는다.


3. 스케줄러 (배치)

@Scheduled 가 프로젝트에 하나도 없다.

  • 미첨부 미디어 정리tbl_media.time_capsule_id IS NULL 인 채로 일정 시간이 지난 pending 업로드는 S3 객체와 행이 모두 고아로 남는다. V4 에서 pending 업로드를 허용하면서 생긴 실제 누수다.
  • 만료 캡슐 키 조각 삭제 — 암호화 설계 문서에 "만료된 캡슐의 키 조각은 스케줄러로 삭제 처리" 로 명시되어 있다. 위 2번 결정이 (A) 일 때만 해당한다.
  • 참고: 캡슐 만료 상태 전이 배치는 불필요하다. CapsuleAccessPolicy.requireAccessible 이 읽기 시점에 expiredAt 을 검사해 차단하고 있다. 배치가 필요한 이유는 정합성이 아니라 저장공간 회수다.

Additional

세 항목의 성격이 서로 달라 진행 중 분리가 필요하다고 판단되면 이슈를 쪼개도 된다.

2번은 결정 전까지 착수 불가다. 1번과 3번(미디어 정리)은 독립적으로 바로 진행할 수 있다.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions