[FE-44] 소스 상태 레지스트리 · 매칭 범위 재평가 패널
작업 내용 (설계 의도)
근거: 지원 관리 확장 FE 웹 설계 S-11 확장 (3단계) — 소스 상태 레지스트리 · 상태 표기 규칙 · 신규 순수 유틸 · Query 규약(무효화 매핑·operations staleTime 0) · API 연동 > 3단계 · Testing Plan > 반드시 커버할 실패·엣지 경로 #44~#46, 지원 관리 확장 TDD 3단계 — 소스 상태 레지스트리 (FR-88) · 3단계 — 소급 재평가 백필 (FR-87).
변경 사항
- 기존 운영 화면(S-11)에 세그먼트 1개를 추가합니다(수집 이력 / 알림 실패 / 웹훅 수신 / 서류 실패 / 소스 상태). 새 라우트를 만들지 않고 운영 탭 하위에 둡니다 — 이상 감지는 운영 화면의 기존 목적입니다.
- 운영 세그먼트 라벨 축약을 이 티켓이 담당합니다(방안 15). 이 티켓이 소스 상태를 추가하면 세그먼트가 5개가 되는데, 운영 화면 컨테이너는
max-w-md(448px) +px-4= 가용 416px이고 5자 라벨 5개는 약 478px라 넘칩니다(4개까지는 약 384px로 안전).Segment(components/ui/Segment.tsx:15)는 주석부터 “2~3개 전환”용이고inline-flex라 넘치면 잘립니다. - 따라서 5개 라벨을 전부 2자로 축약합니다 —
수집·알림·웹훅·서류·소스(약 268px). 운영 화면 안에서는 축약해도 의미가 유지됩니다. 공용Segment프리미티브는 개조하지 않습니다 — 가로 스크롤로 바꾸면 이 프리미티브를 쓰는 기존 5개 화면에 파급되고, 회귀 검증 비용이 라벨 축약보다 큽니다. - 소스 목록은
{ sources: [] }전량 응답(30건 미만)이라 페이지네이션 없이 한 번에 받고, 상태별 집계를 클라이언트에서 합산합니다. 합산 로직은 컴포넌트가 아니라utils/sourceRegistry.ts(FE-40 소유 순수 유틸)를 호출합니다. - 정렬은 문제 있는 상태 우선입니다 — 접근 제한 → 일시 실패 → 미지원 → 발견됨 → 활성 → 비활성. 정상 소스가 위에 쌓이면 이상 소스를 스크롤로 찾아야 해서 화면 목적이 무너집니다. 정렬 기준도 순수 유틸에 고정하고 컴포넌트에서 재정의하지 않습니다.
registryStatus === null(레지스트리 백필 전)은 “상태 미확인” 중립 칩으로 표시합니다. 오류나 비활성으로 표현하면 배포 순서상 정상인 대기 구간이 장애로 보입니다.- 상태 6종 칩은 기존 토큰 매핑만 씁니다 — 활성 filled positive / 발견됨 outlined neutral / 일시 실패 filled warning / 접근 제한 filled danger / 미지원 filled neutral / 비활성 none. 신규 색 토큰 0건입니다.
- 각 카드는 계약 필드만 소비합니다 —
platform·sourceType·searchCategoryCode ?? sourceSlug·consecutiveAbnormalDays·lastNormalAt. FE가lastCollectedAt으로 이상 여부를 추론하지 않고 서버의registryStatus를 그대로 신뢰합니다. - 세그먼트 하단에 매칭 범위 재평가 패널을 둡니다 —
dryRun체크박스 + 실행 버튼 + 결과 4수치(processedCount·newlyMatchedCount·notificationSuppressedCount·unmatchedNowCount). 배포 절차 3-5/3-7에서 쓰는 운영 도구입니다. dryRun=true일 때는 “적용됐어요” 문구를 렌더하지 않습니다. 시뮬레이션 결과를 적용 완료로 읽으면 운영자가 실제 실행을 건너뜁니다. 실행 결과 카드에 dryRun 여부를 명시합니다.- 실행은 동기이며 수 초~수십 초가 걸리므로 진행 중 버튼을 비활성화하고 대기 UI를 유지합니다. 성공 시
['job-postings']접두사 전체를 무효화해 보관함·공고 상세의 매칭 표시가 새 기준으로 갱신되게 합니다. - 롤백: 재평가 실행은 되돌릴 수 없으므로 UI가
dryRun선실행을 권장 문구로 안내하고, 실제 실행 전 확인 단계를 둡니다. 잘못 실행된 결과의 원복은 BE 재평가 재실행으로만 가능합니다. pages/operations/OperationsPage.tsx는 3단계에서 이 티켓만 수정합니다(FE-28은 단계 1, FE-50은 단계 2). 라벨 축약도 같은 파일 수정이므로 이 티켓 범위 안에서 끝납니다.
의존
- FE-40 —
SourceRegistryResponse·JobSourceRegistryStatus·FieldScopeBackfillResponse타입,['operations','source-registry']queryKey, 6종 상태 +nullfixture,dryRun반영 목,utils/sourceRegistry.ts를 사용합니다. - BE-78 —
GET /api/operations/source-registry구현. - BE-74 —
POST /api/matching/field-scope-backfills구현. - 라우트 신설이 없어 FE-41에 의존하지 않습니다.
다이어그램
처리 흐름
sequenceDiagram participant User as 운영자 participant Page as OperationsPage participant Hook as useSourceRegistry participant Backfill as useFieldScopeBackfill participant API as 소스·백필 API User->>Page: 운영 > 소스 상태 열기 Page->>Hook: 전체 소스 조회 Hook->>API: GET source-registry API-->>Hook: sources[] Hook-->>Page: 집계 + 문제 우선 정렬 User->>Backfill: dryRun 체크 후 재평가 실행 Backfill->>API: POST field-scope-backfills API-->>Backfill: 통계 4수치 Backfill-->>User: dryRun 표기된 결과 카드
컴포넌트 의존
flowchart LR Ops[OperationsPage] --> Section[SourceRegistrySection] Section --> Hook[useSourceRegistry] Hook --> Api[fetchSourceRegistry] Section --> Util[utils/sourceRegistry] Section --> Chip[Chip 기존 UI] Section --> Panel[FieldScopeBackfillPanel] Panel --> Mutation[useFieldScopeBackfill] Mutation --> BackfillApi[postFieldScopeBackfill]
테스트 케이스
- 운영 세그먼트가 5개(
수집·알림·웹훅·서류·소스) 축약 라벨로 렌더되고 잘리지 않는다. - 소스 15건을 받으면 상태별 집계(활성 12 · 일시 실패 2 · 접근 제한 1)와 카드 15장이 보인다.
- 소스 목록이 접근 제한 → 일시 실패 → 미지원 → 발견됨 → 활성 → 비활성 순으로 정렬돼 렌더된다.
registryStatus === null인 소스에는 “상태 미확인” 중립 칩이 보이고 비활성·오류 표기로 렌더되지 않는다.- 6종 상태가 각각 다른 칩 라벨로 표시되고
consecutiveAbnormalDays·lastNormalAt이 카드에 함께 보인다. - 소스 목록 조회가 실패하면
ErrorState와[다시 시도]가 보이고, 재시도하면 다시 조회한다. - 등록된 소스가 0건이면 “등록된 소스가 없어요” 빈 상태와
[회사 등록]이 보인다. dryRun=true로 재평가를 실행하면 통계 4수치가 결과 카드에 보이고 “적용됐어요” 문구가 보이지 않는다.dryRun=false로 재평가를 실행하면 적용 완료 표기와 함께 통계 4수치가 보인다.- 재평가 실행 중에는 실행 버튼이 비활성이고 중복 요청이 발생하지 않는다.
- 재평가 실행이 실패하면 에러 토스트가 보이고 이전 결과 카드가 성공으로 바뀌지 않는다.
- 재평가 성공 후 공고 관련 쿼리가 무효화돼 보관함·공고 상세가 새 기준으로 재조회된다.
- 소스 상태 세그먼트를 다크 모드로 렌더하면 시맨틱 토큰 class만 사용하고 하드코딩 색이 0건이다.