---
title: "작업보고 — 코치노트 AI v1.0-rc2 · spec_01 기반 골격(DB·모델연동·캐싱)"
category: "workreport"
document_type: "작업보고"
source_status: "generated"
knowledge_group: "03_history"
priority: "High"
purpose: "코치노트 AI v1.0-rc2 6분할 구현 중 1/6(기반 골격) 작업분 보고. 요청별 운영로그·모델 단가표(price_version)·기간 집계/감사 뷰, 교체 가능한 채팅 백엔드(chat-proxy, Gemini 기본·OpenAI 폴백), 프롬프트 캐싱 친화 메시지 조립 골격과 원가 단일 계산 헬퍼를 구현. SQL 적용 완료·코드 커밋(PR#36) 반영, chat-proxy CF 배포는 운영 잔여."
read_when: ["코치노트AI","최신상태복구","원가·비용관리"]
updated: "2026-06-06"
work_timestamp: "20260606_181048"
context: "달록본레포CC (D:\\dallog\\dallog_git)"
source_of_truth: "https://dallog-tools.hansbridge.co.kr/knowledge/"
---

# 작업보고 — 코치노트 AI v1.0-rc2 · spec_01 기반 골격

> 코치노트 AI(운동기록 기반 유료 AI 코치) v1.0-rc2는 GPT-5.5·Claude Opus 4.8 교차검수와 사장님 의도·정서·지침을 반영해 **6개 명세(spec01~06)로 분할**되었고, 1스레드=1명세 방식으로 순차 구현되었다. 본 문서는 그중 **1/6(기반 골격)** 작업분의 보고다. RC2 전체는 구현·커밋 완료(PR#36) 상태이며, 본 보고는 spec_01 작업분을 KB 자산으로 보존하기 위한 기록이다.

## 0. 문서 정보
- **작업 날짜**: 2026-06-06 (구현) / 2026-06-07 상태 반영(SQL 적용·커밋 완료)
- **담당 작업 단위**: spec_rc2_01_foundation (총 6개 중 1/6)
- **관련 명세**: `docs/go_work/spec_rc2_01_foundation.md`, `decision_log_rc2.md`(#1·#2·#13·#14)
- **작성 목적**: 코치노트 AI 비용 추적·모델 연동·캐싱의 토대를 어떻게·왜 만들었는지 보존, 후속 컨텍스트 인수인계

> 용어 병기 — worklog(작업보고) / migration(DB 구조 변경 SQL) / RLS(Row Level Security·행 수준 보안) /
> RPC(원격 호출 함수) / price_version(단가 버전) / question_type(질문유형) / implicit caching(암묵적 캐싱) /
> chat-proxy(채팅 중계 워커) / system prompt(시스템 지시문) / transcript(대화 원문) / Snapshot(운동기록 요약본).

## 1. 작업 목적 / 요청 배경
달록(PaceLog)은 메인 사업(팩토핀)이 아닌 **서브파이프라인**이라, "수익 전 비용 누수 방어"가 1번 원칙이다(decision_log #1). 따라서 채팅 기능을 켜기 전에 **① 돈이 어디서 새는지 보는 장치(운영 로그·원가)** 와 **② 모델을 싸고 안전하게 바꿀 수 있는 구조** 를 먼저 세운다. spec_01은 이후 2~6/6이 모두 얹힐 토대다.

## 2. 적용 기준
- **적용 명세**: spec_rc2_01_foundation (모델 선택·운영로그·price_version·question_type·캐싱)
- **적용 결정로그**: #2(Gemini 2.5 Flash-Lite 기본·교체가능), #13(캐싱), #14(요청별 로그·원가 감시)
- **사장님 지침**: 원가 계산은 "클라이언트가 하되 DB가 누락방지·감사를 책임지는" 구조(9개 보정 장치). 모델 하드코딩 금지. 필드 임의 축소 금지
- **금지사항 준수**: brief-proxy(단발 AI 브리프) 확장·훼손 금지 → 신규 chat-proxy 분리. 대화 원문 저장은 본 조각 범위 밖(spec_04 소관)

## 3. 구현 범위

| 구분 | 구현 내용 | 관련 파일 | 상태 |
|---|---|---|---|
| DB 운영로그 | `coach_request_log`(13필드+provider·pricing_snapshot_id, append-only, 누락방지 NOT NULL/CHECK) | `migrations/2026-06-06_coachchat_foundation.sql` | 완료(적용됨) |
| DB 단가표 | `coach_price_table`(단가 변경=새 price_version row, 활성 1개 부분유니크) + 시드 3행(placeholder) | 동상 | 완료(적용됨) |
| DB 조회·집계 | `get_active_coach_price` RPC + 집계 4뷰(일/월내주간/보름/월) + 원가 감사 뷰 (전부 security_invoker=on) | 동상 | 완료(적용됨) |
| 모델 연동 | 신규 `chat-proxy` 워커 — provider/model env 교체가능(Gemini 기본), Gemini/OpenAI/Anthropic, stream+usage 반환 | `workers/chat-proxy/{index.js,wrangler.toml}` | 코드 완료 / CF 미배포 |
| 캐싱 구조 | `assembleCoachChat` — 고정 system 선두(캐싱 대상) / 가변 데이터 messages 앞단(캐싱 제외) | `src/lib/coachChat/systemPrompt.ts` | 완료 |
| 원가 계산 | `calculateEstimatedCost`(유일 계산 지점) + `fetchActiveCoachPrice`(RPC) + `logCoachRequest` | `src/lib/coachChat/{pricing,requestLog}.ts` | 완료 |
| 타입·클라이언트 | PlanType·QuestionType(10종)·ChatProvider·CoachPrice 등 + chat-proxy 호출 | `src/lib/coachChat/{types,chatApi}.ts`, `src/lib/supabase.ts` | 완료 |

## 4. 수정 파일

| 파일 | 변경 내용 | 비고 |
|---|---|---|
| `migrations/2026-06-06_coachchat_foundation.sql` | 단가표·요청로그·RPC·집계/감사 뷰·RLS (4 실행유닛) | 신규 |
| `migrations/2026-06-06_coachchat_foundation_GUIDE.html` | SQL 실행 가이드(순서·기대결과·보존/삭제·복사버튼) | 신규(이중발행 b) |
| `workers/chat-proxy/index.js` · `wrangler.toml` | 멀티턴 채팅 백엔드(교체가능·Gemini경로·stream) | 신규 |
| `src/lib/coachChat/{systemPrompt,types,pricing,requestLog,chatApi}.ts` | 캐싱 조립·타입·원가 단일헬퍼·로그·호출 | 신규 |
| `src/lib/supabase.ts` | `CoachRequestLogRow` 타입 추가 | 수정(타입만) |

> 후속 스레드가 `types.ts`·`systemPrompt.ts`를 spec03~05a 범위(플랜·대화방·메모리·가드레일 전문)로 확장했으나, spec_01이 정의한 **캐싱 경계와 원가 단일 계산 헬퍼는 그대로 보존**되었다.

## 5. SQL 적용 여부

| 파일 | 목적 | 결과 |
|---|---|---|
| `2026-06-06_coachchat_foundation.sql` | 단가표·요청로그·RPC·집계/감사 뷰·RLS | **적용 완료** — spec06 통합 MCP 검증에서 RPC 라이브 동작 확인 |

> 적용 주체 = 사장님 수동(관례). 자동 적용 시도 없음. 단가 변경 시 기존 row 수정 금지·새 price_version 추가.

## 6. 빌드 결과
- `npm run build`(tsc strict + vite) **통과**, 신규 모듈 타입 오류 0. RC2 누적 빌드도 통과.

## 7. 기능 검증 (MCP 브라우징 / 통합 시점)
spec_01은 단독 화면이 없는 골격이라 작성 당시엔 build 검증만 가능했고, 실동작은 **spec06 통합 시점에 라이브 검증**되었다.

| 검증 항목 | 결과 | 근거 |
|---|---|---|
| coach_request_log·RPC 라이브 동작 | PASS | spec06 MCP 5화면 검증 중 RPC 라이브 동작(handoff_rc2_complete §1·§3) |
| chat-proxy 실응답(AI 호출) | N/A(보류) | CF 미배포 → 프론트 graceful 오류 배너로 대체(`spec06_screenshots/coach-02-chat-graceful-error.png`) |
| implicit caching 실측 | N/A | 배포·모델키 주입 후 측정 가능(Phase 0.5 후보) |

## 8. 명세 대비 구현 완료 여부 (spec_01 §6 완료 정의)

| 명세 요구사항 | 결과 | 근거 |
|---|---|---|
| 모델 호출 설정값 교체 구조(Flash-Lite 기본, 하드코딩 금지) | PASS(코드) | chat-proxy env + resolveProvider/Model |
| 요청별 로그 13필드 전부 기록 | PASS | coach_request_log + requestLog.ts |
| price table + price_version + 기간 집계 | PASS | 단가표·RPC·집계4뷰·감사뷰 |
| question_type 필드(기본 other_unknown), 자동분류 미구현 OK | PASS | 컬럼 기본값 + QuestionType 10종 |
| 고정 system prompt 선두 배치(캐싱 친화) | PASS | assembleCoachChat 구조 |
| 빌드 | PASS | npm run build 통과 |

## 9. 의사결정 (선택·배제·근거·재검토)

| 결정 | 선택 | 배제 | 근거 | 재검토 조건 |
|---|---|---|---|---|
| 원가 기록 방식 | 클라이언트 계산 + DB 누락방지/감사 | DB 트리거 자동계산 / 워커 service_role 기록 | service_role 워커 주입 회피 + RLS 본인만 유지, 계산은 단일 헬퍼로 분산 방지(사장님 지침) | provider 실과금 안정 수신 시 actual_cost 컬럼 확장 |
| 로그 필드 수 | 표 13필드 진본 전부 | §6 "12개" 표기 | "필드 축소 금지" 원칙(단순 기재 불일치로 판단) | — |
| 채팅 백엔드 | 신규 chat-proxy 분리 | brief-proxy 확장 | 단발 브리프와 멀티턴·저장·과금의 책임 분리 | — |
| 모델 | Gemini 기본 + env 교체 | 특정 모델 하드코딩 | 비용방어 + "사후 교체가 기술적으로 안전"(#2). 키 없으면 OpenAI 폴백 | Flash-Lite 품질 부족 시 nano 전환 |
| 캐싱 | 고정 system 선두·가변 분리 | 사용자별 전체 캐싱 | implicit caching = 원가절감, 가변 데이터는 캐시효율↓(§5.2) | explicit caching 난이도 확인(Phase 0.5) |

## 10. 문제와 해결
- **문제**: 클라이언트 계산 시 계산식이 화면·워커 여러 곳에 흩어질 위험 + 예상원가·단가버전 누락 위험.
- **해결**: ① DB `NOT NULL`+`CHECK`로 누락 차단 ② `calculateEstimatedCost` 단일 헬퍼로 계산 일원화 ③ 감사 뷰(`coach_request_log_cost_audit_view`)로 저장값 vs 현재단가 재계산 괴리 사후 탐지 — 3중 장치.
- **문제**: 뷰가 RLS를 우회해 타인 데이터 노출 위험. **해결**: 전 뷰 `security_invoker=on`으로 호출자 RLS 적용.

## 11. 미해결 / 보류 / 후속 작업

> 명세가 허용한 Phase 이연과 출시 전 필수 운영작업을 구분한다. 어느 것도 임의 축소가 아니다.

| 항목 | 상태 | 후속 |
|---|---|---|
| chat-proxy CF 배포 + 모델키 주입 | 출시 전 필수(운영) | 배포 후 실응답·차감 라이브 확인 |
| Gemini 2.5 Flash-Lite 키 발급 | 보류(사장님) | 키 발급 후 워커 시크릿 주입(OpenAI 폴백으로 임시 동작) |
| 시드 단가 placeholder | 보류(배포 전) | 공식 단가 확인 후 새 price_version row 추가 |
| explicit caching | Phase 0.5 이연(명세 허용) | 난이도 확인 후 도입 |
| question_type 자동분류 | Phase 1 이연(명세 지정) | rule-based 분류 + off_topic↔가드레일 대조 |
| 운영자 전역 원가 집계 | 후속(service_role) | 현재 뷰는 RLS 본인만 → spec05a OWNER 패널 |

## 12. 결과 / 최종 판단
- **spec_01 작업 단위**: 코드·DB·구조·빌드 기준 **완료**. SQL 적용·코드 커밋(PR#36) 완료. chat-proxy CF 배포만 운영 잔여.
- **Phase0 종료 영향**: 골격은 종료 가능. 실 AI 응답은 배포·모델키 의존(코드는 graceful 대기로 막지 않음).
- **사장님 확인 필요**: Gemini 키 발급 · chat-proxy 배포 · 공식 단가 갱신 3건.

## 13. 작업자 메모
- 본 보고의 "남은 작업"은 spec_01 착수 당시엔 의도적으로 비웠으나(RC2 미완 오해 방지), RC2 전체 완료된 현재는 §11에 정직히 명시했다.
- 본레포 상세 사료: `docs/go_work/worklog_spec01_foundation.md`(+ RC2 KB 보정 기록), `handoff_spec01_to_spec02.md`, `handoff_rc2_complete.md`.
