# 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 스크래핑 차단) | ## 로컬 셋업 ```bash 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은 레포에 포함되어 있지 않으므로 수동으로 생성해야 한다. ```sql 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`