iykyka/mobile
Claude 64323b824e
feat: implement 단톡 따라잡기 (group catch-up summary) — roadmap.md §2.7-A
Closes the biggest content gap found against PRD.md §3.1 P0: group chat
catch-up was one of only two v1 MVP scenarios and had zero implementation.

Backend (core-backend):
- ConversationParticipant.LastReadMessageID read marker.
- POST /conversations/:id/read advances the caller's marker (never backward).
- GET /conversations/:id/summary builds context from messages since that
  marker and calls ai-service's new POST /summarize; returns unread_count
  and needs_reply.
- GET /conversations now reports unread_count per room.
- Safety: group conversations now unconditionally block twin-authored
  sends (POST /conversations/:id/messages), regardless of the sender's
  global autonomy level. PRD.md §2.3-③ requires this scenario stay L0-fixed
  with no auto-send; autonomy level is a per-user global setting today, so
  this closes the only path a global L2 whitelist match could otherwise
  auto-send into a group.

AI service (ai-service): new summarize.py module (same Gemini-call shape as
generation.py's draft_reply, no escalation/identity gating since nothing
generated here is ever sent) + POST /summarize.

Mobile: "새 대화" dialog now supports adding/removing multiple peer fields
(2+ peers -> is_group:true automatically); unread badge on conversation
rows; ChatScreen takes isGroup and renders its L1 panel as L0-locked for
groups; new "안 본 동안 요약" AppBar action opens a dialog with the summary
and, when a reply looks needed, a button that feeds straight into the
existing draft-request flow.

Verified with a real Flutter build against a live core-backend + ai-service
instance (Playwright driving 3 demo accounts through group creation, unread
badges, and the summary dialog) — this caught a real ordering bug: marking
the read marker on chat *open* meant the summary was always empty by the
time you could tap it, since opening the room already advanced the marker
past everything you'd come to catch up on. Fixed by marking read on screen
*exit* (dispose) instead, so the marker reflects what was unread that whole
visit and updates once you leave.

go test / pytest / flutter analyze+test all pass.
2026-08-03 03:16:54 +00:00
..
android feat(n4): wire FCM token path and document Master secrets 2026-07-31 04:51:57 +00:00
lib feat: implement 단톡 따라잡기 (group catch-up summary) — roadmap.md §2.7-A 2026-08-03 03:16:54 +00:00
test Merge origin/main: keep gradient/glassmorphism UI, port demo-invite + boot hardening, purge 분신 branding 2026-07-31 01:30:50 +00:00
web 제품명 변경(분신→와카뷰) + 소프트 그라디언트/글래스모피즘 UI + 브랜드 로딩 화면 2026-07-31 01:15:42 +00:00
.gitignore Add Flutter mobile client skeleton and defer human PoC to last 2026-07-30 04:16:41 +00:00
.metadata fix Flutter Web/Chrome compile by stubbing SQLCipher DB 2026-07-30 07:05:31 +00:00
Dockerfile feat(deploy): Docker Compose stack for msn.iykyka.com (N2-B) 2026-07-31 02:26:40 +00:00
Dockerfile.prebuilt feat(deploy): Docker Compose stack for msn.iykyka.com (N2-B) 2026-07-31 02:26:40 +00:00
README.md feat(n4): wire FCM token path and document Master secrets 2026-07-31 04:51:57 +00:00
analysis_options.yaml Add Flutter mobile client skeleton and defer human PoC to last 2026-07-30 04:16:41 +00:00
pubspec.lock Merge remote-tracking branch 'origin/main' 2026-07-31 08:23:28 +00:00
pubspec.yaml feat(n4): wire FCM token path and document Master secrets 2026-07-31 04:51:57 +00:00

README.md

와카뷰 mobile (Flutter)

Phase 1 클라이언트 (docs/roadmap.md §2.3 / A3). v1은 Android 빌드만 대상으로 한다 (docs/tech-design.md §8).

지금 있는 것

  • 초대 코드 가입 (POST /auth/signup) + Bearer 세션
  • 말투 샘플 온보딩(기기 로컬 저장; 최종 카피는 PoC 이후)
  • 대화방 목록/생성 (GET/POST /conversations) — 수동 ID 입력 제거
  • 연락처 CRUD + 대화 시작 (/users/:id/contacts)
  • 채팅 히스토리 로드 + WebSocket 수신
  • 와카뷰 초안 / L1 승인(수정·버리기·재초안·승인 발송)
  • 와카뷰 뱃지 · 거부권 · 되돌리기
  • 사후 알림 함 (GET /users/:id/escalation-logs)
  • 자율성 L0~L2 + 화이트리스트 CRUD UI

실행

# core-backend + ai-service 가 떠 있어야 실제 호출이 된다
cd mobile
flutter pub get

# Android 에뮬레이터 → 호스트의 core-backend(기본 8080)
flutter run --dart-define=CORE_API_BASE=http://10.0.2.2:8080

# 실기기/로컬 네트워크
flutter run --dart-define=CORE_API_BASE=http://<your-lan-ip>:8080

E2E

API 레벨 (클라우드/CI에서 실행 가능)

# core-backend :8080 + ai-service :8001 기동 후
export ADMIN_API_TOKEN=dev-admin-token
python3 scripts/e2e_a3.py

A3 체크리스트(가입·연락처·대화·히스토리·draft/L1·에스컬레이션·되돌리기·거부권·화이트리스트)를 HTTP로 검증한다.

에뮬레이터/실기기 UI 탭 (Android SDK 필요)

  1. 초대 코드로 가입 → 말투 샘플 저장(또는 나중에)
  2. 연락처에 상대 사용자 ID 등록 → 대화 시작
  3. 메시지 전송 · 새로고침 후 히스토리 유지
  4. 초안 요청 → L1 패널에서 수정/버리기/승인 발송 → 와카뷰 뱃지 확인
  5. 민감 문장으로 에스컬레이션 → 사후 알림 함 진입
  6. 와카뷰 메시지 되돌리기 · 거부권
  7. 자율성 L0~L2 + 화이트리스트 추가/삭제

로컬 DB (drift + SQLCipher)

말투 샘플·온보딩 플래그는 lib/db/ 암호화 SQLite에 저장한다. 패스프레이즈는 flutter_secure_storage. Linux 개발 호스트에 libsqlcipher.so가 없으면 메모리 폴백으로 기동한다(Android 릴리즈 경로에서는 SQLCipher 사용).

# Linux에서 drift 테스트/암호화 DB를 쓰려면
sudo apt-get install -y libsqlite3-dev libsqlcipher1

푸시 (FCM)

  • 코드: lib/services/push_token_service.dart — Firebase 가능 시 실 토큰, 아니면 install:
  • Master 설정: docs/fcm-setup.md (google-services.json + FCM_SERVER_KEY)

아직 없는 것

  • Master Firebase 시크릿 주입 후 실기기 푸시 스모크 (N4-1/3/4)
  • 오프라인 메시지 큐 / 멀티디바이스 실시간 설정 동기화 고도화
  • 온보딩 말투 UX 디테일 (PoC #1 결과는 맨 마지막에 반영)
  • iOS 빌드 (v1 범위 밖)