작업 이력

작업 이력 — 2026-06-16

기획 (planner)

A. 요구사항 정의서 정본화 — docs/REQUIREMENTS.md 신규

분산돼 있던 요구사항(CLAUDE.md·ROADMAP.md·ADMIN-PLAN.md·PROJECT-INQUIRY-ANALYSIS.md)을 단일 정본으로 집약. 분산 문서는 대체하지 않고 요약·상호참조(링크).

  • 기능 요구사항 FR-1~FR-12 (각 수용기준 AC 포함), 비기능 요구사항 NFR-1~NFR-8.
  • 안전가드(NFR-1)는 운영 MySQL hp_setting safety 시드값과 일치 — 근거: malgn-helper-api/migrations/002_admin_console.sql INSERT 4-4 (라인 128~134). 값:
    • confidence_threshold=0.6 · escalate_on_low=true · pii_masking=true
    • pii_patterns=주민번호·전화·이메일 정규식 3종(JSON) · blocked_words="비방","욕설","스팸","광고"
  • Phase 1/2 범위 경계, 표준답변 우선(FR-1)·출처 인용(FR-2)·"모름"/에스컬레이션(FR-3)·비공개 자료 비노출(FR-10) 정책 명문화.
  • 추적성 매트릭스(요구사항↔화면/데이터/로드맵), 정책 결정/미정 TODO 5건(Q1~Q5), 후속 핸드오프.

발견한 불일치(Q2): hp_service 시드 슬러그(step/lms-general/lms-mixed/lms-private/lms-public-security/lms-global)와 ADMIN-PLAN §4-3-1·use-bots.ts(lms-general/-refund/-public/-security/-hybrid/-global)가 불일치. 정본 슬러그 세트 확정 필요(DBA+기획).

B. bots/ 화면 기획 결정 — docs/ADMIN-PLAN.md §4-13 신설

malgn-helper-admin/pages/bots/{index,[id]}.vue + use-bots.ts(use-admin-menu.ts:39 메뉴)로 기획 없이 선구현된 "봇 관리" 화면 검토.

  • 결정: 정식 편입 + 백엔드 완성 전까지 메뉴 숨김. 봇 단위 거버넌스(서비스별 말투·답변범위·"모름" 강도·에스컬레이션 임계값·가시성·학습소스)는 분류 정책·P2 다중 챗봇과 정합해 가치 있음. 단 현재 localStorage 데모뿐(hp_bot/hp_bot_source·/admin/bots 부재)이라 노출 시 오인 위험 → 백엔드 게이트.
  • ADMIN-PLAN 반영: IA 트리·§3-2 메뉴표(2.0, 숨김 표기)·§4-13 화면 명세·§5-3 API(/admin/bots)·§9 결정 로그.
  • 후속(api-developer·DBA): hp_bot(페르소나·답변범위·모델 파라미터)·hp_bot_source(bot↔material/standard_answer 다대다) 신설 + GET/POST/PATCH/DELETE /admin/bots(requireRole('admin','developer')). use-bots.ts가 이미 해당 스키마에 1:1 매핑.

핸드오프

  • DBA: Q2 슬러그 정합, FR-12 편입 시 hp_bot/hp_bot_source DDL.
  • api-developer: /admin/bots CRUD, safety 설정값 실제 적용 검증(NFR-1 AC).
  • QA: NFR-1(safety 화면=시드)·FR-2(출처 누락 차단)·FR-3(저신뢰 분기) 테스트.
  • 개인정보보호관리자: Q3 비공개 자료·PII 노출 규칙 확정.

생성/수정 파일

  • 신규: docs/REQUIREMENTS.md
  • 수정: docs/ADMIN-PLAN.md (IA 트리·메뉴표·§4-13·§5-3·§9)

보안 수정 (security-reviewer → deployer)

무인증 노출 라우트 차단 + 디버그 라우트 제거. api/admin 2개 레포 배포.

malgn-helper-api — Cloudflare Workers

  • 커밋: 41d6f6a / Version ID: 31dbb92a-f503-4e76-965a-3d60fe73a885
  • URL: https://malgn-helper-api.malgnsoft.workers.dev
  • 무인증 노출 라우트에 requireAuth/requireRole 가드 추가: /admin/kpi·/admin/cost·/admin/evals·/image-assets(GET·/:id/standard-answers(GET·/:id·PATCH·DELETE). 가드 정의 블록 TDZ 회피 위해 파일 상단으로 이전.
  • 무인증 디버그/일회용 라우트 6개 삭제: GET /db/ping·/db/whoami·/db/tables·/db/columns/:table·/db/sample/:table, POST /admin/migrate/hp_image_asset.
  • 빌드: tsc --noEmit 11 baseline(신규 0, working↔HEAD 동일 확인), wrangler deploy --dry-run 번들 정상.
  • 검증(무인증 curl): /admin/kpi·/admin/evals·/admin/cost·/image-assets·/standard-answers모두 401(이전 200 차단). /db/sample/tb_user·/db/tables·/db/ping모두 404(제거 확인). 루트 / → 200.

malgn-helper-admin — Cloudflare Pages

  • 커밋: f1a4b20 / production: https://malgn-helper-admin.pages.dev / alias: https://e9c060c8.malgn-helper-admin.pages.dev / buildId: 21f06fa3-6824-4219-a009-30b1865b479e
  • index.vue·cost.vue·qa-evals.vue·images.vue fetch에 credentials:'include' 추가(api 가드와 정합). pages/forbidden.vue 신설.
  • 빌드: nuxt build 통과(forbidden 신규 chunk 산출 확인).
  • 검증(curl): prod / 200(buildId 마커 확인). /forbidden200(이전 404 해소, alias도 200). 연동 4페이지 /·/cost·/qa-evals·/images → 모두 200(SSR 셸).

정합

  • 두 레포 working tree clean, origin/main 동기화 완료(미푸시였던 직전 배포 커밋 9cefd48·2d1acf9도 함께 푸시되어 origin↔live 일치).
  • 경계 준수: mng(docs)·pms 미변경.

서비스토큰 관찰모드 (security-reviewer → deployer)

PMS→API 서비스토큰 가드 + LLM rate limit 관찰모드(SERVICE_TOKEN_ENFORCE=0) 점진 도입. api/pms 2개 레포 동시 배포 + 시크릿 양쪽 등록. 하드차단(1) 아님 — 회귀 없음.

시크릿/환경 등록

  • 강한 랜덤 토큰(openssl rand -hex 32, 64 hex, prefix a999ed…) 1개를 양쪽에 동일 등록(값 비노출).
  • api: wrangler secret put PMS_SERVICE_TOKEN (Worker) — secret list 확인.
  • pms: wrangler pages secret put NUXT_PMS_SERVICE_TOKENProduction + Preview 양쪽 등록 확인(Value Encrypted).

malgn-helper-api — Cloudflare Workers

  • 커밋: 85025ce / Version ID: aced5319-a03b-470c-87b1-8483a12e592d
  • URL: https://malgn-helper-api.malgnsoft.workers.dev
  • requireServiceToken(관찰: X-Service-Token-Status: missing|mismatch 헤더만, ENFORCE≠1이면 통과) + rateLimitLlm(route+IP 키) 미들웨어 신설.
  • 적용: LLM generate 4종(/pms/projects/:id/briefing/generate·/pms/posts/:id/announce-eval/generate·/pms/posts/:id/eval/generate·/pms/projects/:id/standard-answer-suggestions)에 guard+ratelimit, /standard-answers(POST)·/standard-answers/:id/use에 guard.
  • wrangler.jsonc: [[ratelimits]] RL_LLM(12/60s), vars.SERVICE_TOKEN_ENFORCE="0".
  • 배포 바인딩 확인: env.RL_LLM (12 requests/60s), env.SERVICE_TOKEN_ENFORCE ("0").

malgn-helper-pms — Cloudflare Pages

  • 커밋: e4b54f7 / production: https://malgn-helper-pms.pages.dev / alias: https://db098a98.malgn-helper-pms.pages.dev / deployment: db098a98-97b8-4f45-90af-7eeee4274b3d
  • server/utils/forward.ts(서버 전용 투명 프록시, x-service-token 서버 주입) + 서버 프록시 라우트 5종(/api/standard-answers, /api/pms/...generate 4종).
  • nuxt.config.ts runtimeConfig.pmsServiceToken(env NUXT_PMS_SERVICE_TOKEN, public 아님). 호출부 6곳을 프록시 경유로 전환 + 안내글평가 UI(AnnounceEvalCard.vue·eval.vue·types/announce-eval.ts).
  • 빌드: nuxt build 통과, 서버 프록시 5 chunk 산출 sanity OK, project-name=malgn-helper-pms 일치.

검증

  • 회귀 없음: pms prod /200. pms 프록시 POST /api/standard-answers(빈 바디) → 400(핸들러 validation 도달=토큰 일치, 가드 통과). 프록시는 x-service-token-status 미전파(정상, forward가 content-type/status/body만 전달).
  • 관찰모드: api 무인증 POST /standard-answers·/pms/.../briefing/generate400(핸들러 validation, 401 아님=관찰 통과) + 헤더 X-Service-Token-Status: missing. 잘못된 토큰 → mismatch. 가드가 missing/mismatch 구분 + 둘 다 통과(ENFORCE=0).
  • rate limit: RL_LLM(12/60s) 바인딩 등록·active 확인. 단 합성 burst(순차 14·병렬 20)에서 429 미발생 — Cloudflare rate-limiting 바인딩은 best-effort/eventually-consistent(버스트 언더카운트 가능). 미들웨어 배선(handler 앞)·바인딩은 정상. ENFORCE=1 전환 전 실트래픽 로그로 재확인 권장.

정합

  • api·pms 두 레포 working tree clean, origin/main 동기화. mng은 이번 단계 비대상(이 history 항목만 별도 커밋 예정).
  • 경계 준수: SERVICE_TOKEN_ENFORCE0(관찰) 유지 — 하드차단(1) 미전환.

배포

배포 시각·커밋 로그(워크스페이스 deploy.sh 기록, helper repo에서 이관).

21:57 — malgn-helper-api → Cloudflare Workers

  • 커밋: 41d6f6a (신규 커밋: yes)
  • 메시지: fix(security): guard admin/kpi·cost·evals·image-assets·standard-answers + remove unauth /db debug routes

21:58 — malgn-helper-admin → Cloudflare Pages

  • 커밋: f1a4b20 (신규 커밋: yes)
  • 메시지: fix(security): send credentials on kpi/cost/evals/images + add /forbidden page

22:18 — malgn-helper-api → Cloudflare Workers

  • 커밋: 85025ce (신규 커밋: yes)
  • 메시지: feat(security): service-token guard + LLM rate limit on PMS routes (observe mode)

22:19 — malgn-helper-pms → Cloudflare Pages

  • 커밋: e4b54f7 (신규 커밋: yes)
  • 메시지: feat: service-token server proxy + announce-eval UI
Malgn Helper(고객상담 AI 챗봇) 프로젝트 문서·작업 이력