• Home
  • About
  • Notes
  • Projects
<- Back to projects
projectsbackendfrontend9/25/2025

kmem: 가족을 위한 사진 관리 시스템

부모님의 폰 용량 문제를 해결하기 위해 만든 개인 사진/동영상 관리 시스템

문제 상황

부모님께서 폰에 사진과 동영상을 많이 저장하시다가 용량이 꽉 차서 정리를 시도하셨는데, 그 과정에서 소중한 사진들을 실수로 삭제하셨다. 상심을 많이 하시는 모습을 보고 구글 클라우드 같은 서비스를 권해드렸지만, 새로운 서비스 사용법을 배우는 것을 부담스러워하셨다.j

"아들이 조악하게나마 만들어두면 자식이 만든 건데 쓰는 시늉이라도 하시지 않을까?" 하는 마음으로 시작한 프로젝트다.

기술 스택

Backend

  • Go + Gin Framework
  • PostgreSQL
  • FFmpeg: 비디오 썸네일 생성
  • JWT: 토큰 기반 인증

Frontend

  • React + TypeScript
  • TailwindCSS

Infrastructure

  • Docker + Docker Compose
  • Ubuntu ZFS: 데이터 백업과 성능

핵심 기능

중복 파일 감지

  • SHA256 해싱을 통한 중복 파일 자동 감지
  • 파일 업로드 시 스트리밍 방식으로 해시 계산 (메모리 효율성)
  • 중복 파일 업로드 시 기존 파일 참조로 저장 공간 절약

썸네일 자동 생성

  • 이미지: Go imaging 라이브러리로 3가지 크기 생성 (150x150, 300x300, 800x600)
  • 비디오: FFmpeg로 영상 길이의 30% 지점에서 썸네일 추출
  • 백그라운드 워커풀(16개 고루틴)로 처리하여 업로드 응답 속도 보장

파일 관리

  • 소프트 삭제: 실제 파일은 30일 후 자동 정리
  • 파일명 변경, 검색, 필터링 (이미지/비디오 구분)
  • 무한 스크롤 방식의 갤러리 인터페이스

캐싱 시스템

  • TTL + LRU 조합의 인메모리 캐시 직접 구현
  • 사용자별 갤러리 캐시 무효화
  • sync.Map으로 동시성 처리

기술적 선택 이유

Go 선택

솔직히 내가 편해서 선택했다. Go를 좋아하는 이유는 동시성 모델이 잘 설계되어 있어서 쓰기 편하기 때문이다. 특히 고루틴을 활용한 백그라운드 작업 처리가 간편했다.

PostgreSQL vs SQLite

이전에 SQLite 사용 시 파일 락 문제를 겪었고, 혼자 쓰는 게 아니라 부모님, 나, 동생까지 4인 가족이 동시에 사용할 가능성을 고려해서 동시 접근에 더 안정적인 PostgreSQL을 선택했다.

SHA256 해싱

처음에는 속도 때문에 MD5를 시도했었는데 혹시나 충돌날까 봐 SHA256으로 바꿨다. 파일 첫 몇 바이트만 해싱하는 것도 고려했지만 결국 정확성을 위해 전체 파일을 해싱했다.

워커 풀 크기

4인 가족 기준으로 인당 4개 스레드면 충분할 것이라고 임의로 16개로 설정했다. 사용하면서 부족하면 늘리고 과하면 줄일 계획이었다.

Ubuntu ZFS

속도와 백업 기능을 위해 선택했다. btrfs의 스냅샷 기능도 고려했지만 ZFS가 더 빠르다는 정보를 바탕으로 결정했다. 원래 BSD 계열 OS 사용을 고려했으나 운영 체제 자체가 익숙하지 않아 Ubuntu ZFS로 타협했다. (당시 Ubuntu ZFS는 완벽 지원이 아닌 실험 단계였음)

FFmpeg

비디오 썸네일 생성에 다른 방법을 몰라서 별 생각 없이 사용했다.

아키텍처 설계

워커 풀 패턴

type Queue struct {
    ctx     context.Context
    list    chan item
    workers int  // 16개 고루틴
}

파일 업로드 플로우

  1. 파일명 인코딩/검증 (Base64 + URL encoding)
  2. 스트리밍으로 파일 저장하면서 동시에 SHA256 해시 계산
  3. 트랜잭션으로 중복 체크 및 DB 저장
  4. 백그라운드에서 썸네일 생성 대기열에 추가

개발 과정에서 고민한 점들

동시성 문제

여러 명이 동시에 같은 파일을 업로드할 때 중복 감지가 제대로 동작할지 고민했다. 트랜잭션을 사용해서 중복 체크와 DB 저장을 원자적으로 처리하도록 설계했다.

메모리 사용량

대용량 파일 처리 시 메모리에 전체 파일을 로드하면 문제가 될 것 같아서 스트리밍 방식으로 처리하도록 했다.

썸네일 생성 타이밍

업로드 직후 바로 썸네일을 생성하면 응답이 늦어질 것 같아서 백그라운드 워커로 분리했다.

테스트해본 내용

중복 파일 감지

같은 이미지 파일을 여러 번 업로드해서 정말로 중복 감지가 되는지 확인했다. 파일명을 바꿔서 업로드해도 해시값이 같으면 중복으로 인식하는 것을 확인했다.

동시 업로드

로컬에서 브라우저 탭을 여러 개 열고 동시에 파일을 업로드해봤다. 큰 문제없이 처리되는 것을 확인했다.

썸네일 생성

다양한 형식의 이미지와 비디오 파일로 썸네일 생성이 정상 동작하는지 테스트했다.

현재 상태와 한계

잘 구현된 부분

  • 중복 파일 감지가 정확하게 동작함
  • 백그라운드 썸네일 생성으로 업로드 응답 속도 확보
  • 소프트 삭제로 실수로 파일 삭제해도 복구 가능
  • 기본적인 갤러리 기능(검색, 필터링, 무한 스크롤)

구조적 한계

  • 모놀리식 구조: 기능이 추가되면서 코드가 한 곳에 집중되는 경향
  • 에러 처리: 일관성 있는 에러 처리 패턴 부족
  • 테스트: 단위 테스트 부족으로 리팩토링 부담
  • 설정 관리: 하드코딩된 값들 (워커 수, 캐시 TTL 등)

개선이 필요한 부분

  • 코드를 기능별로 더 명확하게 분리 (파일 처리, 사용자 인증, 썸네일 생성 등)
  • 테스트 코드 작성으로 리팩토링 시 안정성 확보
  • 설정 파일로 워커 수, 캐시 TTL 등을 동적으로 조정 가능하게
  • 에러 발생 시 일관된 응답 형태로 처리

현재 상황

프로토타입 수준에서 기본 기능은 구현되었으나 현재는 사용하지 않고 있다. 구조를 크게 고민하지 않고 만들다 보니 코드가 복잡해져서 유지보수가 어려워진 상황이다.

하지만 이 프로젝트를 통해 실제 문제를 기술로 해결하는 경험과 백엔드 시스템 설계, 동시성 처리, 미디어 파일 처리 등 다양한 기술적 경험을 쌓을 수 있었다.

GitHub Repository: https://github.com/kangko05/kmem