
최근에 아티워크가 새 단장을 마치고 리뉴얼 오픈을 했습니다!
아티워크는 작가의 작업 과정을 기록하고, 전시·공모 일정을 한눈에 확인할 수 있는 앱입니다.
현재 App Store, Google Play에 올라가 있으니, 궁금하신 분들은 한번 다운받아 사용해보시면 좋겠습니다.
이번 글에서는 개발하면서 마주쳤던 예기치 못한 문제 3가지와, 이를 어떻게 발견하고 해결했는지를 정리해 보려 합니다.
달력 화면에는 두 가지 제스처가 공존합니다. 위아래로 스크롤 하여 달력의 확장 영역을 탐색하고, 좌우로 스와이프 시, 월 전환을 합니다. 그런데 손으로 하는 제스처다 보니 정확히 수직, 수평으로만 움직이지 않습니다. 두 방향이 동시에 인식되면서, 의도와 달리 달력이 대각선으로 끌려가는 현상이 생겼습니다.
원인은 세로 스크롤과 좌우 월 전환 제스처가 경쟁 상태(race condition)에 놓인 것이었습니다. 그래서 제스처에 우선순위를 부여하는 로직을 직접 구현했습니다.(react-native-gesture-handler)
if (type === 'month') {
panGesture = panGesture.activeOffsetX([-6, 6]).failOffsetY([-24, 24]);
}
즉, 특정 방향 이동량이 임계값을 넘으면 해당 방향 스크롤에 우선권 부여하여 사용자가 원하는 방향으로 이동하게끔 수정했습니다.
작업 사진을 등록하는 과정은 아래와 같이 긴 과정을 거칩니다.
사진 촬영 → 캡션 입력 → signed URL 발급 → S3 업로드 → picture/caption API 호출 → 홈 탭으로 이동
업로드 파이프라인이 길고 순차적으로 실행되다 보니 사용자가 작업 사진 등록을 기다리는 시간이 길었습니다.
홈 화면에서는 이미 스켈레톤 UI가 적용돼 있다는 점에 착안했습니다. 사용자를 먼저 홈으로 이동시키고, 업로드는 백그라운드에서 처리하는 방식입니다.
다만 한 가지를 고려하지 않았습니다. 사용자가 빠르게 홈 화면으로 이동을 했지만, 제대로 업로드가 완료됐는지 모릅니다. 그래서 전역 업로드 토스트를 만들어 진행 중·실패 상태를 앱 하단에 항상 노출했습니다.
결과적으로 즉시 화면을 복귀시켜 체감 대기 시간을 줄이고, 진행 상황을 한눈에 보여주면서 중복 제출까지 막을 수 있었습니다.

미술 달력 탭에 진입하면 전시 공모 프로그램, 찜 목록, 광고 등 다양한 API를 호출합니다. 그래서 달력 프레임은 먼저 떠도, 그 안을 채우는 데이터가 한 박자 늦게 노출되는 현상이 있었습니다.
이를 React Query의 prefetch로 해결했습니다. 로그인.온보딩 완료 직후 usePrefetchProgramCalendar로 React Query 캐시에 선적재하고, 탭 버튼을 누르는 시점에도 한 번 더 호출해 최신 데이터를 보장했습니다.
이 조건을 통해서 “메인 탭(작업 달력 홈)에 정상 진입한 사용자”일 때만 백그라운드 prefetch를 돌렸습니다.
// _layout.tsx
// 로그인을 한, 작업 데이터를 불러오는 중이 아닌, 작업이 하나 이상 있을 때
// OAuth 가입자가 첫 작업 만든 뒤 약관 동의 화면에 있을 때 prefetch 동작
const canPrefetchProgram = !!session && !isTasksLoading && !!tasks && tasks.length > 0 && !needsOAuthPostTaskTerms;
usePrefetchProgramCalendar(canPrefetchProgram);
// prefetchProgramCalendar.ts
// 미술달력 탭 진입 전 contests·ads(detail)·pin·programs 데이터를 React Query 캐시에 적재
export function prefetchProgramCalendarQueries(...) {
return Promise.all([
queryClient.prefetchQuery({ ... '/contests' ... }),
queryClient.prefetchQuery({ ... '/ads' placement: 'detail' ... }),
queryClient.prefetchQuery({ ... '/contests/pin' ... }),
queryClient.prefetchQuery({ ... '/programs' ... }),
queryClient.prefetchQuery({ ... '/programs/pin' ... }),
]);
}

3가지 모두 개발을 하며 "동작은 하지만, 사용자 입장에서 생각했을때 이런 부분은 불편하지 않을까?" 생각하며 개선할 점을 찾았습니다.
수직, 수평 제스처 동작을 점검하면서 웹과는 다른 모바일만의 인터랙션을 경험할 수 있었고, 업로드의 백그라운드 처리와 데이터 처리 타이밍 문제까지 차근차근 들여다볼 수 있었던 좋은 시간이었습니다.