목표
사이드바 Notice 필터 탭이 지금 .all로 매핑돼 있다. "뱃지(만료 임박) 달린 Secret만 모아 보여주는 탭"으로 실제 연결한다.
현재 문제
TODO가 두 곳에 그대로 남아있다.
MainFeature.swift:235-237 — .filter(.notice) → .init(collection: .all)
SidebarClient+Live.swift:104-106 — SidebarFilter.notice → .all
둘 다 "도메인 레이어에 .notice collection 추가 후 연결"이라는 주석만 있고 실제 필터링은 없다. 지금은 Notice 탭을 눌러도 All과 똑같은 목록이 뜬다.
왜 단순히 .expired를 재사용할 수 없는가
뱃지 기준 window(critical 3일 + upcoming 7일 = 총 7일 이내)는 SecretQuery.Collection.expired(referenceDate:)에 window를 밀어 넣는 기존 패턴(expiringWindow(from:), Expired 탭이 쓰는 방식)으로 쿼리 자체는 어렵지 않게 재현할 수 있다.
문제는 SecretListView가 store.collection 하나로 화면 정체성(제목·섹션·정렬 표시 여부)을 전부 결정한다는 점이다.
// SecretListView.swift
private var titleText: String {
switch store.collection {
case .expired: return "Expired" // Notice가 .expired를 재사용하면 여기서도 "Expired"가 나온다
...
}
private var list: some View {
if case let .expired(referenceDate) = store.collection {
expirySections(referenceDate: referenceDate) // Expired/7일/30일 섹션 헤더가 자동으로 붙는다
} ...
}
Notice 탭이 .expired 컬렉션을 그대로 쓰면 뷰가 "이건 Expired 탭"으로 착각해서 제목이 "Expired"로 뜨고, 원치 않는 섹션 헤더까지 딸려온다. 쿼리 조건(뭘 가져올지)과 화면 정체성(어떻게 보여줄지)이 Collection 하나에 뭉쳐 있는 게 근본 원인.
작업 범위
결정 필요 — 설계 방향
수정 — DVDomain (설계에 따라 범위 결정)
수정 — DVPresentation
테스트
참고
- 이미 지난 Secret은 Notice에 포함하지 않는다 — Expired 탭이 전담. (#97에서 배지 정책도 이렇게 정리됨: "이미 만료된 항목은 배지 자체를 안 띄운다")
#85/#97이 머지되면 SecretExpiryPolicy가 생기므로, window 상수는 거기서 가져오는 걸 우선 고려
목표
사이드바 Notice 필터 탭이 지금
.all로 매핑돼 있다. "뱃지(만료 임박) 달린 Secret만 모아 보여주는 탭"으로 실제 연결한다.현재 문제
TODO가 두 곳에 그대로 남아있다.
MainFeature.swift:235-237—.filter(.notice)→.init(collection: .all)SidebarClient+Live.swift:104-106—SidebarFilter.notice→.all둘 다 "도메인 레이어에
.noticecollection 추가 후 연결"이라는 주석만 있고 실제 필터링은 없다. 지금은 Notice 탭을 눌러도 All과 똑같은 목록이 뜬다.왜 단순히
.expired를 재사용할 수 없는가뱃지 기준 window(critical 3일 + upcoming 7일 = 총 7일 이내)는
SecretQuery.Collection.expired(referenceDate:)에 window를 밀어 넣는 기존 패턴(expiringWindow(from:), Expired 탭이 쓰는 방식)으로 쿼리 자체는 어렵지 않게 재현할 수 있다.문제는
SecretListView가store.collection하나로 화면 정체성(제목·섹션·정렬 표시 여부)을 전부 결정한다는 점이다.Notice 탭이
.expired컬렉션을 그대로 쓰면 뷰가 "이건 Expired 탭"으로 착각해서 제목이 "Expired"로 뜨고, 원치 않는 섹션 헤더까지 딸려온다. 쿼리 조건(뭘 가져올지)과 화면 정체성(어떻게 보여줄지)이Collection하나에 뭉쳐 있는 게 근본 원인.작업 범위
결정 필요 — 설계 방향
SecretQuery.Collection에.notice처럼 구분되는 새 케이스를 추가할지, 아니면SecretListFeature.State에 collection과 별개로 "화면 정체성" 필드를 둘지 결정SecretFetchDescriptorBuilder의 predicate/countPredicate 양쪽에 케이스 추가 필요. predicate 자체는.expired와 사실상 동일(window만 다름)해서 중복이 생길 수 있음Collection은 순수하게 쿼리 조건만 표현하고, State에SidebarFilter?같은 필드를 둬서 View가 그걸로 title/section/sort 분기.Collection재사용 가능, 다만 State 설계가 한 겹 더 생김수정 — DVDomain (설계에 따라 범위 결정)
SecretExpiryPolicy.upcomingWindowDays가 있다면 재사용 — Feature: 만료 단계 도메인 통합 및 listView 만료 배지 3/7일 분리 #85/Feature/#85 - 만료 배지 tooltip 추가 / 임계값(3/7/30일) SecretExpiryPolicy로 통합 #97 PR 참고)수정 — DVPresentation
MainFeature.makeSecretListState의.filter(.notice)분기를 실제 매핑으로 교체SecretListView가 Notice 탭을 인식해 제목을 "Notice"로, 리스트를 섹션 없는 플랫 형태로 그리도록 처리SidebarClient+Live.swift의SidebarFilter.notice → .all매핑을 실제 카운트 쿼리로 교체 — 사이드바 카드 숫자도 이걸 안 고치면 계속 All과 같은 값이 뜬다테스트
참고
#85/#97이 머지되면SecretExpiryPolicy가 생기므로, window 상수는 거기서 가져오는 걸 우선 고려