[FE-49] 3단계 회귀 · 다크 모드 · 접근성 전수 점검

작업 내용 (설계 의도)

근거: 지원 관리 확장 FE 웹 설계 Testing Plan(레벨별 필수 케이스) · Testing Plan > 반드시 커버할 실패·엣지 경로 #48 · 테마 토큰(검증) · 접근성 · Release Scenario — 점진 공개 · Single Writer per File 검증 > 단계 3 wave 3 · Open Questions #8.

변경 사항

  • 3단계를 닫는 검증 전용 티켓입니다. 테스트 파일만 수정합니다 — 프로덕션 파일을 이 티켓에서 고치면 wave 2·3 티켓의 소유 경계가 무너지고 리뷰 대상이 뒤섞입니다. 수정이 필요한 결함을 발견하면 해당 담당 티켓에 되돌려 보고하고, 이 티켓은 재검증만 수행합니다.
  • [소유권 확정 2026-08-09] 색 가드 헬퍼는 만들지 않고 소비만 합니다. 렌더 단위 색 가드 web/src/test/hardcodedColor.ts(expectNoHardcodedColor)는 1단계 FE-20 소유이므로 main에서 import해 씁니다. 이 헬퍼는 팔레트 이름을 검사하지 않습니다(정당한 시맨틱 토큰 bg-neutral-chip-bg를 오탐하므로) — 원색 리터럴(#hex·rgb())만 봅니다. 파일 단위 소스 스캔인 theme/no-hardcoded-color.test.ts와는 다른 층이며, 이 티켓은 둘 다 소비하고 어느 쪽도 새로 만들지 않습니다.
  • 3단계 신규 화면 4종(연락 검토 목록·연락 검토 상세·추천도 가중치·운영 소스 상태)의 다크 모드 렌더를 전수 확인합니다. 기존 components/**/darkMode.test.tsx 선례를 따르고, theme/no-hardcoded-color 스캔이 신규 디렉토리를 실제로 훑어 하드코딩 색 0건임을 재확인합니다(스캔은 디렉토리 재귀이므로 신규 파일이 자동 포함되는지까지 확인합니다).
  • 접근성을 항목별로 점검합니다 — 대시보드 칸반 컬럼의 aria-label(건수 포함)과 가로 스크롤 컨테이너의 키보드 접근, 추천도 게이지의 role="meter" + aria-valuenow/min/max + 숫자 텍스트 병기, 반영 불가 후보의 disabled + aria-disabled + 사유 aria-describedby 연결, 시트의 포커스 트랩·Esc 닫기·role="dialog", 파일 입력의 <label htmlFor> 연결.
  • 색·길이만으로 정보를 전달하지 않는지 확인합니다 — 신뢰도 칩·소스 상태 칩·축 충족 표시에 텍스트 라벨이 항상 병기되는지 점검합니다. 다크 모드에서 톤이 바뀌어도 의미 전달이 유지돼야 합니다.
  • 1·2단계 화면 회귀를 확인합니다 — 인증 게이트를 통과한 뒤 기존 11개 화면이 3단계 배선(대시보드 배너·공고 상세 섹션·운영 세그먼트) 추가 후에도 정상 동작하는지, 탭 5개 구조와 라우팅이 유지되는지 봅니다.
  • 점진 공개 하위 호환을 회귀 케이스로 고정합니다 — contact.inbound-webhook OFF(연락 0건 긍정 빈 상태), source.registry-status OFF(registryStatus: null → 상태 미확인), matching.field-weighted-scope OFF·재평가 전(matchScore: null → 기존 matched 폴백). 플래그를 조회하지 않고 응답 형태만으로 하위 호환되는지 확인합니다.
  • 완료 기준은 tsc --noEmit · eslint · vitest run이 전부 exit code 0입니다. 파이프로 tail을 걸어 실패를 가리지 않고 exit code로 판정합니다.
  • Open Question 8을 이 티켓에서 판단합니다 — 기존 web/scripts/capture-usecases.mjs(Playwright) 하네스에 3단계 신규 화면을 등록할지 결정합니다. 단위 테스트는 .dark 클래스 렌더만 확인하고 실제 대비를 보지 않으므로, 등록하면 스크린샷으로 대비를 눈으로 확인할 수 있습니다. 등록 여부와 사유를 결정해 문서(Open Questions)에 반영합니다.

의존

  • FE-42 · FE-43 · FE-44 · FE-45 · FE-46 — 3단계 wave 2 화면·컴포넌트 전부가 병합돼 있어야 전수 점검이 성립합니다.
  • FE-47 — 착수된 경우에만 매칭 근거 박스를 점검 대상에 포함합니다(계약 미확정으로 미착수면 제외하고 matchScore: null 폴백만 확인).
  • FE-48 — 대시보드 배너·공고 상세 배선이 회귀 점검 대상입니다.
  • BE-79 — 3단계 E2E·통합 검증과 짝을 이룹니다.

다이어그램

처리 흐름

sequenceDiagram
    participant Runner as 검증 실행
    participant Dark as 다크 모드 렌더 테스트
    participant Scan as no-hardcoded-color 스캔
    participant A11y as 접근성 속성 점검
    participant Gate as 완료 판정
    Runner->>Dark: 3단계 화면 4종 .dark 렌더
    Runner->>Scan: 신규 디렉토리 재귀 스캔
    Runner->>A11y: meter·aria-disabled·포커스 트랩 확인
    Dark-->>Gate: 통과 여부
    Scan-->>Gate: 하드코딩 색 0건 여부
    A11y-->>Gate: 속성 누락 여부
    Gate-->>Runner: tsc·eslint·vitest exit code 0

컴포넌트 의존

flowchart LR
    Suite[3단계 검증 스위트] --> ContactList[연락 목록 화면]
    Suite --> ContactDetail[연락 상세 화면]
    Suite --> Weight[가중치 화면]
    Suite --> Registry[소스 상태 세그먼트]
    Suite --> Wiring[대시보드 배너 · 공고 상세 배선]
    Suite --> Legacy[1·2단계 기존 화면]
    Suite --> ColorScan[no-hardcoded-color 스캔]
    Suite --> Capture[capture-usecases 하네스 판단]

테스트 케이스

  • 3단계 신규 화면 4종을 .dark로 렌더하면 전부 정상 렌더되고 라이트 모드와 동일한 정보가 보인다.
  • no-hardcoded-color 스캔이 3단계 신규 디렉토리를 포함해 실행되고 하드코딩 색 0건을 보고한다.
  • 대시보드 칸반 컬럼에 건수를 포함한 aria-label이 붙고 가로 스크롤 컨테이너를 키보드로 조작할 수 있다.
  • 추천도 게이지에 role="meter"aria-valuenow·aria-valuemin·aria-valuemax가 있고 숫자 텍스트가 함께 보인다.
  • 반영 불가(terminal) 후보가 aria-disabledaria-describedby로 사유에 연결된다.
  • 3단계 시트·다이얼로그가 포커스 트랩과 Esc 닫기를 유지하고 role="dialog" 계약을 승계한다.
  • 신뢰도 칩·소스 상태 칩·축 충족 표시가 색뿐 아니라 텍스트 라벨을 항상 병기한다.
  • 인증 게이트를 통과한 뒤 기존 11개 화면이 3단계 배선 추가 후에도 정상 렌더되고 탭 5개 구조가 유지된다.
  • 연락 0건·registryStatus: null·matchScore: null 응답에서 각각 긍정 빈 상태·상태 미확인 칩·기존 매칭 표시 폴백이 나오고 오류로 표현되지 않는다.
  • tsc --noEmit·eslint·vitest run이 전부 exit code 0으로 종료한다.
  • 프로덕션 파일 수정이 필요한 결함을 발견하면 이 티켓에서 고치지 않고 담당 티켓으로 되돌려 보고한 기록이 남는다.
  • capture-usecases 하네스에 3단계 신규 화면을 등록할지 결정하고 그 사유가 기록된다.