StudyDad Loop 제품을 만들며 배운 운영과 설계를 기록합니다.

FamBlend를 중심으로 실제 구현, 운영 메모, GitHub 포트폴리오를 연결해 쌓아가는 StudyDad의 작업 기록입니다.

성장과 기술/개발과 자동화

최신 데이터, 월별 스냅샷, 감사 백업을 나눠 저장하기

박세식 2026. 6. 13. 12:00

자동화 워크플로우 시리즈 6/8

운영 자동화에서 데이터를 파일로 저장할 때 흔히 하나의 JSON만 만들고 싶어진다.

data.json

처음에는 충분해 보인다. 화면은 최신 데이터만 읽으면 되고, 동기화할 때 파일을 덮어쓰면 된다.

하지만 운영하다 보면 최신 데이터 하나만으로는 부족하다.

언제 어떤 데이터가 동기화되었는지, 월별로 어떤 상태였는지, 문제가 생겼을 때 어디로 되돌아가야 하는지 알 수 있어야 한다.

그래서 최신 데이터, 월별 스냅샷, 감사 백업을 나눠 저장하는 구조가 필요하다.

문제 상황

스프레드시트를 원천 데이터로 두고, 화면 제공을 위해 JSON 파일을 생성해야 했다.

필요한 데이터는 하나가 아니었다.

  • 운영자 화면이 읽는 최신 데이터
  • 월별 화면이나 기록을 위한 스냅샷
  • 외부 사용자에게 보여줄 공개용 데이터
  • 동기화 실패나 데이터 오류를 추적하기 위한 백업

이 모든 것을 data.json 하나로 처리하면 단순하지만 취약하다.

파일이 잘못 생성되면 이전 상태를 잃는다.

월별 기준으로 데이터를 확인하기 어렵다.

공개용 데이터와 내부용 데이터가 섞일 위험도 있다.

저장 구조 예시

일반화한 구조는 다음과 같다.

console-data-bucket/
├── latest/data.json
├── monthly/data-YYYY-MM.json
├── public/calendar-YYYY-MM.json
└── audit/YYYY-MM/YYYY-MM-DD/sync-HHMMSS.json

각 경로는 목적이 다르다.

경로 목적
latest/data.json 운영자 화면이 읽는 최신 데이터
monthly/data-YYYY-MM.json 월별 조회와 기록 보존
public/calendar-YYYY-MM.json 공개 화면용 가공 데이터
audit/.../sync-HHMMSS.json 동기화 시점별 백업

이렇게 나누면 같은 원천 데이터에서 여러 읽기 모델을 만들 수 있다.

latest는 화면을 위한 데이터다

latest/data.json은 가장 단순한 읽기 경로다.

운영자 화면은 매번 복잡한 경로를 계산하지 않고 최신 데이터만 읽으면 된다.

장점은 분명하다.

  • 화면 구현이 단순하다.
  • API 응답이 빠르다.
  • 최신 상태를 확인하기 쉽다.

하지만 latest는 원본이 아니다.

원천 데이터는 스프레드시트이고, latest는 그 결과물이다.

이 구분을 문서에 명확히 남겨야 한다. 그렇지 않으면 운영 중 latest 파일을 직접 수정하려는 일이 생긴다.

monthly는 기준 시점을 만든다

운영 업무는 월 단위로 끊어 보는 경우가 많다.

이때 매번 latest에서 월을 필터링할 수도 있지만, 월별 스냅샷을 따로 두면 장점이 있다.

  • 월별 화면이 빠르게 읽을 수 있다.
  • 특정 월의 상태를 보존할 수 있다.
  • 과거 데이터 확인이 쉬워진다.
  • 최신 데이터 변경과 과거 조회를 분리할 수 있다.

예를 들어 monthly/data-2026-05.json은 2026년 5월 기준의 데이터를 담는다.

정확한 파일명은 시스템마다 다르지만, 핵심은 기준 시점을 경로에 포함하는 것이다.

public은 공개용 데이터다

공개 화면이 있다면 내부 데이터와 공개 데이터를 반드시 나눠야 한다.

내부 데이터에는 다음 정보가 들어갈 수 있다.

  • 담당자 메모
  • 내부 상태값
  • 개인정보
  • 운영 판단 정보
  • 공개하면 안 되는 원본 필드

공개용 JSON은 이 정보를 제거한 별도 파일이어야 한다.

화면에서 숨기는 것만으로는 부족하다.

API 응답이나 JSON 파일 자체에 민감 정보가 없어야 한다.

공개용 데이터는 별도 경로에 저장한다.

public/calendar-YYYY-MM.json

이렇게 분리하면 CloudFront 캐시 정책이나 접근 정책도 다르게 둘 수 있다.

audit은 복구를 위한 데이터다

감사 백업은 평소에는 잘 보지 않는다.

하지만 문제가 생겼을 때 중요하다.

예를 들어 다음 상황을 생각해볼 수 있다.

  • 동기화 스크립트가 잘못된 데이터를 생성했다.
  • 운영자가 시트에서 값을 잘못 수정했다.
  • 공개 화면에 예상과 다른 데이터가 노출되었다.
  • latest 파일이 잘못 덮어써졌다.

이때 audit 백업이 있으면 이전 동기화 시점의 데이터를 확인할 수 있다.

감사 백업은 보통 날짜와 시간을 포함한다.

audit/2026-05/2026-05-18/sync-143022.json

파일이 조금 늘어나더라도 운영 안정성 측면에서 가치가 있다.

한 번의 동기화에서 여러 곳에 쓰기

동기화는 보통 한 번 실행될 때 여러 파일을 만든다.

sync 실행
-> latest/data.json 저장
-> monthly/data-YYYY-MM.json 저장
-> public/calendar-YYYY-MM.json 저장
-> audit/YYYY-MM/YYYY-MM-DD/sync-HHMMSS.json 저장

이 구조를 3-way write 또는 multi-write 패턴처럼 볼 수 있다.

주의할 점도 있다.

모든 쓰기가 성공해야 하는가, 일부 실패를 허용할 것인가를 정해야 한다.

예를 들어 audit 백업이 실패했는데 latest만 갱신되면 나중에 추적이 어려워진다.

반대로 public 파일 생성이 실패했는데 내부 latest만 갱신되는 것은 허용할 수 있을지 판단해야 한다.

작은 시스템이라도 이 기준은 문서에 남겨야 한다.

캐시 정책도 다르게 본다

저장 경로가 다르면 캐시 정책도 달라질 수 있다.

  • latest: 짧은 TTL 또는 필요 시 invalidation
  • monthly: 상대적으로 긴 TTL 가능
  • public: 사용자 경험에 맞춰 TTL 조정
  • audit: 직접 화면에서 읽지 않으므로 캐시 중요도 낮음

모든 JSON에 같은 캐시 정책을 적용하면 운영 중 혼란이 생길 수 있다.

데이터의 성격에 따라 TTL을 다르게 보는 것이 좋다.

정리

운영 자동화에서 파일 저장은 단순히 JSON 하나를 만드는 일이 아니다.

최신 조회, 월별 기록, 공개 데이터, 복구 백업은 서로 목적이 다르다.

그래서 저장 경로도 나눠야 한다.

latest
monthly
public
audit

이 네 가지를 나누면 작은 자동화 시스템도 훨씬 운영하기 쉬워진다.

중요한 것은 원천 데이터와 읽기 모델을 구분하는 것이다.

스프레드시트가 원천이고, S3 JSON은 목적별로 가공된 결과물이다.

이 구조를 문서화해두면 데이터가 어디서 왔고, 어디를 수정해야 하며, 문제가 생겼을 때 어디로 돌아가야 하는지 명확해진다.

함께 볼 GitHub 저장소

Next Step 이 글은 StudyDad 작업 루프의 한 조각입니다.

글에서 정리한 생각은 GitHub의 코드와 포트폴리오로 이어지고, 일부는 FamBlend 같은 제품 실험으로 확장됩니다.