
커플·가족 생활 앱 「우리집」 개발기 — Expo · Supabase · App Store
일정, 가계부, 디데이를 같이 쓰는 모바일 앱 우리집을 만들고 스토어 올리는 과정까지 정리했음.
1. 무엇을 만들었나
우리집은 커플·가족이 일상을 같이 관리하는 앱이다.
- 공유 캘린더(일정) — 반복, 알림, 양력/음력, 사진
- 공유 가계부 — 수입/지출, 카테고리, 반복
- 디데이
- 가족 초대·연결, 프로필, 고객지원(공지/FAQ/문의), 회원탈퇴
타깃은 한국 사용자다. UI 문구는 한국어로 하드코딩했고, 공휴일은 공공데이터 API를 사용했음.
식별 정보:
| 항목 | 값 |
|------|-----|
| 앱 이름 | 우리집 |
| Expo | SDK 54 |
| React Native | 0.81.5 |
| 백엔드 | Supabase (Auth, Postgres, Realtime, Storage, Edge Functions) |
2. 기술 스택
클라이언트
| 분류 | 라이브러리 | 용도 |
|---|---|---|
| 프레임워크 | Expo ~54, React 19, React Native 0.81 | 앱 런타임 |
| 라우팅 | expo-router ~6 | 파일 기반 네비게이션 |
| 백엔드 SDK | @supabase/supabase-js | Auth / DB / Realtime |
| 로컬 저장 | @react-native-async-storage/async-storage | 세션·공휴일 캐시 |
| 제스처·애니메이션 | react-native-gesture-handler, reanimated, worklets | 스와이프 캘린더, 모달 등 |
| 화면 구조 | react-native-screens, safe-area-context | 네이티브 스택·세이프에리어 |
| OAuth | expo-auth-session, expo-web-browser | Google 로그인 |
| Apple | expo-apple-authentication | Sign in with Apple (심사 대응) |
| 알림 | expo-notifications | 일정 리마인더 |
| 미디어 | expo-image-picker | 일정 사진 |
| 입력 | @react-native-community/datetimepicker, @react-native-picker/picker, wheel-picker | 날짜·시간·반복 |
| 음력 | korean-lunar-calendar | 음력 일정 |
| 빌드 | expo-build-properties, EAS Build/Submit | iOS 스토어 배포 |
| 패치 | patch-package | RN 0.81 TurboModule 크래시 우회 |
서버 (Supabase)
- Auth: 이메일, Google, Apple
- Postgres + RLS: household 단위 데이터 격리
- Realtime: 일정·가계부·디데이·멤버십 변경 동기화
- Storage: household 사진
- Edge Functions (Deno) + Resend: 인증메일, 초대메일, 계정/탈퇴 메일, 비밀번호 재설정, 공휴일 프록시
3. 코드 구성
대략적인 디렉터리 역할은 다음과 같다.
app/ # expo-router 화면 (파일 = 라우트)
contexts/ # Auth, AppData, Profile, Toast
services/ # Supabase·OAuth·메일·알림 API 래퍼
components/ # 화면별 UI
constants/ # 테마, 카테고리, household 정책 등
lib/supabase.ts # 클라이언트 싱글톤
hooks/ # 새로고침 등
supabase/
schema.sql
migrations/
functions/ # Edge Functions
상태 관리
전역 상태는 Context로 나눴다.
AuthContext
세션, 프로필, household 멤버(최대 4명), 초대/링크 요청, 가입·로그인·탈퇴, Realtime으로 멤버십 갱신
AppDataContext
calendar_events, ledger_items, dday_items, ledger_categories CRUD
household 기준으로 fetch하고 Realtime으로 상대방 변경을 반영, 토스트로 알림
ProfileContext / ToastContext
프로필 UI·전역 토스트
비즈니스 로직은 services/*에 두고 Context는 조합·구독에 집중했다.
patches/ # react-native 패치
plugins/ # Expo config plugin (Xcode 26 fmt 우회)
docs/ # release / dev-log 핸드오프
4. 페이지(화면)별 기능
인증 — app/(auth)/
| 경로 | 기능 |
|---|---|
welcome | 이메일 가입, Google, Apple 진입 |
login | 이메일 로그인 |
signup/email | 이메일 인증코드 → 프로필 → 혼자/가족과 쓰기 |
signup/google, signup/apple | 소셜 이후 온보딩(닉네임·사용 방식) |
forgot-password, reset-password | 비밀번호 재설정 (Edge Function) |
find-account | 계정 찾기 |
| 가입 시 혼자 쓸게요 / 가족과 쓸게요를 고른다. | |
| 가족과 쓰기면 초대 메일 또는 상대 이메일을 받아 가족에 합류·병합한다. |
메인 탭 — app/(tabs)/
| 탭 | 파일 | 기능 |
|---|---|---|
| 홈 | index | 날짜 스트립, 가계 요약, 오늘 일정, 퀵액션, Expandable FAB(일정/가계/디데이 추가) |
| 일정 | calendar | 월 캘린더, 공휴일·일요일 강조, 일자 상세 시트, 스와이프 월 이동 |
| 디데이 | dday | 디데이 목록·카드·액션 메뉴 |
| 가계부 | ledger | 수입/지출 목록, 카테고리 |
| 마이 | my | 프로필, 메뉴(초대·설정·지원), 버전 |
홈화면
일정 화면
디데이 화면
가계부 화면
마이페이지 화면
기능 모달/스택
| 경로 | 기능 |
|---|---|
schedule/create, [id], edit | 일정 CRUD. 대상(나/상대/우리), 종일, 반복, 색, 리마인더, 양·음력, 사진, 메모 |
ledger/create, [id], edit | 가계부 CRUD, 카테고리, 반복 |
dday/create, edit | 디데이 CRUD |
invite | 가족 초대 |
profile/* | 닉네임·비밀번호 변경 |
support/* | 공지, FAQ, 약관, 문의 |
withdraw | 탈퇴 + 설문 → 관리자 메일 |
일정·가계 작성 UI는 휠 피커·멀티데이트 캘린더 등 커스텀 컴포넌트를 components/schedule, components/ledger에 모았다. |
5. 백엔드 설계 요약
Household
핵심 단위는 household다.
- 가입 시
ensure_personal_household로 개인 가구 생성 - 초대·수락 시 초대자 household로 병합 (
merge_households) - 멤버 상한 4명
- 나가기/탈퇴 시 데이터 정책(남길지·지울지)을 migration으로 정의
앱 데이터 테이블은 대체로household_id로 묶이고, RLS로 “내 household만” 접근한다.
Edge Functions
| 함수 | 역할 |
|---|---|
send-verification-email | 가입·인증 코드 (Resend) |
send-invitation-email | 가족 초대 |
send-account-email | 환영/탈퇴 관련 메일 |
reset-password | 비밀번호 재설정 |
get-holidays | data.go.kr 특일 API 프록시 |
| 시크릿은 Supabase secrets에 두고, 앱에는 anon key만 넣는다. |
Realtime
calendar_events, ledger_items, dday_items, ledger_categories, household_members 등을 구독해 가족이 동시에 수정해도 목록이 갱신되게 했다.
6. 로컬 개발
npm install
# .env 에 EXPO_PUBLIC_SUPABASE_URL / ANON_KEY
npx expo start
# 네이티브 모듈 변경 시
npx expo run:ios
npx expo run:android
os/, android/는 gitignore다. EAS는 app.json 기준으로 클라우드에서 prebuild한다.
로컬에서 Apple 로그인·알림·태블릿 설정을 검증할 때는 expo run:ios가 필요하다.
Supabase는 schema.sql + migrations/*.sql을 SQL Editor 또는 CLI로 적용하고, Edge Function을 deploy한다.
7. 배포 방식 (EAS → App Store)
버전은 app.json의 expo.version(마케팅 버전)과 ios.buildNumber(빌드 번호)로 관리한다.
eas.json의 appVersionSource: local이라 로컬 app.json이 기준이다.
환경 변수
로컬 .env만 있으면 EAS production 빌드에는 값이 안 들어간다.
스토어 바이너리에 Supabase URL/키가 비면 런치·인증이 깨질 수 있어, Expo 대시보드 또는 CLI로 production env를 등록했다.
npx eas-cli env:create --environment production --name EXPO_PUBLIC_SUPABASE_URL ...
npx eas-cli env:create --environment production --name EXPO_PUBLIC_SUPABASE_ANON_KEY ...
빌드·제출
npx eas-cli build --platform ios --profile production --non-interactive
npx eas-cli submit --platform ios --latest --profile production --non-interactive
eas.json submit 프로필에 App Store Connect App ID를 넣어 두었다.
같은 마케팅 버전으로 다시 올리면 buildNumber만 올리고, 새 스토어 버전이면 version을 올린다.
예: 1.0.1 (build 4) 핫픽스 → 1.0.2 (build 1) 기능/디자인 업데이트.
Android는 preview 프로필로 APK, production으로 AAB를 만들 수 있게 설정해 두었다. 현재 스토어 포커스는 iOS다.
App Store Connect 쪽
바이너리 업로드 후 Apple 처리(수분)가 끝나면 해당 버전 페이지에서 빌드를 고르고 심사에 제출한다.
스토어 설명·키워드·새로운 기능 같은 메타데이터는 바이너리와 별개라, 기본 언어(한국어)와 버전 페이지 언어 탭의 문구를 따로 채워야 한다.
심사에서 겪었던 것:
- Guideline 4.8 — Google 로그인만 있으면 Apple 로그인 필요 → Sign in with Apple + iPad(
supportsTablet) 추가 - Guideline 2.1(a) 런치 크래시 — RN 0.81 TurboModule void 예외 처리와 Hermes 이슈 →
patch-package+buildReactNativeFromSource: true - 런치 후 빈 화면 — 스플래시/로딩/
return null+ EAS env 누락 → 부트 hardening + production env 등록
소스로 RN을 빌드하면 Xcode 26에서fmtconsteval 오류가 나서, Expo config plugin으로 Podfile에 워크어라운드를 넣었다.
8. 구현하면서 신경 쓴 점
- 가족 단위 동기화: household + Realtime으로 “상대가 방금 쓴 가계부”가 바로 보이게
- 가입 UX: 혼자/가족 분기와 이후 초대 가능 안내
- 캘린더 UX: 공휴일 캐시, 월 스와이프, 색·반복·음력
- 릴리즈 안정성: 스플래시를 너무 일찍 끄지 않기, Auth timeout, EAS env를 로컬과 맞추기
- 핸드오프 문서:
docs/dev-log.md,docs/release.md,CHANGELOG.md에 빌드 번호·심사 이슈·명령을 남겨 다음 배포를 빠르게
9. 앞으로
- Android 스토어 정식 배포
- App Store 메타데이터(설명, 스크린샷) 한국어 검수 강화
- 알림·반복 일정 고도화, 성능·오프라인 경험
참고 명령 요약
# 로컬
npm install
npx expo start
npx expo run:ios
# Edge Functions (예시)
npx supabase functions deploy send-verification-email
npx supabase functions deploy get-holidays
# 스토어
npx eas-cli build --platform ios --profile production
npx eas-cli submit --platform ios --latest
혼자 쓰는 생활 앱에서 시작해, household·Realtime·스토어 심사까지 한 사이클로 밀어붙인 기록이다.
같은 스택(Expo Router + Supabase)으로 가족형 제품을 만들 때 라우팅·권한·배포 env 쪽을 특히 먼저 고정해 두는 편이 좋다.