bookquote

앱 시나리오 — 책귀 (V1, 현재 구현 기준)

기준일: 2026-05-14 (Stage 2 PR1~5 반영) 대체 관계: docs/discovery/flows.md는 2026-05-09 Validation 초안(Expo/TanStack/Realtime/follow 타임라인 시절) — V1 실제 동선은 이 문서 + docs/design/screens/*.md가 기준. flows.md는 시점 고정 자료로만 본다. 관련: 화면별 세부 = docs/design/screens/*.md · 시각 목업 = docs/design/mockups/{screens,walkthrough}.html · DB = docs/db-schema.md · 결정 = docs/DECISIONS.md


0. 한 줄 요약

책을 읽다 좋은 구절을 만나면 → 폰으로 찍어 텍스트 복사 → 책귀에 붙여넣고 책 연결·페이지·무드 태그 → 저장 → 홈 “내 인용 피드”에 쌓임 → 나중에 무드별로 다시 보고, 카드로 만들어 SNS·단톡방에 공유한다.

V1 = 내가 모으는 인용구 컬렉션 + 카드 공유. 친구 follow/타임라인/Realtime/받은 카드 함은 V1.5 (DECISIONS 2026-05-12).


1. 화면 지도 (구현 상태)

/splash ──(세션 있음)──▶ ┌──────── StatefulShellRoute (BottomNav 4슬롯) ────────┐
        │ ✅              │ [0] /          홈 — 내 인용 피드             ✅       │
        └─(없음)──┐       │ [1] /library   서재 — [책 ↔ 인용구] 세그먼트  ✅       │
                  │       │ [2] (+)       sentinel → push /quote/new            │
   /auth/login ◀──┤ ✅    │ [3] /me        내 정보 — 프로필·내보내기·약관·탈퇴 ✅  │
        │         │       └─────────────────────────────────────────────────────┘
   /auth/callback │       풀스크린 (셸 밖):
   /callback   ✅ │         /quote/new[?bookId=]  인용구 입력            ✅
                  │           └ "카드 만들기 →" → push /quote/:id/card  ⏳ 스텁(Stage 3)
   /book/:id ◀────┘                                  └ "공유" → 시트     ⏳ Stage 3
     ✅ read-only (보강은 PR6)                              └ 카카오톡 등 → 받는 사람 ⏳

  모달 시트(어느 탭에서도): showBookSearchSheet — 알라딘 검색 + 캐시 사전조회   ✅

  받는 사람 deep link: io.github.tgparkk.bookquote://book/:id?from=share        ⏳ deep_link_handler 일반화(PR6)

✅ = 구현·동작 / ⏳ = 스텁 또는 미구현(다음 PR 또는 Stage 3) — 라우트 진실은 lib/app/router.dart.


2. 시나리오 A — 처음 시작 → 첫 인용구 (Activation)

  1. 앱 첫 실행 → 스플래시(/splash)가 세션 hydrate를 기다림 → 세션 없으면 /auth/login.
  2. 로그인: 이메일 입력 → “이메일로 시작” → Supabase 매직링크 발송 → “메일을 확인해주세요”. (카카오 버튼은 placeholder — 비즈 인증 전이라 동선엔 두되 V1 핵심 아님.)
  3. 메일의 링크 탭 → 앱이 deep link(io.github.tgparkk.bookquote://auth/callback?code=...)를 받음 → 인증 콜백(/auth/callback·/callback)이 세션 교환 → 가입이면 트리거가 profiles 자동 생성 → redirect?from= 또는 /로.
  4. (/) 진입 — 인용구 0개면 빈 상태: “아직 인용구가 없어요 / 좋아하는 책의 한 줄을 저장해보세요” + [+ 인용구 추가] 버튼 하나.
  5. 버튼 또는 BottomNav [+] 탭 → 시나리오 B로.

차이(설계 대비): 설계 초안의 “홈 = 친구 타임라인”은 폐기 — V1 홈 = 내 인용 피드(DECISIONS 2026-05-12). 온보딩 튜토리얼 없음(빈 상태 CTA 하나로 학습). 미해결: 릴리스 APK에서 매직링크 발송 실패 사례(Supabase 이메일 한도/ Resend SMTP 물림 확인 필요 — STAGES 백로그).


3. 시나리오 B — 인용구 추가 (핵심, 매일)

  1. BottomNav [+] → /quote/new (풀스크린, 셸 밖). 본문 입력 자동 포커스.
  2. 책에서 찍은 텍스트를 폰 OCR로 복사해 둔 상태면 → “클립보드에서 붙여넣기” 배너 탭 한 번. (앱 내장 OCR 안 함 — DECISIONS 2026-05-11.)
  3. 책 연결 탭 → showBookSearchSheet 모달:
    • 검색어 입력 → 먼저 books 캐시를 ilike 사전조회(빠름) → 없으면 알라딘 검색(Edge Function aladin-search 경유, 키 은닉).
    • 결과에서 책 선택 → upsert_book RPC로 카탈로그에 영속화 → 시트 닫히고 입력 화면에 “📕 제목 · 저자” 표시. (시트는 모달이라 본문 입력 state 보존 — 회귀 테스트.)
    • 책을 안 고르고 닫아도 OK — manual_book_text로 나중에 적거나 책 없이 저장 가능.
  4. 페이지(선택) 입력 + 무드 칩(위로/먹먹/새벽3시/통찰/설렘 — 최대 3개) 선택.
  5. 입력 중 자동으로 draft 저장(shared_preferences) — 앱이 죽거나 뒤로 가도 복원. 본문 비우고 뒤로 = PopScope 폐기 확인.
  6. [카드 만들기 →] 또는 [저장만] 탭:
    • 온라인이면 quotes INSERT → 홈 피드 invalidate → 홈에 즉시 반영.
    • 네트워크 오류면 오프라인 아웃박스(shared_preferences)에 큐잉하고 성공으로 처리 → 다음에 앱이 포그라운드로 돌아올 때 best-effort flush(시나리오 F).
    • “카드 만들기 →”는 /quote/:id/card로 가지만 카드 에디터는 아직 스텁(Stage 3) — V1 현재는 인용구 저장까지가 완성된 동선.

4. 시나리오 C — 다시 보기 / 카드 만들기


5. 시나리오 D — 내 데이터 관리 (내 정보 화면)

/me (BottomNav [내정보]):


6. 시나리오 F — 오프라인 작성 (지하철 등)


7. V1.5+ (지금 동선에 없음)


변경 이력