Skip to content

[Feat] 수집 상태 확인·수동 실행 어드민 웹 추가 - #93

Merged
JangDongHo merged 14 commits into
devfrom
feat/admin-web
Sep 25, 2026
Merged

JangDongHo merged 14 commits into
devfrom
feat/admin-web

Conversation

@JangDongHo

@JangDongHo JangDongHo commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

📌 개요

  • 운영자가 배치 수집(셔틀·공지사항·학식·학사 일정) 상태를 확인하고 수동으로 다시 돌릴 수 있는 어드민 웹을 admin/에 추가했습니다.
  • #92에서 추가한 admin API(/api/admin/*)를 사용하고, 화면은 커넥트 지누 디자인 시스템(토큰·컴포넌트)을 따릅니다.

✨ 작업 내용

프로젝트 (admin/, 루트와 독립된 pnpm 패키지)

  • Vite 5 + React 18 + TypeScript + react-router 6, 테스트는 Vitest + Testing Library.
  • pnpm dev 시 Vite 프록시가 /api를 VITE_API_TARGET(기본 http://localhost:3000)으로 넘깁니다. 서버 CORS 설정은 바꾸지 않았습니다.
  • 루트 pnpm test에 test:admin을 추가했습니다.

디자인 시스템

  • 디자인 시스템 아티팩트의 tokens.json을 tokens.css(라이트/다크)로 옮기고, bundle.css는 jinu.css로 복사했습니다.
  • Button·Card·Badge·Chip·Notice·EmptyState·Icon을 같은 클래스명의 TSX로 이식했습니다.
  • 사이드바·상단 바·표·섹션·입력창은 같은 토큰으로 admin.css에 새로 만들었습니다.

화면

수집 상태 실행 기록
image image
경로 내용
/login ADMIN_API_KEY 입력 → GET /admin/scrapers로 검증 → sessionStorage 보관
/scrapers 타입별 카드(상태 배지, 최근 실행, 소요, 마지막 성공, 실패 오류) + "지금 수집", 최근 실행 10건
/scrape-runs 타입·상태 칩 필터(URL 쿼리), 커서 "더 보기", 행 클릭 시 상세 패널
  • /는 /scrapers로 보냅니다.
  • 진행 중(pending/running)인 수집이 있으면 3초, 없으면 30초마다 다시 불러옵니다. 이전 요청이 끝난 뒤에 다음 요청을 보내고, 탭이 숨겨지면 멈춥니다.
  • 어느 화면에서든 401/403을 받으면 키를 지우고 로그인 화면으로 돌아갑니다. 409는 "이미 수집이 대기 중이거나 실행 중이에요."로 안내합니다.

🔥 변경 이유

  • 수집이 실패했는지 확인하거나 다시 돌리려면 지금은 Swagger에서 직접 API를 불러야 합니다. 운영자가 한눈에 보고 버튼으로 실행할 수 있게 하려는 작업입니다.
  • 운영 도구라 사용자 앱(mobile)과 분리했고, 배포 없이 로컬에서만 띄웁니다. 그래서 서버에는 로그인 엔드포인트를 따로 만들지 않고 기존 ADMIN_API_KEY 헤더 인증을 그대로 씁니다.

🧪 테스트

  • cd admin && pnpm test 91개 통과. API 클라이언트 에러 매핑, 폴링 훅, 로그인, 셸, 카드·표, 두 화면을 다룹니다.
  • pnpm typecheck, pnpm build 통과, 루트 pnpm test(api·mobile·admin) 통과
  • 예외 케이스
    • 서버 꺼짐(프록시 5xx) 시 안내와 다시 시도
    • 필터를 바꾼 뒤 늦게 온 "더 보기" 응답 무시
    • 폴링 중 403이 오면 로그아웃
    • "지금 수집" 연타 시 POST 1회
    • 잘못된 URL 쿼리 무시
    • 없는 run(404)
  • admin API와 같은 응답을 내는 목 서버에 붙여 헤드리스 Chrome으로 로그인 → 수동 실행(pending→running→succeeded) → 실행 기록·상세 → 다크 모드 → 로그아웃 흐름을 확인했습니다.
  • 실제 API 서버에 붙여 확인

실행 방법

# API 서버 (ADMIN_API_KEY 필요)
cd services/api/app
ADMIN_API_KEY="$(grep '^ADMIN_API_KEY=' ../.env | cut -d= -f2-)" pnpm start:dev

# 어드민
cd admin && pnpm install && pnpm dev   # http://localhost:5173

참고

  • docker-compose.dev.yml의 app 컨테이너에는 ADMIN_API_KEY가 전달되지 않습니다. 그래서 compose로 띄우면 admin 요청이 전부 403이 나고, 이 PR에서는 건드리지 않았습니다.
  • 후속으로 다룰 만한 사소한 이슈(리뷰에서 나온 것)
    • 수동 실행 직후 늦게 도착한 폴링 응답이 상태를 잠깐 되돌릴 수 있음
    • 서버가 꺼졌을 때 "HTTP 500" 문구가 나옴
    • 409 안내가 수집이 끝난 뒤에도 남음
    • 상세 패널 포커스 이동 등 접근성

🔗 관련 이슈

🤖 Generated with Claude Code

Summary by CodeRabbit

  • 신규 기능
    • 로컬 운영자 웹에서 API 키로 로그인하고, 수집 상태와 최근 실행 기록을 확인할 수 있습니다.
    • 수집을 수동으로 요청하고, 실행 기록을 유형·상태별로 필터링하거나 상세 정보를 확인할 수 있습니다.
    • 진행 중인 작업과 실행 기록이 주기적으로 갱신됩니다. 사이드바 접기와 화면별 탐색도 지원합니다.
  • 문서
    • 운영자 웹의 실행·로그인 방법과 화면 기능 안내를 추가했습니다.
  • 테스트
    • 운영자 웹의 로그인, 수집 상태, 실행 기록 및 화면 구성에 대한 테스트를 추가했습니다.

JangDongHo and others added 14 commits September 25, 2026 23:05
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
실행 기록 표가 상세 패널과 함께 좁아질 때 한글이 줄바꿈되지 않도록 표 셀 스타일도 정리한다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pnpm-workspace.yaml에 packages 필드를 추가하고 esbuild 빌드 허용을 pnpm 9·10(onlyBuiltDependencies)과 11+(allowBuilds) 형식으로 함께 적는다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JangDongHo JangDongHo self-assigned this Sep 25, 2026
@coderabbitai

coderabbitai Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Repository: GNU-connect/Server-Node/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 92564753-e6e9-49f2-b4fd-012c9a191cb3

📥 Commits

Reviewing files that changed from the base of the PR and between cfe3218 and e5bb952.

⛔ Files ignored due to path filters (1)
  • admin/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (68)
  • admin/.env.example
  • admin/.gitignore
  • admin/README.md
  • admin/index.html
  • admin/package.json
  • admin/pnpm-workspace.yaml
  • admin/public/jinu-app-icon.webp
  • admin/src/App.tsx
  • admin/src/api/adminClient.test.ts
  • admin/src/api/adminClient.ts
  • admin/src/api/errors.ts
  • admin/src/api/types.ts
  • admin/src/auth/AuthContext.tsx
  • admin/src/auth/RequireAuth.tsx
  • admin/src/auth/keyStorage.ts
  • admin/src/design/admin.css
  • admin/src/design/components/Badge.tsx
  • admin/src/design/components/Button.tsx
  • admin/src/design/components/Card.tsx
  • admin/src/design/components/Chip.tsx
  • admin/src/design/components/DataTable.tsx
  • admin/src/design/components/EmptyState.tsx
  • admin/src/design/components/Icon.tsx
  • admin/src/design/components/Notice.tsx
  • admin/src/design/components/Section.tsx
  • admin/src/design/components/TextField.tsx
  • admin/src/design/components/components.test.tsx
  • admin/src/design/components/index.ts
  • admin/src/design/cx.ts
  • admin/src/design/jinu.css
  • admin/src/design/tokens.css
  • admin/src/features/scrapers/RunDetailPanel.tsx
  • admin/src/features/scrapers/RunTable.test.tsx
  • admin/src/features/scrapers/RunTable.tsx
  • admin/src/features/scrapers/ScraperCard.test.tsx
  • admin/src/features/scrapers/ScraperCard.tsx
  • admin/src/features/scrapers/format.test.ts
  • admin/src/features/scrapers/format.ts
  • admin/src/features/scrapers/labels.test.ts
  • admin/src/features/scrapers/labels.ts
  • admin/src/features/scrapers/searchParams.test.ts
  • admin/src/features/scrapers/searchParams.ts
  • admin/src/features/scrapers/useNow.ts
  • admin/src/features/scrapers/usePolling.test.ts
  • admin/src/features/scrapers/usePolling.ts
  • admin/src/layout/AppLayout.test.tsx
  • admin/src/layout/AppLayout.tsx
  • admin/src/layout/PageHeader.tsx
  • admin/src/layout/Sidebar.tsx
  • admin/src/layout/Topbar.tsx
  • admin/src/layout/nav.ts
  • admin/src/main.tsx
  • admin/src/pages/LoginPage.test.tsx
  • admin/src/pages/LoginPage.tsx
  • admin/src/pages/ScrapeRunsPage.test.tsx
  • admin/src/pages/ScrapeRunsPage.tsx
  • admin/src/pages/ScrapersPage.test.tsx
  • admin/src/pages/ScrapersPage.tsx
  • admin/src/test/fixtures.ts
  • admin/src/test/http.ts
  • admin/src/test/renderApp.tsx
  • admin/src/test/setup.ts
  • admin/src/vite-env.d.ts
  • admin/tsconfig.json
  • admin/vite.config.ts
  • docs/superpowers/plans/2026-09-25-admin-web.md
  • docs/superpowers/specs/2026-09-25-admin-web-design.md
  • package.json
 ________________________________________________________________________________________________________________________________________
< Use saboteurs to test your testing. Introduce bugs on purpose in a separate copy of the source to verify that testing will catch them. >
 ----------------------------------------------------------------------------------------------------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@JangDongHo
JangDongHo merged commit 143a6d3 into dev Sep 25, 2026
1 check was pending
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant