Skip to content

fix(afternote): 수정 모드 서버 영상→로컬 교체 후 삭제는 여전히 거짓 삭제 — 폼은 비지만 저장 후 서버 영상 잔존 #1406

Closed

Description

@OnlyReadOneBook

작업 유형

bug — 버그·오동작

주 담당 모듈

afternote — 애프터노트

개요

#1375 는 추억 노트 미디어 시트의 "삭제" 를 이 폼에서 새로 붙인 로컬 첨부(content://)에만 노출해(removableMemorialMediaTargets) 서버 미디어의 거짓 삭제를 막았다. 그러나 다음 교차 경로는 그 가드를 지나쳐 여전히 거짓 삭제다.

재현 경로 (장례식에 남길 영상):

  1. 서버에 영상이 저장된 애프터노트를 수정 모드로 연다 — memorialVideoUrl 에 원격 URL prefill.
  2. 슬롯을 탭해 로컬 영상으로 교체한다 — memorialVideoUrl 이 content:// 로 바뀌므로 이제 삭제 가능 슬롯으로 판정된다.
  3. 시트의 "영상 삭제" 로 그 로컬 영상을 지운다 — memorialVideoUrl = null, 폼은 빈 슬롯.
  4. 저장한다.
  5. 서버 영상이 그대로 남는다. 재진입하면 지웠던 슬롯에 서버 영상이 되살아난다.

원인: 3 이후 저장 시 AfternoteEditorViewModel.videoMediaInput(null) 은 MediaInput.None 이 되고, 수정(PATCH) 계약은 삭제를 표현할 수 없다 — BE AfternotePlaylist.update 가 null 필드를 "기존 값 유지" 로 해석한다. 단계 2 에서 원격 URL 이 로컬 URI 로 덮여 "서버 영상이 아직 존재한다" 는 사실이 폼에서 사라지므로, 로컬 전용 삭제 가드가 이 경로를 가르지 못한다.

완료 조건:

  • 위 경로에서 저장하면 서버 영상이 실제로 제거되거나, 제거가 불가능한 동안에는 폼이 거짓 빈 슬롯을 보여주지 않는다(예: 삭제 시 서버 영상 표시로 복귀).
  • 회귀 테스트로 경로를 고정한다.

자식 이슈

No response

참고

Activity

  1. OnlyReadOneBook commented on Aug 28, 2026

    @OnlyReadOneBook
    CollaboratorAuthor

    근본 해소가 선행이라 적힌 BE 계약 확장을 이슈로 세워 blocked_by 로 걸었다 — Afternote-BE#259. 본문 참고에만 있던 "BE 계약 확장이 선행"을 관계로 바꿔 둔 것이고, BE 현 origin/main(aba24df) 재확인 결과 AfternotePlaylist.update()·PlaylistRelationStrategy.update() 어디에도 삭제 의사가 지나갈 통로가 없다는 게 확정이다.

    착수할 사람이 본문만 보면 놓칠 재료 몇 가지를 실측해 남긴다.

    1. 썸네일이 같은 축에 걸린다 — 복원은 쌍으로 해야 한다

    EditorFormMutations.kt:37 이 영상 갱신 시 썸네일을 함께 비운다.

    internal fun EditorFormState.withMemorialVideo(url: String?): EditorFormState =
        mapMemorial { it.copy(videoUrl = url, thumbnailUrl = null) }

    그래서 단계 2(로컬 교체)에서 잃는 것은 원격 videoUrl 하나가 아니라 서버 영상 URL + 서버 썸네일 URL 쌍이다. 완료 조건의 "삭제 시 서버 영상 표시로 복귀"를 만족하려면 둘 다 되돌려야 하고, 썸네일만 빠지면 복귀한 슬롯이 썸네일 없는 카드로 보인다.

    2. 지금 코드에 복구원이 없다 — 상태를 새로 들여야 한다

    서버 원본이 남아 있을 만한 유일한 후보가 prefill 인데, AfternoteEditorViewModel.onPrefillConsumed() 가 반영 직후 pendingPrefill = null 로 버린다. 즉 단계 2 이후 서버 원본은 FE 어디에도 남지 않으므로, 어떤 처방이든 상태를 새로 추가하는 것이 전제다. "기존 값에서 되살리는" 싼 우회는 없다.

    3. 처방 크기 — 두 판이 있고, 완료 조건은 싼 판으로 닫힌다

    • 싼 판(권장): AfternoteTypeForm.Memorial 에 서버 원본 쌍(예: serverVideoUrl·serverThumbnailUrl)을 두고, withPrefillApplied 에서 채운 뒤 삭제 경로에서 videoUrl·thumbnailUrl 로 되돌린다. 표시·저장 경로는 그대로 두므로 AfternoteTypeForm.kt + EditorFormMutations.kt + feat(afternote): 추억 노트 영정사진·영상 소스 시트에 삭제 항목 추가 (#1114) #1375 의 삭제 조건(removableMemorialMediaTargets) 정도로 닫힌다.
    • 비싼 판: videoUrl 을 사진처럼 pickedVideoUri/서버 URL 로 쪼개고 소비처마다 폴백을 심는 방식. feature/afternote/presentation main 13 파일 + 테스트 7 파일이 걸린다. 완료 조건을 넘어서는 범위다.

    4. 사진과 갈린 건 계약 탓이 아니라 최초 설계 선택이다

    사진은 pickedPhotoUri(로컬)/photoUrl(서버) 두 필드라 이 결함이 없고, 영상은 한 필드다. 이 비대칭은 최초 구현 커밋 860dba8c5(2026-03-29)부터 있었고 이후 리팩터링들은 이름·위치만 옮겼다. 계약이 강제한 구조가 아니므로 FE 재량으로 바꿀 수 있다.

    5. 다만 최종 모델을 지금 확정하지는 말 것

    BE#259 가 삭제 계약을 열면 폼이 표현해야 할 것은 유지·교체·삭제 3상태가 된다. 지금 사진의 nullable 2개 구조를 그대로 미러링해 두면 그때 다시 손대야 할 수 있다. 이 이슈에서는 완료 조건대로 "거짓 빈 슬롯을 보여주지 않는다"까지만 닫고, 삭제 자체의 모델은 BE 결정 뒤로 미루는 편이 안전하다.

  2. OnlyReadOneBook commented on Aug 29, 2026

    @OnlyReadOneBook
    CollaboratorAuthor

    PR #1527 로 완료 조건의 후자를 처리했습니다 — 「제거가 불가능한 동안에는 폼이 거짓 빈 슬롯을 보여주지 않는다」.

    서버 영상을 로컬로 교체한 뒤 지우면 null 이 아니라 서버 원본 표시로 되돌아갑니다. 되돌아간 뒤에는 #1375 의 규칙이 다시 적용돼 삭제 항목도 스스로 감춰집니다. 프로세스 재생성 스냅샷에도 원본을 실어, 복원 뒤 삭제가 다시 거짓이 되지 않게 했습니다.

    원인은 영상 칸 하나가 로컬 픽과 원격 prefill 을 겸하고 있던 것이었습니다 — 영정 사진은 pickedPhotoUri/photoUrl 이 갈려 있어 같은 문제가 없었고, 영상만 대칭이 깨져 있었습니다.

    전자(서버 영상의 실제 제거)는 이 PR 범위 밖이고, FE 가 표현할 수단이 없습니다. BE AfternotePlaylist.update 가 생략·null 을 모두 「기존 값 유지」로 흡수하는 한 어떤 페이로드로도 삭제를 말할 수 없습니다 — 블로커인 #259 의 계약 확장이 선행돼야 합니다.

    그래서 이 이슈는 #259 해소 뒤 다시 열어 볼 갈래가 남습니다: 계약이 삭제를 표현하게 되면 「삭제 = 교체 취소」인 현재 동작을 실제 삭제로 승격할지 판단해야 합니다. 그때까지는 지울 수 없는 것을 지운 척하지 않는 쪽을 택했습니다 — 애프터노트는 사후 전달이라, 사용자가 지웠다고 믿은 채 장례식 영상이 남는 편이 훨씬 나쁩니다.

  3. added
    pr-open이 이슈를 구현하는 PR 이 열려 있다 — base 가 기본 브랜치가 아니어도 드러낸다
    on Aug 29, 2026
  4. removed
    pr-open이 이슈를 구현하는 PR 이 열려 있다 — base 가 기본 브랜치가 아니어도 드러낸다
    on Aug 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

area:afternote애프터노트 기능 영역bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions