182 lines
15 KiB
Markdown
182 lines
15 KiB
Markdown
# 로드맵 & 마일스톤
|
|
|
|
`decision-log.md`의 Q3(자율성 단계), Q7(자체앱→OS레이어 순서)에 따른 단계별 계획.
|
|
각 단계는 이전 단계의 핵심 가설이 검증되어야 다음으로 넘어간다 — 일정보다 검증 결과가 게이트다.
|
|
|
|
## Phase 0 — 기술 PoC (착수 즉시)
|
|
|
|
- 온디바이스 말투 학습 품질 검증 (`PLANNING.md` §4 PoC #1)
|
|
- 에스컬레이션 판정기(규칙 기반) 최소 프로토타입으로 오탐/누락 감 잡기
|
|
- 목표: "분신이 나답게 느껴지는가"에 대해 Go/No-Go 판단 근거 확보
|
|
|
|
## Phase 1 — v1 클로즈드 베타 (자체 앱, `PRD.md` 범위)
|
|
|
|
- 자율성 L0~L2, 시나리오: 읽씹 종결 + 단톡 따라잡기
|
|
- 안드로이드 우선, 초대 기반 소규모 베타 (지인 네트워크)
|
|
- 게이트: `vision.md` 성공 지표(자연스러움 70%, 거부율 10% 미만, 안전선 위반 0건) 충족 여부
|
|
|
|
### Phase 1 상세 작업 분해
|
|
|
|
원칙상 Phase 0(PoC) 검증 후 착수하는 게 맞지만, PoC 실제 실행(참가자 모집)이 보류된 지금
|
|
**PoC 결과와 무관한 기반 작업은 병행 착수**하고, **PoC 결과가 있어야 정할 수 있는 세부 값**은
|
|
자리만 비워두고 나중에 채우는 방식으로 진행한다. 아래 §3이 그 경계선이다.
|
|
|
|
이 체크리스트가 Phase 1 작업의 단일 기준이다 — 작업을 시작하기 전에 여기서 다음 항목을 확인하고,
|
|
끝나면 체크하고, 새로 발견한 하위 작업은 해당 항목 밑에 추가한다 (`AGENTS.md` "Phase 1 앱 빌드
|
|
작업 규칙" 참고).
|
|
|
|
#### 1. 착수 전 확정 필요 (기술 스택)
|
|
|
|
- [x] 기술 스택 결정 — `tech-design.md` §8 (Flutter/Dart 클라이언트, Go 코어 백엔드 +
|
|
Python AI 서비스 투트랙, PostgreSQL, WebSocket 릴레이, drift+SQLCipher, Gemini 키 분리)
|
|
|
|
#### 2. 워크스트림별 작업
|
|
|
|
**2.1 코어 백엔드** (Go, PoC 결과 무관 — 지금 착수 가능)
|
|
- [x] 계정/인증 (초대 코드 기반 가입) — `core-backend/` (Go, Gin), 중복 코드 409 실제 테스트로 확인함
|
|
- [x] 메시지 릴레이 서버 (송수신) — `core-backend/` WebSocket + REST, 실제 테스트로 브로드캐스트 확인함.
|
|
멀티 디바이스 동기화(같은 유저 여러 기기)는 아직 — 지금은 대화방 단위 인메모리 커넥션 매니저뿐
|
|
- [x] DB 스키마: users, invite_codes, contacts, conversations, messages, twin_settings,
|
|
escalation_logs, whitelist_rules — `core-backend/models.go` (GORM), `backend/app/models.py`
|
|
(Python 프로토타입)와 동일 스키마(+ invite_codes는 여기서 새로 추가)
|
|
- [ ] 푸시 알림 서비스 연동
|
|
|
|
`backend/`(Python 프로토타입)는 그대로 참고용으로 남겨둔다 — `core-backend/`(Go)가 실제로 쓰는 것.
|
|
|
|
**2.2 AI 서비스** (Python, PoC 스크립트 → 내부 API로 승격)
|
|
- [x] `poc/tone-corpus/generate_draft.py`·`escalation_filter.py`·`retrieve_style.py`를 감싸는
|
|
FastAPI 서비스로 승격 — `ai-service/` (`POST /draft`, style_examples/history 두 경로 +
|
|
에스컬레이션 하드게이트 + 검증 오류 전부 실제 테스트로 확인함)
|
|
- [x] Go 코어가 이 서비스를 실제로 호출하는 클라이언트 코드 (`core-backend/`에서 `AI_SERVICE_URL` 사용)
|
|
— `core-backend/aiservice.go`(`AIServiceClient.requestDraft`) + `POST /conversations/:id/draft`
|
|
라우트, mock AI 서비스로 정상 프록시·404·400(스타일 소스 없음) 전부 실제 테스트로 확인함
|
|
- [x] 자율성 엔진(L0~L2) 오케스트레이션 최소 버전 — 2.5 QA에서 "자율성 플로우 통합 테스트"를 쓰려면
|
|
실제 분기 로직이 있어야 해서 그때 구현함. 결정: 에스컬레이션 하드게이트(Go 코어, 이미 구현) →
|
|
레벨 확인은 Go 코어 책임(`PATCH /users/:id/twin-settings`로 레벨 변경, 메시지 저장 시 레벨별 분기).
|
|
L0 항상 차단, L1은 `approved:true` 필요, L2는 화이트리스트 매칭 시 즉시 자동발송·매칭 없으면 L1과
|
|
동일. 에스컬레이션은 레벨/화이트리스트 무관 항상 우선. **간소화한 부분**: 검색(retrieve)→초안
|
|
생성은 이미 있는 `/draft` 흐름을 그대로 쓰면 되므로 새로 만들지 않았고, 화이트리스트는
|
|
`ContactID`(상대별) 무시하고 전역 키워드 매칭만 지원 — 대화방↔연락처 연결 모델이 아직 없어서
|
|
(Flutter 클라이언트의 연락처 모델이 생긴 뒤 다시 설계 필요, `core-backend/README.md` 참고)
|
|
- [ ] 온디바이스 말투 이력 저장 + 서버 최소 전송 원칙 구현
|
|
- [ ] 사후 알림 + 되돌리기 로그 스키마/API
|
|
|
|
**2.3 클라이언트 (Flutter, 안드로이드 우선 빌드)** — **Flutter/Dart SDK가 있는 환경(본인 로컬)에서 착수**
|
|
- [ ] 기본 채팅 UI (대화 목록, 대화방) — 무관, 착수 가능
|
|
- [ ] 온보딩 플로우(5분 온보딩) 뼈대 — 무관, 착수 가능. 말투 학습 UX 디테일만 PoC#1 결과로 조정
|
|
- [ ] 분신 뱃지·실시간 본인확인·거부권 UX — 클릭 프로토타입 디자인 그대로 구현 가능
|
|
- [ ] 자율성 설정 화면(L0~L2, 화이트리스트, 상대별 예외) — 무관, 착수 가능
|
|
- [ ] 에스컬레이션 배너·사후알림·되돌리기 UI — 무관, 착수 가능
|
|
|
|
**2.4 안전장치 통합** (전 구간 필수, 타협 불가)
|
|
- [x] 에스컬레이션 하드게이트가 클라이언트·서버 전 구간에서 우회 불가하게 설계 — 실제 발견한 우회
|
|
구멍: `POST /conversations/:id/messages`가 `sender_mode: "twin"`을 검증 없이 그대로 저장·
|
|
브로드캐스트하고 있었음(초안 생성(`/draft`)만 게이트를 탔고, 발송 자체는 게이트가 없었음). 이걸
|
|
막기 위해 `ai-service`에 `/draft`와 별개인 `POST /escalate/check` 하드게이트 엔드포인트를 추가하고,
|
|
`core-backend`가 트윈 발송 저장 *직전에* 무조건 이걸 호출하도록 만듦 — 어떤 경로로 왔든 발송이
|
|
실제로 일어나는 단 하나의 지점(메시지 저장)에서 걸리므로 클라이언트가 뭘 하든 우회 불가.
|
|
AI 서비스 응답 불가 시 fail-safe(발송 차단, 502)로 처리. 사람이 직접 보내는 메시지는 게이트 대상이
|
|
아님. 차단·통과·게이트 불능 3케이스 전부 실제 테스트로 확인함 (`core-backend/main_test.go`)
|
|
- [x] **발견 및 수정**: 거부권(peer veto) 안전 불변식이 코드에 전혀 구현되어 있지 않았음 —
|
|
`Contact.TwinDisabledByPeer` 필드만 스키마에 있고 어디서도 읽거나 쓰지 않았고, `tech-design.md`
|
|
§4는 "대화방 단위 플래그"라는데 실제로는 상대(Contact) 단위로 모델링돼 있어 설계 문서와도
|
|
불일치했음(2.6 작업 중 발견). `Conversation.TwinDisabledByPeer`로 옮기고 `POST
|
|
/conversations/:id/veto` 추가, 메시지 발송 시 **거부권 → 에스컬레이션 → 자율성 레벨** 순으로
|
|
체크(거부권이 전부보다 우선) — L2 화이트리스트 매칭 + `approved:true`여도 거부권이 켜져 있으면
|
|
무조건 차단되는 것까지 테스트로 확인함
|
|
- [~] 데이터 프라이버시: 온디바이스 암호화, 삭제 플로우, 데이터 흐름 대시보드 — 서버 쪽 삭제
|
|
플로우(`DELETE /users/:id`, 유저가 걸린 모든 행을 트랜잭션으로 삭제)만 완료·테스트함. 온디바이스
|
|
암호화(drift+SQLCipher)와 실시간 데이터 흐름 대시보드는 Flutter 클라이언트 책임이라 이 환경(SDK
|
|
없음)에서는 진행 불가 — 2.3과 함께 로컬 환경 대기
|
|
|
|
**2.5 QA/테스트**
|
|
- [x] `escalation_filter.py`의 자체 테스트를 정식 테스트 스위트로 승격, `generate_draft`·`retrieve_style`도
|
|
동일하게 — `ai-service/tests/`(pytest, 34개), SELFTEST_CASES 승격 + Gemini 호출 mock + `/health`·
|
|
`/escalate/check`·`/draft` FastAPI 엔드포인트 테스트까지 포함. `poc/tone-corpus/`의 ad-hoc
|
|
`--selftest`는 실험 도구로 그대로 두고(승격 대상은 "실제 서비스"인 `ai-service/`), 별개로 유지
|
|
- [x] 자율성 플로우(L0→L1→L2) 통합 테스트 — `core-backend/main_test.go`. 위 2.2 최소 오케스트레이션
|
|
구현과 함께: L0 차단, L1 미승인 차단/승인 시 발송, L2 화이트리스트 매칭 자동발송/비매칭 시 승인
|
|
필요, 에스컬레이션이 레벨·화이트리스트·승인 여부와 무관하게 항상 우선한다는 것까지 6개 케이스
|
|
전부 실제 테스트로 확인함
|
|
- [ ] 온보딩·채팅·설정 수동 QA — Flutter 클라이언트가 없어 이 환경에서는 불가, 2.3과 함께 로컬
|
|
환경 대기
|
|
|
|
**2.6 베타 배포 준비**
|
|
- [x] 초대 기반 베타 가입 플로우 — **발견**: 기존 가입은 "아무 문자열이나 처음 쓰면 통과"라
|
|
실제로는 초대 기반이 아니었음. `InviteCode` 테이블 + `POST /invites`(발급) 추가하고
|
|
`/auth/signup`이 미리 발급된 미사용 코드인지 검증하도록 변경(모르는 코드 400, 이미 쓴 코드
|
|
409). 계정 삭제 시 코드는 "사용됨" 상태를 유지한 채 유저 참조만 지움. **아직 없는 것**: 발급자
|
|
인증(`/invites`를 지금은 누구나 호출 가능 — 세션/인증 도입 시 같이 잠글 것)
|
|
- [~] `vision.md` 성공 지표(자연스러움·거부율·안전선 위반) 계측용 분석/피드백 수집 — 거부율은
|
|
`/admin/metrics`의 `peer_veto_rate`로 1차 근사 가능해짐(대화방 단위, 확정 정의 아님). 자연스러움
|
|
피드백 수집 UI는 Flutter 클라이언트 책임이라 보류. 안전선 위반 0건은 런타임에 "수집"하는 지표라기
|
|
보다 지금까지의 하드게이트 테스트들이 이미 보증하는 것 — 별도 계측 불필요
|
|
- [~] 모니터링 대시보드 (에스컬레이션 트리거율, 생성 지연시간, 오류율) — `GET /admin/metrics`로
|
|
카운트 기반 데이터(메시지 수, 에스컬레이션 사유별 집계, 거부권 발동률, 초대 코드 발급/사용 수)는
|
|
노출함. **대시보드 UI 자체와 생성 지연시간·오류율**은 아직 없음 — UI는 Flutter/관리자 웹 쪽이고,
|
|
지연시간·오류율은 요청 타이밍/로깅 계측 계층이 따로 필요해서 이번엔 만들지 않음(허위로 채우지
|
|
않고 명시적으로 비워둠)
|
|
|
|
#### 3. PoC 결과가 있어야 정할 수 있는 것 (맨 마지막 — 그 전엔 손대지 않는다)
|
|
|
|
**§2의 워크스트림(2.1~2.6)이 전부 끝나기 전까지는 이 섹션에 손대지 않는다.** 순서를 앞당겨서
|
|
미리 추측값을 넣지 않는다 — PoC 데이터 없이 정하면 나중에 다시 뒤집어야 하고, 그게 더 큰 낭비다.
|
|
§2가 다 끝난 뒤에만 이 섹션으로 돌아온다.
|
|
|
|
- [ ] 자율성 기본값(L1 vs L2 어디서 시작할지) — Q3 인터뷰 필요
|
|
- [ ] 화이트리스트 기본 주제 목록 — 실사용 데이터 필요
|
|
- [ ] 신뢰 UX 문구/노출 위치 최종 확정 — PoC#3 결과 필요
|
|
- [ ] 실제 베타 오픈 시점 — `vision.md` 게이트 통과 필요
|
|
|
|
#### 4. 권장 착수 순서 (진행 상황)
|
|
|
|
순서대로 하나씩 완료하고 다음으로 넘어간다. **6번(§3)은 1~5번이 전부 끝난 뒤에만 시작한다** —
|
|
중간에 끼워 넣지 않는다.
|
|
|
|
1. [x] §1 기술 스택 결정 (Go 코어 + Python AI 서비스로 재확정, `backend/`는 Python 프로토타입 —
|
|
설계 참고용으로 남기고 Go로 포팅 필요)
|
|
2. [x] 2.1 코어 백엔드 Go 구현 — `core-backend/` (가입·메시지·WebSocket 릴레이 완료, 푸시 알림만 남음).
|
|
병행하려던 2.3 Flutter 채팅 UI 뼈대는 **이 작업 환경에 Flutter/Dart SDK가 없어 빌드 검증이
|
|
불가능**해서 보류 — Flutter는 Windows에 SDK가 설치된 환경(본인 로컬)에서 시작
|
|
3. [x] 2.2 AI 서비스 — `ai-service/`(Python) 완료. Go 코어→AI 서비스 연동(`core-backend/aiservice.go`,
|
|
`POST /conversations/:id/draft`)도 완료·테스트 통과. 자율성 엔진 오케스트레이션도 최소 버전으로
|
|
완료(아래 5번과 함께 구현). 남은 건 온디바이스 말투 이력 저장, 사후 알림/되돌리기 로그 — 클라이언트
|
|
의존이라 2.3(Flutter) 대기
|
|
4. [~] 2.3 나머지 UX(온보딩·설정·뱃지) — Flutter SDK가 없는 이 환경에서는 여전히 착수 불가.
|
|
대신 2.4(안전장치 통합) 중 서버 쪽 몫(에스컬레이션 하드게이트 우회 차단, 삭제 API)을 먼저 진행함
|
|
5. [x] 2.4/2.5 안전장치·QA (서버 쪽) — 2.4: 하드게이트 우회 차단, 거부권 구현, 삭제 플로우. 2.5:
|
|
`ai-service` pytest 스위트 승격, 자율성 플로우(L0→L1→L2) 통합 테스트 — 이걸 쓰려면 실제 분기
|
|
로직이 필요해서 2.2의 자율성 오케스트레이션도 이때 같이 구현함. 남은 건 전부 클라이언트 쪽
|
|
(온디바이스 암호화·데이터 흐름 대시보드·수동 QA) — Flutter 대기
|
|
- 5-1. [x] 2.6 베타 배포 준비(서버 쪽) — 실제 초대 코드 발급/검증(`InviteCode`, `POST
|
|
/invites`), `GET /admin/metrics`(메시지·에스컬레이션·거부율 카운트). **실제 베타 오픈
|
|
시점 자체는 여전히 6번(§3) 이후** — 서버 인프라만 먼저 준비해둔 것
|
|
6. [ ] §3 확정 (PoC 결과 필요 — 1~5번 전부 끝난 뒤에만) → 2.6 실제 베타 오픈
|
|
|
|
1~5는 PoC 실제 실행(A트랙)과 병행 가능 — PoC가 늦어져도 인프라 작업은 막히지 않는다. 다만
|
|
§3 항목과 최종 베타 오픈은 PoC 결과 없이 확정하지 않는다.
|
|
|
|
## Phase 2 — L3 확장 + 베타 확대
|
|
|
|
- 자리비움 전면 응대(L3) 추가 — Phase 1에서 신뢰가 검증된 경우에만
|
|
- 관계 메모, 답장 마감 알림 등 P1 기능
|
|
- 베타 규모를 소규모 지인 네트워크 밖으로 확대
|
|
|
|
## Phase 3 — OS 레이어 진입 (성장 전략)
|
|
|
|
- 전제: Phase 1 자체 앱 베타에서 핵심 가설이 검증된 뒤에만 착수 (`decision-log.md` Q7)
|
|
- 읽기 전용 허브부터 (발송 권한 없음, 문자·이메일 등 안정적 API 채널 우선)
|
|
- OS 레이어 내부 순서: 읽기 전용 → 초안 제안 → 제한적 자동응대(L2 그대로 확장)
|
|
- 확산 후 완전한 기능(L3·L4 등)이 필요하면 자체 앱으로 유도 — 시작 순서를 뒤집는 뜻이 아님
|
|
- 안드로이드 우선, iOS는 이 단계 반응을 본 뒤 자체 앱 전환 유도 전략으로 대응
|
|
|
|
## Phase 4 — L4 분신 협상 + B2B 확장
|
|
|
|
- 사용자 기반이 어느 정도 쌓여 네트워크 효과가 의미 있을 때 착수
|
|
- 기업용 고객 응대 분신(B2B)은 이 시점 이후 별도 트랙으로 검토
|
|
|
|
## 명시적으로 지금 계획하지 않는 것
|
|
|
|
- Phase 1 게이트를 통과하기 전에 Phase 2 이후 기능을 설계/개발하지 않는다.
|
|
- OS 레이어와 자체 앱을 동시에 만들지 않는다 (`decision-log.md` Q7 근거).
|