Files
baekjoon-bot/docs/DEVELOPMENT.md
sm4640 bd045b43c2
Some checks failed
baekjoon-bot-cicd / build_push_deploy (push) Failing after 1m34s
Fix: [main] 리드미 수정 및 cicd md 파일 제외
2026-03-26 00:26:44 +09:00

3.2 KiB

Development Guide

프로젝트 구조

파일 역할
app.py FastAPI 엔트리포인트. /, /today, /admin/* 라우팅
utils.py 환경변수 헬퍼, solved.ac 검색 쿼리 빌드, HTTP 호출(retry), admin 인증
db.py SQLAlchemy async 엔진/세션 설정, get_db() DI
workbook_picker.py 문제집에서 미발송 문제 1개 선택 + workbook_sends 기록
workbook_enricher.py solved.ac problem/show로 문제 메타데이터 채우기
workbook_importer.py BOJ 문제집 페이지 크롤링 (현재 미사용, BOJ 스크래핑 차단)

로컬 셋업

git clone https://nkeystudy.site/gitea/nkey/baekjoon-bot.git
cd baekjoon-bot

python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

cat > .env <<'EOF'
DATABASE_URL=postgresql+asyncpg://USER:PASSWORD@HOST:5432/DBNAME
ADMIN_PASSWORD=change-me
EOF

uvicorn app:app --reload --host 0.0.0.0 --port 8000

의존성

requirements.txt 기준:

  • fastapi / uvicorn - 웹 프레임워크 / ASGI 서버
  • sqlalchemy / asyncpg - 비동기 PostgreSQL ORM
  • requests / httpx - 동기/비동기 HTTP 클라이언트
  • python-dotenv - .env 파일 로딩
  • beautifulsoup4 / lxml - HTML 파싱 (workbook_importer용, 현재 미사용)

데이터베이스

PostgreSQL 필수. DDL은 레포에 포함되어 있지 않으므로 수동으로 생성해야 한다.

CREATE TABLE IF NOT EXISTS workbooks (
  id            BIGINT PRIMARY KEY,
  title         TEXT,
  source        TEXT NOT NULL DEFAULT 'boj',
  created_at    TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at    TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE IF NOT EXISTS workbook_problems (
  workbook_id   BIGINT NOT NULL REFERENCES workbooks(id) ON DELETE CASCADE,
  problem_id    INTEGER NOT NULL,
  title_ko      TEXT,
  title_en      TEXT,
  level         INTEGER,
  tags          TEXT[] DEFAULT NULL,
  added_at      TIMESTAMPTZ NOT NULL DEFAULT now(),
  PRIMARY KEY (workbook_id, problem_id)
);

CREATE INDEX IF NOT EXISTS idx_workbook_problems_workbook
  ON workbook_problems(workbook_id);

CREATE TABLE IF NOT EXISTS workbook_sends (
  workbook_id   BIGINT NOT NULL REFERENCES workbooks(id) ON DELETE CASCADE,
  problem_id    INTEGER NOT NULL,
  sent_at       TIMESTAMPTZ NOT NULL DEFAULT now(),
  PRIMARY KEY (workbook_id, problem_id)
);

CREATE INDEX IF NOT EXISTS idx_workbook_sends_workbook
  ON workbook_sends(workbook_id);

테이블 설명

테이블 역할
workbooks 문제집 메타 (BOJ workbook id를 PK로 사용)
workbook_problems 문제집-문제 매핑 + 메타데이터 (제목, 난이도, 태그)
workbook_sends 발송 기록. 중복 추천 방지의 핵심

환경변수

필수:

  • DATABASE_URL - PostgreSQL 연결 URL (미설정 시 앱 시작 불가)

Admin API 사용 시:

  • ADMIN_PASSWORD - X-Admin-Password 헤더와 비교

검색 기본값 커스터마이징:

  • SOURCE_MODE_DEFAULT, WORKBOOK_ID_DEFAULT
  • DIFFICULTY_MODE_DEFAULT, TAG_MODE_DEFAULT, LANG_DEFAULT
  • DIFFICULTY_EASY/HARD/ALL, TAGS_EASY/HARD/ALL
  • TAG_PICK, TAG_PICK_EASY/HARD/ALL, TAGS_JOIN