.claude/skills/verify-seed-integrity/SKILL.md
테스트 시드 인프라의 3자 SSOT 정합성을 검증합니다 — seed-data 파일 ↔ seed-test-new.ts 의 truncate/insert wiring ↔ verification.ts 의 count check 가 한 세트로 움직여야 함. 새 seed 파일 추가 후, verification.ts 편집 후 사용.
npx skillsauth add junnv93/equipment_management_system verify-seed-integrityInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
E2E / 통합 테스트 시드 인프라의 3자 SSOT 삼각형을 검증합니다:
seed-data/**/*.seed.ts ← 데이터 정의 (single source of data)
↓ imported by
seed-test-new.ts ← Phase 0 truncate + Phase N insert (orchestration)
↓ validated by
verification.ts ← 시드 후 DB 상태 불변조건 검증 (SSOT expected count)
세 꼭짓점 중 하나라도 누락되면:
추가로 verification.ts 내 magic number 하드코딩 금지 — 모든 expected count 는 SEED_DATA.length 또는 .filter().length 로 도출. 2026-04-08 세션에서 stale threshold 2건 발견 후 SSOT 전환.
일반 SSOT 임포트 검증은
/verify-ssot, 일반 하드코딩 탐지는/verify-hardcoding에서 수행합니다. 이 스킬은 시드 인프라 특화 불변조건만 다룹니다.
seed-data/**/*.seed.ts 파일을 추가한 직후seed-test-new.ts 의 truncate 리스트 또는 insert phase 를 편집한 직후verification.ts 의 검증 로직을 추가/수정한 직후SEED_DATA 배열에 rows 를 추가/삭제한 직후| File | Role |
|---|---|
| apps/backend/src/database/seed-data/**/*.seed.ts | 시드 데이터 배열 (SSOT of rows) |
| apps/backend/src/database/seed-test-new.ts | Phase 0 truncate + Phase 1~4 insert orchestration |
| apps/backend/src/database/utils/verification.ts | checkCount helper + 시드 후 불변조건 검증 |
| apps/frontend/tests/e2e/global-setup.ts | 시드 실행 + fail-fast (verify-e2e Step 13 참조) |
모든 *.seed.ts export 는 반드시 seed-test-new.ts 에 import 되어야 한다 (dead seed 방지).
탐지:
find apps/backend/src/database/seed-data -name '*.seed.ts' -type f \
| xargs -I{} basename {} .ts \
| while read seedFile; do
if ! grep -q "from.*seed-data.*${seedFile}" apps/backend/src/database/seed-test-new.ts; then
echo "❌ orphan seed file (not imported): ${seedFile}"
fi
done
PASS: 0 orphans. FAIL: orphan seed 파일 → seed-test-new.ts 에 import + insert phase 에 등록.
seed-test-new.ts 가 db.insert(schema.X) 하는 모든 테이블 X 는 Phase 0 truncate 리스트(const tables = [...])에도 포함되어야 한다 (idempotency invariant).
탐지:
# insert 되는 테이블명 추출 (schema.camelCase → snake_case)
grep -oE "db\.insert\(schema\.\w+\)" apps/backend/src/database/seed-test-new.ts \
| sed 's/db.insert(schema\.//; s/)//' \
| sort -u
# ↑ 이 목록과 Phase 0 `const tables = [...]` 배열 (snake_case) 가 subset 관계여야 함
PASS: 모든 insert 대상이 truncate 리스트에 등재됨. FAIL: 미등재 테이블 → truncate 리스트에 추가.
주의: camelCase ↔ snake_case 변환 수동 확인 필요 (예: equipmentRequests → equipment_requests).
verification.ts 의 checks.push 블록에서 passed: 표현식에 하드코딩된 숫자 리터럴이 나타나면 안 된다. 모든 expected 는 SEED_DATA.length 또는 .filter().length 도출.
탐지:
grep -nE "passed:\s*\w+\s*(>=|===|==)\s*[0-9]+" \
apps/backend/src/database/utils/verification.ts
# 또는 checkCount 호출 인자의 4번째 파라미터가 숫자 리터럴인 경우
grep -nE "checkCount\([^)]+,\s*[0-9]+" \
apps/backend/src/database/utils/verification.ts
PASS: 0 results (Equipment status: X 등 도메인 invariant >= 1 체크는 예외 — Exception 1 참조).
FAIL: magic number → SEED_DATA.length 또는 .filter().length 로 교체.
checkCount helper 가 default 로 === 를 사용해야 한다. >= 는 { minOnly: true } 옵션으로만 opt-in 되어야 함.
탐지:
grep -nA3 "function checkCount" apps/backend/src/database/utils/verification.ts \
| grep -E "actual (>=|===) expected"
PASS: actual === expected 가 default 경로, actual >= expected 는 options.minOnly 분기에만 존재.
FAIL: default 가 >= 이면 silent drift 위험 — === 로 교체.
seed-test-new.ts 가 insert 하는 모든 테이블 은 verification.ts 에 대응하는 checkCount 호출이 있어야 한다 (커버리지 invariant).
탐지:
# Step 2 결과(insert 테이블 목록) 와 verification.ts 의 checkCount table arg 비교
grep -oE "checkCount\([^,]+,\s*'[^']+',\s*'[a-z_]+'" \
apps/backend/src/database/utils/verification.ts \
| grep -oE "'[a-z_]+'$" | tr -d "'" | sort -u
PASS: insert 테이블 ⊆ verification 테이블. FAIL: 누락 테이블 → checkCount 추가.
Phase 0 truncate 는 FK 의존성 역순 (child → parent) 으로 나열되어야 TRUNCATE CASCADE 에러/락 경합을 최소화한다. users/teams 는 반드시 맨 뒤.
PASS: users, teams 가 배열 끝 2개 요소. WARN: 중간에 있으면 실제로 작동은 하지만 리뷰 대상.
form_templates 는 main.ts:158 seedFromFilesystem 이 백엔드 부팅 시에만 docs/procedure/template/ 에서 시드하는 "부팅 전용" 리소스이다. 재시드 경로가 없으므로 seed-test-new 실행 중 한 번이라도 비워지면 모든 export 테스트가 FORM_TEMPLATE_NOT_FOUND 로 일괄 실패한다.
두 가지 경로 모두 검증:
직접 truncate 금지 — form_templates 가 Phase 0 tables 배열에 등장하면 FAIL.
grep -n "'form_templates'" apps/backend/src/database/seed-test-new.ts
# → Phase 0 tables 배열 내 등장 시 FAIL
CASCADE 경로 방어 (2-계층):
2-a. FK runtime semantics — form_templates.uploaded_by → users.id 는 ON DELETE SET NULL 이어야 한다 (migration 0008). 런타임 DELETE 경로에서 관리자 계정 삭제로 템플릿이 함께 사라지는 것을 방지.
grep -n "uploadedBy.*references.*users" packages/db/src/schema/form-templates.ts
# → .onDelete('set null') 필수. 'restrict' 또는 미지정이면 FAIL.
2-b. Seed TRUNCATE 경로 snapshot/restore — PostgreSQL 의 TRUNCATE ... CASCADE 는 FK action 과 무관하게 참조 테이블을 전파 truncate 한다 ("Automatically truncate all tables that have foreign-key references"). 따라서 FK 가 SET NULL 이더라도 seed-test-new 의 TRUNCATE users CASCADE 는 여전히 form_templates 를 비운다. snapshot/restore 패턴이 필수:
grep -n "formTemplatesSnapshot\|formTemplates" apps/backend/src/database/seed-test-new.ts
# → snapshot select + restore insert (uploadedBy: null) 두 블록 모두 존재해야 PASS
두 블록 중 하나라도 누락되면 FAIL. 2-a 와 2-b 는 둘 다 필요 — 2-a 는 런타임, 2-b 는 테스트 reseed 방어.
| # | 검사 | 상태 | 상세 |
|---|-------------------------------------|-----------|-----------------------------------|
| 1 | seed-data orphan 탐지 | PASS/FAIL | import 누락 파일 목록 |
| 2 | truncate ↔ insert 테이블 정합 | PASS/FAIL | 미등재 테이블 |
| 3 | verification.ts magic number | PASS/FAIL | 하드코딩 위치 (file:line) |
| 4 | checkCount default === | PASS/FAIL | default 분기 비교 연산자 |
| 5 | verification checkCount 커버리지 | PASS/FAIL | 누락 테이블 |
| 6 | Phase 0 truncate FK 역순 | PASS/WARN | users/teams 위치 |
| 7 | form_templates 보존 (부팅 전용) | PASS/FAIL | 직접 truncate + snapshot/restore |
Equipment status: X 같은 값별 최소 1건 체크 — count >= 1 은 magic number 가 아닌 도메인 invariant (각 enum 값이 최소 1건 존재해야 한다). filterableStatuses 루프 내 체크는 Step 3 면제.checkCount helper 내부의 actual >= expected — options.minOnly === true 분기에 한해 정상 (명시적 opt-in).equipment 테이블에 EQUIPMENT_SEED_DATA + DISPOSAL_EQUIPMENT_SEED_DATA 를 합산 insert 하는 경우, verification 의 expected 는 두 length 합으로 계산 (이미 적용됨).{ minOnly: true } 플래그 opt-in 허용. 단 주석으로 이유 명시 필수.test.beforeAll 로 처리.testing
Verifies Zod validation pattern compliance — ZodValidationPipe usage (no class-validator), versionedSchema inclusion in state-change DTOs, controller pipe application, query DTO consistency. Run after adding/modifying DTOs or controller endpoints.
testing
Verifies cross-feature workflow E2E test coverage against critical-workflows.md checklist. Checks WF-01~WF-35 coverage, step completeness, role correctness, side-effect verification, and status transition assertions. Run after adding workflow tests or before PR.
testing
SSOT(Single Source of Truth) 임포트 소스를 검증합니다. 타입/enum/상수가 올바른 패키지에서 임포트되는지 확인. 타입/enum 추가/수정 후 사용.
development
Verifies SQL safety — LIKE wildcard escaping, N+1 query pattern detection, COUNT(DISTINCT) for fan-out JOINs, RBAC INNER JOIN enforcement. Run after adding/modifying search or list API endpoints.