[BE-09] 컨텍스트 룸 provision + 커뮤니티 채팅 연동

작업 내용 (설계 의도)

변경 사항

근거 TDD: 20260704-채팅시스템고도화-tdd.md (FR-4/5/16/17, 도메인 이벤트 연동, 자동 가입 멱등).

커뮤니티 이벤트를 소비해 전용 그룹 채팅방을 자동 생성·참여·퇴장시킨다. 도메인 교차 참조 없이 presentation EventWorker + ID로 연결.

  • domain/message/service/RoomContextDomainService.kt (신규): provision(contextType, contextId, name, hostUserId)findByContext 없으면 Room.createForContext(BE-03a) 생성 + 방장 참여. joinContext(contextType, contextId, userId) — 이미 참여자면 skip(멱등). leaveContext(contextType, contextId, userId) — 참여자 soft-delete.
  • application/message/usecase/: ProvisionContextRoomUseCase, JoinContextRoomUseCase, LeaveContextRoomUseCase (신규).
  • presentation/community/worker/CommunityChatIntegrationEventWorker.kt (신규): @TransactionalEventListener(AFTER_COMMIT).
    • CommunityCreatedEvent → ProvisionContextRoomUseCase(COMMUNITY, communityId, name, hostUserId).
    • CommunityMemberJoinedEvent → JoinContextRoomUseCase(COMMUNITY, communityId, userId).
    • CommunityMemberLeftEvent → LeaveContextRoomUseCase(COMMUNITY, communityId, userId).
  • 멱등: eventId 기반 중복 소비 방어 + existsByRoomIdAndUserId skip.
  • 롤백: EventWorker는 community 플래그와 함께 비활성. 컨텍스트 룸은 additive.

의존

  • BE-03a (Room.createForContext, findByContext)
  • BE-08 (커뮤니티 이벤트)

다이어그램

처리 흐름

sequenceDiagram
    participant Com as CommunityDomainService
    participant Pub as EventPublisher
    participant W as CommunityChatIntegrationEventWorker
    participant UC as Provision/Join/LeaveContextRoomUseCase
    participant DS as RoomContextDomainService
    Com-->>Pub: CommunityCreatedEvent
    Pub->>W: AFTER_COMMIT
    W->>UC: provision(COMMUNITY, id, name, host)
    UC->>DS: findByContext or createForContext + 방장 참여

테스트 케이스

  • 커뮤니티 개설 이벤트 수신 시 contextType=COMMUNITY 전용 그룹 방이 자동 생성되고 방장이 참여자로 등록된다.
  • 멤버 가입 이벤트 수신 시 해당 커뮤니티 방에 참여자로 자동 등록된다.
  • 이미 참여 중인 사용자의 가입 이벤트를 재수신해도 중복 참여자가 생기지 않는다 (멱등).
  • 멤버 탈퇴/강퇴 이벤트 수신 시 연결된 방에서 자동 퇴장 처리된다.
  • 동일 커뮤니티에 대해 방이 이미 있으면 provision이 새 방을 만들지 않는다.