본문으로 건너뛰기

JunkBox 코어 가이드

1. 프로젝트 정의

  • JunkBox는 Python 기반 멀티 앱 구조를 사용하는 AI-Native 운영 시스템임.
  • 공통 라이브러리 재사용, API 우선 설계, 운영 허브 집중화, Hub SQLite 공통 저장소, 앱별 SQLite 도메인 저장소, 개발 문서 벡터 캐시를 조합하는 구조를 사용함.
  • 현재 구조에서 apps/hub-api는 상시 운영 허브이자 공통 인증 진입점, 공통 마스터 데이터 제공자 역할을 수행함.
  • 현재 구조에서 apps/raid-api는 WoW 레이드 운영 화면, WCL 점수 동기화, 공대 구인 알림 수집·분석·매칭을 담당하는 독립 앱임.
  • 현재 구조에서 apps/chess-api는 단일 Lichess OAuth 계정의 종료 대국 수집과 주석 포함 PGN 업로드, Stockfish 분석, Codex 코칭 데이터 저장, 복기를 담당하는 독립 앱임.
  • 현재 구조에서 apps/automation-api는 예약 실행, cron 정기 실행, 재시도, 실행 이력, 수동 실행을 독점적으로 소유하는 중앙 작업 실행 플랫폼임.
  • 현재 구조에서 apps/message-api는 외부 시스템의 즉시 알림 요청, 메시지 채널 전달, 발송 이력, 전달 재시도를 관리하고 Apprise API를 실제 전달 엔진으로 사용하는 독립 앱임.
  • 현재 구조에서 apps/track-apiapps/track-ui는 주기 여부와 무관한 개인 관리 항목, 실제 처리 이력, 선택적 도래 알림을 관리하는 모바일 전용 Track 앱임.
  • 현재 구조에서 apps/jeevtrap는 Discord 기반 독립 실행형 툴킷 데몬이며 공통 AI 런타임, GitHub, Linkding, 시스템 명령 실행, 선택적 로컬 음성 호출 인터페이스를 조합하는 별도 앱임.

2. 기술 스택

2.1 백엔드

  • 언어는 Python 계열을 사용함.
  • 웹 프레임워크는 FastAPI임.
  • ORM 계층은 SQLModel과 SQLAlchemy 2 비동기 스택을 사용함.
  • SQLite 비동기 드라이버는 aiosqlite임.
  • 워크스페이스와 패키지 관리는 uv를 사용함.
  • 공통 애플리케이션 로깅은 loguru 기반 구조를 사용함.
  • 체스 분석은 Stockfish를 사용하고 Codex 코칭은 SQLite의 분석 결과를 근거로 별도 작업으로 반영함.
  • 레이드 점수 연동은 httpx 기반 외부 HTTP 호출과 GraphQL 요청을 사용함.
  • 애플리케이션 런타임 저장소는 SQLite를 사용함.
  • AI 개발 문서 지식 검색은 애플리케이션 런타임과 분리된 Vault PostgreSQL pgvector와 OpenAI 호환 embeddings API를 사용함.

2.2 프런트엔드 및 정적 자산

  • 운영 화면 프런트엔드는 apps/hub-ui, apps/chess-ui, apps/raid-ui, apps/rename-ui, apps/workout-ui, apps/message-ui, apps/track-ui의 Vite 6 기반 React + TypeScript 프로젝트를 사용함.
  • FastAPI는 서버 렌더링 HTML 골격 위에 각 앱의 dist 정적 자산을 마운트하여 화면을 제공함.
  • 로컬 개발에서는 각 UI 앱의 Vite 개발 서버와 FastAPI 백엔드를 병행 실행할 수 있음.
  • hub 개발 흐름은 15001 프런트와 18001 백엔드 조합을 사용함.
  • chess 개발 흐름은 15002 프런트와 18002 백엔드 조합을 사용함.
  • workout 개발 흐름은 15003 프런트와 18003 백엔드 조합을 사용함.
  • message 개발 흐름은 15004 프런트와 18004 백엔드 조합을 사용함.
  • rename 개발 흐름은 15006 프런트와 18006 백엔드 조합을 사용함.
  • raid 개발 흐름은 15009 프런트와 18009 백엔드 조합을 사용함.
  • track 개발 흐름은 15008 프런트와 18008 백엔드 조합을 사용함.
  • 운영 배포 포트는 hub-api=8001, chess-api=8002, workout-api=8003, message-api=8004, rename-api=8006, automation-api=8007, raid-api=8009 조합을 사용함.
  • 운영 배포 포트는 jeevtrap=8005를 추가로 사용함.
  • 운영 배포 포트는 track-api=8008을 추가로 사용함.
  • 공통 UI 자산은 libs/shared-ui에서 제공함.
  • 공통 앱 아이콘 자산은 libs/shared-uiapp-icons/{slug}/icon.svg, icon-180.png, icon-192.png, icon-512.png 구조로 제공함.
  • 운영 화면 소스는 .ts.tsx만 사용하며, 신규 화면 로직을 .js로 직접 작성하지 않음.
  • TypeScript 컴파일은 strict 모드를 기준으로 유지함.
  • 운영 자산의 표준 서빙 흐름은 백엔드 포트가 빌드된 프런트 산출물을 직접 서빙하는 구조임.
  • 공통 shared-ui 정적 자산은 서버 템플릿이 버전 쿼리 파라미터를 붙여 링크하므로, 배포 후 CDN이 예전 고정 경로 CSS를 계속 재사용하지 않는 구조임.
  • 공통 CSS는 hub-ui-base.css와 화면 모드별 hub-ui-mobile.css 또는 hub-ui-desktop.css를 조합해서 로드하는 구조임.
  • 공통 CSS와 Tabulator vendor CSS 링크 선언은 libs/shared-ui의 stylesheet 매크로로 중앙화하며, 공통 베이스 템플릿과 standalone 템플릿은 같은 매크로를 호출함.
  • 공통 베이스 템플릿과 standalone 템플릿은 inline <style>을 포함하지 않으며, 모든 CSS는 libs/shared-ui 산출물에서 공급함.
  • 화면 폰트는 shared-ui가 제공하는 PretendardVariable.woff2hub-ui-base.css의 중앙 폰트 선언을 기준으로 통일함.
  • 앱 favicon, Apple touch icon, PWA manifest icon은 포털 메뉴의 APP_ICON + icon_val 관리값을 shared-ui 앱 아이콘 slug로 해석하여 같은 아이콘 세트를 사용함.

2.3 인증

  • JWT 기반 인증을 사용함.
  • 토큰 전달 경로는 Authorization: Bearer 헤더와 COOKIE_NAME 설정값 기준 HttpOnly 쿠키를 병행함.
  • 현재 기본 쿠키 이름은 JUNKBOX_AUTH임.
  • 비밀번호 처리는 passlibbcrypt 조합을 사용함.
  • 로그인 화면은 hub-api가 공통 진입점을 제공하고, 각 앱은 required_moduleredirect를 기준으로 복귀 흐름을 사용함.
  • 공통 로그인 화면은 마지막으로 로그인에 성공한 user_id를 별도 쿠키에 저장하고 다음 로그인 기본값으로 사용함.

3. 워크스페이스 구조

junkbox/
├── apps/
│ ├── hub-api/
│ ├── hub-ui/
│ ├── chess-api/
│ ├── chess-ui/
│ ├── raid-api/
│ ├── raid-ui/
│ ├── rename-api/
│ ├── rename-ui/
│ ├── workout-api/
│ ├── workout-ui/
│ ├── message-api/
│ ├── message-ui/
│ ├── automation-api/
│ ├── track-api/
│ ├── track-ui/
│ └── jeevtrap/
├── libs/
│ ├── shared-core/
│ ├── shared-ai/
│ ├── shared-ui/
│ └── shared-voice/
├── scripts/
├── .env.shared
├── .env.local.template
├── pyproject.toml
└── uv.lock

3.1 apps

  • hub-api는 인증, 운영 허브, 관리자 화면, 공통 마스터 데이터 API를 담당함.
  • hub-ui는 hub 운영 화면 전용 React + TypeScript 프런트엔드 앱임.
  • chess-api는 Lichess OAuth 계정, 종료 대국 수집, 주석 포함 PGN 업로드, Stockfish 분석, Chess SQLite 저장을 담당함.
  • chess-ui는 완료 대국 목록, 보드 복기, 실제 수와 엔진 최선수 비교, 수별 엔진·코칭 정보 표시를 담당하는 React + TypeScript 프런트엔드 앱임.
  • raid-api는 레이드 공대원 관리, 공대 배치, WCL 점수 동기화, 공대 구인 알림 도메인과 화면 진입점을 담당함.
  • raid-ui는 PC 레이드 운영 화면과 모바일 공대 구인 알림 화면을 제공하는 React + TypeScript 프런트엔드 앱임.
  • rename-api는 ASITE 기반 파일명 수집, Favorites, 로그, Rename 작업 API와 데스크톱 화면 진입점을 담당함.
  • rename-ui는 rename 운영 화면 전용 React + TypeScript 프런트엔드 앱임.
  • workout-api는 운동 도메인 API, 체중·선택 투약 기록 API, 설치형 PWA 진입, 운동 기준정보 관리 API, 규칙 엔진 기반 운동 계획 API를 담당함.
  • workout-ui는 운동 기록 목록, 세션 상세, 체중 관리, 운동 계획, 운동 관리, 러닝 기록·계획·실행의 모바일 전용 React + TypeScript 프런트엔드 앱임.
  • automation-api는 작업 정의, 1회·cron 일정, 다음 실행 시각, claim/lease, 재시도, 실행 이력, 수동 실행을 소유하고 등록된 internal Job HTTP API만 호출함.
  • message-api는 Apprise 전달 어댑터, 메시지 이력, 즉시 발송, 수동 재발송과 Message 웹 앱 셸을 담당함.
  • message-ui는 즉시 발송·발송 이력과 Automation이 소유하는 예약·정기 메시지 관리 화면을 제공하는 모바일 전용 React + TypeScript SPA임.
  • track-api는 Track SQLite에서 관리 항목, 처리 이력, 알림 규칙과 발송 중복 방지 상태를 소유하며 Automation internal Job API를 제공함.
  • track-ui챙김 기록, 챙김 관리와 처리 이력 등록·삭제를 제공하는 모바일 전용 React + TypeScript SPA임.
  • jeevtrap는 Discord 기반 독립 실행형 툴킷 앱이며 /md, /북마크, /명령, 선택적 로컬 음성 호출 인터페이스를 담당함.

3.2 libs

  • shared-core는 설정, 비동기 DB, 공통 모델, 인증, 예외, 공통 마스터 데이터 저장소, 공통 master-data 소비 클라이언트, active 포털 메뉴 조회와 TTL 캐시를 제공함.
  • shared-ai는 AI provider 어댑터, 기능별 모델 라우팅, usage log 기록, 공통 예외 정규화를 제공함.
  • shared-ai는 direct runner, graph runner, prompt registry, graph registry를 통해 상위 AI 호출 패턴까지 중앙화함.
  • shared-ui는 공통 템플릿, stylesheet 매크로, Tailwind preset, base / mobile / desktop 분리 CSS 자산, 공통 앱 셸 자산, 앱 아이콘 자산, 공통 React UI 유틸과 모바일 고정 폭 레이아웃 자산을 제공함.
  • shared-voice는 로컬 마이크 입력, STT, 호출어 감지, TTS, 음성 이벤트 런타임을 제공하는 공통 음성 라이브러리임.

4. 핵심 구조 원칙

4.1 운영 허브 집중화

  • 인증, 권한 체크, 공통 마스터 데이터 관리, 운영 관리자 화면은 hub-api에 집중함.
  • 다른 앱이 공통코드와 메타 원본을 자체적으로 소유하지 않음.
  • chess-api, raid-api, rename-api, workout-api를 포함한 보호 앱은 로그인 화면을 독자적으로 소유하지 않고 hub-api 공통 로그인 진입점을 사용함.
  • chess-api, raid-api, rename-api, workout-api는 자체 로그인 API와 credential 검증 API를 제공하지 않고, hub-api가 발급한 JWT를 소비함.
  • 다른 앱은 DB 기반 공통 master-data 로컬 원본 데이터를 직접 소유하지 않고 hub-api 내부 API를 통해 조회함.
  • 다른 앱은 Hub SQLite 파일을 직접 열지 않으며, AI 사용 로그도 shared-ai가 Hub internal API로 전달하고 Hub가 저장함.
  • AI 코딩 컨텍스트도 공통 master-data 로컬 원본을 직접 읽지 않고 hub-apiROLE_AI JWT 기반 통합 snapshot API를 통해 조회함.
  • workout 운동 계획 생성은 workout-api가 Workout SQLite 기준정보와 기록을 사용해 규칙 엔진으로 직접 수행함.
  • 체스 복기는 chess-api가 Lichess 종료 대국과 Stockfish 분석을 저장하고 Codex가 SQLite에 코칭 데이터를 반영하는 구조임.

4.2 공통 로직 중앙화

  • 시간 기반 작업은 automation-api가 유일하게 소유함. 새 배치·예약·cron 작업은 개별 앱의 lifespan, asyncio loop, scheduler 클래스에 추가하지 않고 Automation 작업 계약으로 등록함.
  • 도메인 앱은 자기 SQLite 데이터와 업무 규칙을 소유하고, Automation이 호출할 최소 범위 internal Job API를 제공함.
  • Automation은 Hub·Message·도메인 SQLite 파일을 직접 읽거나 쓰지 않으며, 대상 앱 HTTP API와 service-to-service 인증으로만 작업을 실행함.
  • 도메인 조건이 즉시 발생한 메시지는 도메인 앱 outbox publisher가 Message API를 직접 호출함. 즉시 조건마다 Automation을 경유하지 않음.
  • Message API는 메시지 채널 전달, 발송 이력, 전달 재시도만 소유함. Message UI의 예약·정기 관리 화면은 Automation API가 소유하는 작업 정의를 조회·수정하는 표현 계층임.
  • 설정, JWT/쿠키 유틸리티, 공통 인증 의존성, 예외, 공통 엔티티, 공통 마스터 데이터 저장소, master-data 내부 API 소비 클라이언트, TTL 캐시는 shared-core에 둠.
  • 사용자 로그인 세션의 영속 상태와 유효성 판정은 hub-api에 둠.
  • AI provider 어댑터, 기능별 모델 라우팅, usage-log writer, AI 통신 예외 정규화는 shared-ai에 둠.
  • 레이아웃, 스타일, 공통 템플릿, Tabulator 헬퍼, 앱 셸 동작은 shared-ui에 둠.
  • 로컬 음성 입력, STT/TTS provider, 호출어 감지 런타임은 shared-voice에 둠.
  • 앱별 CSS, 화면별 CSS, inline style은 운영 화면 구현 표준에 포함하지 않음.
  • hub 운영 화면 페이지 진입점과 타입 계약은 hub-ui에 둠.
  • chess 복기 화면 페이지 진입점과 타입 계약은 chess-ui에 둠.
  • raid 운영 화면 페이지 진입점과 타입 계약은 raid-ui에 둠.
  • rename 운영 화면 페이지 진입점과 타입 계약은 rename-ui에 둠.
  • workout 운영 화면 페이지 진입점과 타입 계약은 workout-ui에 둠.
  • Vite 개발 모드 자산 주입과 React refresh preamble 주입은 공통 베이스 템플릿과 서버 템플릿 컨텍스트를 통해 처리함.

4.3 TypeScript 우선 원칙

  • 프런트엔드 소스 코드는 TypeScript 기준으로 유지함.
  • 신규 화면, 공통 헬퍼, 앱 셸 로직은 .ts 또는 .tsx로 작성함.
  • TypeScript 설정은 strict 모드를 유지함.
  • any 사용은 최후 수단으로 제한하며, API 응답과 테이블 데이터는 명시적 타입 계약을 우선함.
  • 브라우저 전역 주입이 필요하면 window 임의 확장보다 import.meta.env와 타입 선언 파일을 우선 사용함.

4.4 현재 데이터 관리 구조

  • 공통코드, 코드 타입, 메타, 포털 메뉴는 DB 기반 마스터 데이터 구조를 사용함.
  • 포털 메뉴의 앱 구분은 menu_type_code=APP을 사용하며, 하위 호환 데이터의 PROJECT 값은 포털 소비 화면에서 APP 그룹으로 해석될 수 있음.
  • 포털 메뉴의 icon_type_code=APP_ICONicon_val은 포털 카드 아이콘, 앱 favicon, PWA 설치 아이콘을 같은 shared-ui 앱 아이콘 slug로 묶는 단일 관리 지점임.
  • 사용자에게 노출되는 일반 UI 텍스트는 소스에 한국어 문구로 직접 작성함.
  • 공통코드 라벨과 메타 설정값처럼 데이터 자체가 마스터데이터인 값은 기존 DB 기반 구조를 사용함.
  • AI 기능별 모델 라우팅은 YAML 기반 정책 파일 구조를 사용함.
  • 사용자, 사용자 세션, AI 로그, 운동 기록, 레이드 운영 데이터는 DB 기반 구조를 사용함.
  • 공통코드, 코드 타입, 메타, 포털 메뉴, 사용자, 사용자 세션, 대시보드 사용자 preference, AI usage log는 Hub SQLite 파일 /sorc001/junkbox/db/hub.sqlite3를 사용함.
  • 운동 도메인 데이터는 workout-api가 단독 writer인 SQLite 파일 DB에 저장함.
  • Track 도메인 데이터는 track-api가 단독 writer인 SQLite 파일 /sorc001/junkbox/db/track.sqlite3에 저장함.
  • 체스 대국 마스터와 게임 로그는 DB 기반 구조를 사용하며, 내 bot 수, 상대 수, Lichess 이벤트, 게임 시작/종료 이벤트를 같은 로그 시간축에 저장함.
  • AI 개발 지식 검색용 문서 캐시는 PostgreSQL vault 스키마와 pgvector 기반 벡터 테이블을 사용함.
  • 개발 문서 캐시의 원본은 vault/docs/**/*.md 파일이며, JunkBox 개발 가이드의 Source of Truth는 vault/docs/junkbox/**/*.md 파일임.
  • 따라서 현재 시스템은 DB 기반 운영 데이터, YAML 기반 AI 라우팅 정책, 벡터 DB 기반 개발 문서 캐시를 함께 다루는 구조임.
  • DB 기반 사용자 구조에서 Hub SQLite tb_user_mid 물리 PK와 user_id 논리 식별자를 함께 사용함.
  • DB 기반 사용자 세션 구조는 Hub SQLite tb_user_session_n을 사용하며 JWT의 sid claim과 세션 테이블의 session_id를 연결함.

4.5 신규 앱 생성 필수 계약

  • 신규 앱은 apps/{app}-api와 화면이 필요한 경우 apps/{app}-ui를 독립 패키지로 구성하고, Python workspace·Vite TypeScript strict·공통 라이브러리 의존성을 기존 앱 구조에 맞춰 등록함.
  • 구현 전에 scripts/search_dev_docs.py로 관련 개발 가이드를 의미 검색함. 공통코드, 메타, 포털 메뉴, 앱 아이콘 또는 Hub 설정이 관련되면 scripts/fetch_master_data.py snapshot을 먼저 조회함.
  • 모바일 전용 앱의 UX 기준 앱은 workout-ui임. 서버 렌더링 공통 앱 셸, BrowserRouter, spa_navigation=true, junkbox:spa-navigate 이벤트 수신, SpaRouteTransition, useSpaRouteSettling, 모바일 고정 폭과 하단 고정 액션바를 공통 기준으로 사용함.
  • 화면 CSS는 반드시 shared-ui 빌드 자산으로 공급함. 앱·모듈·화면 전용 CSS 파일, <style> 태그, inline style과 앱별 font-family 선언을 추가하지 않음.
  • 한글·영문·숫자는 shared-uiPretendardVariable.woff2와 중앙 --jb-font-family 선언으로 렌더링함. 사용자 로컬 Pretendard, 유사 sans, 외부 폰트, 브라우저 기본 monospace가 우선하지 않는지 확인함.
  • 모바일 선택 UI는 네이티브 <select> 대신 jb-select 외형 버튼과 shared-ui BottomOptionPicker를 우선 사용함. 화면 전체를 관통하는 CUD 액션은 jb-mobile-bottom-bar 공통 하단 고정 액션바에 배치함.
  • 공통 앱 셸, 버튼, 입력창, 토스트, 아이콘, 바텀시트, SPA 유틸은 화면에서 복제하지 않고 @shared-ui/*와 공통 템플릿·클래스로 소비함. 새 공통 외형이 필요하면 앱 CSS가 아니라 shared-ui에 추가함.
  • 신규 API·UI 앱의 개발 포트는 기존 사용 포트를 Hub 포털 메뉴 데이터와 현재 서비스 구성에서 확인한 뒤 1500x Vite 포트와 1800x FastAPI 포트를 각각 빈 번호로 배정함. 운영 컨테이너 포트는 8001부터 기존 배정과 포털 데이터를 확인해 빈 800x 번호로 배정하며, 단순히 현재 최대 포트 다음 번호를 가정하지 않음.
  • 신규 앱의 포털 노출이 필요하면 Hub SQLite tb_portal_menu_mmenu_type_code=APP 메뉴를 등록하고 URL, 표시 순서, APP_ICON slug, 운영 포트를 현재 포털 계약에 맞춰 함께 관리함. Hub 데이터 변경 전에는 마스터데이터 조회와 SQLite 직접 반영 또는 수동 산출물 방식을 확정함.
  • 앱 도메인 데이터는 Hub SQLite에 섞지 않고 앱 전용 SQLite 파일과 앱 전용 *_DATABASE_URL을 사용함. SQLite 확인·생성·변경은 대상 파일과 테이블/컬럼을 확인하고 사용자 승인 범위에 따라 수행하며, 변경 뒤 스키마와 결과를 검증함.
  • 보호 웹 화면은 별도 인증 체계를 만들지 않고 Hub JWT Cookie/Header, required_module, allowed_modules, Hub 공통 로그인·복귀 흐름을 사용함. 외부 호출 API와 관리자 화면의 인증·권한 요구는 명시적으로 분리함.
  • 운영 배포 대상 앱은 앱 API Dockerfile, 개발 docker-compose.yml, 운영 docker-compose.prod.yml, 앱 DB·로그 볼륨, Hub 의존성, 환경 파일, docker-compose.prod.yml 서비스 포트와 재시작 정책을 함께 구성함.
  • Dockerfile은 해당 UI distshared-ui 빌드 자산을 런타임 이미지에 포함함. GitHub Actions selective build/deploy의 서비스 정의, 배포 정책, 변경 감지 경로, 수동 배포 선택지까지 같은 서비스명으로 등록함.
  • 신규 앱은 다른 앱과 같은 .vscode/tasks.json 개발 작업을 제공하고, Vite typecheck·build, 백엔드 컴파일 또는 테스트, Docker Compose config 검증, 웹 라우트·포털 진입·공통 CSS와 폰트 적용을 확인함. 검증을 위해 시작한 로컬 서버와 포트는 완료 전에 종료함.
  • 일반 UI 텍스트와 사용자 메시지는 한국어 소스 문구로 작성하며 DB 메시지 마스터를 만들지 않음. 문장형 노출 메시지는 하십시오체와 마침표를 사용함.
  • 기능 구현 뒤 개발 가이드 문서는 자동으로 변경하지 않음. 문서 갱신은 사용자 요청이 있는 경우에만 vault/docs/junkbox Source of Truth를 갱신하고, 사용자가 검토한 뒤 scripts/sync_dev_docs.py로 벡터 캐시를 동기화함.

5. 설정 구조

5.1 Settings 원칙

  • 설정은 pydantic-settings 기반으로 로딩함.
  • 기본 ENV_FILE 값은 .env.local임.
  • ENV_FILE 기준 환경 파일과 같은 디렉터리의 .env.shared를 함께 로드함.
  • ENV_FILE 기준 환경 파일과 같은 디렉터리의 .env.chess를 함께 로드함. Chess OAuth와 Stockfish 설정은 이 파일에서 관리함.
  • ENV_FILE.env.local.jeevtrap, .env.prod.jeevtrap이면 같은 디렉터리의 .env.shared, .env.jeevtrap, 선택된 Jeevtrap 전용 env 파일을 로드함.
  • ENV_FILE이 base profile env 파일명 뒤에 앱 suffix를 붙인 형태이고 Jeevtrap 전용 env가 아니면 같은 디렉터리의 .env.local 또는 .env.prod를 base profile env로 함께 로드할 수 있음.
  • 설정 우선순위는 명시적 초기화 값, .env.chess, 선택된 ENV_FILE, 앱 공통 env, base profile env, .env.shared, 셸 환경 변수, file secret 순서임.
  • import 시점부터 실행 환경 오염을 최소화하는 방향을 사용함.
  • 설정 객체는 app, database, auth, server, modules, masterdata, dashboard, rename, raid, lichess, jeevtrap, ai 중첩 모델 구조를 사용함.
  • 앱 코드는 중첩 모델 접근을 기준으로 구현하며, 일부 flat alias는 호환 목적에 한해 유지함.

5.2 주요 설정 범주

  • 앱별 SQLite DSN과 DB_ECHO
  • HUB_DATABASE_URL
  • CHESS_DATABASE_URL
  • WORKOUT_DATABASE_URL
  • MESSAGE_DATABASE_URL
  • MESSAGE_APPRISE_DEFAULT_CONFIG_KEY: Apprise 요청에 설정 키가 없을 때 사용할 기본 설정 키이며 현재 값은 apprise임.
  • RAID_DATABASE_URL
  • JEEVTRAP_DATABASE_URL
  • JWT_SECRET_KEY, JWT 알고리즘
  • apps/hub-api/var/auth-policy.yml 기반 사용자 세션 만료 시간과 슬라이딩 갱신 임계 시간
  • apps/hub-api/var/dashboard-policy.yml 기반 hub 대시보드 HTTP 수집 타임아웃, 캐시 TTL, Glances 호출 타임아웃
  • DASHBOARD_OPENROUTER_MANAGEMENT_API_KEY 기반 hub 대시보드 OpenRouter credits/API key 사용량 조회 설정
  • 쿠키 이름, 도메인, secure, same_site
  • CORS 허용 원본
  • 공통 로깅 정책인 LOG_ROTATION_LIMIT, LOG_RETENTION_DAYS, LOG_COMPRESSION_TYPE
  • profile별 로깅 동작인 LOG_LEVEL, LOG_DIAGNOSE_TOGGLE
  • MASTER_DATA_DIR
  • AI_ROUTING_YAML_PATH
  • HUB_BASE_URL, WORKOUT_BASE_URL, RAID_BASE_URL
  • CHESS_BASE_URL
  • HUB_INTERNAL_BASE_URL, HUB_API_INTERNAL_TOKEN, HUB_API_INTERNAL_TOKEN_HEADER
  • MASTERDATA_CODES_TTL_SECONDS, MASTERDATA_METAS_TTL_SECONDS, MASTERDATA_HTTP_TIMEOUT_SECONDS
  • AI_ACCESS_TOKEN, FASTAPI_BASE_URL
  • ASITE_BASE_URL, ASITE_LOGIN_URL, ASITE_USERNAME, ASITE_PASSWORD
  • RENAME_BASE_DIR, RENAME_TARGET_DIR_NAME
  • WCL_API_URL, WCL_TOKEN_URL, WCL_CLIENT_ID, WCL_CLIENT_SECRET, WCL_MAX_CONCURRENCY
  • LITELLM_API_KEY, LITELLM_BASE_URL, AI_HTTP_TIMEOUT_SECONDS
  • LICHESS_OAUTH_CLIENT_ID, LICHESS_OAUTH_REDIRECT_URI, LICHESS_OAUTH_SYNC_INTERVAL_SECONDS, CHESS_STOCKFISH_PATH, CHESS_STOCKFISH_TIME_LIMIT_SECONDS, CHESS_STOCKFISH_DEPTH, CHESS_STOCKFISH_MULTIPV, JUNKBOX_CHESS_RESTART_POLICY
  • JEEVTRAP_PORT, JEEVTRAP_DISCORD_TOKEN, JEEVTRAP_DISCORD_TEST_GUILD_ID
  • JEEVTRAP_VOICE_ENABLED, JEEVTRAP_VOICE_CONFIG_YAML_PATH
  • JEEVTRAP_GITHUB_TOKEN, JEEVTRAP_GITHUB_OWNER, JEEVTRAP_GITHUB_REPO, JEEVTRAP_GITHUB_BRANCH, JEEVTRAP_GITHUB_DEFAULT_DOCS_PATH
  • JEEVTRAP_LINKDING_BASE_URL, JEEVTRAP_LINKDING_API_TOKEN
  • JEEVTRAP_COMMAND_DEFAULT_TIMEOUT_SECONDS, JEEVTRAP_DISCORD_COMMAND_INTENT_DEBUG_REPLY
  • JEEVTRAP_TARGET_DESKTOP_MAIN_DISPLAY_NAME, JEEVTRAP_TARGET_DESKTOP_MAIN_MAC_ADDRESS, JEEVTRAP_TARGET_DESKTOP_MAIN_BROADCAST_IP, JEEVTRAP_TARGET_DESKTOP_MAIN_HOST, JEEVTRAP_TARGET_DESKTOP_MAIN_SSH_PORT, JEEVTRAP_TARGET_DESKTOP_MAIN_SSH_USER, JEEVTRAP_TARGET_DESKTOP_MAIN_SSH_KEY_PATH

5.3 AI 개발 지식 동기화 설정

  • 개발 문서 벡터 캐시 동기화와 검색 스크립트는 애플리케이션 런타임 설정을 사용하지 않음.
  • 수동 빌드/인프라 타임 및 AI 에이전트 전용 설정은 scripts/.env.ai만 사용함.
  • 공유 가능한 설정 예시는 scripts/.env.ai.template에 둠.
  • scripts/.env.ai는 Git 추적 대상이 아니며 로컬 또는 운영 작업자별 비밀값을 담음.
  • FASTAPI_BASE_URL은 AI 에이전트가 hub-api 통합 snapshot API를 호출할 때 사용하는 base URL임.
  • AI_ACCESS_TOKENROLE_AI claim을 가진 AI 에이전트 전용 JWT이며 scripts/fetch_master_data.py가 Bearer 토큰으로 사용함.
  • VAULT_DATABASE_URLjb_ai 계정 기준 PostgreSQL 접속 문자열임.
  • AI_EMBEDDING_API_KEY는 개발 문서 chunk와 검색 query를 임베딩하기 위한 API 키임.
  • AI_EMBEDDING_BASE_URL은 LiteLLM proxy 같은 OpenAI 호환 embeddings API base URL임.
  • VAULT_EMBEDDING_MODEL은 개발 문서 벡터 캐시와 검색 query가 공유하는 임베딩 모델 식별자이며 LiteLLM에 등록된 embedding model id 또는 alias를 사용함.

5.4 AI 라우팅 설정 원칙

  • 로컬 Git 관리 기준 AI 라우팅 기본 파일은 apps/hub-api/var/master-data/ai-routing.yml임.
  • 컨테이너 런타임 기본 경로는 /app/var/master-data/ai-routing.yml임.
  • 운영 호스트 공통 파일 경로는 /sorc001/junkbox/master-data/ai-routing.yml임.
  • APP_PROFILE 값이 있으면 ai-routing.{profile}.yml을 우선 사용함.
  • profile별 파일이 없으면 기본 ai-routing.yml을 fallback으로 사용함.
  • provider 선택과 model 선택은 라우팅 YAML이 결정하고, API 키와 base URL은 profile env와 ENV_FILE 조합이 결정함.
  • 어떤 provider 구현이 선택되는지는 provider 값이 결정하고, model 값은 선택된 provider 내부에서 실제 원격 모델 식별자로 사용됨.

5.5 환경 파일 분류 원칙

  • .env.shared에는 프로필과 무관한 공통 인프라 정책을 둠.
  • .env.local, .env.prod에는 프로필별로 달라지는 값과 운영 민감도가 높은 값을 둠.
  • RENAME_BASE_DIRRENAME_TARGET_DIR_NAME은 모든 프로필에서 같은 비민감 파일 시스템 작업 기준값이므로 .env.shared에 둠.
  • AUTOMATION_BASE_URL은 프로필별 서비스 연결 값임. .env.localhttp://localhost:18007, Docker Compose 기반 .env.prodhttp://junkbox-automation-api:8007을 사용함.
  • .env.chess에는 Lichess OAuth, Stockfish, Chess 서비스 재시작 정책처럼 Chess 전용으로 공유되는 설정을 둠.
  • .env.local.template은 local/prod env 파일이 공유하는 단일 템플릿으로 사용함.
  • .env.local.env.prod는 같은 변수 항목과 같은 주석 구조를 유지하여 프로필별 값 비교가 가능해야 함.
  • jeevtrap 전용 공통 실행 설정은 .env.jeevtrap에 두고, 프로필별 차이는 .env.local.jeevtrap, .env.prod.jeevtrap에 둠.
  • .env.jeevtrap.template은 local Jeevtrap env 파일 작성 기준 템플릿으로 사용함.
  • .env.jeevtrap는 민감하지 않고 profile과 무관한 Jeevtrap 공통값을 보관함.
  • .env.local.jeevtrap, .env.prod.jeevtrap.env.local, .env.prod를 참조하지 않으며, .env.shared, .env.jeevtrap와 함께 독립 실행에 필요한 APP_PROFILE, JEEVTRAP_DATABASE_URL, HUB_INTERNAL_BASE_URL, LITELLM_BASE_URL, JEEVTRAP_PORT, JEEVTRAP_VOICE_ENABLED, 민감한 profile별 JEEVTRAP_* 값을 보관함.
  • 현재 공통 로깅 정책인 LOG_ROTATION_LIMIT, LOG_RETENTION_DAYS, LOG_COMPRESSION_TYPE.env.shared에 위치함.
  • 현재 프로필별 로깅 동작인 LOG_LEVEL, LOG_DIAGNOSE_TOGGLE.env.local, .env.prod에 각각 위치함.
  • Jeevtrap의 프로필별 로깅 동작인 LOG_LEVEL, LOG_DIAGNOSE_TOGGLE.env.local.jeevtrap, .env.prod.jeevtrap에 각각 위치함.
  • 운영 jeevtrap은 host network로 실행되므로 .env.prod.jeevtrapHUB_INTERNAL_BASE_URL, JEEVTRAP_LINKDING_BASE_URL, LITELLM_BASE_URL은 Docker DNS 서비스명이 아니라 호스트 네트워크에서 접근 가능한 주소를 사용함.
  • 운영 jeevtrap의 LiteLLM proxy 접근은 호스트 publish 포트를 기준으로 하며, 현재 운영 기준 LITELLM_BASE_URLhttp://127.0.0.1:8083/v1 형태임.
  • 운영 jeevtrap의 PC 종료 명령은 컨테이너 내부 /run/secrets/jeevtrap_desktop_main_ssh_key에 read-only로 마운트된 SSH 비밀키를 사용함.
  • 운영 jeevtrap의 음성 런타임은 기본적으로 JEEVTRAP_VOICE_ENABLED=False로 비활성화함.
  • 로컬 jeevtrap의 음성 런타임은 JEEVTRAP_VOICE_ENABLED=True로 활성화할 수 있으며, 실제 음성 동작은 JEEVTRAP_VOICE_CONFIG_YAML_PATH가 가리키는 YAML이 결정함.
  • VS Code build task env:copy-to-sorc001는 프로젝트 루트의 .env.chess, .env.prod, .env.jeevtrap, .env.prod.jeevtrap, .env.shared/sorc001/junkbox/env/로 덮어쓰기 복사하는 운영 보조 흐름임.
  • scripts/copy_env_files.sh는 복사 시작 전 Enter 확인, 대상 디렉터리 준비, 파일별 복사 진행 출력, 완료 후 Enter 대기 흐름을 제공함. 런타임에서 로드되는 프로젝트 루트 환경 파일을 새로 추가하면 ENV_FILES와 이 문서의 복사 대상 목록을 함께 갱신해야 함.

6. 데이터베이스 전략

  • 애플리케이션 런타임은 SQLite 파일 DB를 사용함.
  • Hub 공통 운영 데이터, 인증, 마스터데이터, 포털 구성, 대시보드 사용자 preference, AI 사용 로그는 Hub SQLite 파일 DB를 사용함.
  • Hub SQLite 파일은 호스트 /sorc001/junkbox/db/hub.sqlite3에 위치함.
  • hub-api 컨테이너 내부 표준 DB 경로는 /app/db/hub.sqlite3이며, Docker compose는 호스트 /sorc001/junkbox/db를 컨테이너 /app/db에 마운트함.
  • HUB_DATABASE_URL의 운영 및 Docker 기준 DSN은 sqlite+aiosqlite:////app/db/hub.sqlite3임.
  • 로컬 비컨테이너 실행의 기본 Hub DSN은 sqlite+aiosqlite:////sorc001/junkbox/db/hub.sqlite3임.
  • Hub SQLite 연결은 PRAGMA journal_mode=WAL, PRAGMA busy_timeout=5000, PRAGMA foreign_keys=ON을 적용함.
  • Hub SQLite 파일은 Docker 이미지 생명주기와 분리된 호스트 영속 파일이며 컨테이너 내부 임시 파일로 관리하지 않음.
  • Hub SQLite의 단일 writer는 hub-api임.
  • 다른 앱은 공통 기준정보, 사용자 인증, 세션 검증, 포털 메뉴, AI usage log를 직접 DB 파일로 소유하거나 write하지 않고 hub-api internal API와 JWT/Cookie 계약을 사용함.
  • Raid 도메인 데이터는 /sorc001/junkbox/db/raid.sqlite3 SQLite 파일을 사용함.
  • raid-api 컨테이너 내부 표준 DB 경로는 /app/db/raid.sqlite3이며, Docker compose는 호스트 /sorc001/junkbox/db를 컨테이너 /app/db에 마운트함.
  • RAID_DATABASE_URL의 운영 및 Docker 기준 DSN은 sqlite+aiosqlite:////app/db/raid.sqlite3이며, 로컬 비컨테이너 기본 DSN은 sqlite+aiosqlite:////sorc001/junkbox/db/raid.sqlite3임.
  • Raid SQLite 연결은 PRAGMA journal_mode=WAL, PRAGMA busy_timeout=5000, PRAGMA foreign_keys=ON을 적용함.
  • Raid SQLite 파일은 Docker 이미지 생명주기와 분리된 호스트 영속 파일이며 단일 writer는 raid-api임.
  • Raid SQLite는 Hub 사용자·공통코드·메타 또는 다른 SQLite 파일에 DB 레벨 FK를 걸지 않으며, 해당 데이터는 hub-api internal API와 JWT/Cookie 계약으로 소비함.
  • Chess 도메인 데이터는 /sorc001/junkbox/db/chess.sqlite3 SQLite 파일을 사용함.
  • chess-api 컨테이너 내부 표준 DB 경로는 /app/db/chess.sqlite3이며, 개발·운영 Docker compose는 호스트 /sorc001/junkbox/db를 컨테이너 /app/db에 마운트함.
  • CHESS_DATABASE_URL의 운영 및 Docker 기준 DSN은 sqlite+aiosqlite:////app/db/chess.sqlite3이며, 로컬 비컨테이너 기본 DSN은 sqlite+aiosqlite:////sorc001/junkbox/db/chess.sqlite3임.
  • Chess SQLite 연결은 PRAGMA journal_mode=WAL, PRAGMA busy_timeout=5000, PRAGMA foreign_keys=ON을 적용함.
  • Chess SQLite 파일은 Docker 이미지 생명주기와 분리된 호스트 영속 파일이며 단일 writer는 chess-api임.
  • Chess SQLite는 OAuth 연결 계정, 완료 대국, 수순, Stockfish 분석, Codex 코칭 데이터를 소유하며 Hub SQLite 사용자 ID를 저장하거나 SQLite 파일 간 FK를 만들지 않음.
  • Jeevtrap 명령 정의와 실행 로그는 /sorc001/junkbox/db/jeevtrap.sqlite3tb_command_m, tb_command_logs_n을 사용함.
  • JEEVTRAP_DATABASE_URL은 Jeevtrap 전용 SQLite DSN임. 컨테이너는 /sorc001/junkbox/db/app/db에 마운트하여 같은 영속 파일을 사용함.
  • Jeevtrap SQLite 연결도 PRAGMA journal_mode=WAL, PRAGMA busy_timeout=5000, PRAGMA foreign_keys=ON을 적용함.
  • 과거 명령 로그에 명령 정의가 없는 행이 존재할 수 있으므로 Jeevtrap command log에는 DB 수준 command_id FK를 두지 않음.
  • 운동 기준정보, 운동 세션, 운동 기록, 운동 계획, 체중 측정, 투약 기록은 /sorc001/junkbox/db/workout.sqlite3 SQLite 파일을 사용함.
  • workout-api 컨테이너 내부 표준 DB 경로는 /app/db/workout.sqlite3이며, Docker compose는 호스트 /sorc001/junkbox/db를 컨테이너 /app/db에 마운트함.
  • WORKOUT_DATABASE_URL의 운영 및 Docker 기준 DSN은 sqlite+aiosqlite:////app/db/workout.sqlite3임.
  • 로컬 비컨테이너 실행의 기본 workout DSN은 sqlite+aiosqlite:////sorc001/junkbox/db/workout.sqlite3임.
  • Workout SQLite 연결은 PRAGMA journal_mode=WAL, PRAGMA busy_timeout=5000, PRAGMA foreign_keys=ON을 적용함.
  • Workout SQLite 파일은 Docker 이미지 생명주기와 분리된 호스트 영속 파일이며 컨테이너 내부 임시 파일로 관리하지 않음.
  • 공통코드, 메타, 사용자 인증, 사용자 세션, 포털 메뉴, AI usage log는 Workout SQLite 파일로 복제하지 않음.
  • 운동 도메인 데이터는 Hub SQLite 파일로 흡수하지 않음.
  • Workout이 참조하는 공통 기준정보는 hub-api internal master-data API를 통해 조회함.
  • 운동 종목 기준정보는 workout SQLite tb_workout_exercise_m이 런타임 소스 오브 트루스이며, hub 공통코드 EXERCISE는 초기 bootstrap source로만 사용할 수 있음.
  • SQLite 파일 간 DB 레벨 FK를 전제로 하지 않으며, user_id 같은 cross-domain 식별자는 서비스 계층의 느슨한 참조로 유지함.
  • 메시지 발송 이력은 /sorc001/junkbox/db/message.sqlite3 SQLite 파일을 사용함.
  • message-api 컨테이너 내부 표준 DB 경로는 /app/db/message.sqlite3이며, Docker compose는 호스트 /sorc001/junkbox/db를 컨테이너 /app/db에 마운트함.
  • MESSAGE_DATABASE_URL의 운영 및 Docker 기준 DSN은 sqlite+aiosqlite:////app/db/message.sqlite3이며, 로컬 비컨테이너 기본 DSN은 sqlite+aiosqlite:////sorc001/junkbox/db/message.sqlite3임.
  • Message SQLite 파일은 Docker 이미지 생명주기와 분리된 호스트 영속 파일이며 message-api가 유일한 writer임.
  • Message SQLite는 tb_message_log_n 발송 이력만 소유함. schedule_id, recurrence_id, recurrence_scheduled_at은 기존 이력 호환용 컬럼이며 새 일정 정의로 사용하지 않음.
  • Automation SQLite는 /sorc001/junkbox/db/automation.sqlite3 파일을 사용함. automation-api와 automation worker만 writer이며 작업 정의·수정 이력·실행 이력 테이블을 소유함.
  • AI 개발 지식 캐시는 vault 스키마를 사용함.
  • vault.docs는 markdown 파일 단위의 원본 경로, 제목, route, namespace, kind, project, frontmatter, content hash, 삭제 상태를 저장함.
  • vault.doc_chunks는 문서를 heading 기반 chunk로 나눈 검색 단위이며 heading_path, heading_level, content, content_hash, token_count, metadata를 포함함.
  • vault.doc_embeddings는 chunk별 VECTOR(1536) 임베딩을 저장하며 embedding_model, embedding_dimension, content_hash를 함께 보관함.
  • vault.index_runs는 문서 색인 실행 이력, 처리 파일 수, 변경/삭제 수, chunk 수, 오류 메시지를 기록함.
  • content_hash는 SHA-256 기반 변경 감지에 사용됨.
  • vault.docs.is_deleted=true는 로컬 원본에서 삭제되어 검색 대상에서 제외된 문서를 나타냄.
  • jb_ai 계정은 vault 스키마 내 기존 테이블 데이터 CRUD와 시퀀스 사용 권한을 가진 AI 전용 계정이며 앱 구동 계정 jb_app과 분리됨.
  • Linkding 북마크 저장은 Linkding REST API를 사용하며, Jeevtrap은 Linkding DB 파일이나 테이블에 직접 접근하지 않음.
  • 앱 추가 시 앱별 단독 writer가 명확한 도메인은 별도 SQLite 파일 DB를 사용하고, 다른 앱의 SQLite 파일에는 직접 접근하지 않음.
  • DB 기반 운영 엔티티는 created_at, updated_at 같은 감사 컬럼 NOT NULL 제약을 충족하는 기본값 전략을 함께 가져야 함.
  • 모든 JunkBox SQLite의 일시 컬럼은 Asia/Seoul(KST, UTC+9)을 기준으로 저장함. 신규 앱은 datetime.now(timezone.utc), datetime.utcnow(), SQLite CURRENT_TIMESTAMP로 UTC 값을 저장하지 않고 shared-corenow_kst_naive()를 사용함.
  • SQLite의 timezone 없는 일시는 KST 로컬 일시로 해석함. 외부 API가 UTC 또는 offset을 포함한 일시를 제공하면 저장 전에 KST로 정규화하며, timezone-aware 컬럼 계약이 없는 SQLite 저장소에서는 timezone 정보를 제거함. 날짜 전용 값과 사용자가 직접 입력한 업무 시각은 변환 대상이 아님.
  • Chess 저장소는 tb_lichess_account_m, tb_chess_game_m, tb_chess_game_move_n, tb_chess_engine_analysis_n, tb_chess_coaching_n을 사용함.
  • 대국 원본 PGN·FEN, 모든 수의 Stockfish 분석, 사용자 수의 코칭 결과를 분리 저장하며 세부 계약은 Chess API 가이드를 따름.

7. 비동기 ORM 규격

7.1 엔진과 세션

  • create_async_engine()async_sessionmaker()를 사용함.
  • 의존성 주입은 async def get_session() 제너레이터 패턴을 사용함.
  • 세션 타입은 sqlalchemy.ext.asyncio.AsyncSession임.

7.2 SQLModel 사용 규칙

  • Field(..., sa_column=Column(...)) 조합에서는 중복 옵션 선언을 피함.
  • SQLite 엔티티는 PostgreSQL schema qualifier와 PostgreSQL 전용 타입을 사용하지 않음.
  • 믹스인 컬럼 재사용으로 인한 선언 충돌을 피함.

7.3 조회 패턴

  • AsyncSession에서는 SQLModel 동기 exec()를 사용하지 않음.
  • await session.execute(select(...)) 기반 SQLAlchemy 네이티브 패턴을 사용함.
  • 결과 해석은 scalar_one_or_none(), scalars().all(), all() 등으로 명시함.

8. 인증 및 권한 구조

8.1 인증 책임 경계

  • 사용자 credential 검증, JWT 발급, 공통 로그인 화면, 공통 로그아웃 API는 hub-api가 담당함.
  • 사용자 세션 정책, 사용자 세션 영속 상태, JWT 세션 유효성 판정, JWT 슬라이딩 갱신 판단은 hub-api가 담당함.
  • chess-api, workout-api, raid-api, rename-api는 자체 /api/auth/login 또는 /api/auth/check 계열 credential 검증 API를 제공하지 않음.
  • 개별 앱은 hub-api가 발급한 JWT를 Authorization: Bearer 헤더 또는 COOKIE_NAME 기준 HttpOnly 쿠키에서 읽고, 일반 사용자 JWT의 세션 유효성 판정은 hub-api 내부 인증 API에 위임함.
  • 개별 앱은 브라우저 쿠키 기반 요청에 대해 shared-core 슬라이딩 세션 미들웨어를 등록하고, 갱신 판단과 새 토큰 발급은 hub-api 내부 인증 API에 위임함.
  • 개별 앱의 앱 셸 로그아웃 동작은 HUB_BASE_URL 기준 hub-api/api/auth/logout을 호출함.

8.2 공통 의존성

  • get_current_user는 필수 인증임.
  • get_optional_user는 선택 인증임.
  • require_module(module_code)는 모듈 권한 강제 의존성임.
  • require_modules(*module_codes)는 전달된 모든 모듈 권한을 강제하는 공통 의존성임.
  • 공통 인증 의존성은 일반 사용자 JWT의 서명과 만료를 검증한 뒤 HUB_INTERNAL_BASE_URLPOST /api/internal/auth/validate를 호출해 세션 유효성을 확인함.
  • AI 에이전트 전용 ROLE_AI JWT는 사용자 세션 테이블 검증 대상이 아니며 require_ai_role 전용 read-only API에서만 허용됨.
  • SlidingSessionMiddleware는 브라우저 쿠키 기반 interaction마다 hub 내부 인증 API를 호출해 세션 갱신 필요 여부를 확인함.
  • SlidingSessionMiddleware는 인증 실패한 토큰을 강제로 갱신하지 않으며, 만료되었거나 유효하지 않거나 hub에서 revoke된 토큰은 표준 인증 의존성과 페이지 라우터 실패 흐름이 처리함.
  • SlidingSessionMiddleware/api/internal/*, 정적 자산, 로그인, 로그아웃, 헬스체크, 문서 경로를 갱신 대상에서 제외함.

8.3 세션 정책

  • 사용자 세션 만료와 슬라이딩 갱신 임계값은 hub-api 소유 정책 파일인 apps/hub-api/var/auth-policy.yml에서 관리함.
  • 현재 세션 정책은 expiration_minutes=120, sliding_threshold_minutes=30임.
  • 로그인 성공 시 hub-api는 세션 정책의 만료 시간을 기준으로 Hub SQLite tb_user_session_n에 세션 row를 생성하고, JWT sid, JWT exp, HttpOnly 쿠키 max_age를 설정함.
  • 일반 사용자 JWT는 sid claim을 포함하며, sid는 Hub SQLite tb_user_session_n.session_id와 매칭되어야 유효함.
  • hub-api는 세션 row의 is_active, revoked_at, expires_at, 사용자 is_active를 기준으로 JWT 세션 유효성을 판정함.
  • 요청 토큰의 남은 시간이 슬라이딩 갱신 임계값 이하이면 hub-api는 같은 sid를 유지하고 DB의 최신 사용자 권한을 기준으로 새 JWT를 발급하며 브라우저 쿠키를 다시 설정함.
  • 로그아웃, 사용자 비밀번호 변경, 계정 비활성화, 권한 변경, 사용자 삭제는 관련 사용자 세션을 revoke하여 기존 일반 사용자 JWT를 무효화함.
  • JWT_SECRET_KEY, 알고리즘, 쿠키 보안 옵션은 환경 설정으로 관리하고, 세션 만료와 슬라이딩 임계값은 hub 정책 YAML로 관리함.
  • HUB_INTERNAL_BASE_URL, HUB_API_INTERNAL_TOKEN, HUB_API_INTERNAL_TOKEN_HEADER는 개별 앱이 hub 내부 인증 API와 master-data API를 호출할 때 사용하는 서버 간 설정임.

8.4 권한 데이터

  • allowed_modules는 Hub SQLite JSON 배열을 기준으로 저장됨.
  • 애플리케이션 내부에서는 list[str]로 다룸.
  • 비교와 판정은 대문자 모듈 코드 기준으로 수행함.
  • 과거 SYSTEM 값은 인증 계층에서 HUB로 정규화하여 처리함.

8.5 실패 정책

  • HTML 페이지 요청은 리다이렉트 기반 인증 흐름을 사용함.
  • API 요청은 JSON 401/403 응답을 유지함.
  • HTML 페이지의 모듈 권한 부족은 hub-api 로그인 화면에 permission_denied=1을 전달하는 흐름으로 처리함.
  • 로그인 화면은 permission_denied=1이 있으면 권한 없음 alert를 1회 표시하고 쿼리 플래그를 제거함.
  • 앱별 권한 오류 템플릿은 사용하지 않으며, 하위 호환 라우트는 로그인 alert 흐름으로 연결함.
  • 운영 관리자 영역은 HUB 권한을 기준으로 접근을 제어함.
  • 운동 기록 영역은 WORKOUT 권한을 기준으로 접근을 제어함.
  • Workout의 공유 운동 기준정보 관리 영역은 WORKOUTHUB 권한을 모두 기준으로 접근을 제어함.
  • 레이드 운영 화면과 API는 RAID 권한을 기준으로 접근을 제어함.
  • 체스 복기 화면과 API는 CHESS 권한을 기준으로 접근을 제어함.
  • 개발 모드 로그인 복귀 시 redirect는 원래 UI 앱 origin을 유지하고, hub-api는 허용 origin 검증 후 해당 UI 앱 경로로 복귀시킴.

9. 공통 마스터 데이터 구조

9.1 현재 대상

  • 공통코드
  • 메타
  • 포털 메뉴
  • AI 라우팅

9.2 저장 방식

  • 공통 마스터 데이터의 소스 오브 트루스는 hub-api가 관리하는 Hub SQLite /sorc001/junkbox/db/hub.sqlite3 파일임.
  • 코드 타입은 tb_code_type_c, 공통코드는 tb_common_c, 메타는 tb_meta_m, 포털 메뉴는 tb_portal_menu_m을 사용함.
  • AI 라우팅 로컬 원본은 apps/hub-api/var/master-data/ai-routing.yml 계열 파일을 사용함.
  • 마스터 데이터 CRUD는 hub-apishared-core 저장소 계층을 통해 수행함.
  • AI 에이전트 표준 통합 snapshot API는 GET /api/v1/master/all이며 ROLE_AI JWT를 사용함.

9.3 운영 방식

  • DB 기반 공통 마스터데이터는 hub-api가 단일 관리 주체임.
  • 화면과 API는 파일 저장소를 직접 노출하지 않고 shared-core 저장소 계층을 통해 접근함.
  • 다른 앱과 모듈은 shared-core.masterdata.MasterDataService를 통해 hub-api 내부 master-data API를 소비함.
  • shared-core.masterdata.HubMasterDataClientHUB_INTERNAL_BASE_URL, HUB_API_INTERNAL_TOKEN, HUB_API_INTERNAL_TOKEN_HEADER로 내부 API를 호출함.
  • shared-core.masterdata.TtlAsyncCache는 코드와 메타 조회 결과를 TTL 기준으로 재사용함.
  • Python 서버 렌더링 문구와 React UI 문구는 각 템플릿/컴포넌트 소스에 한국어로 직접 작성함.
  • APP_PROFILE=local에서 HUB_API_INTERNAL_TOKEN이 비어 있으면 개발 편의용 local store fallback을 사용할 수 있음.
  • 운영 profile에서 HUB_API_INTERNAL_TOKEN이 비어 있으면 내부 master-data API 소비는 실패해야 하며, 조용히 로컬 DB 조회로 전환하지 않음.
  • AI 코딩은 scripts/fetch_master_data.py 실행 결과인 통합 snapshot을 우선 사용함.
  • AI가 대량 문맥을 확보할 때는 FASTAPI_BASE_URL/api/v1/master/all 결과를 기준으로 함.
  • AI 라우팅 정책 파일은 Git 형상관리 원본을 apps/hub-api/var/master-data에 두고, 운영 배포 시 /sorc001/junkbox/master-data/ai-routing.yml로 동기화한 뒤 hub-api, jeevtrap 컨테이너가 공통 볼륨으로 공유함.

10. 운동 계획 규칙 엔진 구조

  • 운동 계획 공개 생성과 화면 진입은 workout-apiworkout-ui가 담당함.
  • 운동 계획 생성 실행 주체는 workout-api이며, hub AI 오케스트레이션이나 shared-ai 그래프를 사용하지 않음.
  • 운동 계획 생성은 Workout SQLite의 운동 기준정보, 운동 세션, 운동 기록, 운동 계획 테이블을 사용함.
  • 운동 계획 루틴 모드 option은 hub 공통코드 WORKOUT_ROUTINE_MODE의 활성 row를 그대로 사용함.
  • 규칙 엔진의 명시 계산 대상은 UPPER, LOWER이며 알 수 없는 루틴 모드는 상체 루틴으로 정규화함.
  • 상체 루틴은 렛 풀다운, 체스트 프레스, 숄더 프레스, 리어 델트 플라이, 펙 델트 플라이, 인클라인 바이셉스 컬 순서를 사용함.
  • 하체 루틴은 옴니 레그 프레스, 라잉 레그 컬, 레그 익스텐션, 힙 어덕션 순서를 사용함.
  • 각 운동은 기본 3세트로 저장하며, 1세트는 탑세트보다 한 단계 낮은 중량 8회, 2세트는 계산된 탑세트, 3세트는 탑세트보다 한 단계 낮은 중량 10회를 사용함.
  • 기준 탑세트는 같은 사용자의 같은 운동에 대한 가장 최근 유효 세션 안에서 성공 세트 중 최대 중량, 같은 중량이면 최대 반복수 기준으로 산정함.
  • 유효 기준 기록은 활성 세션과 활성 기록, SUCCESS 상태, 중량, 반복수, RPE를 모두 필요로 함.
  • 8회 미만 성공은 같은 중량 8회 재시도, RPE 10 이상은 같은 중량과 같은 반복수 유지, 8~11회 RPE 9 이하는 같은 중량에서 1회 증가, 12회 이상 RPE 9 이하는 한 단계 증량 후 8회 재시작 규칙을 사용함.
  • 운동 계획 저장은 tb_workout_plan_n 계획 헤더와 연결 tb_workout_session_n, tb_workout_record_n 세트 레코드로 구성함.
  • tb_workout_plan_n은 AI 응답 JSON, AI 조언, AI usage log 연결을 저장하지 않음.
  • 운동 세션, 운동 기록, 운동 계획 조회와 저장은 현재 사용자 user_id 기준으로 격리됨.
  • 러닝 계획과 블록·단계 하위 데이터 조회·저장도 현재 사용자 user_id 기준으로 격리됨.
  • Workout의 공유 운동 기준정보를 제외한 신규 도메인 기능은 소유자 user_id를 저장하고, API/service 계층의 모든 조회·집계·계산·변경 경로에서 현재 사용자 조건을 강제함.

11. Jeevtrap 구조

  • jeevtrap는 Discord 상호작용을 UI 레이어로 사용하고, 서비스 레이어는 Discord 전용 객체를 받거나 반환하지 않음.
  • 인터페이스 레이어는 interfaces/discordinterfaces/voice로 분리됨.
  • discord.py 의존성은 interfaces/discord 내부에서만 사용함.
  • 로컬 음성 인터페이스는 interfaces/voice가 담당하며, 실제 마이크/STT/TTS 구현은 shared-voice를 사용함.
  • 서비스 레이어는 markdown_generator, bookmark_processor, command_executor로 분리됨.
  • 평문 Discord 멘션 명령 의도 판별은 CommandIntentResolverService가 담당함.
  • /md는 AI 초안 생성 후 GitHub repository contents API에 마크다운 문서를 저장함.
  • /북마크는 URL 스크래핑 후 AI 분석을 수행하고 Linkding REST API로 저장함.
  • /명령jeevtrap.tb_command_m, jeevtrap.tb_command_logs_n 기준 명령을 조회하고 패키지 내장 스크립트를 실행함.
  • 봇이 멘션된 일반 메시지는 AI 명령 의도 판별 후 실행 확인 UI로 연결할 수 있음.
  • Discord slash command와 멘션 메시지는 JEEVTRAP_DISCORD_TEST_GUILD_IDAPP_PROFILE 기준의 guild guard를 통과한 서버 이벤트만 처리함.
  • 일반 메시지 명령 실행 로그는 DISCORD_MESSAGE, slash command 메뉴 명령 실행 로그는 DISCORD_SLASH request channel code를 사용함.
  • 내장 명령 스크립트는 테스트 콘솔 출력, 데스크탑 WOL 켜기, 데스크탑 SSH 종료를 포함함.
  • jeevtrapshared-aiDirectAiRunner를 사용하며 JEEVTRAP_MD, JEEVTRAP_BOOKMARK, JEEVTRAP_COMMAND_INTENT route key를 기준으로 모델을 선택함.
  • jeevtrap는 공통 로그인 체계를 사용하지 않으며 사용자 인증은 Discord 계정과 interaction context에 의해 결정됨.
  • jeevtrap는 FastAPI /health, Discord 봇 런타임, 선택적 voice 런타임을 단일 프로세스 안에서 함께 구동함.
  • voice 런타임은 JEEVTRAP_VOICE_ENABLED가 true일 때만 시작함.
  • voice 런타임은 apps/jeevtrap/var/voice.yml을 기본 설정 파일로 사용하며, 호출어, alias, STT 모델, TTS provider, 오디오 장치 설정을 YAML에서 읽음.
  • 현재 voice 호출어는 하이파이브 계열이며, 호출 성공 응답은 Supertonic TTS의 남성 voice preset으로 하이파이브!를 합성함.
  • voice 런타임은 shared-voice의 blocking wake loop를 별도 thread로 실행하여 FastAPI 이벤트 루프를 점유하지 않음.
  • jeevtrap의 Discord UI 문구와 slash command 설명은 앱 내부 MessageCatalog의 한국어 문구를 사용함.
  • jeevtrap 런타임에서 HUB_API_INTERNAL_TOKEN이 설정되어 있으면 HUB_INTERNAL_BASE_URLhub-api 내부 API가 가용해야 함.
  • jeevtrap의 일반 Discord UI 문구는 텍스트 DB 마스터데이터에 의존하지 않음.

12. 체스 복기 구조

  • 체스 복기 API와 화면은 chess-apichess-ui가 담당함.
  • 단일 Lichess OAuth 계정의 종료 대국을 커서 기준으로 수집하며, 주석이 포함된 Lichess PGN 파일도 업로드할 수 있음.
  • 대국 식별자는 자동 수집과 수동 업로드를 통틀어 중복 저장하지 않으며, 연결 계정이 백색 또는 흑색인 대국만 사용자 관점으로 판정함.
  • 연결 계정이 대국에 없으면 관전 대국으로 저장하며, 사용자 수 판정과 Codex 코칭 대상에서 제외함.
  • 대국 원본 PGN, 수순별 착수 전후 FEN, SAN/UCI, Stockfish 결과와 주 변형을 저장함.
  • Codex는 엔진 분석이 완료된 사용자 수에만 구조화된 코칭 결과를 저장함.
  • 화면은 최신 등록 순의 대국 목록, 보드 복원, 실제 진행·엔진 최선수 비교·PV 재생, 수별 엔진 정보와 사용자 수 코칭 정보를 제공함.
  • 실시간 착수, 대국 생성, WebSocket 관전은 제공하지 않음.
  • Chess 컨테이너는 JUNKBOX_CHESS_RESTART_POLICY 기본값 unless-stopped를 사용함.
  • 상세 계약은 docs/junkbox/apps/guide-apps-chess-api.md, docs/junkbox/apps/guide-apps-chess-ui.md를 따름.

13. 레이드 구조

  • 레이드 운영 화면과 API는 raid-apiraid-ui가 담당함.
  • 공대원 목록과 관리는 PC/FHD 밀도 기준의 Tabulator 단일 그리드 중심 구조를 사용함.
  • 공대원 목록공대원 관리 화면 모두 Tabulator 기반 전체 로딩 구조를 사용함.
  • 공대 구인 알림은 모바일 우선 카드·시트·하단 고정 액션바 구조를 사용하며, 검색 조건은 프로필의 추가·제외 검색어만 사용함.
  • 공대 구인 본문은 수집·AI 분석 중 메모리에만 두고 저장하지 않음. Raid는 분석·매칭·발송 조건을 소유하고, Automation은 예약 실행을, Message는 실제 전달·이력·재시도를 소유함.
  • 레이드 화면은 shared-ui 공통 다크 자산과 Tabulator 공통 자산을 그대로 사용함.
  • 레이드 멤버 풀과 레이드별 배치는 분리된 테이블 구조를 사용하며, 하나의 멤버가 여러 레이드에 중복 배치될 수 있음.
  • 레이드 멤버 풀의 구분은 RAID_MEMBER_CATEGORY 공통코드로 관리하며, , 추적, 공대원의 공통코드 정렬 순서를 목록과 관리 화면에 적용함. 구분은 레이드별 배치가 아닌 멤버 풀 속성임.
  • 공대원 목록은 를 항상 포함하고, 추적공대원은 멀티 선택 조회 조건으로 제어함. 점수 갱신은 구분과 무관하게 현재 레이드의 전체 멤버 집합을 대상으로 수행함.
  • 레이드 점수 동기화는 Warcraft Logs API 연동을 사용하며, 설정은 settings.raid.wcl 중첩 구조를 기준으로 로드함.
  • 레이드 점수 갱신은 전체 레이드 멤버 집합 기준으로 수행하며, 결과는 Raid SQLite의 복합 PK 점수 테이블에 반영됨.
  • 레이드 화면은 공통 로그인 진입점을 hub-api에 두고 required_module=RAID 기준으로 복귀 흐름을 처리함.

14. 운영 원칙

  • 모듈 간 직접 DB 결합보다 내부 API 재사용을 우선함.
  • 공통 규칙은 shared-core, shared-ai, shared-ui, shared-voice로 수렴시킴.
  • 운영 화면은 관리 생산성과 빠른 확인을 우선함.
  • apps/hub-ui, apps/chess-ui, apps/raid-ui, apps/rename-ui, apps/workout-ui, apps/message-ui 빌드 결과물 dist와 Vite manifest는 각 백엔드 앱이 직접 서빙하는 운영 자산임.
  • 개발 모드에서는 Vite dev server가 화면 엔트리와 HMR 자산을 제공하고, FastAPI는 서버 렌더링 HTML과 API를 제공함.
  • 개발 서버 기준 루트 진입 경로는 hub 모드에서 /portal, chess 모드에서 /chess, workout 모드에서 /workout-sessions, message 모드에서 /messages, rename 모드에서 /rename, raid 모드에서 /raid/members임.
  • VS Code backend task는 각 앱 패키지 의존성을 기준으로 실행하기 위해 uv run --package {package-name} uvicorn ... 형태를 사용함.
  • .venv/bin/uvicorn을 직접 호출하는 방식은 workspace 앱별 런타임 의존성이 설치되지 않은 환경을 만들 수 있으므로 backend task의 표준 실행 방식으로 사용하지 않음.
  • 운영 배포는 docker-compose.prod.yml 기준 독립 컨테이너 구조를 사용하며, automation-api와 automation worker는 같은 junkbox-automation 이미지를 별도 서비스로 실행함.
  • 운영 배포 자동화는 GitHub Actions selective build/deploy 흐름을 사용하며, junkbox-message를 포함한 각 앱은 독립 서비스 단위로 감지, 빌드, 배포됨.
  • junkbox-chess 배포 정책은 autoStartOnDeploy=truerestartPolicy=unless-stopped를 사용하므로, 배포 후 Chess 컨테이너를 생성 상태로 남기지 않고 기동함.
  • 운영 CDN이 고정 경로 정적 자산을 오래 캐시할 수 있으므로, 공통 shared-ui CSS/JS는 버전 쿼리 파라미터 링크를 기본 구조로 사용함.
  • 운영 Chess 컨테이너는 /sorc001/junkbox/env/.env.chess, /sorc001/junkbox/env/.env.shared, /sorc001/junkbox/env/.env.prod를 참조하고, ENV_FILE=/app/env/.env.prod 기준으로 로딩함.
  • 운영 jeevtrap 컨테이너는 /sorc001/junkbox/env/.env.shared, /sorc001/junkbox/env/.env.jeevtrap, /sorc001/junkbox/env/.env.prod.jeevtrap를 함께 참조하고, ENV_FILE=/app/env/.env.prod.jeevtrap 기준으로 로딩함.
  • 프로젝트 루트의 .env.chess, .env.prod, .env.jeevtrap, .env.prod.jeevtrap, .env.shared를 운영 env 디렉터리에 반영할 때는 VS Code build task env:copy-to-sorc001 또는 동일한 scripts/copy_env_files.sh 흐름을 사용함.
  • 운영 배포 compose는 automation-api=/logs001/junkbox/automation-api, automation-worker=/logs001/junkbox/automation-worker를 포함한 앱별 호스트 로그 경로를 각 컨테이너의 /app/logs에 마운트하는 구조를 사용함.
  • 운영 배포 compose는 Hub/Chess/Workout/Message/Raid/Jeevtrap SQLite 호스트 경로 /sorc001/junkbox/db를 각 앱 컨테이너의 /app/db에 마운트함.
  • 각 백엔드 컨테이너의 공통 애플리케이션 로그 파일 경로는 /app/logs/app.log임.
  • 로컬 개발 로그는 프로젝트 루트의 var/log/{app-name} 하위에 생성되며 Git 추적 대상이 아님.
  • 로그 파일 rotation, retention, compression, diagnose 정책은 shared-core의 공통 로깅 초기화와 .env.shared 및 실행 앱별 profile env 파일 조합이 결정함.
  • rename-api${RENAME_BASE_DIR}:${RENAME_BASE_DIR} 동일 경로 바인드 마운트를 전제로 동작하며, RENAME_TARGET_DIR_NAME은 마운트된 작업 루트 내부의 입력 작업 폴더를 지정함.
  • 로컬 AI 라우팅 Git 원본은 apps/hub-api/var/master-data를 사용하고, 운영 런타임은 /sorc001/junkbox/master-data/ai-routing.yml 공유 파일을 사용함.
  • 운영에서는 APP_PROFILE=prod, HUB_BASE_URL=https://hub.sleepzz.xyz, HUB_DATABASE_URL=sqlite+aiosqlite:////app/db/hub.sqlite3, CHESS_BASE_URL, CHESS_DATABASE_URL=sqlite+aiosqlite:////app/db/chess.sqlite3, WORKOUT_BASE_URL=https://workout.sleepzz.xyz, WORKOUT_DATABASE_URL=sqlite+aiosqlite:////app/db/workout.sqlite3, RAID_BASE_URL=https://raid.sleepzz.xyz, RAID_DATABASE_URL=sqlite+aiosqlite:////app/db/raid.sqlite3, HUB_INTERNAL_BASE_URL, COOKIE_DOMAIN=.sleepzz.xyz, COOKIE_SECURE=true 값을 우선 점검함.
  • 운영 기본 bridge network 컨테이너의 HUB_INTERNAL_BASE_URLhttp://junkbox-hub:8001 계열 Docker DNS 주소를 사용함.
  • 운영 jeevtrap은 WOL 브로드캐스트 전송을 위해 host network로 실행되므로 HUB_INTERNAL_BASE_URL, JEEVTRAP_LINKDING_BASE_URL, LITELLM_BASE_URL은 호스트 네트워크에서 접근 가능한 주소를 사용함.
  • 운영 jeevtrap의 PC 종료 명령은 컨테이너 내부에 read-only로 마운트된 SSH 비밀키 경로를 JEEVTRAP_TARGET_DESKTOP_MAIN_SSH_KEY_PATH로 사용함.
  • 운영 jeevtrap의 voice 런타임은 기본 비활성 상태이며, 활성화 시 PulseAudio/PipeWire socket과 cookie 마운트, PULSE_SERVER, PortAudio/ALSA 런타임 패키지, apps/jeevtrap/var/voice.yml 설정이 함께 유효해야 함.
  • 레이드 운영에서는 WCL_CLIENT_ID, WCL_CLIENT_SECRET, WCL_API_URL, WCL_TOKEN_URL, WCL_MAX_CONCURRENCY 값을 함께 점검함.
  • 체스 운영에서는 CHESS_DATABASE_URL, Lichess OAuth 설정, Stockfish 실행 파일 경로와 분석 제한값, JUNKBOX_CHESS_RESTART_POLICY 값을 함께 점검함.
  • HUB_API_INTERNAL_TOKENraid-api, workout-api, rename-api, chess-api, jeevtraphub-api 내부 인증 API, 내부 master-data API, AI usage-log 기록 API를 호출할 때 사용하는 서버 간 토큰임.
  • hub-api 세션 정책 파일은 apps/hub-api/var/auth-policy.yml이며, 운영 컨테이너에서는 동일 경로가 이미지 또는 마운트에 포함되어야 함.
  • AI_ACCESS_TOKEN은 AI 에이전트 전용 ROLE_AI JWT 값이며 scripts/.env.ai에 보관함.
  • FASTAPI_BASE_URLscripts/fetch_master_data.py가 호출할 hub-api base URL임.
  • vault/docs/**/*.md 문서 원본은 사람이 Git으로 검증하고 커밋하는 Source of Truth임.
  • vault/docs/junkbox/**/*.md는 JunkBox 개발 가이드 문서 원본이며 docs/junkbox/common, docs/junkbox/libs, docs/junkbox/apps로 책임을 나눔.
  • vault 스키마의 문서 벡터 테이블은 AI 에이전트가 필요한 문서 chunk를 먼저 찾기 위한 읽기 최적화 캐시임.
  • 개발 문서 벡터 캐시는 로컬 markdown 원본에서 DB로만 동기화되며, DB 내용을 markdown으로 역동기화하지 않음.
  • scripts/sync_dev_docs.pyvault/docs/**/*.md 파일의 생성, 수정, 삭제를 SHA-256 해시 기준으로 감지하여 vault.docs, vault.doc_chunks, vault.doc_embeddings, vault.index_runs에 반영함.
  • 변경되지 않은 문서는 임베딩을 재생성하지 않음.
  • 변경된 문서는 기존 chunk와 embedding을 문서 기준으로 교체하고 새 chunk를 임베딩하여 저장함.
  • 로컬에서 사라진 문서는 hard delete하지 않고 vault.docs.is_deleted=true로 표시함.
  • scripts/search_dev_docs.py는 검색 query를 임베딩한 뒤 vault.doc_embeddings에서 cosine similarity 기준 상위 chunk를 조회함.
  • AI 작업 프롬프트는 vault/docs/junkbox 전체 파일을 무작정 읽기보다 scripts/search_dev_docs.py 검색 결과의 source, namespace, kind, project, heading, chunk를 기준으로 필요한 원본 문서만 좁혀 읽는 흐름을 우선함.
  • JWT_SECRET_KEYHUB_API_INTERNAL_TOKEN은 용도가 다르므로 서로 다른 랜덤 값을 사용하는 것을 기본 원칙으로 함.
  • AI_ACCESS_TOKEN은 사용자 인증 JWT, 서버 간 내부 토큰과 분리된 별도 값으로 관리함.

15. 관련 문서

  • hub-api 구조는 docs/junkbox/apps/guide-apps-hub-api.md를 따름.
  • hub-ui 구조는 docs/junkbox/apps/guide-apps-hub-ui.md를 따름.
  • chess-api 구조는 docs/junkbox/apps/guide-apps-chess-api.md를 따름.
  • chess-ui 구조는 docs/junkbox/apps/guide-apps-chess-ui.md를 따름.
  • raid-api 구조는 docs/junkbox/apps/guide-apps-raid-api.md를 따름.
  • raid-ui 구조는 docs/junkbox/apps/guide-apps-raid-ui.md를 따름.
  • rename-api 구조는 docs/junkbox/apps/guide-apps-rename-api.md를 따름.
  • rename-ui 구조는 docs/junkbox/apps/guide-apps-rename-ui.md를 따름.
  • workout-api 구조는 docs/junkbox/apps/guide-apps-workout-api.md를 따름.
  • workout-ui 구조는 docs/junkbox/apps/guide-apps-workout-ui.md를 따름.
  • 공통 AI 런타임과 개발 문서 벡터 캐시 구조는 docs/junkbox/libs/guide-lib-shared-ai.md를 따름.
  • 공통 음성 런타임 구조는 docs/junkbox/libs/guide-lib-shared-voice.md를 따름.
  • 공통 마스터 데이터 규칙은 docs/junkbox/common/guide-jb-common-master-data.md를 따름.
  • 공통 UI 원칙과 운영 화면 시각 규칙은 docs/junkbox/common/guide-jb-common-ui.md를 단일 기준으로 따름.