메뉴 취합하는 막내를 위해 Day2

개발공부를해보자·2026년 2월 22일

프로젝트

목록 보기
3/4

동기 : 지인용에서 누구나 쓸 수 있는 서비스로

  • Day1에서 기본 기능은 다 만들었다. 투표, 사진, 가격, 그룹까지.
  • 그런데 이걸 지인이 아닌 다른 사람들도 쓸 수 있게 하려면 문제가 있었다.
    • 홈에 들어가면 다른 사람이 만든 투표방이 다 보인다. 내 방만 보고 싶은데?
    • 누군가 만든 방에 아무나 들어가서 장난칠 수도 있고, 오래된 데이터가 계속 쌓인다.
    • 사진을 원본 그대로 올리면 용량이 어마어마하다. 누가 5MB짜리 사진 10장 올리면...
  • 그래서 오늘의 목표는 "모르는 사람도 편하게 쓸 수 있는 구조"로 바꾸는 것이었다.

큰 흐름

1. 이미지 자동 압축

  • 사용자가 사진을 올리면 업로드 전에 자동으로 압축된다.
  • Canvas API를 이용해서 최대 1920×1920px로 리사이즈하고, JPEG 품질 70%로 변환한다.
  • 500KB 이하의 작은 파일은 굳이 압축하지 않고 그대로 올린다.
  • 3~5MB짜리 사진이 300~500KB 수준으로 줄어드니까 Storage 용량이 확 줄었다.
  • 검색 키워드 : Canvas API, toBlob, image resize, JPEG compression

2. 공개 서비스 모드 전환

  • 기존에는 홈에 들어가면 Firestore에서 전체 그룹 목록을 가져와서 보여줬다.
  • 이제는 그걸 없애고, 두 가지만 보여준다.
    • "🗳️ 새 투표 만들기" 버튼 → 방 이름 입력하면 바로 생성
    • "📋 내 투표방" 목록 → 내가 만들거나 방문한 방만 표시
  • "내 투표방"은 Firestore가 아니라 localStorage에 저장한다. 최대 20개까지.
  • 방을 만들면 자동 저장되고, 공유 링크로 방문해도 자동 저장된다.
  • 검색 키워드 : localStorage, JSON.parse/stringify

3. 링크 공유

  • 투표 페이지 헤더에 🔗 공유 버튼을 추가했다.
  • 누르면 현재 방 URL이 클립보드에 복사된다.
  • 친구한테 카톡으로 링크 보내면 같은 방에서 바로 투표 가능.
  • 이게 핵심이다. 방을 만들고 → 링크를 공유하고 → 각자 투표하고 → 끝.
  • 검색 키워드 : navigator.clipboard.writeText, window.location.href

4. 자동 만료 (24시간)

  • 방을 만들면 lastUsedAt 타임스탬프가 찍힌다.
  • 투표하거나, 사진 올리거나, 방에 접속할 때마다 이 시각이 갱신된다.
  • 누군가 방에 들어왔을 때 마지막 활동으로부터 24시간이 지났으면?
    • 투표 데이터, 사진, 그룹 문서를 전부 자동 삭제하고 홈으로 보낸다.
  • 서버(Cloud Functions) 없이 클라이언트 코드만으로 구현했다.
  • 검색 키워드 : Firestore serverTimestamp, Timestamp.toMillis, deleteDoc, deleteObject

조금 헤맸던 부분들

1. localStorage와 Firestore의 싱크

  • "내 투표방" 목록은 localStorage에 저장하는데, 방이 만료되어 Firestore에서 삭제되면 localStorage에는 남아있다.
  • 그래서 방에 접속했을 때 만료 확인 후 localStorage에서도 같이 지워주는 처리를 추가했다.
  • 클라이언트 저장소와 서버 데이터의 정합성을 맞추는 게 은근히 신경 쓸 부분이 많다.

2. 만료 체크 타이밍

  • 자동 만료를 서버 없이 구현하려면 "누군가 방에 접속하는 시점"에서만 체크할 수 있다.
  • 아무도 안 들어오면 데이터는 24시간이 지나도 Firestore에 남아있긴 하다.
  • 하지만 다음에 누군가 접속하면 그때 삭제되니까, 실질적으로는 문제없다.
  • 완벽하게 하려면 Cloud Functions의 스케줄러를 써야 하는데, 무료 플랜에서는 못 쓰니까 이 정도면 충분하다고 판단했다.

3. 이미지 압축과 원본 보존 사이

  • 처음에는 모든 이미지를 무조건 압축했는데, 이미 작은 파일까지 압축하면 오히려 용량이 커지는 경우가 있었다.
  • 그래서 500KB 이하는 압축을 건너뛰도록 조건을 추가했다.
  • Canvas API로 JPEG 변환하면 PNG의 투명 배경이 사라지는 점도 알아두면 좋다. 메뉴판 사진은 대부분 JPG라 상관없었지만.

오늘 추가된 기능 정리

기능설명
이미지 자동 압축업로드 전 Canvas API로 리사이즈 + JPEG 70% 압축
홈페이지 리뉴얼"새 투표 만들기" + "내 투표방" (localStorage 기반)
링크 공유🔗 버튼으로 방 URL 클립보드 복사
자동 만료24시간 미사용 시 방 자동 삭제

현재까지의 전체 기능

기능설명Day
실시간 투표이름 + 메뉴 입력 → 모든 사용자 화면에 즉시 반영1
빠른 참여기존 메뉴에 "+ 참여" 버튼으로 바로 합류1
메뉴 사진다중 업로드, 캐러셀, 전체화면 모달, 개별 삭제1
가격 & 총 금액메뉴별 가격 입력 → 소계, 총 예상 금액 자동 계산1
그룹여러 팀이 독립 그룹으로 동시 사용 가능1
전체 초기화투표 + 사진 한 번에 리셋1
이미지 자동 압축큰 사진 자동 리사이즈 + JPEG 압축2
공개 서비스 모드방 만들기 + 내 투표방 + 링크 공유2
자동 만료24시간 미사용 방 자동 삭제2

기술 스택 (변경 없음)

분류기술
프론트엔드React 19, CSS (순수)
라우팅react-router-dom
백엔드/DBFirebase Firestore (실시간 NoSQL)
파일 저장Firebase Storage
배포Firebase Hosting
새로 사용Canvas API (이미지 압축), localStorage (방 목록)

결과

👉 https://vote-eat.web.app

  • 이제 링크를 공유하면 누구나 방을 만들고 투표할 수 있다.
  • 방은 24시간 후 자동으로 사라지니까 데이터가 쌓이는 걱정도 없다.
  • Day1에서는 "일단 돌아가게" 만들었고, Day2에서는 "남한테 보여줄 수 있게" 다듬었다.
  • 다음에 하고 싶은 것들 : 여러 그룹 결과 합산 뷰, 투표 마감 기능, 결과 차트 시각화, 1인 1투표 제한.
    텍스트
profile
개발 공부하는 30대 비전공자 직장인

0개의 댓글