F3 + F4-E 카피 정리 (v0.2.1 dogfood-feedback Track #6) #7

Merged
altair823 merged 3 commits from feat/f3-f4e-copy into main 2026-04-26 02:33:11 +00:00
10 changed files with 68 additions and 25 deletions

View File

@@ -373,7 +373,7 @@ Rules:
- 화면 중앙, 포커스 자동 획득
- 단일 textarea + 썸네일 스트립 (이미지 있을 때만)
- placeholder: "지금 머릿속에 있는 것 한 줄. 정리는 나중입니다."
- 하단 힌트: "Ctrl+Enter 구출 · Esc 취소 · 이미지 붙여넣기"
- 하단 힌트: "Ctrl+Enter 저장 · Esc 취소 · 이미지 붙여넣기"
├─ 사용자 타이핑 / Ctrl+V (이미지)
│ └─ 클립보드 이미지 감지 → 썸네일 추가 (메모리 버퍼)
@@ -399,8 +399,8 @@ Rules:
- 채널: OS 네이티브 알림 (`new Notification(title, {body, silent})`). Inbox in-app 토스트 아님 — 사용자가 작업 중인 다른 앱 위에 즉시 떠야 보상 즉시성을 살림.
- 회전 카피 4종 (noteId 해시 mod 4로 결정론적 선택):
1. "이 생각은 이제 Inkling이 들고 있습니다."
2. "나중에 찾을 수 있게 보관했습니다."
3. "방금 하나의 업무 기억을 구출했습니다."
2. "머릿속에서 꺼내 두었습니다."
3. "방금 한 줄 잡아뒀습니다."
4. "기록 완료. 이제 잊어도 됩니다."
- 권한: 첫 submit 시 OS 권한 다이얼로그. 거부 시 무음 폴백 (캡처는 정상 동작).
- 알림 본문에는 `raw_text``ai_title`을 포함하지 않는다. 오직 회전 카피만 표시 (PII 보호와 일관성).
@@ -503,7 +503,7 @@ Rules:
Slice는 온보딩 위자드를 제공하지 않는다.
1. 최초 기동 시 `{userData}/Inkling/profiles/default/`가 자동 생성된다.
2. Inbox 창이 열리고 빈 상태 메시지("첫 기억을 구출해보세요. `Ctrl+Shift+J`")가 노출된다.
2. Inbox 창이 열리고 빈 상태 메시지("머릿속에 떠다니는 한 줄을 적어보세요. `Ctrl+Shift+J`")가 노출된다.
3. Ollama 헬스 체크가 실행되고 결과에 따라 배너가 표시된다.
### 5.4 카피 카탈로그
@@ -513,14 +513,14 @@ Slice는 온보딩 위자드를 제공하지 않는다.
| 위치 | 문구 |
|------|------|
| QuickCapture placeholder | 지금 머릿속에 있는 것 한 줄. 정리는 나중입니다. |
| QuickCapture hint | Ctrl+Enter 구출 · Esc 취소 · 이미지 붙여넣기 |
| QuickCapture hint | Ctrl+Enter 저장 · Esc 취소 · 이미지 붙여넣기 |
| QuickCapture 제출 실패 | 저장에 실패했습니다. 다시 시도해주세요. |
| QuickCapture 취소 confirm (5자+) | 이 한 줄을 흘려보낼까요? |
| Inbox 빈 상태 | 첫 기억을 구출해보세요. `Ctrl+Shift+J` |
| Inbox 빈 상태 | 머릿속에 떠다니는 한 줄을 적어보세요. `Ctrl+Shift+J` |
| Inbox 처리 중 카드 | Inkling이 정리하는 중… |
| Inbox AI 실패 카드 | 정리 보류 — 원문은 안전합니다 |
| 트레이 메뉴: Quick Capture | 기억 구출하기 |
| 트레이 메뉴: Inbox 열기 | 구출한 메모 보기 |
| 트레이 메뉴: Quick Capture | 한 줄 적기 |
| 트레이 메뉴: Inbox 열기 | 보관한 메모 보기 |
| 트레이 메뉴: Quit | 종료 |
| 삭제 confirm | 이 기억을 버릴까요? 되돌릴 수 없습니다. |
| Continuity 0건 | 이번 주 한 줄이면 시작입니다 |

View File

@@ -163,7 +163,9 @@ H1 이 미달이면 본 항목 ❌ rejected.
---
## F3. "구출" 카피가 한국어로 어색함 (🌱 raw)
## F3. "구출" 카피가 한국어로 어색함 (🚀 promoted)
**Promoted →** `docs/superpowers/specs/2026-04-26-f3-f4e-copy.md` (F4-E 와 함께 한 PR)
**발견:** 2026-04-26 dogfood 첫날, 메모 1건 캡처 후 OS 토스트 알림에서 "방금 하나의 업무 기억을 구출했습니다" 문구가 떴을 때.
@@ -272,6 +274,10 @@ H1 이 미달이면 본 항목 ❌ rejected.
**발견:** 2026-04-26 dogfood 시작 직전 사고 실험. 슬라이스 v0.4 와 strategy.md §3 가 **이미 알고 있는 contextual cue** (회의 후, 퇴근 전, 디버깅 후) 의 if-then 만 다루고, **ambient/spontaneous 떠오름** (샤워, 산책, 대화 중, 자기 전) 은 사각지대.
**진행 상태:**
- E (Zeigarnik priming) — 🚀 promoted → `docs/superpowers/specs/2026-04-26-f3-f4e-copy.md`
- A·B·C·D·F — 🌱 raw, 측정 후 결정
### 관찰
캡처 자체의 마찰은 거의 0 — `Ctrl+Shift+J` + 한 줄 + Enter = 3초. 하지만 dogfood 의 진짜 실패 모드는 **"3초가 너무 길다"** 가 아니라 **"그 3초가 머릿속에 안 떠오른다"** 다. 떠오름 → Inkling 연상 사이의 인지적 다리가 약하면, 메모 자체가 시도되지 않는다.

View File

@@ -0,0 +1,35 @@
# F3 + F4-E Copy Spec (Promoted)
**Extracted from:** `2026-04-25-dogfood-feedback.md` F3, F4 §"E. Zeigarnik 효과 활용"
**Status:** 🚀 promoted — implemented 2026-04-26
## 결정 (mini-brainstorm 결과)
| 결정 | 값 | 근거 |
|------|-----|------|
| F3 단일 vs 분배 | 표면별 자연 동사 (꺼내 두다 / 잡아두다 / 한 줄 적다 / 보관) | 자연스러움 > 브랜딩 통일 |
| Strategy.md 동반 갱신 | YES — §1, §4.1, §7 | 어휘 일관성 |
| 회전 카피 4종 | #2, #3 교체 (#1, #4 유지) | 톤 보존 + 핵심 변경 최소화 |
| F4-E priming 위치 | Inbox 빈 상태 (가장 첫 사용 순간) | Zeigarnik 효과 자극 시점 |
| Package description | 동반 갱신 (외부 노출 표어) | code-spec 드리프트 차단 |
| e2e smoke 단언 | 직접 카피 단언 갱신 (selector 약화 X) | 카피 정책 변경 시 의도된 e2e 업데이트 |
## 신규 카피 (코드 표면별)
| 표면 | 신규 |
|------|-----|
| 트레이: Inbox 열기 | 보관한 메모 보기 |
| 트레이: 새 메모 | 한 줄 적기 |
| 토스트 #1 | (변경 없음) 이 생각은 이제 Inkling이 들고 있습니다. |
| 토스트 #2 | 머릿속에서 꺼내 두었습니다. |
| 토스트 #3 | 방금 한 줄 잡아뒀습니다. |
| 토스트 #4 | (변경 없음) 기록 완료. 이제 잊어도 됩니다. |
| Inbox 빈 상태 | 머릿속에 떠다니는 한 줄을 적어보세요. |
| QC 힌트 | Ctrl+Enter 저장 · Esc 취소 · 이미지 붙여넣기 |
| package.json description | Inkling — local-first 한 줄 보관 도구 |
## 후속
- 회전 카피 4종 전면 재작성 (현재 #1, #4 만 보존, 다른 변형 도입 가능)
- onboarding 흐름 카피 (슬라이스 외)
- 다국어 (영어 카피)

View File

@@ -4,17 +4,17 @@ Inkling 심리학 기반 습관화 전략
핵심은 사용자를 “메모 잘하는 사람”으로 훈련시키는 것이 아니라, 메모가 즐겁고 즉시 쓸모 있으며, 반복할수록 업무 불안을 줄여주는 행동 루프를 만드는 것입니다.
1. 핵심 행동 정의를 바꾼다: “메모 작성”이 아니라 “기억 구출
1. 핵심 행동 정의를 바꾼다: “메모 작성”이 아니라 “머릿속에서 꺼내 두기”
메모를 하지 않던 사람에게 “메모를 잘 써라”는 요구는 너무 큽니다. Inkling의 최소 행동은 다음처럼 재정의해야 합니다.
메모 = 지금 머릿속에 있는 것을 잊기 전에 바깥으로 꺼내는 1회 행동
즉, 사용자가 해야 할 일은 “정리”가 아니라 구출입니다. 정리는 AI와 나중의 리뷰가 담당합니다.
즉, 사용자가 해야 할 일은 “정리”가 아니라 꺼내 두기입니다. 정리는 AI와 나중의 리뷰가 담당합니다.
제품 문구도 이렇게 바꿉니다.
“새 메모 작성” → “기억 구출하기”
“새 메모 작성” → “한 줄 적기”
“제목을 입력하세요” → “한 줄만 던져도 됩니다”
“분류 선택” → “나중에 Inkling이 찾아드립니다”
“저장 완료” → “이제 이 생각은 잊어도 됩니다”
@@ -108,12 +108,14 @@ Gollwitzer의 실행 의도 연구는 “언제/어디서/무엇을 할지”를
“좋아요. 이 생각은 이제 Inkling이 들고 있습니다.”
나중에 찾을 수 있게 보관했습니다.”
머릿속에서 꺼내 두었습니다.”
“방금 하나의 업무 기억을 구출했습니다.”
“방금 한 줄 잡아뒀습니다.”
이는 “메모 = 귀찮은 일”이 아니라 메모 = 인지적 부담을 줄이는 행동으로 느끼게 합니다. 인지적 오프로딩 연구는 사람들이 외부 도구를 사용해 내부 기억·주의 부담을 줄인다는 점을 설명합니다.
회전 카피의 톤은 Zeigarnik 효과(미완결 과제가 머릿속에 남아 주의 자원을 잡아먹는 현상)를 외재화로 해소한다는 framing 으로 옮겼습니다 — F4-E. “꺼내 두다 / 잡아두다” 동사는 “머리에서 외부로 옮겨두면 더 이상 떠올라 괴롭히지 않는다” 라는 인지 부담 해소 감각을 직접 환기합니다.
4.2 능력감 보상: “내가 일을 잘 관리하고 있다”
자기결정성이론은 사람의 지속 동기에 자율성, 유능감, 관계성이 중요하다고 봅니다. Inkling은 사용자를 통제하기보다 선택권을 주고, 작은 성공을 보여주고, 동료에게 도움이 되는 연결을 만들어야 합니다.
@@ -320,7 +322,7 @@ Week 0: 첫 성공
성공 문구:
“첫 번째 기억을 구출했습니다. 이제 Inkling이 당신의 업무 맥락을 쌓기 시작합니다.”
“첫 한 줄을 잡아뒀습니다. 이제 Inkling이 당신의 업무 맥락을 쌓기 시작합니다.”
Week 12: 마찰 제거
@@ -358,7 +360,7 @@ Week 58: 정체성 강화
주간 리포트 예:
이번 주 Inkling이 구출한 업무 기억
이번 주 Inkling이 잡아둔 업무 기억
결정 근거 4개
트러블슈팅 2개
다음 주 액션 후보 5개
@@ -420,7 +422,7 @@ A안:
B안:
“이번 주 결정 근거 3개를 구출했습니다.”
“이번 주 결정 근거 3개를 잡아뒀습니다.”
가설:

View File

@@ -2,7 +2,7 @@
"name": "inkling",
"version": "0.2.0",
"private": true,
"description": "Inkling — local-first 기억 구출 도구",
"description": "Inkling — local-first 한 줄 보관 도구",
"author": "altair823 <dlsrks0734@gmail.com>",
"main": "out/main/index.js",
"scripts": {

View File

@@ -2,8 +2,8 @@ import { createHash } from 'node:crypto';
export const REWARD_COPIES = [
'이 생각은 이제 Inkling이 들고 있습니다.',
'나중에 찾을 수 있게 보관했습니다.',
'방금 하나의 업무 기억을 구출했습니다.',
'머릿속에서 꺼내 두었습니다.',
'방금 한 줄 잡아뒀습니다.',
'기록 완료. 이제 잊어도 됩니다.'
] as const;

View File

@@ -12,8 +12,8 @@ function buildMenu(
runImport: () => void
) {
const items: MenuItemConstructorOptions[] = [
{ label: '구출한 메모 보기', click: showInbox },
{ label: '기억 구출하기', click: showCapture },
{ label: '보관한 메모 보기', click: showInbox },
{ label: '한 줄 적기', click: showCapture },
{ type: 'separator' },
{ label: '지금 백업', click: runBackup },
{ label: '내보내기...', click: runExport },

View File

@@ -85,7 +85,7 @@ export function App(): React.ReactElement {
{loading && notes.length === 0 ? (
<div className="empty"> </div>
) : notes.length === 0 ? (
<div className="empty"> . <code>Ctrl+Shift+J</code></div>
<div className="empty">릿 . <code>Ctrl+Shift+J</code></div>
) : filtered.length === 0 ? (
<div className="empty"> .</div>
) : (

View File

@@ -65,7 +65,7 @@ export function App(): React.ReactElement {
{images.map((i, idx) => (<img key={idx} src={i.url} alt="" />))}
</div>
)}
<div className="hint">Ctrl+Enter · Esc · </div>
<div className="hint">Ctrl+Enter · Esc · </div>
{err && <div className="err">{err}</div>}
</div>
);

View File

@@ -26,6 +26,6 @@ test('inbox shell shows v0.2 empty state', async () => {
}
await inbox.waitForLoadState('load');
await expect(inbox.getByRole('heading', { name: 'Inkling' })).toBeVisible();
await expect(inbox.getByText('첫 기억을 구출해보세요.')).toBeVisible();
await expect(inbox.getByText('머릿속에 떠다니는 한 줄을 적어보세요.')).toBeVisible();
await app.close();
});