PRD.md §3.1 P0 "자율성 설정(L0~L2) | 전역 기본값 + 상대별 예외 설정" / §4 엣지케이스 대비 미구현 갭 해소. 관계별 페르소나(2.7-B)의 RelationshipTier 오버라이드 패턴을 그대로 미러링: - core-backend/models.go: Contact.AutonomyLevel *AutonomyLevel 추가(nil = 전역 기본값), validAutonomyLevel() 검증 헬퍼 추가(twin-settings PATCH의 인라인 검증도 이 헬퍼로 통일) - core-backend/autonomy_resolve.go: resolveAutonomyLevel() 신규 — 연락처 오버라이드 (1:1 전용) → 전역 TwinSettings 기본값 → L0 순으로 해석. L1/L2가 아니라 L0으로 폴백하는 이유는 이 코드베이스 전반의 안전 우선 기본값과 동일(불확실하면 항상 초안만 생성, 사람이 직접 발송). 그룹 대화는 RelationshipTier와 동일하게 항상 전역 기본값만 사용 — main.go의 그룹 대화 무조건 차단과 이중으로 안전 - core-backend/main.go: POST /conversations/:id/messages의 자율성 게이트가 TwinSettings 전역값만 읽던 걸 resolveAutonomyLevel() 호출로 교체. peer-veto→그룹 차단→도배 감지→에스컬레이션 순서와 각 하드게이트는 그대로 유지, "level" 계산 방식만 바뀜 - core-backend/a1_a2_routes.go: createContactRequest/updateContactRequest에 AutonomyLevel 필드 추가, contactJSON()에 포함, 생성/수정 핸들러가 RelationshipTier와 동일한 전체 교체(full-replace) 시맨틱으로 처리(PATCH에서 필드 생략 시 nil로 리셋) - core-backend/autonomy_resolve_test.go: 연락처 오버라이드 우선순위, 전역 기본값 폴백, 그룹 대화는 오버라이드 무시, 잘못된 값 검증 거부, PATCH 전체 교체 리셋 커버 - mobile: models.dart에 Contact.autonomyLevel(nullable) 추가, api_client.dart createContact/updateContact에 선택적 autonomyLevel 파라미터 스레딩, contacts_screen.dart에 _AutonomyLevelPicker(_RelationshipTierPicker와 동일 구조) 추가해 추가/수정 다이얼로그에 배치 + 연락처 목록 서브타이틀에 표시 ai-service는 변경 없음 — 자율성 레벨은 발송 게이트 로직일 뿐 초안 톤에 영향을 주지 않아 ai-service 프롬프트까지 전달될 필요가 없음. 테스트: go test ./... 61개 전부 PASS, flutter analyze/test 클린(기존 무관 info 린트 1건 제외). docs/roadmap.md §2.7-D, docs/deploy-checklist.md N4-C4a/b/c를 done으로 갱신하고 NOW/바로 다음 5개 요약도 동기화. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014YSB5PqF38raTxP5ABgr9m |
||
|---|---|---|
| .. | ||
| android | ||
| lib | ||
| test | ||
| web | ||
| .gitignore | ||
| .metadata | ||
| Dockerfile | ||
| Dockerfile.prebuilt | ||
| README.md | ||
| analysis_options.yaml | ||
| pubspec.lock | ||
| pubspec.yaml | ||
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 필요)
- 초대 코드로 가입 → 말투 샘플 저장(또는 나중에)
- 연락처에 상대 사용자 ID 등록 → 대화 시작
- 메시지 전송 · 새로고침 후 히스토리 유지
- 초안 요청 → L1 패널에서 수정/버리기/승인 발송 → 와카뷰 뱃지 확인
- 민감 문장으로 에스컬레이션 → 사후 알림 함 진입
- 와카뷰 메시지 되돌리기 · 거부권
- 자율성 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 범위 밖)