01 / 문제
복사한 링크, 코드, 이미지 등을 한번에 확인할 대시보드가 필요해 만든 서비스입니다.
02 / 선택과 실행
개인은 로컬에, 팀 공유 자료는 서버로
개인 보드는 IndexedDB에 저장하고, 팀 자료만 서버로 공유하도록 경계를 나눴습니다. 작업 중 바로 꺼내 쓰는 미니 창도 구현했습니다.
03 / 결과와 배움
개인·팀 보드, 변경분 동기화와 미니 창을 라이브 서비스로 구현했습니다. 많은 정보가 담기는 대시보드인 만큼, 개인 자료의 로컬 저장과 팀 공유 링크의 접근 제어 등 보안을 탄탄히 하려 노력했습니다. 기능 구현 이후에는 실제 사용 흐름을 살펴보고 개선하는 일이 중요하다는 점을 배웠습니다. Google Analytics로 자주 사용하는 기능의 이벤트를 확인하고, 영어 버전 추가 등 사용자의 생산성을 높일 방법을 고민하고 있습니다.
기술 설명과 구현 기록
공개 저장소에 사용된 서비스 대표 이미지입니다.

간단 아키텍처
개인 클립 · 서버 전송 없이 보관
- 01클립 입력개인 코드·메모·민감 정보
- 02IndexedDB브라우저 내부 저장소
- 03대시보드 / PiP작업 중 조회와 활용
팀 공유 · 검증된 요청만 저장
- 01공유 요청공유할 데이터
- 02Next.js APIShare Token 검증
- 03Supabase팀 공유 데이터 저장
고려한 보안적 요소
- 01
로그인 없이 시작하는 개인 보드는 IndexedDB에 저장하고, 기본 동작에서는 저장된 클립을 서버로 전송하지 않습니다.
- 02
팀 보드는 Next.js API를 서버 경계로 두고 Supabase와 연결했습니다. 공유 링크에는 보드 ID와 접근 키를 AES-256-GCM 토큰으로 감쌉니다.
- 03
민감 문자열은 정규식으로 표시해 저장 전 확인하고, 이미지는 PNG·JPEG·WebP·GIF만 허용했습니다. 별도 살균이 필요한 SVG는 MVP 범위에서 제외했습니다.
구현 중 마주한 문제
Vercel에서 발견한 팀 보드 동기화 무한 루프
발생한 상황
Vercel에서 사용자 약 7명 규모에 비해 요청 수와 전송량이 비정상적으로 증가한 것을 발견했습니다. DB를 확인해 팀 보드 쪽 이슈인 것을 확인하고 조회·저장 흐름을 살펴보니, 조회할 때마다 새로 생성되는 암호화된 shareToken을 프론트엔드가 데이터 변경으로 판단하고 있었습니다. 상태 갱신과 useEffect 재실행이 이어지며 전체 클립 GET과 PUT이 반복됐고, 두 API가 각각 약 5,700회 호출됐습니다. base64 이미지까지 매번 전송되면서 전송량은 12.18GB까지 증가했습니다.
바꾼 부분
shareToken을 변경 비교에서 제외하고 기존 토큰을 유지하도록 핫픽스 4774cd2를 배포했습니다. 이후 변경 없는 보드의 전체 PUT도 생략하도록 개선했습니다. 이 경험을 통해 조회 응답의 값이 달라지는 것과 실제 사용자 데이터가 변경되는 것을 구분해야 한다는 점을 배웠습니다.
클립 하나의 수정이 팀 보드 전체 전송으로 이어지는 문제
발생한 상황
무한 루프를 해결한 뒤에도, 클립 하나에 메모를 추가하거나 고정 상태만 바꿔도 팀 보드의 전체 클립을 다시 전송하는 구조가 남아 있었습니다. 수정하지 않은 클립의 base64 이미지까지 포함돼 데이터가 쌓일수록 저장 요청이 커졌습니다. 또한 여러 팀원이 함께 사용할 때 오래된 로컬 데이터를 전체 저장하면 다른 팀원의 변경을 덮어쓸 위험도 있었습니다.
바꾼 부분
추가·수정한 클립 ID와 삭제한 클립 ID를 따로 추적해, 변경된 클립과 삭제 ID만 서버에 보내도록 바꿨습니다. 아직 저장하지 못한 변경 목록은 IndexedDB에도 보관해 새로고침 뒤에도 동기화를 이어갈 수 있도록 했습니다. 서버에서 다른 팀원의 변경을 받아왔을 때는 미처리 로컬 변경이 없으면 바로 반영하고, 로컬 변경이 남아 있으면 갱신 알림을 띄워 사용자가 적용하도록 했습니다. 이 과정에서 동기화는 전송량뿐 아니라 저장되지 않은 사용자의 작업을 보존하는 흐름까지 함께 고려해야 한다는 점을 배웠습니다.
공유 링크만으로 팀 보드를 삭제할 수 있는 문제
발생한 상황
팀 보드는 로그인 없이 공유 링크로 참여할 수 있도록 만들었습니다. 그런데 권한 처리 흐름을 살펴보니, 클립 조회·수정에 사용하는 접근 키로 보드 삭제까지 가능한 구조였습니다. 팀원이 함께 쓰기 위해 전달하는 링크에 전체 보드를 삭제할 권한까지 연결돼 있어, 링크가 유출되거나 참여자가 실수했을 때 피해 범위가 커질 수 있었습니다.
바꾼 부분
팀 생성 시 공유 링크와 별도로 4자리 관리 PIN을 설정하고, 보드 삭제와 PIN 변경 시 서버에서 확인하도록 바꿨습니다. PIN은 원문 대신 무작위 salt를 적용한 scrypt 해시로 저장했습니다. 반복적인 추측 시도를 줄이기 위해 보드와 IP를 기준으로 15분 동안 PIN 확인이 5회 실패하면 추가 시도를 제한했습니다. 다만 실패 횟수는 서버 메모리에 저장하므로, 여러 서버 인스턴스에서도 제한을 일관되게 적용하려면 공용 저장소로 옮겨야 한다는 한계가 남아 있습니다.