{"id":"cmq4ni3cr005dpl01hrmprobn","docId":"cmq4nh0ww004npl01zd0npn54","version":1,"title":"테스트 체크리스트 v3 — 단위 71 + 로컬 e2e 35 + 외부 e2e 35 = 141 PASS","content":"# 테스트 체크리스트 v3 (2026-06-08 갱신 — 외부 도메인 풀스택 검증)\n\n작성: G2 진행. 단위 71 PASS + Playwright e2e 35 (로컬) + 35 (외부 dev-shred.irosafe.com) = **141 PASS / 0 FAIL**.\n산출물 위치: `docs/09_테스트/테스트결과서_irosafe_shred.{xlsx,pptx}`\n\n## 1. 범위 + 도구\n\n| 분류 | 도구 | 목적 |\n|---|---|---|\n| 단위 (Unit) | JUnit 5 + Mockito + AssertJ | Service / mapping helpers / pure logic |\n| 통합 (Integration) | @SpringBootTest + Testcontainers (MariaDB) | Controller ↔ DB round-trip + Security filter chain |\n| e2e (Playwright) | Playwright MCP | UI 시각 + 화면 시나리오 |\n| 부하 (Load) | — (G3 이후) | Phase E 대용량 마이그 후 |\n\n목표 커버리지 (G2): **30%+** (lines). 우선순위는 비즈니스 critical path.\n\n## 2. 단위 테스트 체크리스트 — 71 PASS / 0 FAIL ✓\n\n| ID | 클래스 | 시나리오 | 우선 | 상태 |\n|---|---|---|---|---|\n| U-001 | JwtServiceTest | 발급 토큰 parseClaims 후 sub/uid 회복 | P0 | PASS |\n| U-002 | JwtServiceTest | TTL 0 → isValid=false | P0 | PASS |\n| U-003 | JwtServiceTest | 다른 secret/issuer/깨진 → false | P0 | PASS |\n| U-004 | AuthServiceTest | bcrypt 일치 → LoginResponse | P0 | PASS |\n| U-005 | AuthServiceTest | 비밀번호 불일치 / unknown loginId → IllegalArg | P0 | PASS |\n| U-006 | AuthServiceTest | SUSPENDED / LEFT → IllegalState + FAIL audit | P1 | PASS |\n| U-007 | ContractExpiryJobTest | autoExtend RECURRING + 과거 → +1y | P0 | PASS |\n| U-008 | ContractExpiryJobTest | autoExtend=false CONTRACT + 과거 → EXPIRED | P0 | PASS |\n| U-008b | ContractExpiryJobTest | RECURRING autoExtend expire 제외 | P0 | PASS |\n| U-009 | ContractExpiryJobTest | 미래 ended_on → no-op | P1 | PASS |\n| U-010 | ScheduleServiceTest | reassign — primary 해제 + 신규 primary + audit | P0 | PASS |\n| U-011 | ScheduleServiceTest | bulkStatus — 일괄 변경 + count | P1 | PASS |\n| U-012 | LegacyMappersTest | normalizeBiz — 숫자만 | P0 | PASS |\n| U-013 | LegacyMappersTest | mapPartnerStatus A/S/C → ENUM | P0 | PASS |\n| U-014 | LegacyMappersTest | mapContractStatus DRAFT/TERMINATED → ENUM | P0 | PASS |\n| U-015 | LegacyMappersTest | mapCertificateType C1210000~4 → 5종 | P1 | PASS |\n| U-016 | LegacyMappersTest | mapShredOption SITE/WAREHOUSE | P1 | PASS |\n| U-017 | CodeControllerTest | duplicate 거부 + create/update | P1 | PASS |\n| U-018 | ContractControllerTest | RECURRING start only → endedOn+1y / ONE_CALL autoExtend=false / 명시 endedOn 보존 | P1 | PASS |\n| U-019 | ExcelStatusLabelTest | PLANNED→수거예정 외 5종 + null | P2 | PASS |\n| U-020 | AuthorityResolverTest | Member → ROLE_* + permission codes (합집합/중복제거) | P1 | PASS |\n\n**실행**: `./gradlew test --tests \"*Test\"` · 9 클래스 · 71 case · 12s\n\n## 3. 통합 테스트 체크리스트\n\n> 모든 IT 는 Testcontainers MariaDB + Flyway V1~V6 적용 후 실행. JWT 토큰은 /auth/login 으로 발급해 사용.\n\n| ID | 영역 | 시나리오 | 우선 | 예상결과 | 상태 |\n|---|---|---|---|---|---|\n| I-001 | Auth | POST /auth/login admin/admin1234 → 200 + accessToken | P0 | accessToken !=null | ☐ |\n| I-002 | Auth | POST /auth/login admin/wrong → 401 | P0 | 401 + body code | ☐ |\n| I-003 | Auth | GET /api/v1/contracts no token → 401 | P0 | 401 | ☐ |\n| I-004 | Auth | GET /v3/api-docs no token → 200 (permitAll) | P1 | 200 | ☐ |\n| I-005 | Contract | GET /api/v1/contracts → list 7건 (V4 seed) | P0 | size >= 7 | ☐ |\n| I-006 | Contract | POST /api/v1/contracts ONE_CALL → autoExtend=false | P1 | autoExtend false | ☐ |\n| I-007 | Contract | POST /api/v1/contracts RECURRING + start only → endedOn auto +1y | P1 | endedOn 정확 | ☐ |\n| I-008 | Subcontractor | GET /api/v1/subcontractors → 8건 (V4) | P0 | size>=8 | ☐ |\n| I-009 | Schedule | GET /api/v1/schedules?from&to → 8건 (V4) | P0 | size>=8, contractName 노출 | ☐ |\n| I-010 | Schedule | GET ?track=ONE_CALL → 원콜만 | P1 | track 단일 | ☐ |\n| I-011 | Schedule | POST /api/v1/schedules/bulk-status → updated 정확 | P1 | DB status 변경 | ☐ |\n| I-012 | Calendar | GET /api/v1/calendar/month?year&month → schedule list | P1 | non-empty | ☐ |\n| I-013 | DailyWork | GET /api/v1/dailywork/today?date=2026-06-15 (admin assigned) | P0 | 1건 (코웨이) | ☐ |\n| I-014 | DailyWork | POST /api/v1/dailywork/{id}/complete → status=COMPLETED | P0 | DB COMPLETED | ☐ |\n| I-015 | Console | GET /api/v1/consoles → 6건 | P0 | size>=6 | ☐ |\n| I-016 | Console | POST /api/v1/consoles/{id}/barcode → Barcode row + QR | P1 | Barcode 생성 | ☐ |\n| I-017 | Certificate | POST /api/v1/certificates → row | P1 | id 발급 | ☐ |\n| I-018 | Certificate | POST /api/v1/certificates/{id}/issue → status=ISSUED | P1 | ISSUED | ☐ |\n| I-019 | Code | GET /api/v1/codes/categories → 4 categories | P0 | size=4 | ☐ |\n| I-020 | Code | POST /api/v1/codes BUSAN + PUT 이름변경 + DELETE | P1 | CRUD round-trip | ☐ |\n| I-021 | Excel | GET /api/v1/excel/contracts → xlsx > 1000 bytes + OOXML magic | P1 | 첫 4 byte PK header | ☐ |\n| I-022 | Excel | GET /api/v1/excel/schedules?track=RECURRING → xlsx | P2 | 200 + Content-Disposition | ☐ |\n| I-023 | Swagger | GET /v3/api-docs → paths count >= 30 | P1 | path size >= 30 | ☐ |\n| I-024 | CORS | OPTIONS /api/v1/contracts with Origin=localhost:5173 → 200 + headers | P0 | 200 + Access-Control-* | ☐ |\n| I-025 | JWT | 만료된 토큰 → 401 | P1 | 401 | ☐ |\n| I-026 | RBAC | WORKER 계정으로 POST /codes → 403 | P1 | 403 | ☐ |\n| I-027 | Flyway | V1~V6 적용 후 schema_version 6 rows | P0 | Successfully validated 6 migrations | ☐ |\n| I-028 | ContractExpiryJob | runOnce(today=과거포함) → DB 변경 검증 | P1 | extended/expired count > 0 | ☐ |\n\n## 4. e2e (Playwright) 체크리스트 — 35 PASS / 0 FAIL ✓\n\n### 4-1. UI 시나리오 (apps/frontend/e2e/01-auth-and-dashboard.spec.ts)\n\n| ID | 영역 | 시나리오 | 우선 | 상태 |\n|---|---|---|---|---|\n| E-001 | 로그인 | admin/admin1234 → /calendar | P0 | PASS |\n| E-001b | 로그인 실패 | 잘못된 비밀번호 → /login + 에러 | P0 | PASS |\n| E-002 | 다크모드 | 토글 → html.dark class | P0 | PASS |\n| E-002b | 다크모드 순환 | system→light→dark | P1 | PASS |\n| E-003 | W01 원콜 | 데이터 + 검색 + 엑셀버튼 | P0 | PASS |\n| E-004 | W03 정기 | TAB 본사 클릭 | P0 | PASS |\n| E-005 | W05 캘린더 | 그리드 표시 | P0 | PASS |\n| E-005b | 캘린더 네비 | 다음 달 버튼 | P1 | PASS |\n| E-006 | W06 일정 | track 필터 변경 | P0 | PASS |\n| E-007 | W07 협력사 | 검색 입력 | P0 | PASS |\n| E-008 | W08 콘솔 | 검색 입력 | P0 | PASS |\n| E-009 | 증명서 | 필터 변경 | P1 | PASS |\n| E-010 | 일일업무 | 카드 + 날짜 변경 | P0 | PASS |\n| E-011 | 코드 마스터 | REGION+ITEM+CERT 탭 | P1 | PASS |\n| E-012 | 주소 검색 | 모달 + SDK load | P1 | PASS |\n| E-013 | 사이드바 네비 | 8 메뉴 순회 | P1 | PASS |\n| E-014 | 로그아웃 | → /login redirect | P0 | PASS |\n| E-015 | ProtectedRoute | 미인증 → /login | P0 | PASS |\n\n### 4-2. API 시나리오 (apps/frontend/e2e/02-api-endpoints.spec.ts)\n\n| ID | 영역 | 시나리오 | 우선 | 상태 |\n|---|---|---|---|---|\n| E-A01 | health | /actuator/health → 200 | P0 | PASS |\n| E-A02 | Swagger | /v3/api-docs paths >= 30 | P1 | PASS |\n| E-A03 | Auth 차단 | no token → 401/403 | P0 | PASS |\n| E-A04 | Contract | list >= 6 | P0 | PASS |\n| E-A05 | Subcontractor | list >= 7 | P0 | PASS |\n| E-A06 | Schedule | JOIN(계약명/협력사) 노출 | P0 | PASS |\n| E-A07 | Schedule filter | ?track=ONE_CALL | P1 | PASS |\n| E-A08 | Console | list >= 5 | P0 | PASS |\n| E-A09 | DailyWork | ?date=2026-06-15 → 1+ | P0 | PASS |\n| E-A10 | Code categories | 4 카테고리 | P0 | PASS |\n| E-A11 | Code CRUD | POST→PUT→DELETE | P1 | PASS |\n| E-A12 | Excel 계약 | xlsx OOXML magic | P1 | PASS |\n| E-A13 | Excel 협력사 | xlsx Content-Type | P1 | PASS |\n| E-A14 | Excel 일정 | ?track=RECURRING xlsx | P2 | PASS |\n| E-A15 | Invalid token | → 401/403 | P1 | PASS |\n| E-A16 | Code REGION | 7건 | P0 | PASS |\n\n## 5. 운영 시나리오 (수용 테스트, Phase G3)\n\n| ID | 시나리오 | 운영자 |\n|---|---|---|\n| A-001 | 사무실 계약 등록 → 작업자 캘린더 표시 | 사용자 |\n| A-002 | 정기 본사 등록 + 지점 5개 → 25일 배치 → 일정 생성 | 사용자 |\n| A-003 | 작업자 일일업무 수거완료 → 캘린더 색상 변경 | 작업자 1 |\n| A-004 | 증명서 5종 발급 + PDF 출력 | 사용자 |\n\n## 6. 우선순위 정의\n\n- **P0** — 비즈니스 critical (인증/계약/일정/수거완료). 실패하면 즉시 운영 불가.\n- **P1** — 운영 편의 (검색/필터/엑셀/관리). 실패 허용 X (다음 sprint).\n- **P2** — UX / 부가 (정렬/색상/툴팁).\n\n## 7. 변경 이력\n\n- v1 (2026-06-06): 초안 — 단위 20 + 통합 28 + e2e 12 + 수용 4 = 64 시나리오\n- v2 (2026-06-06): e2e 12 → 35 확장 (UI 19 + API 16). 모두 PASS. 결과서 xlsx/pptx 산출 (`docs/09_테스트/`)\n- v3 (2026-06-08): 외부 도메인 (https://dev-shred.irosafe.com) 대상 35 PASS 추가. PLAYWRIGHT_BASE_URL 환경변수로 동일 spec 재사용. V7 admin seed + V8 dailywork 재실행 보완. backend eb7d563 / frontend b49fde9.\n","sourceHash":"4ed3e5045b50128761e96c6987b5039e","archivedAt":"2026-06-08T12:28:10+09:00","archivedBy":"sync"}