# AGENTS.md ## Stack - **Backend**: FastAPI 0.104 + SQLAlchemy 2.0 + PostgreSQL 16 (`yzr_nr`) - **Frontend**: Vue 3 (CDN, no build step) + Element Plus — static HTML served by FastAPI - **Auth**: JWT (`python-jose` + bcrypt), default admin `admin/admin123` - **Scheduler**: APScheduler (daily cron: 01:00 searchcache, 01:10 trends, 01:30 collect, 02:00 generate, 03:00 optimize, 05:00 sources, 06:00 metrics) - **Task DB**: `TaskLog` (module_id/status/error_trace/result_data/triggered_by) + `TaskConfig` (params/enabled/schedule) - **LLM**: Multi-provider (opencode-go primary, nvidia backup). API keys only in `.env`, not DB. ## Commands ```bash # Start/stop/restart server (systemd service, auto-restart on failure) systemctl start yzr-platform.service # 启动 systemctl stop yzr-platform.service # 停止 systemctl restart yzr-platform.service # 重启 systemctl status yzr-platform.service # 查看状态 journalctl -u yzr-platform.service -n 50 --no-pager # 查看日志 # Fallback: start without systemd (用于调试) cd /root/openclaw-workspace/projects/yu-zhi-ran setsid ./start-platform.sh 8001 # Run full integration test cd /root/openclaw-workspace/projects/yu-zhi-ran && python3 tests/test_new_features.py # Run specific scripts (from project root) python3 scripts/collector.py python3 scripts/creator.py --topic-id B02 ``` ## Project layout ``` yu-zhi-ran/ ├── platform/ │ ├── backend/app/main.py # FastAPI entry, mounts frontend at / │ ├── backend/app/api/*.py # 21 API routers │ ├── backend/app/core/ # nvidia_client.py, scheduler.py, etc. │ ├── backend/app/models.py # SQLAlchemy models (593 lines) │ ├── backend/app/schemas.py # Pydantic schemas (504 lines) │ ├── backend/app/database.py # PG env config + ALTER TABLE migrations │ ├── backend/app/initial_data.py │ └── backend/.env # API keys, DB creds ├── scripts/ # creator.py, writer.py, collector.py, etc. ├── tests/test_new_features.py # 33-test integration suite └── PROGRESS.md # Single source of truth for project status ``` ## Gotchas & conventions ### Server - Shell timeout kills background processes — always use `setsid` to start - Env in `platform/backend/.env`, loaded via `dotenv` at each module level ### Database - `init_db()` in `database.py` runs ALTER TABLE migrations at startup (PostgreSQL) - `USE_POSTGRES=false` falls back to SQLite (used in tests) - Models have timezone-aware `DateTime(timezone=True)` columns ### Prompts (`prompt_configs` table) - **DB 是唯一来源**,修改 prompt 直接 `UPDATE prompt_configs SET content = '...' WHERE key = '...';` - 代码 `scripts/prompt_loader.py` 中的 `_PROMPT_DEFAULTS` **仅作种子数据**,第一次写入后就不再生效 - 新增 prompt:在 `_PROMPT_DEFAULTS` 添加定义 → 重启后自动补入 DB(仅当该 key 不存在时) - 修改 prompt:**直接改 DB,不要改代码**(除非要更新种子供新环境用) - DB 不可用时回退代码默认值(仅紧急模式) ### Prompt quality checks (`compliance_checker.py`) - 软质量问题(AI套话/人称混用/阅读体验)只降分、不挡流程(`passed=true`) - 硬合规问题(敏感词/法律/品牌)扣分多且阻塞流程 ### LLM - `call_llm()` in `core/nvidia_client.py` — reads active provider from DB `LLMConfig.is_active`, API key from env - DeepSeek reasoning models return `reasoning_content` (thinking) + `content` (answer). `call_llm` prefers `content`, falls back to tail of `reasoning_content` - `max_tokens` must be generous (≥500 for tags/titles, ≥2000 for article content) — reasoning models consume tokens for thinking - Schema (`LLMConfigResponse`) must include `provider`, `base_url`, `api_key` fields or they get silently dropped from API responses ### Frontend - No npm build step — edit `.html` files directly - H5 mobile nav only created when `window.innerWidth <= 768` - `navigation-component.js` + `navbar-component.js` injected as Vue components - For date filters on topics, use backend `?today=true` (server-side `date.today()`) — client-side `new Date()` gives UTC which differs from Asia/Shanghai by 8h ### Tests - `test_new_features.py` starts its own uvicorn on port 18503, runs against SQLite - Run from project root: `python3 tests/test_new_features.py` ### Project status - PROGRESS.md is the single truth source for progress — update it after any significant task - `archive/` dir keeps historical/outdated docs with `YYYY-MM-DD` date suffix