[FE-17] 앱 셸 통합 — 내비게이션 · 404 · 에러 바운더리 · 실 API 통합 · 컨테이너

작업 내용 (설계 의도)

근거 설계: 20260722-공고알림앱-design-fe-web.md — “라우팅·내비게이션 흐름”, “Release Scenario”

변경 사항

마지막 wave의 단독 통합 티켓입니다. 공통 파일(앱 셸·루트 compose)을 수정하는 유일한 티켓이라 다른 티켓과 같은 wave에 두지 않습니다(Single Writer per File).

포함 범위:

  1. AppShell 완성 — FE-01이 만든 골격 스텁을 실제 내비게이션으로 대체합니다. 4탭(회사·지원·매칭·운영) + 현재 경로 활성 표시 + 테마 토글. 반응형: sm 이하 하단 탭, md 이상 상단 탭(설계 Open Questions #3 — 2단 레이아웃은 만들지 않습니다).
  2. 404 페이지 — FE-01 스텁 대체. 홈 이동 수단 포함.
  3. 전역 에러 바운더리 — 렌더 예외가 흰 화면이 되지 않게 합니다. “문제가 생겼어요 + 새로고침” + 개발 모드에서만 스택 노출.
  4. 계약 동기화 — BE-1219가 머지된 시점이므로 실 API와 MSW 목·types/api.ts의 차이를 대조해 정합화합니다. 설계의 “BE에 요청할 계약 변경 목록” #19의 수용 결과를 반영하며, 미수용 항목은 설계 문서에 명시된 폴백으로 전환합니다(예: 계약 요청 #7 미수용 시 클라이언트 전이 맵 유지).
  5. 실 API 통합 확인 — MSW를 끈 상태로 BE와 연결해 전 화면의 4상태를 확인합니다. 계약 불일치가 발견되면 이 티켓에서 잡습니다.
  6. 컨테이너·배포web/Dockerfile(빌드 → nginx 서빙) 추가, 루트 docker-compose.ymlweb 서비스 추가. 루트 compose는 BE-01이 만든 파일이지만 BE wave와 시간축이 완전히 분리돼 있어 충돌하지 않습니다. docker-compose.prod.yml에도 동일하게 추가합니다.
  7. 두 모드 회귀 확인 (의무) — 전 화면을 라이트·다크 두 모드로 확인합니다. 한 모드만 동작하는 화면은 미완성입니다(no-single-mode).
  8. 접근성 점검 — 인터랙티브 요소의 label·키보드 조작·포커스 순서·시트 포커스 트랩을 전 화면에서 확인합니다.

롤백: compose 변경은 web 서비스 블록 제거로 즉시 되돌릴 수 있습니다. 셸 변경은 티켓 revert로 되돌아가며 각 화면은 영향받지 않습니다(라우트 파일 무수정).

의존

  • FE-06 ~ FE-16 (전 화면)
  • BE 의존: BE-12 ~ BE-19 전부 (실 API 통합 확인의 전제)

다이어그램

처리 흐름

sequenceDiagram
    participant U as 사용자
    participant Shell as AppShell
    participant EB as ErrorBoundary
    participant R as Router
    participant P as 화면
    U->>Shell: 앱 진입
    Shell->>R: 현재 경로 매칭
    R->>P: lazy 로드
    alt 렌더 예외
        P-->>EB: throw
        EB-->>U: "문제가 생겼어요" + 새로고침
    else 매칭 실패
        R-->>U: 404 + 홈 이동
    else 정상
        P-->>U: 화면 렌더
    end
    U->>Shell: 탭 전환 · 테마 토글
    Shell-->>U: 활성 탭 갱신 · dark 클래스 전환

클래스 의존

flowchart LR
    subgraph Layout["components/layout"]
        Shell[AppShell]
        Nav[NavTabs]
        Toggle[ThemeToggle]
        EB[ErrorBoundary]
    end
    subgraph Pages["pages"]
        NF[NotFoundPage]
        All[화면 11종]
    end
    subgraph Store["stores"]
        Theme[useThemeStore]
    end
    subgraph Deploy["배포"]
        Docker[web/Dockerfile]
        Compose[docker-compose.yml]
    end
    Shell --> Nav
    Shell --> Toggle
    Shell --> EB
    EB --> All
    Shell --> NF
    Toggle --> Theme
    Docker --> Compose

테스트 케이스

  • 4개 내비게이션 탭이 각각 /·/applications·/settings/matching·/operations로 이동한다
  • 현재 경로에 해당하는 탭이 활성 상태로 표시된다
  • 하위 경로(/companies/1)에서도 상위 탭(회사)이 활성으로 표시된다
  • 테마 토글 클릭 시 <html>dark 클래스가 전환되고 설정이 유지된다
  • 알 수 없는 경로 진입 시 404 화면과 홈 이동 수단이 렌더된다
  • 자식 컴포넌트가 렌더 중 예외를 던지면 에러 바운더리가 안내를 렌더하고 흰 화면이 되지 않는다
  • 에러 바운더리의 새로고침 액션이 동작한다
  • 전 화면(11종)이 라이트 모드에서 오류 없이 렌더된다
  • 전 화면(11종)이 다크 모드에서 오류 없이 렌더된다
  • 소스 전체에 색 하드코딩이 0건임을 lint가 검증한다
  • 모든 인터랙티브 요소가 접근 가능한 이름(label·aria-label)을 가진다
  • 시트가 열린 상태에서 Tab 포커스가 시트 밖으로 나가지 않는다
  • MSW를 끈 상태에서 실 API로 전 화면이 정상 동작한다 (통합 확인)
  • types/api.ts가 실 API 응답과 일치한다 (계약 동기화 확인)
  • docker compose up -d 후 웹과 API가 함께 기동되고 웹에서 API 호출이 성공한다
  • npm run build·tsc --noEmit·lint·전체 테스트가 exit 0으로 완료된다

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

  • 화면 13종(S-12 애그리게이터 소스 등록 추가)을 라이트·다크 두 모드로 회귀 확인합니다.
  • 의존에 FE-18 추가 — 전 화면 완성 후 통합.
  • 실 API 통합 확인 대상에 애그리게이터 API 추가: POST /api/aggregator-sources, POST /api/companies/{id}/promotion, GET /api/companies?companyOrigin=&page=.
  • 계약 동기화 범위 확대: 1차 응답(수용 8건)의 목·타입 정합화 + 2차 요청 3건(#10~#12)의 BE 수용 결과 반영(미수용 시 폴백: #10 등록 전용 유지 / #11 요청안 shape 유지 / #12 FE 상수 유지).
  • 내비게이션은 4탭 유지 — 애그리게이터 소스 등록은 홈 발견 탭 헤더에서 진입하므로 탭을 늘리지 않습니다. 발견 탭 진입점([+ 발견 소스 추가])이 /aggregator-sources/new로 연결되는지 확인합니다.

추가 테스트 케이스

  • 애그리게이터 소스 등록 화면(13번째)이 라이트·다크 두 모드에서 오류 없이 렌더된다
  • 홈 발견 탭에서 /aggregator-sources/new로 이동이 동작한다
  • MSW를 끈 상태에서 애그리게이터 등록·승격·발견 회사 조회가 실 API로 동작한다

3차 갱신 반영 (2026-07-22, BE 최종 확정)

  • 화면 14종(S-13 애그리게이터 소스 관리 추가)을 라이트·다크 두 모드로 회귀 확인합니다.
  • 실 API 통합 확인 대상에 추가: GET /api/aggregator-sources/categories?platform=, GET /api/aggregator-sources, DELETE /api/aggregator-sources/{id}.
  • 모든 계약(1차 9 + 2차 3 = 12건)이 확정됐으므로, FE-04 목·types/api.ts를 확정 shape로 최종 정합화합니다 — 미해소 계약 없음.
  • 발견 탭 헤더 [발견 소스 관리]/aggregator-sources/aggregator-sources/new 계층 이동이 동작하는지 확인합니다.

추가 테스트 케이스

  • 애그리게이터 소스 관리 화면(14번째)이 라이트·다크 두 모드에서 오류 없이 렌더된다
  • 홈 발견 탭 → /aggregator-sources/aggregator-sources/new 계층 이동이 동작한다
  • MSW를 끈 상태에서 카테고리 조회·소스 목록·소프트 삭제가 실 API로 동작한다