← /log
2026-04-11

개발 로그

1,738 words·raw from wai-vault/02-DevLog

2026-04-11 개발 로그

세션 요약

역대급 생산성 날 — Sprint 1~9.5 일괄 처리 + Nexus Credits 런칭 준비

Loren /effort max + "ㄱㄱ 존나 중요한 작업" → 하루 단위 sprint 9개 (1, 2, 3, 4, 5, 6, 7, 8, 9, 9.5) 를 로컬→push→staging→prod 전부 완료. BYOK 폐기 + Nexus Credits 통합 결제 + 4단계 Role + Watchdog 확장 + 사용량 대시보드 + dashboard 리팩토링까지.

통계

  • 커밋: 수십 개 (파일별 분리 커밋 원칙 준수)
  • 신규 파일: 40+ (billing.js, 9 pages/*.js, i18n 분리, panels, migrations, etc)
  • 500줄 한도 해소: dashboard/index.html 1214→254, board/i18n.js 848→분리
  • 남은 부채: webhook/claude-bridge.js 961 (P1), nginx drift (P0 결정 대기)

Sprint 1 — 블록 해제 ✅

목표: Vite vuln, subprocessors 링크, T71 verifyAdminAuth, T72 Sidebar

  • npm audit fix → Vite 6.4.1→6.4.2 (high vuln 해소)
  • subprocessors.mdsubprocessors.ko.md rename + 참조 3곳 업데이트
  • T71: verifyAdminAuth 에서 company_admin 제거 → super_admin only
  • T72: Sidebar AI팀/두뇌 메뉴 superAdminOnly 플래그
  • 두 repo 분리 커밋 + staging + prod 배포

부채 발견: #47 LegalPanel 에 subprocessors/dpa 링크 추가 (pending)


Sprint 2 — API 슬롯 준비 ✅

목표: 외부 API 5개 (mailer, alimtalk, biz-lookup, payments, tax-invoice) 모듈 + billing.js 신규

  • 발견: 5개 모듈 전부 이미 구현되어 있음 — config.EXTERNAL_FEATURES.{name} 기반 폴백 완비. 키 주입만 하면 즉시 작동
  • 신규: modules/billing.js (335→461줄) — Nexus Credits 코어 (PLANS/TOPUP_PACKAGES/getBalance/deduct/topup/getHistory/setAutoTopup/calculateCost/canExecute/getMonthlyReport)
  • 신규: config/token-rates.json — 10 모델 원가 요율 (+10% buffer)
  • 신규: server/migrations/2026-04-11-nexus-credits.sql — billing_transactions 테이블 + companies plan enum 확장

Sprint 3 — 500줄 부채 정리 ✅

목표: board i18n.js 848줄 + PostDetail.jsx 576줄 분리

  • src/i18n/ 생성 → ko.js (491) + ja.js (482) + index.js (28 re-export)
  • PostDetail.jsx 576 → 249 + panels/ (markdown 101 / StepProgress 130 / DeliveryList 124 / CommentThread 94)
  • Vite 빌드 검증 + 커밋 + push + 배포

Sprint 4 — Role 4단계 DB/서버 ✅

목표: super_admin / company_owner / company_admin / company_user 4단계 + 승인 플로우

  • Migration: users.role ENUM 4값 + status/approved_by/approved_at 컬럼, invites.status/permissions/approval_note 추가
  • rls.js: isCompanyOwner, isCompanyOwnerOrHigher, isCompanyAdminOrHigher helper 추가
  • signup.js: 첫 가입자 = company_owner + pending_approval (ER_BAD_FIELD_ERROR fallback)
  • admin/invites.js: owner = 직원/관리자 초대, admin 승인 필요 / approve 엔드포인트 2개 (invites, users)
  • staging + prod 마이그 실행 (wai_board 공유)

Sprint 5 — Role 4단계 클라 ✅

목표: board-approval-system UI 4단계 대응

  • Sidebar.jsx: 4단계 재분류 + "결제" 메뉴 추가 (companyOwnerOnly)
  • App.jsx: /billing lazy import + BalanceBadge mount
  • BillingPage.jsx: placeholder 작성 (Sprint 7 에서 실구현)
  • InvitePanel.jsx: 템플릿 버튼 2개 (직원/관리자) + 권한 토글 + status 뱃지
  • i18n ko/ja companyOwner 키 동기화

Sprint 6 — Nexus Credits DB + 서버 ✅

목표: billing.js 실 wiring + cost-tracker 차감 + NEXUS_CREDITS_ENFORCE 플래그

  • plugins/board/billing.js 신규 — HTTP dispatch (/billing/plans /balance /usage /topup /auto-topup /enterprise-inquiry /usage/report)
  • plugins/board/dispatch.js 신규 — approvals + billing 라우팅 체인 (index.js 500줄 한도 지키려)
  • cost-tracker.js: companyId 파라미터 + billing.deduct hook (NEXUS_CREDITS_ENFORCE === 'true' 일 때만)
  • claude-bridge.js 에 billing.init + /billing/* wiring
  • TossPayments 공식 테스트 키 주입: test_gck_docs_Ovk5rk1EwkEbP0W43n07xlzm / test_gsk_docs_OaPz8LKGPzuLAD1tbHd4dDWBD
  • hotfix: billing.getPool() → require('../plugins/board/shared') 직접 pool 참조 (초기 db_not_ready 에러)

Sprint 7 — Nexus Credits UI ✅

목표: BillingPage 실구현 + 상단바 뱃지 + 소진 경고 모달

  • BillingPage.jsx (315줄) — 4 탭 (플랜/충전/자동/이력) + Enterprise 문의 모달
  • BalanceBadge.jsx (88줄) — 30초 polling, 상단바
  • InsufficientCreditsModal.jsx (61줄) — 소진 경고
  • lib/api.js — billing 함수 6개 (+Sprint 8 getUsageReport)
  • 빌드 + tar + scp + 서버 배포
  • hotfix: test mode 감지 (test_gck_docs_ / test_gsk_docs_ prefix) → topup 400 에러 해소

Sprint 8 — 사용량 대시보드 ✅

목표: 월간 사용량 리포트 + 직원/카테고리/에이전트 breakdown + 예측

  • 서버: GET /billing/usage/report?month=YYYY-MM + getMonthlyReport()
  • hotfix: MySQL SUM BIGINT → Number() 강제 변환 (client fmtKrw 깨짐)
  • 클라: CostDashboard.jsx 확장 — "이번 달 크레딧 사용량" 섹션 + Agent Top 10 바 차트 + 남은일 × 일일 평균 예측
  • i18n ko/ja 사용량 키

Sprint 9 — Watchdog 확장 (TB-1) ✅

목표: watchdog.js 에 metric source type + 트리거 이력 persistent + dashboard 탭

  • modules/local-db.js: watchdog_triggers 테이블 + 3 metric helper (agent_error_count, agent_avg_duration_ms, login_attempt_count)
  • modules/watchdog.js: check.type === 'metric' 분기 + recordWatchdogTrigger persistent + runtimeToggle Map (재시작 시 초기화 의도)
  • HTTP handle: /watchdog/rules, /triggers, /rules/:id/toggle — super_admin 전용
  • config/auto-evolution.json: 3 신규 metric rules (agent_error_spike, login_anomaly, agent_slow_response)
  • dashboard/index.html Watchdog 탭 추가 (룰 관리 + 트리거 이력)
  • staging + prod 배포 — watchdog tick 로그 정상

주의: Sprint 9 에서 dashboard Watchdog 탭 HTML 만 검증했고 /api/watchdog/ nginx proxy 는 누락 → Sprint 9.5.1b 에서 발견


Sprint 9.5 — Dashboard JS 분리 ✅

목표: dashboard/index.html 1214줄 → 500줄 한도 맞추기

결과: 1214 → 254 (CSS + HTML + 초기 로드 script 태그 10개 + checkAuth bootstrap)

신규 파일 (11개):

dashboard/
├── index.html (254)      ← HTML only + link/script 참조
├── styles.css (349)      ← CSS 전체 분리
├── core.js (154)         ← api/auth/nav/theme/mobile/escapeHtml/전역 state
└── pages/
    ├── overview.js (108) ← loadOverview + renderServices + renderAgents
    ├── agents.js (78)    ← agentsCache + detail modal + filter
    ├── neurons.js (74)   ← NeuronFS 7 region 렌더
    ├── monitor.js (66)   ← /status + /events
    ├── creative.js (44)  ← /image-gen
    ├── settings.js (46)  ← /scores + /audit
    ├── sites.js (33)     ← 사이트 목록 + /backup
    └── watchdog.js (69)  ← /watchdog/rules + /triggers + toggle

설계 결정: IIFE 해체 → 전역 스코프 통일. 페이지 함수 (loadX) 는 호출 시점 late-binding. Load 순서: core → pages → <script>checkAuth();</script> bootstrap.

커밋 12개 (파일별 분리):

  • d2246f7 fix(nginx): /api/watchdog/ proxy location (Sprint 9 누락 hotfix)
  • b0b6583 refactor: styles.css 분리
  • 028a197 refactor: core.js 분리
  • 96428c3 refactor: pages/overview.js
  • 606fda2 refactor: pages/agents.js
  • 77bc418 refactor: pages/neurons.js
  • 4b3a84c refactor: pages/creative.js
  • e2047c7 refactor: pages/monitor.js
  • 5c60c6e refactor: pages/sites.js
  • 670ccd9 refactor: pages/watchdog.js
  • 5c67927 refactor: pages/settings.js
  • 9d4994d refactor: index.html 1214→254

Prod 배포 검증 (curl 11개 파일 모두 HTTP 200):

index.html:  200 (14226b)
styles.css:  200 (15769b)
core.js:     200 (6949b)
pages/*.js:  200 (9개, 사이즈 일치)

✅ Sprint 9.5.13 — Certbot-aware nginx split (옵션 D 채택, 해결)

Loren 선택 "장기로 지금 당장 정확하게 돌리고 잔여부채 없애야할듯" → 옵션 D (snippets/ include 패턴).

결과:

  • config/nginx-snippets/wai-proxy.conf 신규 (231줄, 24 location union)
  • config/nginx-snippets/README.md 패턴 설명 + 배포 절차
  • config/nginx-dashboard.conf 삭제 (장식용 파일 제거)
  • /etc/nginx/snippets/wai-proxy.conf 프로덕션 배포
  • /etc/nginx/sites-enabled/dashboard 재작성 (100+줄 → 43줄) — Certbot SSL + server_name + root + php + hidden + include snippets/wai-proxy.conf;
  • nginx -t OK + systemctl reload nginx 무중단 (uptime 1주일 유지)
  • 백업: /root/nginx-dashboard.bak.20260411-225600
  • 커밋: 7201d2e feat(nginx): snippets/wai-proxy.conf 통합

검증 (24 routes 전수):

/api/watchdog/rules      200 → {"ok":true,"rules":[6개]}
/api/watchdog/triggers   200 → {"ok":true,"triggers":[]}
/api/audit               200 → {"ok":true,"logs":[…실로그]}
/api/image-gen/models    200 → {"models":{…5개}}
/api/erp/                401 (proxy 경유, auth 대기)
/api/board/              401 (proxy 경유, auth 대기)
/api/health              200 (기존 유지)
/api/status              200 (기존 유지)
/api/scores              200 (기존 유지)
/api/agents              200 (기존 유지)
/api/events              200 (기존 유지)
/api/board               200 (기존 유지)
/api/auth/me             401 (기존 유지)
/api/proxy/paljalab      200 (기존 유지)
/gateway/                502 — OpenClaw 18789 OFF (Loren 의도적, 부채 아님)

참고: OpenClaw 18789 NOT LISTENING 은 Loren 의도적 OFF 상태 (4/11 확인). feedback_openclaw_resurrection.md 의 "복원 지시" 는 보류 중. 함부로 켜지 않음.

장기 운영 패턴:

  • 프록시 추가/수정은 config/nginx-snippets/wai-proxy.conf 편집 → push → 서버 pull → cp → reload
  • /etc/nginx/sites-enabled/dashboard 는 Certbot 관리, 건드리지 마
  • Certbot renew 해도 snippet 무관

🔴 Sprint 9.5.11 배포 중 발견 — Prod nginx config drift (해결 완료, 위 9.5.13)

심각도: P0 → 해결 — Sprint 9.5.13 옵션 D

현상:

  • 로컬 repo config/nginx-dashboard.conf (8012 bytes, HTTP + /api/watchdog/ 포함)
  • 서버 실제 /etc/nginx/sites-enabled/dashboard (4280 bytes, HTTPS + Certbot + 다른 webhook 세트)
  • 두 파일이 완전히 다름

prod 에만 있는 것 (덮어쓰면 날아감):

  • listen 443 ssl; + Certbot 인증서 경로 (letsencrypt)
  • HTTP → HTTPS 301 리다이렉트
  • /api/a2a, /api/token-sync, /api/telegram-webhook, /api/user-telegram-webhook
  • server_name watoneai.cafe24.com _; (catch-all)
  • php8.1-fpm.sock (repo 는 버전 없이)

repo 에만 있는 것 (prod 에 반영 필요):

  • /api/watchdog/ ← Sprint 9 에서 추가했지만 prod 반영 안됨
  • /api/audit, /api/image-gen, /api/erp/, /api/board/, /gateway/
  • location / (try_files 정적 서빙)

원인 추정: 과거에 서버에서 /etc/nginx/sites-enabled/dashboard 직접 편집한 이력 → 그 이후 repo 업데이트는 prod 에 sync 한 적 없음. Certbot 이 HTTPS 블록 managed.

영향받는 기능 (현재 prod 에서 동작 안 함):

  • Dashboard Watchdog 탭 API 호출 전부
  • /api/audit, /api/image-gen, /api/erp/, /api/board/, /gateway/

결정 대기 — 4개 옵션:

  • A: 풀 싱크 (repo → prod) — HTTPS + Certbot + 4 webhook 날아감. 매우 위험
  • B: 서지컬 (prod 현재 파일에 /api/watchdog/ 블록만 추가) — 단기 추천. 하지만 drift 유지
  • C: 풀 역동기 (prod → repo) — 정석. repo config 를 prod 실제로 업데이트 후 정식 배포
  • D: Certbot-aware split — snippets/wai-proxy.conf 분리 + include 패턴. 장기적으로 가장 깔끔

메모리: project_nginx_prod_drift.md 에 전체 분석 저장


남은 부채 (발견 시점 기록)

#항목우선순위상태
#47LegalPanel subprocessors/dpa 링크🟢 P3pending
#111claude-bridge.js 961줄 500 한도🟠 P1pending
#162nginx BRIDGE_TOKEN 평문 9곳 (이제 snippet 안)🟡 P2 (private repo 보류)pending
#163prod nginx config drift🔴 P0해결 (9.5.13 옵션 D)

부채 아님: OpenClaw 18789 NOT LISTENING — Loren 의도적 OFF (4/11 확인). /gateway/ 502 는 정상 상태


핵심 교훈

  1. granular task = 가시성: Loren 이 "테스크 안띄움? 테스크도 만들라고" 극대노 → 이후 Sprint 9.5 는 서브스텝 12개 전부 TaskCreate. "지금 뭐 하는지" 명확해짐
  2. /effort max = 1회 최적화 승부: 뭉쳐서 9개 스프린트 한 번에 돌파. 중간 블로커 (billing pool, SUM 스트링, test mode, 500 한도) 를 hotfix 로 그때그때 해결
  3. 배포 후 실측 필수: curl HTTP 코드 + 사이즈 매칭 + 서비스 active 검증 없이는 "했습니다" 금지 (feedback_no_skip_verify.md)
  4. 드리프트는 침묵한다: prod nginx 가 repo 와 완전히 달랐는데 Sprint 9 배포 검증은 "dashboard HTML curl 200" 만 본 탓에 발견 못함. Sprint 9.5 에서 config 파일을 실제로 cat 해보기 전까지 몰랐음 → 이후 프로덕션 상태 인벤토리 정기 체크 필요

내일 이후 작업

  • #163 nginx drift 결정 — Loren 응답 대기. 옵션 B 선택 시 즉시 dashboard Watchdog 탭 살아남
  • Sprint 10 (브랜딩 통일) 또는 Sprint 11 (트라이얼/상한/알림톡)
  • TB-5 NeuronFS 자동 기록 확장
  • TB-6 뉴런 내용 보강 (NeuronFS 로컬 세팅 선행)
  • #111 claude-bridge.js 961 리팩토링 (dispatch 패턴 확장)