@@ -251,8 +251,9 @@ public boolean canReadCollection(Long userId, Long collectionId) {
251251 return canReadCollection (userId , getActiveCollection (collectionId ));
252252 }
253253
254- // 이미 조회된 컬렉션 엔티티로 판단 — 호출부가 이미 non-deleted 엔티티임을 보장해야 함
254+ // 이미 조회된 컬렉션 엔티티로 판단 — soft-delete된 엔티티면 COLLECTION_NOT_FOUND
255255 public boolean canReadCollection (Long userId , DocumentCollection collection ) {
256+ validateActiveCollection (collection );
256257 if (collection .getOwner ().getId ().equals (userId )) return true ;
257258 if (collection .getVisibility () == VisibilityType .PUBLIC ) return true ;
258259 Long collectionId = collection .getId ();
@@ -267,6 +268,7 @@ public boolean canWriteCollection(Long userId, Long collectionId) {
267268 }
268269
269270 public boolean canWriteCollection (Long userId , DocumentCollection collection ) {
271+ validateActiveCollection (collection );
270272 if (collection .getOwner ().getId ().equals (userId )) return true ;
271273 Long collectionId = collection .getId ();
272274 if (collectionPermissionRepository .existsUserWritePermission (userId , collectionId )) return true ;
@@ -280,6 +282,7 @@ public boolean canAdminCollection(Long userId, Long collectionId) {
280282 }
281283
282284 public boolean canAdminCollection (Long userId , DocumentCollection collection ) {
285+ validateActiveCollection (collection );
283286 if (collection .getOwner ().getId ().equals (userId )) return true ;
284287 Long collectionId = collection .getId ();
285288 if (collectionPermissionRepository .existsUserAdminPermission (userId , collectionId )) return true ;
@@ -288,15 +291,19 @@ public boolean canAdminCollection(Long userId, DocumentCollection collection) {
288291 }
289292
290293 // collectionId로 조회하되, status가 DELETED인 컬렉션은 필터링해서 제외한다 (없는 것으로 취급).
291- // → DELETED가 아닌 컬렉션만 찾아서 반환하고, 없거나 DELETED면 COLLECTION_NOT_FOUND를 던진다.
292- // collectionId로 조회하는 다른 지점에서도 이 필터링을 동일하게 적용해야
293- // "삭제된 컬렉션을 살아있는 것처럼" 취급하는 구멍이 생기지 않는다.
294294 private DocumentCollection getActiveCollection (Long collectionId ) {
295295 return collectionRepository .findById (collectionId )
296296 .filter (c -> c .getStatus () != CollectionStatus .DELETED )
297297 .orElseThrow (() -> new DocGridException (ErrorCode .COLLECTION_NOT_FOUND ));
298298 }
299299
300+ // 엔티티 오버로드 방어 로직 — 호출부가 soft-delete 필터를 빠뜨리고 넘긴 엔티티도 여기서 최종 차단한다(추가 조회 없음).
301+ private void validateActiveCollection (DocumentCollection collection ) {
302+ if (collection .getStatus () == CollectionStatus .DELETED ) {
303+ throw new DocGridException (ErrorCode .COLLECTION_NOT_FOUND );
304+ }
305+ }
306+
300307 private double ms (long fromNano ) {
301308 return (System .nanoTime () - fromNano ) / 1_000_000.0 ;
302309 }
0 commit comments