Skip to main content

JunkBox apps/raid-api 가이드

1. 애플리케이션 역할

  • apps/raid-api는 JunkBox의 독립 레이드 운영 백엔드 앱임.
  • 공대원 목록, 공대원 관리, WCL 점수 전체 갱신, 공대 구인 알림 수집·분석·매칭, 레이드 전용 서버 렌더링 진입점을 담당함.
  • 공통 로그인과 공통 권한 체계를 재사용하면서, 레이드 도메인 데이터와 화면 자산 서빙을 한 앱에서 통합함.
  • 공통 코드와 메타 조회는 hub-api의 내부 master-data API를 통해 수행함.

2. 런타임 구성

  • FastAPI 애플리케이션 엔트리포인트는 junkbox_raid_api.main:app임.
  • 기본 루트 //raid/members로 리다이렉트됨.
  • 상태 확인 경로는 /health임.
  • OpenAPI 노출 경로는 /docs, /redoc, /openapi.json임.
  • apps/raid-ui/dist/raid-ui 경로로 직접 마운트함.
  • libs/shared-ui 산출 자산은 /shared-ui 경로로 직접 마운트함.
  • 앱 favicon은 포털 메뉴의 menu_type_code=APP, icon_type_code=APP_ICON, icon_val 조합에서 raid 앱 아이콘 slug를 해석해 사용하며, 조회 실패 시 raid slug를 fallback으로 사용함.
  • CORS 허용 origin 목록은 shared-core 설정의 server.cors_origins를 공통으로 사용함.

2.1 로컬 개발 서버 연동

  • raid-api18009 포트 기준 백엔드로 실행할 수 있음.
  • apps/raid-ui15009 포트 기준 Vite 개발 서버로 실행할 수 있음.
  • 페이지 HTML은 18009가 렌더링하고, React 엔트리와 HMR 자산은 15009/raid-ui/* 경로에서 로드함.

2.2 운영 배포 기준

  • 운영 컨테이너 기본 포트는 8009임.
  • 운영 이미지는 apps/raid-ui/dist, libs/shared-ui 자산, raid-api 실행 코드를 함께 포함함.
  • 운영 환경변수는 /sorc001/junkbox/env/.env.shared/sorc001/junkbox/env/.env.prod를 함께 참조하고, 컨테이너 내부 ENV_FILE=/app/env/.env.prod 기준으로 로딩함.
  • 운영과 개발 Compose는 호스트 /sorc001/junkbox/db를 컨테이너 /app/db에 마운트함.
  • 컨테이너의 RAID_DATABASE_URLsqlite+aiosqlite:////app/db/raid.sqlite3임.
  • 운영 로그 볼륨은 /logs001/junkbox/raid-api 호스트 경로를 컨테이너 내부 /app/logs에 연결함.
  • 공통 애플리케이션 로그 파일 경로는 /app/logs/app.log임.
  • RAID_BASE_URL, RAID_DATABASE_URL, WCL_CLIENT_ID, WCL_CLIENT_SECRET, WCL_TOKEN_URL, WCL_API_URL 설정 정합성이 중요함.

2.3 공통 로깅 초기화

  • 앱 import 시점에 shared-coresetup_app_logging()을 호출함.
  • 설정값은 settings.modules.raid.logging에서 읽음.
  • 로그 sink는 콘솔 출력과 파일 출력 두 축으로 동시에 구성됨.

2.4 Raid SQLite engine 초기화

  • 앱 import 시점에 shared-corecreate_async_engine(settings.modules.raid.database_url)를 호출하여 Raid 전용 SQLite engine을 초기화함.
  • 로컬 비컨테이너 기본 RAID_DATABASE_URLsqlite+aiosqlite:////sorc001/junkbox/db/raid.sqlite3임.
  • SQLite 연결은 DB 파일의 부모 경로를 준비하고 PRAGMA journal_mode=WAL, PRAGMA busy_timeout=5000, PRAGMA foreign_keys=ON을 적용함.
  • Raid SQLite의 단일 writer는 raid-api임. 다른 앱은 이 파일을 직접 write하지 않음.

3. 라우팅 구조

3.1 인증 API

  • raid-api는 자체 인증 발급 API를 제공하지 않음.
  • 사용자 credential 검증, JWT 발급, logout API는 hub-api가 담당함.
  • raid-apishared-core 인증 의존성으로 hub-api가 발급한 JWT를 검증함.

3.2 raid API

  • GET /api/raid/members
  • POST /api/raid/members/roles
  • POST /api/raid/scores/all
  • GET /api/raid/members/manage
  • POST /api/raid/members/manage
  • POST /api/raid/members/manage/sort
  • DELETE /api/raid/members/manage/{raid_member_id}
  • DELETE /api/raid/members/manage/member/{member_id}
  • GET /api/raid/recruitment/profiles
  • POST /api/raid/recruitment/profiles
  • PUT /api/raid/recruitment/profiles/{profile_id}
  • GET /api/raid/recruitment/results

공대원 목록 조회·저장 계약

  • GET /api/raid/membersraid_id, difficulty_code, 반복 가능 쿼리 member_category_codes를 수용함.
  • member_category_codes를 생략하면 활성 공대원 구분 전체를 조회함. 값이 전달되면 서버는 전달값과 무관하게 SELF를 항상 조회 대상에 포함함.
  • 응답 행은 공통코드 RAID_MEMBER_CATEGORY.sort_order_no와 레이드 멤버 정렬 순서를 기준으로 정렬함.
  • 응답의 server_slugSERVER.attribute02 값이며, UI가 Warcraft Logs 캐릭터 URL을 만들 때 사용함.
  • 응답의 wow_check_urlhttps://wow-check.ryuar.in/ 고정 base URL에 선택 difficulty_coded 값으로, 캐릭터명과 SERVER.attribute01을 결합한 값을 q 값으로 사용해 구성함.
  • POST /api/raid/members/manage는 공대원 풀 저장 시 member_category_code를 함께 저장함. 신규 공대원 풀 행의 기본 구분은 RAID_MEMBER임.

3.3 공대 구인 Automation 내부 API

  • POST /api/raid/internal/automation/recruitment-scan은 게시판 목록 수집, 신규 글 본문 분석, 프로필 매칭을 수행함. 요청 body의 dry_run은 선택값임.
  • POST /api/raid/internal/automation/recruitment-deliver-pending은 보류 중인 매칭을 발송 가능 시간대와 중복 발송 조건으로 판정한 뒤 Message internal API에 전달함.
  • 두 경로는 일반 사용자 JWT 경로가 아니며 require_automation_job 검증을 통과해야 함.
  • 호출자는 AUTOMATION_SERVICE_TOKEN, X-Junkbox-Service: automation, 허용된 X-Junkbox-Job-Type, Idempotency-Key를 제공해야 함.

3.4 웹 화면

  • GET /raid/members
  • GET /raid/members/manage
  • GET /raid/recruitment
  • GET /error/403
  • /error/403은 하위 호환 진입점이며 별도 권한 오류 페이지를 렌더링하지 않고 hub-api 로그인 화면의 권한 없음 alert 흐름으로 연결함.

4. 인증 및 권한 흐름

4.1 토큰 입력 경로

  • API는 Authorization: Bearer 헤더와 COOKIE_NAME 설정값 기준 HttpOnly 쿠키를 모두 수용함.
  • 현재 기본 쿠키 이름은 JUNKBOX_AUTH임.
  • 인증 해석 우선순위는 Authorization 헤더가 먼저임.

4.2 로그인과 페이지 접근 흐름

  • 보호 페이지는 강제 인증 구조를 사용함.
  • 비로그인 요청은 hub-api 공통 로그인 화면 /login?redirect=...&required_module=RAID로 리다이렉트됨.
  • 로그인 성공 시 redirect 값이 허용된 경로 또는 허용된 앱 origin이면 해당 위치로 이동함.
  • 요구 모듈 권한이 없으면 hub-api 공통 로그인 화면으로 이동하며 permission_denied=1을 전달함.
  • 공통 로그인 화면은 권한 없음 alert를 한 번 표시하고 URL의 permission_denied 플래그를 제거함.
  • allowed_modulesRAID가 포함된 사용자만 레이드 화면과 API에 접근할 수 있음.

4.3 슬라이딩 세션 갱신

  • raid-api는 FastAPI 앱 초기화 시 shared-coreSlidingSessionMiddleware를 등록함.
  • 브라우저 쿠키 기반 요청은 hub 내부 인증 API를 통해 세션 갱신 필요 여부를 확인함.
  • raid-api의 JSON API와 HTML 페이지 접근 검증은 일반 사용자 JWT에 대해 hub 내부 인증 API의 세션 유효성 검증을 사용함.
  • 세션 갱신 판단과 새 JWT 발급은 hub-apiPOST /api/internal/auth/refresh가 담당함.
  • 만료되었거나 유효하지 않거나 hub에서 revoke된 토큰은 미들웨어가 갱신하지 않으며, 표준 인증 실패 흐름에서 로그인 재진입 또는 JSON 401로 처리됨.

5. 데이터 저장 책임

5.1 레이드 도메인 저장소

  • 레이드 도메인의 소스 오브 트루스는 /sorc001/junkbox/db/raid.sqlite3 SQLite 파일임.
  • 컨테이너 내부 표준 경로는 /app/db/raid.sqlite3임.
  • RAID_DATABASE_URL은 Raid 도메인 DB 연결에만 사용하며 Raid 런타임은 전역 DATABASE_URL을 사용하지 않음.
  • 공대원 풀은 tb_member_m을 기준으로 관리함.
  • tb_member_m.member_category_code는 공대원 구분 코드이며 기본값은 RAID_MEMBER임. 구분은 레이드별 배치가 아닌 공대원 풀 속성이므로 한 캐릭터의 구분은 모든 레이드 소속에 공통 적용됨.
  • 레이드 소속과 정렬 순서는 tb_raid_member_n을 기준으로 관리함.
  • 난이도별 레이드 전체 점수는 tb_raid_member_raid_score_n을 사용함.
  • 보스별 점수와 최근 갱신 시각은 tb_raid_member_boss_score_n을 사용함.
  • 레이드, 난이도, 보스 메타는 Raid SQLite에 복제하지 않고 hub-api internal master-data API 계약으로 조회함.
  • tb_raid_member_raid_score_n의 PK는 (raid_member_id, raid_id, difficulty_code)임.
  • tb_raid_member_boss_score_n의 PK는 (raid_member_id, boss_id, difficulty_code)임.
  • SQLite 파일 간 또는 Hub 데이터에 대한 DB 레벨 FK를 전제로 하지 않음.
  • 같은 공대원이 여러 레이드에 중복 소속될 수 있음.
  • 앱 시작 시 공대원 구분 컬럼이 없는 기존 Raid SQLite에 member_category_code를 추가하고 기존 행을 RAID_MEMBER로 보정하는 멱등 스키마 보정이 수행됨.
  • 삭제 정책은 물리 삭제 기준임.

5.2 공통 master-data 의존 구조

  • 레이드, 난이도, 역할, 근/원, 직업, 서버, 보스 메타는 hub-api 내부 master-data API를 통해 조회함.
  • 공대원 구분은 RAID_MEMBER_CATEGORY 공통코드를 사용하며, 활성 코드의 sort_order_no가 목록·관리 선택지의 표시 순서임.
  • SERVER.attribute01은 wow-check 서버 식별자, SERVER.attribute02는 Warcraft Logs URL 서버 slug, SERVER.attribute03은 Warcraft Logs region 값으로 사용함.
  • 앱 내부에서 공통 코드와 메타를 직접 DB 조회하지 않음.
  • raid-apishared-core.masterdata.MasterDataService를 통해 공통 코드와 메타를 조회함.
  • 내부 master-data 조회 결과는 shared-core의 TTL 캐시를 통해 재사용함.

5.3 WCL 연동

  • WCL 연동은 settings.raid.wcl 설정을 사용함.
  • OAuth 토큰 발급 후 GraphQL API를 호출하는 구조를 사용함.
  • 레이드 화면에서는 페이지 전체 갱신만 지원하며, 개별 행 단건 갱신은 제공하지 않음.
  • 점수 갱신은 현재 레이드의 전체 멤버 집합을 대상으로 하며 공대원 구분으로 갱신 대상을 제외하지 않음.
  • 점수 갱신은 복합 PK로 기존 점수 row를 조회한 뒤 생성 또는 갱신하여 전체 점수, 보스별 점수, 최근 업데이트 시각을 함께 동기화함.
  • 점수 생성·갱신 시각은 KST(UTC+9) 기준 timezone 없는 datetime으로 Raid SQLite에 저장함. 목록 응답의 전체 최근 업데이트 시각은 선택 레이드·난이도의 tb_raid_member_raid_score_n.updated_at 또는 created_at 최댓값을 변환 없이 문자열로 반환함.

5.4 공대 구인 알림 저장소와 수집 범위

  • 공대 구인 알림은 와우 인벤 파티찾기 게시판의 고정 원본 https://www.inven.co.kr/board/wow/2972[공격대_구인] 분류만 대상으로 함.
  • 원본 URL, CSS selector, 전송 webhook은 프로필에서 변경하지 않음.
  • 최초 수집은 현재 목록 첫 페이지에 노출된 [공격대_구인] 글을 대상으로 하며 과거 페이지를 순회하지 않음. 이후 수집은 아직 저장되지 않은 inven_post_no만 신규 글로 처리함.
  • 목록은 수집 실행당 한 번 요청하고, 신규 글의 본문만 추가 요청함. 댓글, 이미지, 첨부 파일은 수집하지 않음.
  • 본문은 분석 요청이 끝날 때까지 메모리에만 존재하며 DB, AI 사용량 로그 입력 파라미터, Telegram 메시지에 저장하지 않음.
  • tb_raid_recruitment_profile_mprofile_id, name, user_id, is_active, allowed_weekdays_json, weekly_count, additional_keywords_json, excluded_keywords_json, allowed_start_time, allowed_end_time, 생성·수정 시각을 저장함.
  • 프로필 제목은 사용자의 식별용 이름이며 자동 기본값을 두지 않음. 직업, 역할, 전문화, 프리셋, 자동 검색어 설정은 프로필 모델과 저장소에 존재하지 않음.
  • tb_raid_recruitment_post_n은 원본 게시글 번호, URL, 제목, 본문 해시, 수집·분석 시각, 구조화 분석 결과, 분석 상태와 오류 요약만 저장함. 원문 본문 컬럼은 두지 않음.
  • tb_raid_recruitment_match_n은 프로필과 게시글 조합, 판정, 판정 요약, 알림 상태, 보류·발송 시각, delivery key를 저장함. (profile_id, post_id) 유니크 제약으로 같은 프로필·게시글의 중복 매칭을 막음.

5.5 분석, 매칭, 발송 책임 경계

  • 신규 본문 분석은 shared-aiDirectAiRunnerSharedAiRuntimeFactory를 사용하며, 라우팅 키 RAID_RECRUITMENT_ANALYSIS의 구조화 출력 계약을 따름.
  • AI 사용량 기록은 HubApiAiUsageLogWriter를 통해 Hub에 남김. Raid SQLite에 별도 AI 사용량 로그를 만들지 않으며, 기록에는 원문 본문을 포함하지 않음.
  • 분석 결과는 공격대 구인 여부, 요일, 주당 횟수, 구인 인식어, 제외 사유, 신뢰도, 근거를 구조화해 사용함. 게시글 본문은 신뢰할 수 없는 입력으로 취급함.
  • 매칭은 요일·주당 횟수 조건을 먼저 검사하고, 분석된 구인 인식어에 제외 검색어가 하나라도 있으면 제외함. 추가 검색어는 하나 이상 일치해야 함.
  • 일정 정보가 불명확하거나 분석 신뢰도가 낮으면 검토 필요 상태로 남김. 추가 검색어와 제외 검색어는 직업·역할별 고정 규칙을 대체하는 유일한 검색 조건임.
  • 발송 시간대와 최종 중복 판정은 Raid가 소유함. 발송 대상은 제목, 판정, 요약, 원문 URL만 포함하며 원문 본문을 포함하지 않음.
  • 실제 Telegram 전달, 전송 이력, 재시도는 Message가 소유함. Raid는 Message SQLite를 직접 읽거나 쓰지 않으며, Message internal API 성공 후에만 매칭을 발송 완료로 전환함.
  • raid-recruitment:{match_id} 형식의 idempotency key로 전달 요청을 식별함.

5.6 공대 구인 스키마 초기화와 예약 실행

  • 앱 lifespan은 공대 구인 테이블 스키마를 초기화함. 앱 자체 scheduler loop는 두지 않음.
  • Automation이 raid.recruitment-scanraid.recruitment-deliver-pending 작업의 cron, 실행 claim, lease, 재시도, 실행 이력, idempotency를 소유함.
  • 기본 작업은 수집·분석을 매시 정각, 보류 알림 발송을 5분마다 실행하며 timeout은 60초, 최대 시도는 3회, backoff는 60초임.

6. 화면 진입 데이터 구성

  • 서버 템플릿은 공통 베이스 템플릿과 raid-ui React 마운트 지점을 제공함.
  • 페이지는 page_props.view 값을 통해 members, manage, recruitment 화면을 구분함.
  • 초기 props에는 현재 사용자, 레이드 관련 코드 목록, 현재 선택 가능한 필터 목록, RAID_MEMBER_CATEGORY 활성 목록이 포함됨.
  • 서버 템플릿 문구는 템플릿 또는 라우터 컨텍스트에 한국어 문구로 직접 작성함.
  • 공통코드 라벨과 메타 설정값처럼 데이터 자체가 마스터데이터인 값만 DB 조회 구조를 사용함.

7. API 계약 특성

  • 두 화면 모두 기본적으로 풀 로딩형 Tabulator 편집 화면을 사용함.
  • 공대원 목록 저장은 역할, 근/원, 참여 여부, 정렬 순서 같은 레이드 소속 정보를 기준으로 처리함.
  • 공대원 관리 저장은 공대원 풀 자체의 생성, 수정, 삭제와 공대원 구분 저장을 기준으로 처리함.
  • 신규 행 삭제는 프런트 메모리에서만 제거되고, 저장된 행 삭제만 실제 삭제 API를 호출함.
  • 공대원 관리의 일괄 삭제는 선택 체크박스 기반으로 수행함.
  • 공대 구인 프로필 CRUD와 최근 탐색 결과 조회는 전용 JSON API를 사용함.

8. 배포 및 운영 체크

  • Docker Compose 서비스명은 junkbox-raid임.
  • GitHub Actions 배포 감지 경로와 서비스 정책에 raid-api, raid-ui, junkbox-raid가 포함됨.
  • 운영 reverse proxy는 RAID_BASE_URL8009 컨테이너로 연결되는 전제를 가짐.
  • 점수 갱신 기능을 사용하려면 WCL 인증 환경변수가 모두 채워져 있어야 함.
  • Raid SQLite 생성과 dump 기반 데이터 적재는 scripts/migrate_raid_pg_dump_to_sqlite.py를 사용함.
  • 이관 스크립트의 기본 입력은 프로젝트 루트 dbjbp1_20260719-080001.sql, 기본 출력은 /sorc001/junkbox/db/raid.sqlite3임.
  • 기존 raid.sqlite3은 기본적으로 덮어쓰지 않으며, --force 사용 시 SQLite backup API로 사전 백업한 뒤 교체함.
  • 이관 스크립트는 raid dump의 tb_member_m, tb_raid_member_n, tb_raid_member_raid_score_n, tb_raid_member_boss_score_n COPY 블록만 적재하고 row count와 복합 PK 중복을 검증함.

9. 관련 문서

  • 프로젝트 전체 구조는 docs/junkbox/common/guide-jb-core.md를 따름.
  • 공통 설정, DB, 인증은 docs/junkbox/libs/guide-lib-shared-core.md를 따름.
  • 공통 UI 자산은 docs/junkbox/libs/guide-lib-shared-ui.md를 따름.
  • 레이드 프런트 구조는 docs/junkbox/apps/guide-apps-raid-ui.md를 따름.