01. 자료는 많지만, 일관된 접근 방식이 없었다
기관의 발간물·세미나·보고서가 서로 다른 경로와 형식으로 존재할 때, 이용자는 원하는 자료를 찾기 어렵고 관리자는 공개 범위와 업로드 상태를 일일이 확인해야 합니다.
자료 유형에 맞는 게시판과 검색 흐름을 만들고, 관리자가 직접 콘텐츠를 등록·수정·정리할 수 있는 환경을 구축했습니다.
02. 메타데이터와 파일을 분리한 구조
자료의 제목, 작성일, 게시판, 공개 범위는 PostgreSQL에서 관리하고 실제 문서·이미지·영상 파일은 Cloudflare R2에 저장했습니다. Next.js 서버 API에서 인증, 입력 검증, 공개 범위 판단과 업로드 흐름을 제어하도록 나누었습니다.
자료 정보와 객체 저장을 분리해 검색·목록 조회와 실제 파일 제공의 책임을 구분했습니다.
공개 범위를 public / member / admin으로 구분하고, 삭제 상태·검색어·카테고리·날짜 등을 조회 조건으로 반영했습니다.
자료 삭제는 행을 지우지 않고 삭제 시각만 기록하는 방식으로 처리합니다. 목록과 검색에서는 빠지지만 기록은 남아, 지금까지 삭제한 37건도 언제 지웠는지 확인할 수 있습니다.
03. 정상 경로만 설계하지 않기
R2 업로드는 성공했지만 DB 저장이 실패한다면?
서로 다른 저장소는 하나의 데이터베이스 트랜잭션으로 묶이지 않습니다. 파일 업로드만 성공하고 자료 메타데이터 저장이 실패하면 저장소에는 조회되지 않는 객체가 남을 수 있습니다.
자료의 실제 파일을 저장소에 기록합니다.
게시판·접근 범위·파일 키 등의 레코드를 저장합니다.
파일만 고립된 상태로 남지 않도록 보상 처리합니다.
이후 신규 콘텐츠만 고려하는 대신, 기존 자료를 새 분류와 날짜 기준에 맞춰 옮기기 위한 스크립트도 함께 만들었습니다. 재실행과 입력 검증을 고려해 관리 작업의 반복 부담을 줄이는 것이 목표였습니다.
04. 결과와 배운 점
이번 프로젝트에서는 웹 UI를 만드는 일 외에도 자료 저장 위치, 접근 권한, 업로드 실패, 기존 데이터 이관이라는 운영 영역을 직접 다뤘습니다. 특히 하나의 요청이 여러 외부 서비스에 걸쳐 있을 때 각 단계의 실패 상태를 어떻게 처리할지 고민하는 경험이었습니다.