diff --git a/docs/v0-1-40-backlog.md b/docs/v0-1-40-backlog.md new file mode 100644 index 00000000..e8324312 --- /dev/null +++ b/docs/v0-1-40-backlog.md @@ -0,0 +1,174 @@ +# v0.1.40 작업 목록 + +> v0.1.39 발행(2026-08-03) 이후 확정. 유건 지시 5건이 머리고, 나머지는 v0.1.39 배치와 QA 조사에서 나온 이월이다. +> 각 항목은 **왜 하는지**와 **어디까지 실측했는지**를 함께 적는다 — 미검증을 검증된 것처럼 물려주지 않기 위해. + +## 1. 루틴 생성 — 한 줄만 써도 설계된 루틴이 나오게 (유건 지시 2026-08-05) + +**왜**: 지금은 사장이 입력한 문장이 **그대로** 크루에게 전달된다. "Claude Code 루틴"이 그렇듯, 목적을 읽고 +필요한 절차·판단 기준·산출물 형식까지 짜 주는 것이 이 기능의 값인데 현재는 전달자에 그친다. + +**설계 방향** +- 루틴 저장 시점에 **한 번** 목적 맥락을 확장한다(매 실행마다가 아니라 — 실행마다면 비용이 주기마다 곱해진다). +- 원문은 반드시 보존한다. 확장본은 별도 필드로 두고 화면에서 **둘 다 보이게** 한다 — + 사장이 "내가 쓴 게 아닌 지시"를 발견하는 일이 없어야 한다(via 표식 신고 2026-07-28과 같은 계열). +- 확장은 러너 중립이어야 한다. SDK 크루만 좋은 루틴을 얻으면 그 자체가 편파(러너 중립성 원칙). + 확장은 서버가 oneshot으로 수행하고 결과를 저장하는 쪽이 자연스럽다. +- 화면에 이미 "말로 쓰면 자동 설정" 입력이 있다(자연어 → 주기·시각 파싱). **그 자리를 확장한다** — + 새 UI를 만들지 말고 같은 문에서 주기·시각과 함께 본문까지 짜 준다. + +**검증**: 같은 한 줄("매일 아침 인스타 댓글 확인하고 정리해줘")로 만든 루틴이 확장 전/후에 어떤 결과를 +내는지 실제 턴으로 비교. 빌드 통과는 증거가 아니다. + +## 2. '추천 Top 20' 문구 교체 (유건 지시 2026-08-05) + +실제 항목 수가 20개가 아닌데 화면은 `추천 Top 20`이라고 단정한다 — 거짓 표기다. + +- 자리: `app/i18n.jsx:1042` `'market.topLabel': ['추천 Top 20 · {source}', 'Top 20 Recommended · {source}']` +- 교체: `추천 스킬` / `추천 플러그인`처럼 개수를 말하지 않는 문구로(ko·en 둘 다). +- 같은 화면에 개수를 단정하는 다른 문구가 더 있는지 함께 훑는다(3번 스윕과 묶어도 된다). + +## 3. 영문 사용자 피드백 오류 (유건 지시 2026-08-05) + +**제보**: 영문 사용자가 피드백을 보낼 때 오류가 난다는 이야기가 있다. **재현 미확인** — 제보 원문·환경을 +아직 특정하지 못했다. + +**조사 시작점(코드 실측 2026-08-05)** +- `app/api/feedback/route.js`의 오류 응답 4곳이 **한국어 하드코딩**이다(35·37·40·71행). + 다국어 상시 규칙 위반이고, 어딘가 이 문구가 그대로 노출되면 영문 사용자에겐 깨진 화면으로 읽힌다. +- 다만 `FeedbackModal`은 자기 `t('feedback.error')`를 쓰므로(`app/ui.jsx:580`) **모달 안에서는** 서버 문구가 + 안 보인다 → 위 하드코딩이 신고의 원인이라고 단정할 수 없다. 별개로 고치되, 진짜 원인은 따로 찾는다. +- 다음 확인 순서: 제보 원문 확보 → 영문 로케일에서 실제 전송 재현 → 실패 시 서버 로그(`insert 실패` 코드). + +## 4. 모니터링 강화 — 개선 근거를 우리가 먼저 갖기 (유건 지시 2026-08-05) + +**왜**: 지금 우리는 **활성 사용자를 제대로 못 센다.** 로컬 우선 제품이라 턴이 서버에 안 남고, 셀 수 있는 건 +로그인 이벤트(`last_sign_in_at`)뿐인데 그마저 세션이 유지되면 갱신되지 않는다 — 실측 2026-08-04: +08-04에 제보한 사용자의 마지막 로그인이 07-27로 찍혀 있었다. 즉 현재 수치는 **활성의 하한**이다. + +**모을 것**(최소 침습 — 개인정보·본문 금지) +- 접속: 일시, OS·앱 버전, 언어 +- 사용: 턴 수(집계값만), 쓰는 러너·모델, 실패 종류(코드 단위) +- **원칙**: 대화 내용·파일 경로·프롬프트는 절대 올리지 않는다. 로컬 우선 제품의 약속이 먼저다. + +**DB 부담 최소화** +- 행을 턴마다 만들지 않는다. **기기별 1행을 upsert**하고 카운터를 누적하는 형태(일 단위 롤업)로. + 2026-07-26 사고가 정확히 이 반대였다 — `storage.search`가 8초마다 돌아 DB CPU 80%를 찍었다. +- 전송 주기를 상수로 두고 주석에 **"100명이면 분당 몇 회"**를 숫자로 적는다(출하 관문 0.5 규모 질문). +- 실패해도 제품 동작에 영향이 없어야 한다(사본 원칙 — 피드백 이슈 미러링과 같은 계약). + +**선행**: 사용자에게 무엇을 모으는지 알리는 표기. 동의 없이 늘리지 않는다. + +## 5. 기기 리스 공백 — 리더가 꺼지면 최대 2분 (유건 지시 2026-08-05, 백로그 승격) + +**증상**: 텔레그램 봇과 예약 루틴은 **리더 기기 한 대**에서만 돈다(봇 토큰 하나에 폴러 하나 — 텔레그램 규격). +리더가 꺼지면 리스 만료(120초) + 다음 사이클(8초) + 게이트웨이 재점검(10초) ≈ **최대 2분 20초** 동안 +어느 기기에서도 안 돈다. 새 기기에 러너 자격이 없으면 양보 로직 때문에 **최대 5분**까지 늘어난다. + +- 근거: `src/sync.mjs:35·57·179-181·210-224`, `src/gateway.mjs:806·859-862·926`, + 선행 기록 `docs/ux-sweep-backlog-2026-07-17.md:54` +- 메시지 유실은 없다(at-least-once, `src/gateway.mjs:322-324`) — **지연**만 문제다. +- 방향: 정상 종료 시 리스를 **명시적으로 반납**하면 2분이 몇 초로 준다. 비정상 종료(전원 차단)는 + 여전히 TTL을 기다려야 하므로 TTL 단축과는 별개 트레이드오프(짧게 잡으면 일시적 네트워크 끊김에 + 리더가 튄다 — 이중 실행 위험). 반납부터 하고 TTL은 건드리지 않는 쪽을 권한다. + +## 5-B. 구독 관리 — 서버 창구로 이전 (유건 지시 2026-08-05, **결제 개시 전 필수**) + +**정본 설계: `docs/billing-portal-design.md`** + +데스크톱 앱은 사용자 기기에서 Next 서버를 돌린다. `LEMONSQUEEZY_API_KEY`를 릴리스 빌드에 넣으면 +**전 사용자에게 결제 API 키가 배포되고**, 안 넣으면 구독 관리 링크가 죽는다(실측 2026-08-05: +릴리스 CI에 없음 → 데스크톱에서 `결제 연동이 아직 설정되지 않았습니다`). + +**지금 결제를 열면 결제는 되는데 해지·카드 변경을 못 한다.** 환불·분쟁으로 돌아온다. + +- 해법: Supabase Edge Function `ls-portal`(웹훅과 같은 인프라) + 키는 Supabase secret으로만 +- 상태의 단일 진실을 `entitlements`로 모아 로컬 서버가 LS를 직접 호출하지 않게 한다 +- 키가 앱 산출물에 없음을 테스트로 잠근다 — 그 순간이 이 설계가 무너지는 순간이다 +- **선행 조건**: 이게 끝나기 전에는 실결제를 열지 않는다 + +## 5-C. 체험 임박 알림을 설정 밖으로 + 딥링크 (유건 지시 2026-08-05) + +지금 체험 임박(D-3) 안내는 **설정 페이지 안에서만** 뜬다(`trialImminent`가 settings에만 존재). +사용자가 설정에 안 들어가면 만료될 때까지 아무 말도 못 듣는다. + +- 설정 밖(사이드바 하단 또는 상단 바)에 임박 알림을 노출 +- 알림 → `/c/{ws}/settings?billing=1` 딥링크로, **그 카드까지 스크롤 + 잠깐 강조** + (선례: 러너 연결 안내가 `?ai=1`로 들어와 `scrollIntoView` — `settings/page.jsx:37-40`) +- **결제 직행 대신 설정 경유**를 택한 이유: 결제창엔 맥락이 없고, 같은 카드의 '자료 내보내기' + 선택지가 감춰지며, 링크에 `user_id`를 붙이는 경로가 하나로 유지된다 + +## 6. 기억 그래프 — 인터랙션 재작업 (유건 지시 2026-08-04) + +지금 것은 **회전하는 그림**이지 그래프 뷰가 아니다. 코드 실측(2026-08-04): + +- **이웃 강조·감광이 0건** — hover는 간선만 굵게 그린다. 옵시디언에서 시냅스처럼 느껴지는 감각의 본체가 없다. +- **카메라가 카메라가 아니다** — 초점거리 `f = 460`·깊이 오프셋 `z + 260` 하드코딩, 줌은 화면 스케일 배수라 + **카메라 거리를 못 움직인다**(`app/c/[ws]/graphview.jsx:143·149·151`). +- 그래서 노드 반지름이 `Math.min(view.zoom, 1.4)`로 **상한**이라 확대해도 밀도가 안 풀린다(같은 파일 202행). +- **v0.1.39가 자동 맞춤을 이월한 진짜 이유가 이것이다** — 카메라를 못 움직이니 "위치만 축소 / 위치+크기 축소" + 같은 편법만 남았고 둘 다 깨졌다. 원인을 잘못 짚고 이월했다(정정). +- 라벨 LOD 없음(타입 고정), 노드 드래그 없음, 검색·필터 없음. + +**할 것** +- 카메라 거리를 상태로 올린다 → 투영 `k = f/(f + z + dist)`, 휠 = `dist` 변경. + 화면 맞춤은 공식 한 줄이 된다: 바운딩 구 반지름 r에서 `dist = r / tan(fov/2)`. 반지름 상한도 제거. +- hover → 1홉 이웃만 정상 알파, 나머지 감광(인접 리스트는 차수 계산 자리에서 함께 만든다). +- 클릭 → 그 노드로 카메라 이동 + 로컬 모드(주변 1~2홉). +- 줌 레벨별 라벨, 노드 드래그로 집기, 검색어 → 매치 발광 + 카메라 이동. +- 집계(폴더·시기 단위 접기)는 **위가 끝난 뒤 선택지로** 얹는다. 대체재로 내지 않는다. + +**검증**: 노드 1,800개(실제 데이터 규모)에서 띄워서 눈으로. 프레임 유지·라벨 가독·클릭 후 이동. + +## 7. 안내 문구 전수 스윕 (유건 지시 2026-08-04) + +같은 계열 결함이 반복된다 — Grok 크레딧을 "인증 실패"로(2026-08-03 신고), 윈도우 러너 크래시를 +"AI 연결 확인"으로(v0.1.39에서 수정), codex 401·Gemini 정책 폐기도 같은 모양이었다. + +**대상**: 사용자에게 보이는 실패·거부 문구 전부 — 러너별 벤더 오류(401·402·403·429·5xx·타임아웃·크래시), +자격 저장/검증, 동기화 실패, 요금제·결제, MCP·스킬 미지원, 게이트·결재 거부, 메신저 전달 실패. + +**방법(두 방향 교차 — 한쪽만 하면 샌다)** +1. 코드에서 사용자 문구를 만드는 지점을 전수 열거하고, 문구마다 "이게 참이려면 무엇이 사실이어야 하는가"를 적는다 +2. 벤더가 실제로 주는 응답을 무자격 프로브로 모아(2026-08-03 xAI에 한 방식) 우리 번역과 대조한다 + +**판정 게이트 셋** +- **중립성**: 같은 사정인데 러너별로 안내 품질이 다르면 그 자체가 결함 +- **정직성**: 확인 안 된 원인을 단정하지 않는다 — 사용자가 엉뚱한 곳을 고치게 된다 +- **갈 곳**: "안 됩니다"로 끝나면 미완성. 다음 행동(충전·재연결·다른 엔진)을 준다 + +## 8. 피드백에 앱 버전 자동 첨부 + +**왜**: 제보 17건의 버전을 몰라 원인 추적에 하루를 썼다(2026-08-04~05). UA에는 OS만 있고 앱 버전이 없다 +(`meta.ua` 실측 — Tauri WebView 표준 UA뿐). + +**할 것**: 서버가 이미 아는 버전을 저장 시 `meta`에 함께 넣는다. 한 줄이다. 4번 모니터링의 선행 조각이기도 하다. + +## 9. 기억 검색 — FTS5 (P1b, 이월) + +설계는 이미 있다(`docs/memory-store-design.md` §5-2·5-3): `node:sqlite`가 FTS5까지 도는 것 실증, +스키마 초안(`docs_fts … tokenize='trigram'`)과 한국어 토크나이저 근거까지 적혀 있다. **미착수**. + +지금 크루의 검색 수단은 `Grep` 도구 + `_index.md`뿐이고(`src/chat.mjs:250`), 인덱스는 메타데이터 캐시만 +담는다(`src/memindex.mjs` — `docs(rel, kind, title, links, updated)`). 문서가 수천 건이 되면 여기가 병목이다. + +**전에 막혀 있던 것**: FTS를 붙여도 크루가 쿼리할 도구가 없었고, 도구를 노출하면 SDK 러너만 쓸 수 있어 +편파가 됐다. **이제 해소됐다** — ```` ```argo tool ```` 지시 블록(`src/cli-directives.mjs`)이 CLI 러너에도 +도구 통로를 열었다. 커넥터 US-3/US-4와 같은 구조로 두 표면에 같은 코어를 붙일 수 있다. + +## 10. 운영 — 제보자 회신 (코드 아님) + +v0.1.39 + 신규 설치 Windows에서 쓰기 차단이 **재현되지 않았다**(2026-08-05 실측: codex 샌드박스 정상, +제품 경로로 파일 생성 성공). 제보 17건 중 14건이 v0.1.36(전권 출하) 이전이다. + +1. **08-03·08-04 제보자 2명에게 버전 문의** — 최신에서도 나는지가 유일한 미확정 +2. **전체 제보자에게 업데이트 안내** — 대부분 막힌 뒤 재로그인 기록이 없다(이탈 신호) + +## 11. v0.1.39 이월 (미검증으로 발행한 것들) + +- **Grok 모델 id 실턴 스모크** — 카탈로그 규칙("실턴 통과분만 등재")의 예외 상태. xAI 자격 필요 +- **깃헙 이슈 미러링 라이브 확인** — `ARGO_GITHUB_ISSUE_TOKEN` 필요. 넣기 전까지 기능은 꺼져 있다 +- **대화 큐의 스티어링** — 큐만 출하했다. SDK는 스트리밍 입력 개조 필요, CLI 러너는 주입 지점 없음(정직 표기 전제) +- 러너 3종(Codex·Gemini·Antigravity) 라이브 스모크, Gemini 정책 안내 UI 확인 — v0.1.36부터 이월 중 +- 구글 캘린더 커넥터 프로덕션 게시(현재 테스트 모드 = 유건 계정 전용) +- 큰 그래프 자동 맞춤 — 6번에 흡수됨