← 목록
AI 2026-06-13 6KB 읽기 6분

크라우니AI 계정·프라이버시 격리·회원가입 넛지·대화 보고서

개요

crowny.org(크라우니AI, :9852)에 4가지를 추가/수정했다.
  1. 대화 프라이버시 격리 — 비로그인 시 남의 대화가 보이던 누수를 차단(owner 스코핑).
  2. 계정(아이디/비밀번호) 회원가입·로그인 — scrypt 해싱, 계정마다 비밀 ownerToken.
  3. 회원가입 넛지 — 대화 중 점진 권유(배너 3턴→토스트 5턴→모달 7턴), 로그인 상태 표시, 비로그인 데이터 손실 경고.
  4. 대화 보고서(명세서) — 대화 종료/저장 시 Gemini 구조화 요약 → 저장·열람·마크다운 다운로드.
리서치(울트라 딥리서치 워크플로): 넛지 3~7턴 점진+손실회피 문구가 전환 최고, 익명→계정 멱등 이관, 보고서 구조화 JSON.

1. 프라이버시 격리 (누수 수정)

  • 근인: /api/conversations/sync가 클라 로컬 대화를 서버 전체 대화(listConvs())와 병합해 전원의 대화 전문을 반환. 누구나 접속 시 남의 채팅이 사이드바에 떴다.
  • 수정: 대화에 owner 필드 도입. 모든 대화 API(list/get/post/put/delete/sync)를 X-Crowny-Owner 헤더로 스코핑. owner 없는(레거시) 대화는 누구에게도 노출 안 됨. 프론트는 브라우저별 익명 토큰(anon_...) 생성·전송. 진입 시 항상 새 채팅.
  • 검증: 익명/타인 목록=빈배열, 직접열람=404, 레거시=404.

2. 계정 인증 (engine/auth.js)

  • 사용자 레코드 data/users.json: {username, salt, hash(scrypt), ownerToken(비밀), created}.
  • API: POST /api/auth/signup|login|migrate|change-password (분당 12회 제한).
  • 계정 ownerToken = 로그인 후 대화 스코핑 자격증명(별도 세션검증 불필요, 토큰이 곧 자격).
  • 회원가입 시 anonOwner 동봉 → 익명 대화/보고서를 계정으로 이관(migrateOwner/migrateReports).

3. 회원가입 넛지 (index.html)

  • triggerNudge(턴): 비로그인 + 사용자 턴수 기준 3=배너 / 5=토스트 / 7+=모달. 세션 내 1회씩.
  • 문구: 손실회피("이 대화는 저장되지 않습니다 / 탭을 닫으면 사라집니다").
  • 헤더 우측 로그인 상태 표시(mountAuthStatus/updateAuthUI): 비로그인=로그인·회원가입 버튼, 로그인=아바타+아이디+로그아웃.
  • 대화 중 로그인onAuthSuccess/api/auth/migrate 호출해 직전 익명 대화를 계정으로 매칭 저장.
  • beforeunload: 비로그인 3턴 이상이면 이탈 경고.

4. 대화 보고서 (engine/report.js)

  • 트리거: 헤더 "보고서" 버튼(현재 대화 저장) + 새 채팅 전환 시 6메시지↑ 자동 저장(silent).
  • 흐름: POST /api/reports/generate(비동기 jobId) → Gemini flash 구조화 요약 → data/reports/<id>.json(owner 스코핑) → /api/reports/result 폴링.
  • 구조: title/summary/keyPoints/decisions/actionItems/keywords/sentiment/followUpNeeded + rawMessages(최근 100턴).
  • 열람: 목록·상세 모달, 마크다운 다운로드(?o= 쿼리로 owner 인증, <a> 링크라 헤더 불가).
  • 실패(429/503) 시 첫 메시지 기반 최소 보고서로 폴백.

관련 파일

  • /Users/ef/crowny-ai/server.js — owner 스코핑, /api/auth/, /api/reports/, reportJobs, migrate
  • /Users/ef/crowny-ai/engine/auth.js — 가입/로그인/비번변경/findByOwnerToken (scrypt)
  • /Users/ef/crowny-ai/engine/report.js — generateReport/listReports/migrateReports/toMarkdown
  • /Users/ef/crowny-ai/public/index.html — owner 동적화, 인증/넛지/보고서 UI(자가 마운트)
  • /Users/ef/crowny-ai/대화계정보고서.한선 — 동반(넛지 단계·소유자검증·보고서골격, 컴파일 검증)

검증 (GREEN)

  • 익명 격리 7종, 인증 6종, 통합 플로우(익명→가입 이관→계정목록→보고서생성→마크다운다운로드) 전부 PASS.
  • 외부 crowny.org 200 + 신규 기능 반영 17건 + 외부 익명 보고서 빈배열.

잔여 / 후속

  • 비밀번호 재설정·이메일 없음(아이디/비번만). 추후 복구 수단 필요.
  • 보고서 자동 트리거는 새 채팅 전환 시 6메시지↑만. 30분 무활동 자동 생성은 미구현(Phase 2).
  • PDF 다운로드 미구현(현재 마크다운). puppeteer 도입 시 추가.
  • 리서치 워크플로 verify 단계는 세션 한도로 미완(설계·리서치는 확보).

후속 3종 완료 (2026-06-13, 울트라 딥리서치 검증)

리서치(워크플로 wp3cqsoro)가 내 접근을 확증: 비번복구=복구코드(이메일 없으면 필수), PDF=무의존성 print-to-PDF(puppeteer 금지).

5. 비밀번호 재설정 (복구코드 — 이메일 없음)

  • 가입 시 1회용 복구코드(XXXX-XXXX-XXXX-XXXX, 32자모집합) 발급 → scrypt 해시 저장(평문 미저장), 응답에 1회 노출.
  • POST /api/auth/reset {username, recoveryCode, newPassword} → 검증 후 비번+복구코드 회전(옛 코드 무효). 분당 12회 제한(무차별 방어).
  • 정규화: 대문자/하이픈 무시. 프론트: 가입 후 복구코드 모달(복사), 로그인 모달 "비밀번호를 잊으셨나요?" → 재설정 폼.
  • engine/auth.js: makeRecoveryCode/hashRecovery/resetPassword.

6. 30분 무활동 자동 보고서

  • 프론트 markActivity()(send 시) + 60초 인터벌. 30분 무활동 + 현재 대화 6메시지↑ + 미보고 → saveReport(silent). 1회 후 재무장.

7. PDF 다운로드 (무거운 의존성 0)

  • engine/report.js toHtml(r, autoPrint) → 인쇄용 단독 HTML(print CSS, 한글 시스템폰트, ☐ 체크박스).
  • GET /api/reports/:id/view?print=1&o=owner → 새 창 → window.print() → 사용자 PDF 저장. printReport() 버튼.

검증

  • 재설정 5종(발급→재설정→새비번로그인→정규화→옛코드회전거부) PASS, PDF뷰 200+체크박스+프라이버시404, 외부 17매칭.
  • 동반 대화계정보고서.한선에 복구코드유효·무활동자동보고서 판정 추가(컴파일 검증).

리서치 권고 중 미채택(향후)

  • 복구코드 8~16개 다발 + 실패 잠금(지수백오프): 현재는 단일 회전코드 + 12/min 레이트리밋으로 갈음. 다발 코드는 후속.