Next.js + Capacitor로 영어 단어 앱 만들어 보았습니다!
제목: Next.js + Capacitor로 영어 단어 앱 만들어 iOS/Android 출시했습니다
안녕하세요.
지하철에서 손잡이 잡고 폰을 한 손으로 쓸 때도
영어 단어를 짧게 외울 수 있는 앱이 있으면 좋겠다고 생각해서 직접 만들어봤습니다.
iOS는 한손공부, Android는 한공이라는 이름으로 양쪽 스토어에 출시되어 있습니다.
스토어별 검색명은 다르지만 같은 앱입니다.
> 컨셉
출퇴근길이나 쉬는 시간에
한 손으로 카드 넘기듯 영어 단어를 외우는 앱입니다.
단어 카드를 보고 뜻을 확인한 뒤,
좌우 스와이프 한 번으로 알아요 / 몰라요만 분류하면 됩니다.
> 기술 스택
Next.js 14 App Router, SSG export
Capacitor 기반 iOS/Android 네이티브 빌드
Supabase Auth + Postgres로 로그인/학습 기록 동기화
비로그인 사용자는 localStorage 전용, 로그인 시 Supabase 동기화
Zustand 클라이언트 상태 관리
SM-2 알고리즘을 이진 응답으로 단순화한 SRS
SRS 알고리즘 단순화
원래 SM-2는 1~5점 응답을 기반으로 하지만,
한 손 조작에 맞추기 위해 알아요 / 몰라요 이진 응답으로 단순화했습니다.
구현은 대략 이런 방식입니다.
- 정답: repetitions++, ease_factor += 0.1, 간격 1 → 3 → n × EF일
- 오답: repetitions = 0, ease_factor -= 0.3, 간격 1일
- 마스터 조건: 2연속 정답
- ease_factor 범위: [1.3, 4.0]
이론적인 학습 효율만 보면 손해가 있을 수 있지만,
이 앱에서는 “매일 켜기 쉬운 단순함”이 더 중요하다고 판단했습니다.
> 만들면서 어려웠던 점
SSG + trailingSlash
Capacitor WebView에서 라우팅이 깨지는 문제가 있어서
next.config.js에 trailingSlash: true를 적용하고, 내부 Link href를 모두 슬래시로 끝나게 통일했습니다.
localStorage SSR 가드 하이드레이션 불일치 때문에 모든 localStorage 접근에 typeof window 체크를 넣고,
useEffect와 로딩 상태를 통해 마운트 이후 렌더링되도록 처리했습니다.
localStorage와 Supabase 동기화
비로그인 사용자는 localStorage만 사용하고, 로그인 사용자는 Supabase와
학습 기록을 동기화하는 구조로 만들었습니다.
이 과정에서 기존 로컬 데이터를 언제 서버로 올릴지, 서버에 이미 데이터가 있을 때 로컬 데이터를 어떻게 복원할지 정하는 부분이 까다로웠는데, 결국 "DB 우선" 정책으로 정리했습니다.
로그인 시 DB에 데이터가 있으면 로컬을 덮어쓰고, DB가 비어 있으면 로컬을 업로드하는 방식입니다.
카드 3D flip / swipe UX
카드 플립 애니메이션에서 perspective, backface-visibility 쪽이 Tailwind 클래스만으로는 안정적이지 않아서 일부는 인라인 style로 처리했습니다.
> 스토어 출시 준비
실제 출시 단계에서는 코드 외에도 개인정보처리방침, 회원탈퇴 안내, 스크린샷, 앱 설명, 권한 설명 같은 메타데이터 작업이 생각보다 오래 걸렸습니다.
> 주요 기능
좌우 스와이프로 알아요 / 몰라요 분류
모르는 단어 중심 반복 복습
스트릭, XP, 레벨, 뱃지 기반 학습 동기부여
시험대비, 일상, 비즈니스, 트렌드 단어장 제공
> ps.. 피드백 받고 싶은 부분
혼자 만들다 보니 객관적으로 잘 안 보이는 부분이 많습니다.
첫 화면에서 5초 안에 뭘 해야 할지 보이는지
카드 학습 흐름이 자연스러운지
스토어 설명/스크린샷이 설치하고 싶게 보이는지
개발자분들은 Capacitor + Next.js SSG 조합의 트레이드오프를 어떻게 보고 계신지 등등..
스토어 검색명은 아래와 같습니다.
iOS 앱스토어: 한손공부
Android 플레이스토어: 한공
앱 내에서도 메일을 통해 피드백주실 수 있도록 창구를 만들어두었습니다.
부족한 점 솔직하게 말씀해주시면 다음 빌드에 반영하겠습니다.
부정적인 피드백일수록 더 도움이 됩니다.
