[FE-05] 도메인 표시 컴포넌트 — 확신도 라벨 · 상태 칩 · 공고 카드

작업 내용 (설계 의도)

근거 설계: 20260722-공고알림앱-design-fe-web.md — “확신도 위계”, “컴포넌트 트리”, “도메인 표시 규칙 → 토큰 매핑”

변경 사항

2개 이상 화면에서 쓰이는 것이 확정된 도메인 표시 컴포넌트만 공용화합니다(토스 “두 번째 사용처” 원칙). 한 화면에서만 쓰이는 CompanyCard·SourceCandidateCard는 각 화면 티켓이 소유하고 여기에 넣지 않습니다 — 선제 추상화를 만들지 않습니다.

대상 (src/components/domain/**):

컴포넌트사용처핵심 규칙
WorkArrangementLabelS-03 목록, S-04 상세확신도 위계를 형태로 표현합니다. CONFIRMED=채운 칩, LIKELY=테두리 칩 + “본문 언급” 보조 문구, UNKNOWN=칩 없이 회색 텍스트 “근무형태 정보 없음”. 색만 바꾸면 사용자가 색-신뢰도 매핑을 학습해야 하므로 형태를 바꿉니다. 다크 모드에서 채도 대비가 달라져도 위계가 유지되는 실용적 이점도 있습니다
DeadlineTextS-03 목록, S-04 상세null=상시채용(중립), D-3 이내=danger Bold, 그 외=일반 보조 텍스트, CLOSED=마감 사유 병기. 판정은 FE-03의 describeDeadline에 위임
ApplicationStatusChipS-03 배지, S-04, S-06, S-078개 상태의 한글 표기 + 톤 매핑. REJECTEDrejectedAtStage를 병기(“불합격 · 서류전형”)
AppliedBadgeS-03, S-04[지원함] accent-subtle 배지
JobPostingCardS-03, (계약 요청 #3 수용 시 전체 공고 뷰)제목 + 근무형태 라벨 + 마감 표기 + 지원 배지 + 접근 제한 배지를 조립. 클릭 시 공고 상세로 이동하되 라우팅은 props 콜백으로 받아 컴포넌트가 라우터를 모르게 합니다
AccessRestrictedBadgeS-03, S-04warning 톤. 시나리오 6의 P0 표현 수단(알림 대신 배지)
SourceHealthBadgeS-01, S-11소스 고장 danger 배지

전부 프레젠테이션 컴포넌트입니다 — 훅을 호출하지 않고 props만 받습니다. 판단 로직은 FE-03의 순수 함수에 있고 이 티켓은 그 결과를 토큰에 매핑해 렌더하기만 합니다.

의존

  • FE-02 (UI 프리미티브), FE-03 (표기 규칙 순수 함수)

다이어그램

처리 흐름

sequenceDiagram
    participant P as 화면 (props)
    participant C as JobPostingCard
    participant W as WorkArrangementLabel
    participant U as describeWorkArrangement
    participant Chip as Chip 프리미티브
    P->>C: jobPosting · onSelect
    C->>W: workArrangement
    W->>U: confidence · keyword
    U-->>W: fill · text · note
    alt fill 이 none (UNKNOWN)
        W-->>C: 회색 텍스트만 렌더
    else filled 또는 outlined
        W->>Chip: fill · tone · label
        Chip-->>C: 칩 렌더
    end

클래스 의존

flowchart LR
    subgraph Ui["components/ui"]
        Chip
        Card
        Badge
    end
    subgraph Utils["utils · constants"]
        Work[describeWorkArrangement]
        Dead[describeDeadline]
        Label[statusLabel · statusTone]
    end
    subgraph Domain["components/domain"]
        WA[WorkArrangementLabel]
        DT[DeadlineText]
        SC[ApplicationStatusChip]
        JC[JobPostingCard]
        AB[AccessRestrictedBadge]
    end
    WA --> Chip
    WA --> Work
    DT --> Dead
    SC --> Chip
    SC --> Label
    JC --> Card
    JC --> WA
    JC --> DT
    JC --> AB

테스트 케이스

  • CONFIRMED 확신도가 채운 칩으로 렌더되고 키워드 텍스트가 보인다
  • LIKELY 확신도가 테두리 칩으로 렌더되고 “본문 언급” 보조 문구가 함께 보인다
  • UNKNOWN 확신도가 칩이 아닌 텍스트 “근무형태 정보 없음”으로 렌더된다
  • CONFIRMEDLIKELY 칩의 렌더 형태가 서로 다르다 (색만 다른 것이 아니다)
  • 마감일이 null이면 “상시채용”이 렌더되고 D-day가 렌더되지 않는다
  • 마감일이 내일이면 “D-1”이 danger 톤으로 렌더된다
  • CLOSED 공고에 “마감됨”과 마감 사유가 함께 렌더된다
  • ApplicationStatusChip이 8개 상태의 한글 표기를 정확히 렌더한다
  • REJECTED 칩에 rejectedAtStage가 병기된다 (“불합격 · 서류전형”)
  • ACCEPTED·REJECTED·WITHDRAWN 칩이 서로 다른 톤으로 렌더된다
  • JobPostingCard 클릭 시 onSelect가 공고 ID와 함께 호출된다
  • JobPostingCard가 지원 기록이 있으면 [지원함] 배지를 렌더한다
  • accessRestricted=true면 접근 제한 배지가 렌더된다
  • 근무형태 정보가 없고 마감일도 없는 공고가 크래시 없이 렌더된다
  • 전 컴포넌트가 .dark 트리에서 오류 없이 렌더된다

2차 갱신 반영 (2026-07-22)

CrossSourceChip 추가 (크로스 소스 중복, FR-64)

  • alternateSourceCount > 0인 공고에 🔗 N곳 게재 테두리(neutral) 칩을 렌더합니다. S-03 목록·S-04 상세 요약 두 곳에서 쓰이므로 공용화합니다.
  • accent를 쓰지 않습니다 — 정보성 표식이 CTA와 시각 무게로 경쟁하면 안 됩니다.
  • alternateSourceCount === 0이면 렌더하지 않습니다.

AppliedBadge 판정 기준 변경 (계약 응답 #3)

  • applied: boolean이 아니라 **applicationId != null**로 지원 여부를 판정합니다. 배지 클릭 시 applicationId로 지원 상세로 바로 이동할 수 있게 onSelect(applicationId) 콜백을 받습니다.

추가 테스트 케이스

  • alternateSourceCount가 3이면 ”🔗 3곳 게재” 칩이 렌더된다
  • alternateSourceCount가 0이면 크로스 소스 칩이 렌더되지 않는다
  • 크로스 소스 칩이 accent가 아닌 neutral 톤으로 렌더된다
  • applicationId가 있으면 지원함 배지가 렌더되고 null이면 렌더되지 않는다
  • 지원함 배지 클릭 시 applicationId와 함께 콜백이 호출된다