정말 우여곡절이 많았던 4차 프로젝트를 끝으로 프로그래머스 데브 코스를 수료하게 되었다. 2차, 3차, 4차 모두 최우수작으로 선정되며 성공적으로 마무리한 것 같아 마음이 뿌듯했고 기분이 정말 좋았다. 팀원들을 잘 만나기도 했지만, 열심히 노력한 내 역할도 컸지 않았을까? 오늘만이라도 자화자찬을 해보고 싶다!
# 프로젝트 개요
평소 우리는 프로젝트나 보고서를 준비할 때 뉴스, 블로그, 논문 등 여러 플랫폼을 오가며 자료를 수집하곤 했다. 하지만 자료가 흩어져 있어 찾기 복잡하고, 정리하고 관리하는 과정도 번거로웠다. 게다가 수집한 자료 간의 연관성을 파악하기 어렵고, 팀원들과 공유하기도 까다로웠다.
여기에 자동화와 AI 기반 분석, 그리고 실시간 협업 기능을 더한다면 어떨까 하는 아이디어가 떠올랐다. 그래서 웹상의 자료를 자동으로 수집·정리하고, 시각화를 통해 인사이트를 제공하며, 팀 단위로 협업할 수 있는 지식 관리 플랫폼을 기획하게 되었다. 지루한 자료 조사 시간을 줄이고 창의적인 업무에 집중할 수 있도록 돕는 것, 그것이 ZoopZoop의 목표였다.
•프로젝트명 : ZOOPZOOP (줍줍)
•개발 기간 : 5주 (2025.09.11 ~ 2025.10.20)
•팀 구성 : 프론트엔드 3명, 백엔드 5명
•기술 스택 : Next.js, React(크롬 확장 프로그램), Husky, Storybook, Liveblocks
•사용 라이브러리 : Zustand, Tanstack-query, Tailwind-CSS, Shadcn
# 기획과 설계 단계
이번 프로젝트에선, 기술적인 깊이를 더하고 싶었다. Next.js와 Tanstack Query의 캐시를 제대로 활용하고, FSD(Feature-Sliced Design) 아키텍처로 확장성 있는 구조를 설계해보자는 목표를 세웠다. 백엔드 팀과는 Jira를 활용해 협업하기로 했다.
가장 고민했던 부분은 캐시 전략과 FSD 구조 설계였다. AWS로 프로젝트를 진행하다 보니 비용 문제도 있고, 리소스를 최대한 아껴야 했다. 실무에서도 캐시 전략이 중요할 것이라 판단했기에 이번 기회에 제대로 다뤄보고 싶었다. FSD 구조는 처음 도입하는 만큼, 기능별로 어떻게 레이어를 나누고 의존성을 관리해야 할지 팀원들과 정말 많은 시간을 할애했다. 백엔드와의 첫 협업이었기에 API 명세를 명확히 정의하고, 서로의 작업 상황을 투명하게 공유할 수 있는 프로세스를 만드는 것도 중요했다.
주요 기능 설계
•개인 아카이브 (웹 자료 개인 저장소)
•공유 아카이브 (팀 단위 자료 공유)
•대시보드 (자료 시각화 및 협업)
•AI 기반 관련 콘텐츠 추천
•크롬 확장 프로그램 (자료 자동 수집)
# 개발 과정
내가 맡은 파트는 크게 네 가지였다. 첫 번째로 Next.js 서버 캐시와 Tanstack Query 클라이언트 캐시 전략을 설계했고, 두 번째로 API 흐름 설계와 공통 에러 처리 로직을 구현했다. 세 번째는 크롬 확장 프로그램 개발을 담당했고, 마지막으로 토큰 관리 및 인증 기능을 맡았다.
프로젝트를 진행하면서 마주한 트러블 슈팅을 정리해 보았다.
1. 이중 캐시 전략
Next.js와 Tanstack Query를 함께 사용하면서 이중 캐시 전략을 활용하고 싶었다. SSR이 필요한 페이지는 Next.js 캐시를 사용하고, 하이드레이션 이후 데이터 변화는 클라이언트 캐시로 관리하여 데이터 패칭을 최소화하는 것이 목표였다.
문제 상황
초기에는 SSR로 데이터를 가져온 후 props로 넘겨 Tanstack Query의 initialData로 설정하는 방식을 사용했다. 하지만 두 가지 문제가 있었다. 첫째, 동일한 데이터임에도 서버 캐시 키(Next fetch의 캐시 키/태그)와 클라이언트 캐시 키(Query key)를 따로 관리해야 해서 복잡했다. 둘째, page.tsx에서 초기 데이터를 가져와 props drilling으로 하위 컴포넌트에 전달하는 방식이 비효율적이게 느껴졌다..
해결 방안
먼저 서버와 클라이언트의 캐시 키를 통합 관리하는 캐시 키 객체를 만들었다. 그리고 Tanstack Query의 prefetching 기능을 활용하기로 했다. page.tsx에서 서버 API를 호출해 데이터를 가져와 queryClient에 query key와 함께 저장하고, hydrateBoundary로 직렬화하여 하위 컴포넌트를 감쌌다. 이렇게 하면 하위 컴포넌트에서는 prefetch된 querykey로 서버에서 캐시된 데이터를 바로 불러올 수 있게 되었다. props drilling 없이 서버와 클라이언트 캐시를 일관되게 관리할 수 있게 되었고, 코드도 훨씬 깔끔해졌다.
2. 크롬 확장 프로그램 스타일 격리
크롬 확장 프로그램의 content script를 개발하면서 React 컴포넌트를 웹 페이지에 주입해야 했다. content script는 웹페이지의 DOM에 직접 삽입되기 때문에 React로 구현한 UI를 사용자가 보는 페이지에 렌더링할 수 있었다.
문제 상황
호스트 페이지의 전역 CSS가 React 컴포넌트 스타일에 영향을 미쳐 버튼 UI가 깨지고 의도하지 않은 스타일이 적용되었다. 원인은 스타일 스코프가 공유된다는 점이었다. React는 기본적으로 전역 CSS를 격리하지 않으며, content script가 삽입된 DOM은 페이지의 스타일 시트와 충돌했다. 외부 CSS가 컴포넌트 내부까지 침투하면서 UI 일관성이 완전히 무너졌다.
해결 방안
Shadow DOM을 사용하기로 했다. Shadow DOM을 통해 독립된 DOM 트리를 생성하고, 그 내부에 React 컴포넌트를 렌더링했다. 이렇게 하면 외부 스타일로부터 완전히 분리된 환경을 만들 수 있었다. 스타일이 캡슐화되면서 content script의 UI가 어떤 페이지에서도 동일한 형태로 유지되었고, 호스트 페이지의 CSS와 충돌 없이 안정적으로 작동하게 되었다.
# 결과
2차, 3차에 이어 4차 프로젝트도 최우수작으로 선정되며 성공적으로 마무리했다. FSD 아키텍처와 통신 로직의 구조화, 공통 에러 처리, 공통 컴포넌트의 적극적 활용으로 3명의 프론트엔드 개발자가 동일한 구조와 흐름으로 개발할 수 있었다. 이중 캐시 전략을 통해 동일한 데이터에 대한 중복 요청을 제거하고, SSR 캐시와 클라이언트 캐시를 효율적으로 활용하면서 사용자에게 빠른 피드백을 제공할 수 있었다. 특히 AWS 리소스 사용을 최소화하면서도 원활한 사용자 경험을 유지할 수 있었다는 점이 의미 있었다. 백엔드 팀과의 첫 협업에서도 Jira를 활용한 애자일 방식으로 원활하게 소통하며 프로젝트를 완수했다.
# 배운점 과 성장
우리 팀은 팀 빌딩 과정에서 약간의 이슈가 있었다. 백엔드 팀과는 처음 보는 자리였고, 여러 팀과 소통하며 함께할 팀을 찾는 중에 의사소통 문제로 서로 기분이 상한 채로 시작하게 되었다. 하지만 팀 빌딩이 끝난 후 첫 회의에서 곧바로 오해를 풀었고, 결국 어떤 팀보다 끈끈한 팀워크를 보여주는 팀으로 거듭났다. 이러한 팀워크 덕분에 좋은 결과를 얻어낼 수 있었다.
팀원들과는 정말 5주 동안 밤낮없이 함께 밤을 새가며 기획했던 모든 기능을 구현해냈다. 처음 해보는 기술과 아키텍처로 정신없었지만, 끊임없이 소통하며 우리 팀만의 아키텍처와 컨벤션을 만들어냈다. 이 과정이 생각보다 오래 걸렸지만, 그만큼 성장을 할 수 있는 계기가 되지 않았을까 싶다.
# 마치며
5개월간의 데브 코스가 4차 프로젝트를 끝으로 마무리되었다. 이전 프로젝트에서도 많은 것을 배웠지만, 이번 4차 프로젝트는 기술적 도전이 가장 많았다. Next.js, Tanstack Query, FSD 등 수업 시간에 배운 것은 아니지만, 마지막 프로젝트인 만큼 이것저것 많이 도전해보고 싶었다.
처음 프로젝트를 설계할 때는 새로 배운 것들 때문에 머리가 너무 아프고 시간도 많이 걸렸다. 하지만 결국 우리만의 스타일을 만들어냈고, 이를 적극적으로 활용하며 내 것으로 만들 수 있었다. 2차, 3차에 이어 이번에도 최우수작으로 선정되면서 나 자신을 증명할 수 있는 기간이었다고 생각한다.
📑 ZOOPZOOP 체험해보기
저희 서비스 ZOOPZOOP은 여기서 직접 사용해 볼 수 있습니다.
웹 세상에 흩어져있는 데이터들을 손쉽게 아키이빙하며, 시각적으로 아이디어를 확장하고 공유해보세요!