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