store.SchemaDrift 의 스크래치 스키마 이름에서 `-` 를 제거해 verify-schema 명령과 TestVerifyingTheSchemaReportsWhatTheBuildIsMissing 을 살리기
4/1/S
대기
NewID()[:12] 는 9번째 글자가 항상 `-` 라 CREATE SCHEMA 가 구문 오류. base 커밋(a0dbd0f)에서도 DSN 을 주면 실패. 캠페인 밖이라 이번엔 손대지 않음.
2026-09-12
payloads vitest 를 get/del/upload 경로까지 넓혀 화면이 부르는 모든 메서드+경로를 server.go 의 s.handle 등록과 대조
3/1/M
대기
지금은 본문이 있는 호출만 본다. `${…}` 를 `{*}` 로 정규화해 s.handle("METHOD /path") 목록과 맞추면 된다.
2026-09-12
방문 추적 탭(admin-settings-analytics.png)을 캡처해 ADMIN_GUIDE 3-2 에 다른 탭처럼 싣기
2/1/S
대기
다른 여섯 탭은 그림이 있는데 새 탭만 없다. capture_all.js 에 장면 하나 추가 후 SECCHECK_CAPTURE_ONLY 로 한 장만. 서버+Playwright 필요.
2026-09-12
DecisionModal 의 종류별 본문을 정적 표로 빼고 payloads vitest 가 그 표까지 읽게 하기
2/1/S
대기
ReviewDetail.tsx 의 action(path, data) 는 경로·본문이 모두 변수라 정적으로 못 읽는다(008c9ec 의 현장).
2026-09-12
USER_GUIDE 3-7 에 알림 수신 설정 창을 캡처해 싣기
2/1/S
대기
서버 필요. 2026-09-12 재평가: 타당.
2026-09-12
캡처 스크립트에 시드 데이터 정리(--cleanup) 옵션 추가
2/2/S
대기
서버 기동 비용 대비 가치가 낮아 뒤로. 2026-09-12 재평가: 여전히 타당.
2026-09-12
Notifications.tsx 의 adminDestination 에 API_KEY_REVOKED·ACCOUNT_LOCKED·USER 대상 인계 알림의 이동 버튼 추가
2/2/S
대기
캠페인 밖. 붙이면 docs_test 가 USER_GUIDE 3-7 표 갱신을 요구한다.
2026-09-12
프록시를 끈 외부 도구를 위해 추적 활성 화면에서만 COEP 를 credentialless 로 낮출지 검토
2/3/S
대기
화면은 Cross-Origin-Embedder-Policy: require-corp 라 CORP 헤더 없는 외부 스크립트는 CSP 와 별개로 안 읽힘. 지금은 ADMIN_GUIDE 3-4 에 요건만 적음. Safari 는 credentialless 미지원.
2026-09-12
search-command.png 를 심의·항목·증적 세 종류 결과가 한 화면에 보이는 검색어로 다시 찍기
1/1/S
대기
서버 필요. 2026-09-12 재평가: 타당하나 가치 낮음.
2026-09-12
캠페인 tracking-2026-09: 관리자가 화면에서 방문 추적 스크립트를 붙이는 체계(설정 행·nonce CSP·스니펫 출처 추출·차단 출처 기록·Momento 같은 오리진 프록시)와 ADMIN_GUIDE 3-4 절
4/2/M
완료
internal/analytics 패키지, 미들웨어의 요청별 nonce 정책, SPA Inject 훅, csp-report·violations·allow 라우트, /momento/* 역프록시, 마이그레이션 034(꺼짐), Settings.tsx 방문 추적 탭, ADMIN_GUIDE 3-2 표·3-4 절, PDF 재생성. 단위 14개 + 통합 1개 테스트. 'unsafe-inline' 없음, 새 설치는 셸·정책 불변.
2026-09-12
원장 (에이전트가 남긴 기록)
2026-09-11
선택: 사용자·관리자 가이드를 GUIDE-STANDARD 구조로 재작성하고 실제 화면 캡처 34장을 싣기 (가치 5 / 위험 2 / 작업량 M)
결과: 성공
요약: docs/USER_GUIDE.md·pdf, docs/ADMIN_GUIDE.md·pdf 를 표준 구성(처음 5분·화면별·자주 하는 작업·막혔을 때·용어 / 구성 요소·설치·환경 변수 전수 표·역할·운영·장애 대응·보안)으로 새로 썼고, scripts/capture_all.js 를 전용 환경 변수(URL·계정·시드 비밀번호) 필수화 + loopback 가드 + workflow·security 설정 읽고-복원 방식으로 고쳐 로컬 Postgres + go build 서버에 데모 데이터를 시드한 뒤 Playwright Chromium 1440x900 으로 docs/screenshots/*.png 34장을 찍었다. 옛 user-guide.md·admin-guide.md 는 “대체되었습니다” 안내로 새 문서를 가리키고, README·docs/README.md·docs/index.html·features.md 의 링크와 캡처 파일명을 새 이름으로 바꾸고 옛 PDF 2종은 지웠다. 검증: 캡처 스크립트 실행 성공(설정 복원 확인), md2pdf 로 PDF 2종 생성(23·29쪽, 이미지 15·18장), 참조 이미지 전수 존재 확인, node –check, CI 와 같은 gitleaks 스캔 “no leaks found”. 환경 변수 표는 internal/app/config.go 와 selftest.go 에서, 설정 기본값은 마이그레이션 SQL 에서, API 메서드는 server.go 라우트 등록에서 읽어 적었다.
보류 아이디어: 캡처 스크립트로 반려·승인 대기·승인자 결재 화면(approval_enabled 켠 상태)까지 추가 촬영해 승인자 절 보강 (가치 3 / 위험 1 / S); docs/features.md·seccheck_features_guide.pdf 도 새 캡처 파일명 기준으로 재생성 (가치 2 / 위험 1 / S); scripts/generate_pdf.js 를 공용 md2pdf 로 대체해 저장소 전용 변환기 제거 (가치 2 / 위험 2 / S); GUIDE PDF 생성을 CI 릴리즈 단계에 붙여 md 와 pdf 가 어긋나지 않게 하기 (가치 3 / 위험 2 / M); 캡처 스크립트에 시드 데이터 정리(생성한 사용자·심의 삭제) 옵션 추가 (가치 2 / 위험 2 / S)
2026-09-11
선택: 승인 프로세스를 켠 상태의 승인 대기·결재 전 확인·최종 승인 창·반려 화면을 실제로 찍어 사용자 가이드 4-4 절(승인자)에 싣기 (가치 3 / 위험 1 / 작업량 S)
결과: 성공
요약: 이전 회차의 가이드 커밋(14412d6)이 아직 main 에 없어 그 브랜치 위로 fast-forward 한 뒤 작업했다. scripts/capture_all.js 가 실행 중에 workflow.approval_enabled 도 켜고(기존 읽고-복원 방식 그대로), 승인 게이트를 넘도록 캡처 계정을 승인자로 지정하며, 승인 대기 심의 1건과 반려 심의 1건을 더 시드하고 기존 승인 심의도 결재를 거치게 해 목록에 모든 상태가 보이게 했다. 로컬 Postgres 컨테이너 + go build 서버 + Playwright Chromium 1440x900 으로 38장을 다시 찍었고(새 캡처 4장: review-approval-pending/brief/modal, review-detail-rejected), USER_GUIDE 4-4 절을 캡처 4장과 단계별 설명으로 다시 쓰고 회수·재개 오류 메시지 3개를 막혔을 때 표에 더했으며 ADMIN_GUIDE 의 approval_enabled 설명에 “승인자 미지정 심의는 제출 불가” 를 추가했다. 촬영 중 결재 요청 회수·보완 재개 버튼이 UI 에서 comment 를 보내는데 서버는 reason 만 받아 항상 400 INVALID_JSON 이 나는 실제 버그를 발견해 별도 커밋으로 고쳤고(대화 제목·버튼 문구도 종류별로 바로잡음), Playwright 로 실제 화면에서 두 버튼을 눌러 REVIEWING / CHANGE_REQUESTED 로 바뀌는 것을 확인했다. 검증: 캡처 스크립트 완주 및 설정 복원 로그, tsc -b + vite build 통과, 참조 이미지 전수 존재, md2pdf 로 PDF 2종 재생성(28·29쪽, 4-4 절 페이지 렌더링 육안 확인), CI 와 같은 gitleaks 스캔 “no leaks found”. 임시 컨테이너·바이너리는 삭제했다.
보류 아이디어: docs/features.md·seccheck_features_guide.pdf 를 새 캡처 파일명 기준으로 scripts/generate_pdf.js 로 재생성 (가치 2 / 위험 1 / S); scripts/generate_pdf.js 를 공용 md2pdf 로 대체해 저장소 전용 변환기 제거 (가치 2 / 위험 2 / S); GUIDE PDF 변환만 CI 릴리즈 단계에 붙여 md 와 pdf 가 어긋나지 않게 하기 (가치 3 / 위험 2 / M); 캡처 스크립트에 시드 데이터 정리(–cleanup) 옵션 추가 (가치 2 / 위험 2 / S); DecisionModal 처럼 UI 가 보내는 필드와 payloads.go 의 필드 목록이 어긋나는 곳이 더 없는지 프런트엔드 post 호출과 payloads.go 를 대조하는 테스트 추가 (가치 3 / 위험 1 / M)
2026-09-11
선택: 저장소 전용 PDF 변환기(scripts/generate_pdf.js)를 공용 md2pdf 로 대체하고, 옛 캡처로 만들어진 features·complete manual PDF 를 새 캡처 기준으로 재생성 (가치 3 / 위험 1 / 작업량 S)
결과: 성공
요약: 이전 두 회차의 가이드 커밋(14412d6·008c9ec·95bbaa7)이 아직 main 에 없어 auto/2026-09-11-2220 위로 fast-forward 한 뒤 작업했다. scripts/build_docs_pdf.sh 를 새로 두어 docs 의 PDF 6종(USER_GUIDE·ADMIN_GUIDE·features·api·architecture·complete manual)을 모두 공용 md2pdf 로 굽게 했고(문서 이름 인자로 일부만 선택 가능, MD2PDF 환경 변수로 도구 경로 지정, 종합 매뉴얼은 docs/ 안에서 세 문서를 이어 붙여 그림 경로 유지), generate_pdf.js 와 그것만 쓰던 web 의 marked devDependency, 아무 데서도 참조하지 않던 docs/pdf/ 중복본 4개를 지웠다. features·api·architecture·complete manual PDF 를 재생성해 두 회차 전에 지운 옛 캡처(01_login.png 등)를 아직 싣고 있던 PDF 2종을 현재 캡처로 맞췄고, README·docs/README 의 종합 매뉴얼 설명(“사용자 실무·관리자 운영 포함”)을 실제 구성(기능·API·아키텍처)으로 고치고 재생성 방법 절을 더했다. 두 번째 커밋으로 precheck.sh 에 “가이드 그림” 단계를 추가해 문서가 참조하는 screenshots/*.png 가 모두 있는지, 찍어 두고 안 쓰는 캡처가 없는지 양방향으로 검사한다. 검증: PDF 4종 생성 성공(페이지 수 3·10·26·37, 종합 매뉴얼 표지 텍스트 확인, 아키텍처·기능 가이드 페이지를 PNG 로 렌더해 육안 확인), bash -n, 잘못된 MD2PDF 경로·잘못된 문서 이름의 종료 코드 확인, precheck 새 단계를 정상 트리와 고의로 깨뜨린 트리(없는 그림 참조 + 고아 캡처) 양쪽에서 실행해 확인, 손으로 정리한 package-lock 으로 npm ci + tsc –noEmit + vite build 통과, CI 와 같은 gitleaks 스캔 “no leaks found”. 임시 web/dist 는 .gitignore 대상이라 커밋에 들어가지 않았다.
보류 아이디어: GUIDE PDF 변환만 CI 릴리즈 단계에 붙여 md 와 pdf 가 어긋나지 않게 하기 — build_docs_pdf.sh 가 생겼으니 md2pdf 를 CI 에서 어떻게 가져올지만 정하면 된다 (가치 3 / 위험 2 / M); 캡처 스크립트에 시드 데이터 정리(–cleanup) 옵션 추가 (가치 2 / 위험 2 / S); 프런트엔드 post 호출 필드와 payloads.go 필드 목록을 대조하는 vitest 추가 (가치 3 / 위험 1 / M); md2pdf 가 넓은 ASCII 다이어그램 코드 블록을 가로 스크롤바째 인쇄하는 문제를 공용 도구 쪽에서 pre { white-space: pre-wrap } 또는 overflow:visible 로 고치기 — architecture.md 의 다이어그램에서 확인 (가치 2 / 위험 1 / S, aidev 저장소 작업); build_docs_pdf.sh 실행을 precheck.sh 에 넣어 md 를 고치고 pdf 를 안 굽는 커밋을 로컬에서 잡기 — md2pdf 는 aidev 밖에서 접근 못 하므로 도구가 없으면 건너뛰는 형태여야 한다 (가치 2 / 위험 1 / S)
2026-09-12
선택: 원고(Markdown·그림)가 PDF 를 마지막으로 구운 뒤 바뀌었는지 precheck.sh 가 git 으로 잡게 하고, 문서→PDF 매핑을 build_docs_pdf.sh 한 곳으로 모으기 (가치 3 / 위험 1 / 작업량 S)
결과: 성공
요약: 이전 세 회차의 가이드 커밋(14412d6~4713046)이 아직 main 에 없어 auto/2026-09-11-2350 위로 fast-forward 한 뒤 작업했다. 사용자·관리자 가이드는 표준 구성·캡처 38장·환경 변수 표·API 메서드까지 이미 갖춰져 있어(모든 web/src/pages 화면이 절로 덮임, VERSION·compose·config.go 와 일치 확인) 이번 회차는 “md 만 고치고 pdf 를 안 굽는” 재발 위험을 막는 데 썼다. build_docs_pdf.sh 의 case 분기를 describe() 함수 하나로 모으고 md2pdf 없이도 도는 --list 모드(이름·PDF·원고 목록)를 두었으며, precheck.sh 에 “가이드 PDF” 단계를 추가해 각 PDF 마다 원고 md 와 거기 실린 screenshots/*.png 를 입력으로 잡아 (1) PDF 없음, (2) 작업 트리에서 입력만 바뀌고 PDF 는 그대로, (3) 입력의 마지막 커밋이 PDF 의 마지막 커밋의 조상이 아님(merge-base –is-ancestor) 을 실패로 보고하고 실행할 build_docs_pdf.sh 이름을 알려 준다. PDF 자체가 수정된 상태면 방금 구운 것으로 보고 통과한다. 릴리즈 워크플로에 PDF 를 붙이는 안은 release.yml 이 “release asset 은 정확히 하나” 를 검증하고 md2pdf 가 저장소 밖에 있어 기각했다. 검증: bash -n, --list 가 잘못된 MD2PDF 경로에서도 동작, 잘못된 문서 이름 종료 코드 2, 다섯 가지 경우(정상 / md 만 수정 / md+pdf 수정 / 그림만 수정 → user·features·manual 3건 검출 / api-guide.md 만 바꾼 임시 커밋 → api·manual 검출 / PDF 삭제)를 실제로 만들어 확인, 재구성한 빌드 경로로 architecture·manual PDF 를 실제로 구워 3·37쪽(이전과 동일)과 임시 파일 정리 확인 후 바이트는 원복, 전체 precheck.sh 실행 통과(go vet·go test·가이드 그림·가이드 PDF·gitleaks “no leaks found”). 교훈: 테스트용 임시 커밋을 git reset --hard HEAD~1 로 지우다 미커밋 편집을 한 번 날렸다 — 파괴적 테스트 전에는 WIP 커밋을 먼저 만들었다.
보류 아이디어: 캡처 스크립트에 시드 데이터 정리(–cleanup) 옵션 추가 (가치 2 / 위험 2 / S); 프런트엔드 post 호출 필드와 payloads.go 필드 목록을 대조하는 vitest 추가 — 캠페인 밖이라 뒤로 (가치 3 / 위험 1 / M); ADMIN_GUIDE 설치 절에 compose.yaml 본문을 싣기 — 릴리즈 자산은 이미지 tar 하나뿐이라 오프라인 현장은 저장소 없이 compose 를 얻을 수 없다 (가치 3 / 위험 1 / S); precheck 가이드 그림 단계에서 캡처 너비가 표준 1440px 인지 확인 (가치 2 / 위험 1 / S); 재심의 복사 결과 안내·참여자 카드·Ctrl+K 통합 검색 화면을 추가 촬영해 4-3·3-4 절 보강 (가치 2 / 위험 1 / S, 서버 필요)
2026-09-12
선택: ADMIN_GUIDE 설치 절에 compose.yaml 전문을 싣고 테스트로 저장소 파일과 대조하기 + precheck 에 캡처 너비 1440px 검사 (가치 3 / 위험 1 / 작업량 S)
결과: 성공
요약: 이전 네 회차의 가이드 커밋(14412d6~dea3205)이 아직 main 에 없어 auto/2026-09-12-0031 위로 fast-forward 한 뒤 작업했다. 릴리즈 자산이 이미지 tar 하나뿐이라(release.yml 이 자산 1개를 검증) 폐쇄망 현장은 “저장소의 compose.yaml 을 그대로 씁니다” 를 따를 수 없었으므로, ADMIN_GUIDE 2-4 절에 compose.yaml 본문을 코드 블록으로 싣고 바꿔도 되는 줄(호스트 포트 바인딩)과 :?required·보안 옵션의 뜻을 적었으며, 5-8 업그레이드 예시가 다음 버전(v1.0.145)을 박아 두어 일괄 치환 시 sed 가 무의미해지던 것을 <새 태그> 자리표시자로 바꿨다. 사본은 어긋나므로 internal/web/docs_test.go 에 가이드의 yaml 블록이 compose.yaml 과 바이트 단위로 같은지 보는 테스트를 더하고, 기존 “릴리즈 버전이 모든 파일에서 같다” 테스트에 docs/ADMIN_GUIDE.md(seccheck-v…tar.gz)를 여섯 번째 파일로 넣어 릴리즈 세션이 가이드를 빠뜨리면 CI 가 잡게 했다. 두 번째 커밋으로 precheck.sh 의 가이드 그림 단계에 PNG IHDR 을 od 로 읽어 너비가 1440 이 아닌 캡처를 보고하는 검사를 추가했다(전체 페이지 캡처가 있을 수 있어 높이는 보지 않음). 검증: 두 테스트가 정상 트리에서 통과하고 고의로 어긋낸 트리(compose 블록 한 줄 변경 / 가이드의 tar 버전 1.0.143)에서 실패하는 것 확인, 가이드에서 추출한 블록이 compose.yaml 과 cmp 동일하고 docker compose config 통과, md2pdf 로 ADMIN_GUIDE.pdf 재생성(30쪽) 및 2-4 절을 Chrome 으로 렌더해 코드 블록이 잘리지 않음을 육안 확인, precheck 너비 검사를 현재 38장(모두 1440x900)과 1px PNG 를 끼운 트리 양쪽에서 확인, 전체 precheck.sh 통과(gofmt·go vet·go test·가이드 그림·가이드 PDF·gitleaks “no leaks found”). 릴리즈 세션에 대한 참고: 버전 일괄 치환 대상이 ADMIN_GUIDE.md 를 포함해 여섯 파일이 되었다.
보류 아이디어: 캡처 스크립트에 시드 데이터 정리(–cleanup) 옵션 추가 (가치 2 / 위험 2 / S, 서버 필요); 프런트엔드 post 호출 필드와 payloads.go 필드 목록을 대조하는 vitest 추가 — 캠페인 밖 (가치 3 / 위험 1 / M); 재심의 복사 결과 안내·참여자 카드·Ctrl+K 통합 검색 화면을 추가 촬영해 USER_GUIDE 4-3·3-4·3-1 절 보강 (가치 2 / 위험 1 / S, 서버 필요); ADMIN_GUIDE 3-1 환경 변수 표를 코드의 os.Getenv 호출(config.go·selftest.go·recover.go)과 대조하는 docs_test 추가 — 표준의 “환경 변수 표가 코드와 일치” 를 테스트로 (가치 3 / 위험 1 / S); ADMIN_GUIDE 3-2 서비스 설정 키·기본값 표를 마이그레이션 SQL 의 기본값과 대조하는 docs_test 추가 (가치 3 / 위험 1 / M)
2026-09-12
선택: ADMIN_GUIDE 3-1 환경 변수 표와 3-2 서비스 설정 표를 코드(os.Getenv·마이그레이션 시드·Settings.tsx)와 양방향 대조하는 docs_test 추가 + 그 테스트가 잡아낸 표 오류 수정 (가치 3 / 위험 1 / 작업량 M)
결과: 성공
요약: 이전 다섯 회차의 가이드 커밋(14412d6~774d35b)이 아직 main 에 없어 auto/2026-09-12-0131 위로 fast-forward 한 뒤 작업했다. 사용자·관리자 가이드는 이미 표준 구성과 캡처 38장을 갖추고 있어, 이번 회차는 표준 검증 항목 “환경 변수 표가 코드와 일치” 를 테스트로 못 박는 데 썼다. internal/web/docs_test.go 에 두 테스트를 더했다: (1) 3-1 표의 이름이 internal/·cmd/ 의 os.Getenv("…") 호출(테스트 전용 testdb 제외)과 양방향으로 같은지, (2) 3-2 의 탭별 표가 마이그레이션 시드(INSERT 와 '{…}'::jsonb || value_json 채움 — 처음 쓴 값이 기본값)와 Settings.tsx 의 {tab === '…' && 블록이 그 탭에 두는 키와 양방향으로 같고, 기본값이 시드 값(없으면 화면의 ?? / || 폴백)과 같은지. 두 번째 테스트가 실제 오류 세 가지를 잡았다 — 삭제 증적 보관(일) 이 일반 탭 표에 있었으나 화면은 파일 보안 탭에 둠(행 이동), service_name 이 바꿀 수 있는 값처럼 적혀 있었으나 화면에서는 고정 입력(설명 보강), Keycloak OIDC 탭에 키 표가 없어 PUT /api/v1/admin/settings/oidc 로 다룰 이름을 알 수 없었음(admin.go 의 검증 규칙·auth.go 의 구조체를 읽어 10개 키 표 추가). ADMIN_GUIDE.pdf 를 공용 md2pdf 로 다시 구웠다(32쪽). 검증: 두 테스트가 정상 트리에서 통과하고 고의로 어긋낸 트리(표에 없는 변수 추가 / selftest.go 의 변수 이름 변경 / retention_days 기본값 변경 / 행을 잘못된 탭으로 이동)에서 각각 실패하는 것 확인, 새 OIDC 표를 md2pdf 중간 HTML 로 Chrome 렌더해 육안 확인, 전체 precheck.sh 통과(gofmt·go vet·go test·가이드 그림·가이드 PDF·gitleaks “no leaks found”; 프런트엔드 단계는 node_modules 없음으로 건너뜀 — web 소스는 건드리지 않음). 참고: scripts/*.sh 가 git 에 100644 로 들어 있어 bash scripts/… 로 실행해야 한다.
보류 아이디어: 캡처 스크립트에 시드 데이터 정리(–cleanup) 옵션 추가 (가치 2 / 위험 2 / S, 서버 필요); 프런트엔드 post 호출 필드와 payloads.go 필드 목록을 대조하는 vitest 추가 — 캠페인 밖 (가치 3 / 위험 1 / M); 재심의 복사 결과 안내·참여자 카드·Ctrl+K 통합 검색 화면을 추가 촬영해 USER_GUIDE 4-3·3-4·3-1 절 보강 (가치 2 / 위험 1 / S, 서버 필요); USER_GUIDE “막혔을 때” 표의 오류 문구가 서버의 problem()/fault() 메시지·프런트 errorMessage 와 글자 그대로 일치하는지 대조하는 docs_test (가치 3 / 위험 1 / M); scripts/*.sh 의 git 모드를 100755 로 바꿔 README·가이드의 scripts/precheck.sh 예시가 그대로 실행되게 하기 (가치 2 / 위험 1 / S)
2026-09-12
선택: USER_GUIDE “막혔을 때” 표의 오류 문구와 ADMIN_GUIDE “장애 대응” 표의 로그 문구·5-3 로그 컴포넌트 목록을 코드와 대조하는 docs_test 추가 + 그 테스트가 잡아낸 표 오류 수정 (가치 3 / 위험 1 / 작업량 M)
결과: 성공
요약: 이전 여섯 회차의 가이드 커밋(14412d6~eb90797)이 아직 main 에 없어 auto/2026-09-12-0221 위로 fast-forward 한 뒤 작업했다. 사용자·관리자 가이드는 표준 구성과 캡처 38장을 이미 갖추고 있어, 이번 회차는 표준의 “사용자가 실제로 만나는 오류 메시지를 그대로” 와 “로그에 실제로 찍히는 문구를 싣는다” 를 테스트로 못 박는 데 썼다. internal/web/docs_test.go 에 두 테스트를 더했다: (1) USER_GUIDE 5절 표의 첫 열에서 백틱으로 인용한 문구가 internal/·cmd/ 의 Go 리터럴 또는 web/src 의 TS/TSX 어딘가에 글자 그대로 있는지 — 런타임에 채워지는 부분은 N분·N건 같은 N+단위와 <…> 자리표시자로 적고 그 앞뒤만 비교, 인용 문구가 없는 행도 실패; (2) ADMIN_GUIDE 6절 표에서 “로그에 …” 는 Go 코드에 있는 문자열인지, “서버 로그 컴포넌트 의 …” 는 정확히 그 (컴포넌트, 메시지) 쌍으로 Store.Log 를 호출하는 곳이 있는지, 그리고 5-3 의 컴포넌트 목록이 코드가 쓰는 집합과 양방향으로 같은지. 테스트가 실제 오류를 잡았다 — audit event could not be recorded 는 slog 로 표준 출력에만 가고 서버 로그 화면에는 감사 이벤트를 기록하지 못했습니다. 가 남는데 표는 서버 로그 행처럼 적었음(행 수정), 5-3 이 컴포넌트 7개만 나열했으나 코드는 12개(admin·bootstrap·evidence·export·review 추가), 허용되지 않은 확장자입니다: .exe 는 %s 포맷이라 <확장자> 로 변경. 두 PDF 를 공용 md2pdf 로 다시 구웠다(28·32쪽, 변경 행을 pymupdf 로 추출·페이지 렌더해 육안 확인). 두 번째 커밋으로 scripts/*.sh 세 개의 git 모드를 100755 로 바꿔 docs/README·operations.md 의 scripts/precheck.sh 예시가 bash 없이 그대로 실행되게 했다. 검증: 두 테스트가 정상 트리에서 통과하고 고의로 어긋낸 8가지 트리(가이드 문구 변경 / 서버 리터럴 변경 / 포맷 문자열 변경 / 인용 없는 행 / 로그 컴포넌트 이동 / 기동 오류 문구 변경 / 5-3 목록에서 제거 / 코드에 없는 컴포넌트 추가)에서 각각 실패하는 것 확인, 전체 precheck.sh 통과(gofmt·go vet·go test·가이드 그림·가이드 PDF·gitleaks “no leaks found”; 프런트엔드 단계는 node_modules 없음으로 건너뜀 — web 소스는 건드리지 않음). 교훈 재적용: 파괴적 테스트 전에 WIP 커밋을 먼저 만들었다.
보류 아이디어: 캡처 스크립트에 시드 데이터 정리(–cleanup) 옵션 추가 (가치 2 / 위험 2 / S, 서버 필요); 프런트엔드 post 호출 필드와 payloads.go 필드 목록을 대조하는 vitest 추가 — 캠페인 밖 (가치 3 / 위험 1 / M); 재심의 복사 결과 안내·참여자 카드·Ctrl+K 통합 검색 화면을 추가 촬영해 USER_GUIDE 4-3·3-4·3-1 절 보강 (가치 2 / 위험 1 / S, 서버 필요); USER_GUIDE 3절·4절 본문이 백틱으로 인용한 버튼·메뉴·필터 이름(제출 전 점검, 재심의 복사, 내 차례 등)이 web/src 의 JSX 문구와 글자 그대로 같은지 대조하는 docs_test — 표준의 “화면·메뉴 이름은 실제 UI 문구와 한 글자도 다르지 않게” (가치 3 / 위험 1 / M); ADMIN_GUIDE 5-1 상태 점검 엔드포인트·5-4 작업 큐의 작업 유형(SEND_EMAIL 등)이 server.go 라우트·jobs 코드와 일치하는지 대조하는 docs_test (가치 2 / 위험 1 / S)
2026-09-12
선택: USER_GUIDE 2·3·4·6절이 백틱으로 인용한 버튼·메뉴·필터·상태 이름을 web/src·Go 소스와 대조하는 docs_test 추가 + 그 테스트가 잡아낸 인용 3건 수정, 그리고 ADMIN_GUIDE 5-1 상태 점검 엔드포인트·5-4 작업 유형을 server.go 라우트·INSERT INTO jobs 와 대조하는 docs_test 추가 (가치 3 / 위험 1 / 작업량 M)
결과: 성공
요약: 이전 일곱 회차의 가이드 커밋(14412d6~e014035)이 아직 main 에 없어 auto/2026-09-12-0311 위로 fast-forward 한 뒤 작업했다. 사용자·관리자 가이드는 표준 구성과 캡처 38장을 이미 갖추고 있어, 이번 회차는 표준의 “화면·메뉴 이름은 실제 UI 문구와 한 글자도 다르지 않게” 와 “API 의 메서드와 경로를 라우트 등록 자리에서 확인” 을 테스트로 못 박는 데 썼다. 첫 커밋: internal/web/docs_test.go 에 USER_GUIDE 2·3·4·6절의 모든 백틱 인용(중복 제외 100건 이상)이 web/src 의 TS/TSX 또는 internal·cmd 의 Go 리터럴에 글자 그대로 있는지 보는 테스트를 더하고, 5절 테스트와 자리표시자(N건·<…>) 처리 로직을 phraseIsShown/userFacingSources 헬퍼로 공유했다. 테스트가 인용 3건을 잡았다 — + 신규 심의 요청 은 + 가 아이콘이고 문구는 신규 심의 요청(ADMIN_GUIDE 4-2 의 + 로컬 사용자 도 같은 식으로 수정), 2 / 210 과 SC-2026-000001 은 런타임 값이라 백틱 없는 예시로 바꿨다(심의번호는 SC- 접두사만 인용). 두 PDF 를 공용 md2pdf 로 다시 구웠다(28·32쪽, 변경 문구를 pymupdf 로 추출 확인). 둘째 커밋: 5-1 표의 각 행을 server.go 의 s.handle 등록과 메서드·경로·공개 여부·역할까지 대조하고, 5-4 표의 작업 유형을 Go 코드의 INSERT INTO jobs … 'TYPE' 과 양방향 대조하는 테스트를 더했다(두 표는 이미 코드와 일치). 검증: 두 테스트가 정상 트리에서 통과하고 고의로 어긋낸 8가지 트리(옛 + 신규 심의 요청 복원 / 화면의 내 담당 항목 필터 이름 변경 / 절 제목 변경 / 서버의 알림 제목 최종 승인 요청 변경 / /ready 를 POST 로 / server.go 에서 /metrics 를 로그인 필수로 / 5-1 역할을 AUDITOR 로 / 5-4 의 SEND_EMAIL 을 SEND_SMS 로)에서 각각 실패하는 것 확인, 전체 precheck.sh 통과(gofmt·go vet·go test·가이드 그림·가이드 PDF·gitleaks “no leaks found”; 프런트엔드 단계는 node_modules 없음으로 건너뜀 — web 소스는 건드리지 않음). ADMIN_GUIDE 전체로 인용 검사를 넓히는 안은 명령·PromQL·경로 인용이 많아 잡음이 커서 기각했다. 교훈 재적용: 파괴적 테스트 전에 WIP 커밋을 먼저 만들었다.
보류 아이디어: 캡처 스크립트에 시드 데이터 정리(–cleanup) 옵션 추가 (가치 2 / 위험 2 / S, 서버 필요); 프런트엔드 post 호출 필드와 payloads.go 필드 목록을 대조하는 vitest 추가 — 캠페인 밖 (가치 3 / 위험 1 / M); 재심의 복사 결과 안내·참여자 카드·Ctrl+K 통합 검색 화면을 추가 촬영해 USER_GUIDE 4-3·3-4·3-1 절 보강 (가치 2 / 위험 1 / S, 서버 필요); USER_GUIDE 3절이 web/src/pages 의 모든 화면(Layout.tsx 메뉴)을 절 하나씩 덮는지 보는 docs_test — features.md 에는 있으나 USER_GUIDE 에는 없음 (가치 2 / 위험 1 / S); ADMIN_GUIDE 4-1 역할 표의 역할 이름을 서버의 역할 상수·Users.tsx 역할 목록과 양방향 대조하는 docs_test (가치 2 / 위험 1 / S)
2026-09-12
선택: 재심의 복사 결과 안내·참여자 카드·Ctrl+K 빠른 이동 화면을 실제로 찍어 USER_GUIDE 4-3·3-4·3-1 절에 싣기 + 두 가이드가 사이드바의 모든 메뉴를 절 제목 또는 그림 설명으로 다루는지 보는 docs_test (가치 2 / 위험 1 / 작업량 S)
결과: 성공
요약: 이전 여덟 회차의 가이드 커밋(14412d6~b0723c0)이 아직 main 에 없어 auto/2026-09-12-0401 위로 fast-forward 한 뒤 작업했다. 두 가이드는 표준 구성과 캡처 38장을 이미 갖추고 있었고, 글로만 설명돼 있던 세 화면을 로컬 Postgres 컨테이너 + go build 서버 + Playwright Chromium 1440x900 으로 찍어 실었다(search-command.png: 푸시 검색 결과가 뜬 빠른 이동 창, review-participants.png: 작성 가능·열람 전용 참여자가 나란히 있는 카드, review-copy-result.png: 107/107개 항목의 답변을 복사했습니다. 토스트와 이월 답변 배지). scripts/capture_all.js 에 SECCHECK_CAPTURE_ONLY=<파일명,…> 을 두어 시드와 화면 순회는 그대로 하되 지정한 파일만 쓰게 해 기존 38장은 바이트 그대로 남겼고, 참여자 시드(hong CONTRIBUTOR·park VIEWER)와 세 장면을 더했다. 복사 장면은 처음에 토스트가 빠져 찍혔는데 text=이월 답변 이 숨은 <option> 에 먼저 걸려 5초를 기다리다 4.2초짜리 토스트를 놓친 것이라, 토스트 자체를 기다린 뒤 카드의 배지를 찾도록 고쳤다. 3-1 절에 빠른 이동 설명(입력 전 메뉴 목록·두 글자 이상이면 심의·항목·증적 검색·?item= 으로 항목이 펼쳐진 채 이동·더 많은 결과가 있습니다… 문구)을 Layout.tsx 에서 읽어 적었다. 둘째 커밋: internal/web/docs_test.go 에 Layout.tsx 의 모든 메뉴 라벨이 USER_GUIDE 또는 ADMIN_GUIDE 의 ### 제목이나 ![ 그림 설명에 있는지 보는 TestGuidesPictureEveryMenu 를 더했고, 그것이 잡은 Rule 시뮬레이터(그림 설명이 화면 제목 Rule Engine 시뮬레이터 만 썼음)를 메뉴 이름으로 고쳤다. 셋째 커밋: USER_GUIDE 가 버튼을 심의 요청자 인계(대화 제목)로 인용하던 것을 실제 버튼 문구 요청자 인계 로 바꿨다(참여자 캡처에서 발견). 검증: 캡처 스크립트 완주 및 설정 복원 로그, 세 캡처 육안 확인, 새 테스트가 정상 트리에서 통과하고 가짜 메뉴(용량 관리)를 Layout.tsx 에 끼운 트리에서 실패하는 것 확인, md2pdf 로 USER_GUIDE·ADMIN_GUIDE PDF 재생성(29·32쪽, 새 절 페이지를 pymupdf 로 렌더해 육안 확인), 전체 precheck.sh 통과(gofmt·go vet·go test·프런트엔드 tsc+vite build·가이드 그림 1440px·가이드 PDF 신선도·gitleaks “no leaks found”). 임시 컨테이너·바이너리·/tmp 의 비밀값 파일은 삭제했다. 참고: pkill -f <경로> 는 자기 셸까지 죽이므로(종료 코드 144) PID 로 죽여야 한다.
보류 아이디어: 캡처 스크립트에 시드 데이터 정리(–cleanup) 옵션 추가 (가치 2 / 위험 2 / S, 서버 필요); 프런트엔드 post 호출 필드와 payloads.go 필드 목록을 대조하는 vitest 추가 — 캠페인 밖 (가치 3 / 위험 1 / M); ADMIN_GUIDE 4-1 역할 표를 서버 역할 상수·Users.tsx 역할 목록과 양방향 대조하는 docs_test (가치 2 / 위험 1 / S); search-command.png 를 항목·증적 결과까지 함께 뜨는 검색어(예: 항목 제목에 있는 단어)로 다시 찍어 세 종류 결과가 한 화면에 보이게 하기 (가치 1 / 위험 1 / S, 서버 필요); USER_GUIDE 3-2 의 상태 흐름(작성 중 → … → 종료)이 서버 상태 상수와 프런트 StatusBadge 라벨 전체를 빠짐없이 담는지 보는 docs_test (가치 2 / 위험 1 / S)
2026-09-12
선택: ADMIN_GUIDE 4-1 역할 표와 USER_GUIDE 3-2 상태 흐름을 코드와 양방향 대조하는 docs_test 두 개 + ADMIN_GUIDE 5-5 정기 점검 절을 Sweep 이 기록하는 요약 키 기준 표로 다시 써 누락 5건·오기 1건을 고치고 그것도 테스트로 못 박기 (가치 3 / 위험 1 / 작업량 S)
결과: 성공
요약: 이전 아홉 회차의 가이드 커밋(14412d6~51608cb)이 아직 main 에 없어 auto/2026-09-12-0441 위로 fast-forward 한 뒤 작업했다. 두 가이드는 표준 구성과 캡처 41장을 이미 갖추고 있어, 보류 목록의 서버 불필요 항목 두 개를 한 커밋으로 처리했다: (1) 4-1 역할 표의 역할 코드·화면 이름을 마이그레이션 001 의 INSERT INTO roles 시드(코드·한국어 이름)와 Users.tsx 의 roleNames 에 양방향으로 대조하고, server.go 의 s.handle 이 요구하는 모든 역할이 시드에 있는지(아무도 가질 수 없는 역할 방지) 확인; (2) 서버에 상태 목록 상수가 없어 cancellableStatuses(취소 가능) ∪ review_requests.status NOT IN (…)(확정) 을 서버 상태 집합으로 잡고, 핸들러가 UPDATE review_requests SET status='X' 로 쓰는 값이 모두 그 집합에 있는지, ui.tsx statusLabel 이 각 상태의 라벨을 갖는지, 3-2 의 “상태의 뜻” 줄이 그 라벨 전부를 인용하고 다른 것은 인용하지 않는지 확인. 두 표는 이미 코드와 일치했다. 그 뒤 근처의 5-5 정기 점검 절을 worker.go 의 Sweep 과 대조하니 실제 오류가 있었다 — 작업 큐 정체·실패 작업·저장 공간 부족 알림, 고아 증적 파일 수, 유실된 스캔 작업 되돌리기(최근 커밋 adc9ce1) 다섯 단계가 빠져 있고, “알림 요약 발송” 은 정기 점검이 아니라 알림 발송 워커(notify)가 하는 일이라 “멈추면 모두 멈춘다” 는 문장이 틀렸다. 절을 retention sweep completed 로그와 시스템 정보 요약에 쓰이는 요약 키 20개를 첫 열로 하는 표로 다시 쓰고(각 단계의 알림 제목·임계값은 worker.go 상수와 문자열에서 읽음), 요약 키를 Sweep 과 양방향 대조하고 인용한 알림 제목이 worker.go 또는 화면에 실제로 있는지 보는 세 번째 테스트를 더했으며 ADMIN_GUIDE.pdf 를 공용 md2pdf 로 다시 구웠다(33쪽, 표가 28~29쪽에 헤더 반복으로 잘리지 않고 렌더되는 것을 pymupdf 로 확인). 검증: 세 테스트가 정상 트리에서 통과하고 고의로 어긋낸 12가지 트리(화면 역할 이름 변경 / 시드에 역할 추가 / 표 행 삭제·이름 변경 / 라우트가 미시드 역할 요구 / 가이드 상태 체인 누락·오기 / 핸들러가 새 상태 기록 / 취소 가능 목록에 라벨 없는 상태 추가 / 화면 라벨 변경 / Sweep 에 키 추가 / Sweep 키 삭제·이름 변경 / 가이드가 없는 알림 제목 인용)에서 각각 실패하는 것 확인, 전체 precheck.sh 통과(gofmt·go vet·go test·가이드 그림·가이드 PDF 신선도·gitleaks “no leaks found”; 프런트엔드 단계는 node_modules 없음으로 건너뜀 — web 소스는 건드리지 않음). 교훈 재적용: 파괴적 테스트 전에 WIP 커밋을 먼저 만들었다.
보류 아이디어: ADMIN_GUIDE 6절 장애 대응 표에 정기 점검이 관리자 종에 보내는 알림(작업 큐가 처리되지 않고 있습니다·작업이 재시도를 모두 소진했습니다·증적 저장 공간이 부족합니다·증적 볼륨에 쓸 수 없습니다)을 증상으로 한 행 추가 — 지금은 5-5 표에만 제목이 있고 받은 뒤 볼 곳·조치가 없다 (가치 3 / 위험 1 / S); USER_GUIDE 3-2 의 필터·정렬 목록을 Reviews.tsx 의 필터 토글·정렬 옵션과 양방향 대조하는 docs_test (가치 2 / 위험 1 / S); 프런트엔드 post 호출 필드와 payloads.go 필드 목록을 대조하는 vitest 추가 — 캠페인 밖 (가치 3 / 위험 1 / M); 캡처 스크립트에 시드 데이터 정리(–cleanup) 옵션 추가 (가치 2 / 위험 2 / S, 서버 필요); search-command.png 를 심의·항목·증적 세 종류 결과가 한 화면에 보이는 검색어로 다시 찍기 (가치 1 / 위험 1 / S, 서버 필요)
2026-09-12
선택: ADMIN_GUIDE 6절 장애 대응 표를 관리자 종에 실제로 뜨는 알림 제목 기준으로 고쳐 정기 점검·감사·잠금 알림 7종이 모두 행을 갖게 하고 그것을 코드의 발송 지점과 양방향 대조하는 docs_test 추가 + 알림 본문의 없는 로그 컴포넌트 이름 수정 + USER_GUIDE 3-2 필터·정렬 대조 docs_test (가치 3 / 위험 1 / 작업량 S)
결과: 성공
요약: 이전 열 회차의 가이드 커밋(14412d6~595f543)이 아직 main 에 없어 auto/2026-09-12-0511 위로 fast-forward 한 뒤 작업했다. 두 가이드는 표준 구성과 캡처 41장을 이미 갖추고 있어 보류 목록의 서버 불필요 항목 두 개를 처리했다. 첫 커밋: 6절 표가 작업 재시도 소진·감사로그 무결성 실패 처럼 알림 설정 화면의 라벨을 인용하고 있어 종에 뜬 제목(작업이 재시도를 모두 소진했습니다·감사로그 체인 검증 실패)으로 가이드를 검색하면 아무것도 안 나왔고, 작업 큐가 처리되지 않고 있습니다·증적 볼륨에 쓸 수 없습니다 는 행 자체가 없었다. worker.go·admin.go·auth.go 의 관리자 대상 발송 7건(, admin, … 수신자 관례)을 제목으로 하는 행을 두고 알림의 버튼(작업 큐 열기·시스템 정보 열기)이 여는 곳과 조치를 적었으며(5-3·5-4·5-5 의 라벨 인용과 6시간 재알림 제한도 함께 수정), internal/web/docs_test.go 에 가이드의 모든 “… 알림” 인용이 코드가 관리자에게 보내는 제목이고 그 제목 전부가 6절 증상 열에 있는지 보는 테스트를 더한 뒤 ADMIN_GUIDE.pdf 를 공용 md2pdf 로 다시 구웠다(34쪽, 32쪽 표를 pymupdf 로 렌더해 육안 확인). 둘째 커밋: 작업 큐 정체 알림 본문이 존재하지 않는 notify 로그 컴포넌트를 찾으라고 하던 것을 notification 으로 고치고 worker_test 에 단언을 더했다(임시 Postgres 컨테이너로 실제 실행해 옛 본문에서 실패·새 본문에서 통과 확인). 셋째 커밋: USER_GUIDE 3-2 의 필터·정렬 줄을 Reviews.tsx 의 aria-pressed 칩 라벨·sorts 표와 양방향 대조하는 테스트. 검증: 새 테스트들이 정상 트리에서 통과하고 고의로 어긋낸 7가지 트리(옛 라벨 복원 / worker.go 제목 변경 / auth.go 에 새 관리자 알림 추가 / 화면에 칩 추가 / 정렬 라벨 변경 / 가이드에서 필터 삭제 / 옛 알림 본문)에서 각각 실패하는 것 확인, 전체 precheck.sh 통과(gofmt·go vet·go test·가이드 그림·가이드 PDF 신선도·gitleaks “no leaks found”; 프런트엔드 단계는 node_modules 없음으로 건너뜀 — web 소스는 건드리지 않음). 교훈: git commit 을 git add 없이 && 체인에 넣어 뒤의 git checkout HEAD -- 파일 이 미커밋 수정을 덮었다 — 파괴적 테스트 전 WIP 커밋은 git add -A && git commit 으로.
보류 아이디어: 캡처 스크립트에 시드 데이터 정리(–cleanup) 옵션 추가 (가치 2 / 위험 2 / S, 서버 필요); 프런트엔드 post 호출 필드와 payloads.go 필드 목록을 대조하는 vitest 추가 — 캠페인 밖 (가치 3 / 위험 1 / M); search-command.png 를 심의·항목·증적 세 종류 결과가 한 화면에 보이는 검색어로 다시 찍기 (가치 1 / 위험 1 / S, 서버 필요); USER_GUIDE 3-5 알림 절과 ADMIN_GUIDE 가 인용하는 알림 유형 라벨(작업 재시도 소진 등 account.go 의 preference 목록)을 알림 설정 화면 기준으로 한 표로 싣고 코드와 대조 — 지금은 라벨과 제목의 관계가 어디에도 없다 (가치 2 / 위험 1 / S); Notifications.tsx 의 알림 유형별 이동 버튼(작업 큐 열기 등)을 USER_GUIDE 알림 절 표로 싣고 코드와 대조하는 docs_test (가치 2 / 위험 1 / S)
2026-09-12
선택: USER_GUIDE 3-7 알림 절에 알림 유형(수신 설정의 이름) · 언제 오나 · 종에 뜨는 제목 · 열기 버튼 표 27행을 싣고, account.go 의 유형 목록·모든 발송 지점의 제목·Notifications.tsx 의 버튼과 양방향 대조하는 docs_test 추가 (가치 2 / 위험 1 / 작업량 S)
결과: 성공
요약: 이전 열한 회차의 가이드 커밋(14412d6~0e023e7)이 아직 main 에 없어 auto/2026-09-12-0541 위로 fast-forward 한 뒤 작업했다. 두 가이드는 표준 구성과 캡처 41장을 이미 갖추고 있어, 보류 목록의 서버 불필요 항목 두 개(알림 유형 라벨↔제목 표, 알림별 이동 버튼 표)를 한 표로 합쳐 처리했다. 종에 뜨는 제목(작업이 재시도를 모두 소진했습니다)과 수신 설정·유형 필터의 이름(작업 재시도 소진)이 서로 달라 어느 유형을 꺼야 하는지 어디에도 없었으므로, 3-7 절에 유형 27개를 화면 순서대로 두고 설명은 수신 설정 화면 문구 그대로, 제목은 발송 지점에서 읽은 것(보완 요청 N건·업무 인계·새 심의 제출 같은 기본값 포함), 버튼은 발송 대상(항목/심의/감사 이벤트)과 adminDestination 표에서 읽어 적었다. internal/web/docs_test.go 에 Go 소스의 모든 발송 지점(Store.Notify 계열·add*Notification·notifyReviewer·Sweep 의 직접 INSERT)을 인자 위치로 파싱해 유형별 제목 집합(리터럴, Sprintf 의 %d→N, “” 이면 피호출자의 기본값, title 변수면 그 함수의 대입, 승인/반려의 map 리터럴)과 버튼 집합을 만들고, 표의 이름·순서·설명이 account.go 목록과 같은지, 제목·버튼이 양방향으로 같은지, 그리고 코드가 보내는 모든 유형이 목록에 있는지(없으면 끌 수 없고 종에 코드가 그대로 뜸) 보는 테스트를 더했다. USER_GUIDE.pdf 를 공용 md2pdf 로 다시 구웠다(31쪽, 17~18쪽 표를 pymupdf 로 렌더해 육안 확인). 검증: 새 테스트가 정상 트리에서 통과하고 고의로 어긋낸 11가지 트리(가이드의 제목 변경/제목 누락/행 순서 교환/설명 변경/버튼 오기, worker 의 리터럴 제목·title 대입 변경, notifyReviewer 기본 제목 변경, Sprintf 제목 변경, 목록에 발송 없는 유형 추가, 화면에 버튼 추가)에서 각각 실패하는 것 확인, 전체 precheck.sh 통과(gofmt·go vet·go test·가이드 그림·가이드 PDF 신선도·gitleaks “no leaks found”; 프런트엔드 단계는 node_modules 없음으로 건너뜀 — web 소스는 건드리지 않음). 교훈 재적용: 파괴적 테스트 전에 git add -A && git commit 으로 WIP 커밋을 먼저 만들었다. 참고: API_KEY_REVOKED(대상 API_KEY)·ACCOUNT_LOCKED(대상 USER)·일괄 업무 인계(대상 USER) 알림은 화면에 이동 버튼이 없어 표에 “없음” 으로 적었다 — 버튼을 붙이는 것은 가이드 캠페인 밖이라 보류.
보류 아이디어: Notifications.tsx 의 adminDestination 에 API_KEY_REVOKED(API 키 열기)·ACCOUNT_LOCKED(사용자 관리 열기)·USER 대상 인계 알림의 이동 버튼 추가 — 표가 “없음” 인 세 유형, 캠페인 밖 (가치 2 / 위험 2 / S); 캡처 스크립트에 시드 데이터 정리(–cleanup) 옵션 추가 (가치 2 / 위험 2 / S, 서버 필요); 프런트엔드 post 호출 필드와 payloads.go 필드 목록을 대조하는 vitest 추가 — 캠페인 밖 (가치 3 / 위험 1 / M); search-command.png 를 심의·항목·증적 세 종류 결과가 한 화면에 보이는 검색어로 다시 찍기 (가치 1 / 위험 1 / S, 서버 필요); USER_GUIDE 3-8 개인 프로필 절의 알림 이메일 수신 설정 화면(수신 설정 창)을 캡처해 3-7 표 옆에 싣기 — 지금은 알림 목록 화면만 있고 유형 토글 화면은 없다 (가치 2 / 위험 1 / S, 서버 필요)
2026-09-12
선택: 수정 과제 — 러너 검증이 다음에 멈출 자리(cd web && npm test 가 테스트 파일 0개로 exit 1)를 미리 고치기: 프런트엔드 post/put/patch 호출의 리터럴 본문 키를 payloads.go 와 대조하는 vitest 추가 + precheck.sh·ci.yml 프런트엔드 단계에 그 실행을 포함 (가치 3 / 위험 1 / 작업량 M)
결과: 성공
요약: 이전 열두 회차의 가이드 커밋(14412d6~5963517)이 아직 main 에 없어 auto/2026-09-12-0611 위로 fast-forward 한 뒤 작업했다. 수정 과제 확인: GitHub 의 release.yml 실행은 API 로 조회한 최근 5건(v1.0.140~v1.0.144)이 모두 success 라 릴리즈 워크플로 자체는 실패한 적이 없고, 12회 연속 실패는 러너의 [ -d node_modules ] || npm ci 가 lock 없는 루트에서 돈 것(러너 쪽에서 수정 완료)이었다. 그런데 고쳐진 러너(bin/run.sh)는 이제 web/ 에서 npm ci → npm test --silent → npm run build --silent 를 돌리는데, web/package.json 의 test 는 vitest run 이고 테스트 파일이 하나도 없어 “No test files found, exiting with code 1” 로 exit 1 이 된다 — 로컬에서 재현해 확인. 다음 회차도 같은 자리에서 실패할 것이므로 보류 목록의 vitest 아이디어를 앞당겨 web/src/lib/payloads.test.ts 를 만들었다: web/src 의 post/put/patch(path, { … }) 와 api(path, { method, body: JSON.stringify({ … }) }) 중 본문을 호출 자리에 리터럴로 적은 28곳을 괄호·문자열 균형 파서로 읽어 (1) 메서드+경로(${…}↔{id} 정규화)가 payloads.go 의 요청 본문 표에 있는지, (2) 적은 키가 모두 서버가 읽는 필드인지(008c9ec 의 comment/reason 어긋남 류) 확인하고, 스캐너가 망가져 0건이 되는 것을 막는 하한(15건)을 둔다. 스프레드(...form)·변수 본문은 검사 대상에서 제외한다. 검증: 정상 트리 3/3 통과, 고의로 어긋낸 세 트리(comments 의 {body}→{text} / totp/enable 경로를 totp/verify 로 / payloads.go 의 to_user_id 를 target_user_id 로)에서 각각 실패 확인, 러너와 동일한 세 명령(cd web && [ -d node_modules ] || npm ci, npm test --silent, npm run build --silent)을 bash -o pipefail 로 실행해 모두 exit 0, precheck.sh 전체 통과(gofmt·go vet·go test·프런트엔드 tsc+vitest+vite build·가이드 그림·가이드 PDF 신선도·gitleaks “no leaks found”). precheck.sh 프런트엔드 단계와 ci.yml 의 “Frontend build and dependency gate” 에 npm --prefix web test --silent 를 넣어 CI 가 이 대조를 돌리게 했다(워크플로를 느슨하게 한 것이 아니라 한 단계 더한 것). 가이드는 표준 구성·캡처 41장·PDF 2종이 이미 갖춰져 precheck 의 그림·PDF 검사를 통과하므로 이번 회차는 원고를 바꾸지 않았다. 참고: DecisionModal 이 action('reopen', data) 로 경로와 본문을 모두 변수로 넘기는 바로 그 자리(008c9ec 의 현장)는 정적으로 읽을 수 없어 아직 검사 밖이다.
보류 아이디어: DecisionModal 의 종류별 본문을 정적 표({ reopen: ['reason'], withdraw: ['reason'], … })로 빼고 vitest 가 그 표까지 읽게 해 008c9ec 의 현장을 검사 범위에 넣기 (가치 2 / 위험 1 / S); vitest 를 get/del/upload 경로까지 넓혀 화면이 부르는 모든 메서드+경로가 server.go 의 s.handle 등록에 있는지 대조 — 라우트 이름이 바뀌면 화면이 404 를 받는 것을 잡는다 (가치 3 / 위험 1 / M); USER_GUIDE 3-8 의 알림 수신 설정 창을 캡처해 3-7 표 옆에 싣기 (가치 2 / 위험 1 / S, 서버 필요); Notifications.tsx 의 adminDestination 에 API_KEY_REVOKED·ACCOUNT_LOCKED·USER 대상 인계 알림의 이동 버튼 추가 — 캠페인 밖, docs_test 표 갱신 동반 (가치 2 / 위험 2 / S)
2026-09-12
선택: 캠페인 tracking-2026-09 — 관리자가 화면에서 방문 추적 스크립트를 붙이는 체계(설정 행·nonce CSP·스니펫 출처 추출·차단 출처 기록·Momento 같은 오리진 프록시)와 ADMIN_GUIDE 3-4 절 (가치 4 / 위험 2 / 작업량 M)
결과: 성공
요약: TRACKING-STANDARD.md 와 kanpic 참조 구현(analytics.go·violations.go·policyFor)을 읽고 SecCheck 의 구조(설정은 settings 표의 JSON 한 행, 화면은 Settings.tsx 의 탭, 정책은 setSecurityHeaders 의 고정 문자열)에 맞게 같은 능력을 만들었다. 새 패키지 internal/analytics 는 Config(analytics 행, provider 는 momento 를 첫 자리에 두고 none·ga4·gtm·matomo·custom)·Validate(8KB 상한, 켜져 있는데 도구 없음 거절)·Snippet(nonce 를 모든 <script> 에 부착)·PolicySources(스니펫에서 http(s) 출처 추출 + allowed_hosts)·Recorder(출처×지시어로 100개 고리, 허용 여부 표시)를 갖고, internal/web 은 미들웨어에서 요청마다 nonce 를 만들어 화면 경로에는 script-src 'self' 'nonce-…' <출처> + report-uri 를, /api·/mcp·/health·/ready·/metrics·/momento 에는 default-src 'none' 을 보내며, SPA 가 Inject 훅으로 index.html 에 스니펫을 넣는다(/admin* 은 include_admin 일 때만). 라우트: POST /api/v1/analytics/csp-report(공개, 추적이 켜진 동안만 기록) · 관리자용 violations GET/DELETE · POST …/analytics/allow(한 번 눌러 allowed_hosts 에 추가) · /momento/* 역프록시(세션 쿠키·Authorization 제거, momento_proxy 가 켜진 동안만 존재). 마이그레이션 034 가 꺼짐 상태로 행을 심어 새 설치는 바이트 단위로 같은 셸·같은 정책을 받고, ‘unsafe-inline’ 은 어디에도 없다. Settings.tsx 에 방문 추적 탭(도구별 입력·프록시 토글·차단 출처 표와 허용/목록 비우기)을 더했고, ADMIN_GUIDE 3-2 에 키 표(docs_test 가 시드·화면과 양방향 대조), 3-4 절에 CSP 가 왜 문제인지·nonce·출처 추출·차단 기록·붙지 않는 곳·Momento 설정 3단계·COEP(require-corp) 주의·끄면 원래대로를 적었으며 5-3 로그 컴포넌트에 analytics 를, api-guide 에 4개 엔드포인트를, operations.md 에 034 를 더했다. 검증: analytics 패키지 단위 테스트 9개(꺼짐 기본·비화면·프록시 기본·nonce 부착·출처 추출·Validate·Inject·Recorder 고리·AddAllowedHost), web 단위 테스트 5개(pagePolicy 가 꺼짐일 때 옛 정책과 글자 그대로 같음·프록시 Momento 는 외부 출처 없음·SPA 삽입·csp-report·nonce), 임시 Postgres 컨테이너로 통합 테스트 1개(새 설치 셸·정책 불변 → 8KB 거절 → Momento 켬 → 스니펫 nonce = 헤더 nonce, 요청마다 다름, /admin 미삽입, API 좁은 정책, 프록시가 스텁 수집기에 쿠키 없이 전달 → 신고 3건이 1행 count 3 → 허용 → 다음 정책에 반영 → 비우기 → 끄면 원래대로·프록시 닫힘), 전체 go test ./...(DSN 포함), precheck.sh 통과(gofmt·go vet·go test·tsc+vitest+vite build·가이드 그림·가이드 PDF·gitleaks “no leaks found”), ADMIN_GUIDE·api·manual PDF 를 md2pdf 로 다시 구워 15·16쪽을 렌더해 육안 확인. 실제 브라우저로 수집이 들어오는 것은 Momento 수집기가 없어 확인하지 못했다(통합 테스트의 스텁 수집기로 대신). 참고: TestVerifyingTheSchemaReportsWhatTheBuildIsMissing 은 이 변경과 무관하게 base 커밋에서도 실패한다 — SchemaDrift 가 NewID()[:12] 로 스키마 이름을 만들어 항상 - 가 들어가 CREATE SCHEMA 가 구문 오류(verify-schema 명령 자체가 깨진 상태). 교훈 재적용 실패: git checkout docs/ADMIN_GUIDE.md 로 미커밋 가이드 편집을 한 번 날렸다 — 파괴적 확인 전에는 반드시 git add -A && git commit 먼저.
보류 아이디어: store.SchemaDrift 의 스크래치 스키마 이름에서 - 를 제거해 verify-schema 명령과 그 테스트를 살리기 (가치 4 / 위험 1 / S); 방문 추적 탭(admin-settings-analytics.png)을 캡처해 ADMIN_GUIDE 3-2 에 다른 탭처럼 싣기 (가치 2 / 위험 1 / S, 서버 필요); 프록시를 끈 외부 도구를 위해 추적 활성 화면에서만 COEP 를 credentialless 로 낮출지 검토 — 지금은 가이드에 CORP 헤더 요건만 적음 (가치 2 / 위험 3 / S); payloads vitest 를 get/del/upload 경로까지 넓혀 s.handle 등록과 대조 (가치 3 / 위험 1 / M); DecisionModal 의 종류별 본문을 정적 표로 빼 vitest 가 읽게 하기 (가치 2 / 위험 1 / S)