# baekjoon-bot(폴더 구조화 이전 버전) 작성: AI / 수정: nkey 매일 백준(BOJ) 문제를 추천해주고, 디스코드 메시지(payload)로 쓸 수 있는 형태로 반환하는 FastAPI 서비스입니다. `/today`에서 추천 문제 + 링크 + Discord embed payload를 생성하며, (선택) PostgreSQL에 문제집(workbook) 진행상황을 저장해 “문제집에서 아직 안 보낸 문제”를 고르는 모드도 제공합니다. 디스코드 메시지 자동화는 n8n을 활용하였습니다. ## Quickstart ### Recommended ```bash # clone git clone https://nkeystudy.site/gitea/nkey/baekjoon-bot.git cd baekjoon-bot # venv python -m venv .venv source .venv/bin/activate # deps pip install -r requirements.txt # env (필수: DATABASE_URL) cat > .env <<'EOF' DATABASE_URL=postgresql+asyncpg://USER:PASSWORD@HOST:5432/DBNAME # (admin API 사용 시 필수) ADMIN_PASSWORD=change-me EOF # run uvicorn app:app --host 0.0.0.0 --port 8000 # verify curl -s http://localhost:8000/ | cat curl -s "http://localhost:8000/today" | cat ``` ### Alternative (optional) - Docker ```bash docker build -f dockerfile -t baekjoon-bot:local . docker run --rm -p 8000:8000 --env-file .env baekjoon-bot:local # verify curl -s http://localhost:8000/ | cat ``` ## Requirements - Runtime/Language: Python 3.12+ (Dockerfile 기준) - Dependencies: `fastapi`, `uvicorn`, `sqlalchemy>=2.0`, `asyncpg`, `requests`, `httpx`, `python-dotenv` 등 (`requirements.txt`) - Tools: (optional) Docker ## Configuration ### Environment Variables | Key | Description | Default | Required | |---|---|---:|:---:| | `DATABASE_URL` | SQLAlchemy async DB URL (예: `postgresql+asyncpg://...`) | - | ✅ | | `ADMIN_PASSWORD` | Admin API 인증 비밀번호 (`X-Admin-Password` 헤더와 비교) | `""` | ✅ (admin API) | | `SOURCE_MODE_DEFAULT` | `/today` 기본 소스 모드 | `search` | | | `WORKBOOK_ID_DEFAULT` | `source_mode=workbook`에서 `workbook_id` 미지정 시 기본값 | - | | | `DIFFICULTY_MODE_DEFAULT` | `/today` 기본 난이도 모드 | `easy` | | | `TAG_MODE_DEFAULT` | `/today` 기본 태그 모드 | `easy` | | | `LANG_DEFAULT` | `/today` 기본 언어 | `all` | | | `DIFFICULTY_EASY` | easy 난이도 범위 | `6..10` | | | `DIFFICULTY_HARD` | hard 난이도 범위 | `11..15` | | | `DIFFICULTY_ALL` | all 난이도 범위 | `1..30` | | | `TAGS_EASY` | easy 태그 프리셋(CSV) | `""` | | | `TAGS_HARD` | hard 태그 프리셋(CSV) | `""` | | | `TAGS_ALL` | all 태그 프리셋(CSV) | `""` | | | `TAG_PICK` | 태그 선택 정책 (random/none/전체) | `random` | | | `TAG_PICK_EASY` | easy 태그 선택 정책 | `TAG_PICK` | | | `TAG_PICK_HARD` | hard 태그 선택 정책 | `TAG_PICK` | | | `TAG_PICK_ALL` | all 태그 선택 정책 | `TAG_PICK` 또는 `none` | | | `TAGS_JOIN` | 태그 결합 방식 | `or` | | ### Ports | Service | Port | Description | |---|---:|---| | API | 8000 | FastAPI(Uvicorn) | ## Usage (minimal) - 오늘의 추천 문제(검색 모드, 기본값) - `GET /today` - 난이도/태그/언어 지정 - `GET /today?difficulty=6..10&tags=dp,graphs&lang=ko,en` - 문제집(workbook) 모드로 추천 - `GET /today?source_mode=workbook&workbook_id=12345&workbook_pick=level_asc` - Admin: 문제집 메타(제목/레벨/태그) 보강 - `POST /admin/workbooks/{workbook_id}/enrich` + `X-Admin-Password: ...` ## Docs - Operations: `docs/OPERATIONS.md` - Development: `docs/DEVELOPMENT.md` - API: `docs/API.md` ## CI/CD - Workflow: `.gitea/workflows/cicd.yml` - Trigger: `main` 브랜치로 `push` 시 실행 - Flow: 1) (수동) checkout: Gitea 서브패스(`/gitea`)를 고려해 `git init` + `git fetch`로 소스 가져옴 2) Docker Hub 로그인 3) 이미지 빌드/푸시: `${DOCKERHUB_USERNAME}/baekjoon-bot:latest` 4) 서버 배포: 서버에 존재하는 app 관련 compose 파일(`/nkeysworld/compose.apps.yml`)로 `pull/up -d` 수행 5) Discord Webhook으로 성공/실패 알림 전송 ### Required Secrets | Key | Used for | |---|---| | `NKEY_PAT` | workflow 내 수동 checkout 시 Gitea repo fetch 인증 | | `DOCKERHUB_USERNAME` | Docker Hub 이미지 네임스페이스 | | `DOCKERHUB_TOKEN` | Docker Hub 로그인 토큰 | | `DISCORD_WEBHOOK` | CI/CD 결과 알림 전송 | > NOTE: workflow의 빌드 단계는 `docker build -t ... .`(기본 Dockerfile 사용) 형태입니다. 레포의 빌드 파일명은 `dockerfile`(소문자)이므로, CI 환경에서 기본 Dockerfile을 쓰려면 파일명/옵션 정합성을 확인하세요.