diff --git a/docs/DATABASE_SETUP.md b/docs/DATABASE_SETUP.md new file mode 100644 index 0000000..e23c650 --- /dev/null +++ b/docs/DATABASE_SETUP.md @@ -0,0 +1,429 @@ +# PostgreSQL 数据库搭建指南 + +本项目运行时**必须**连接 PostgreSQL 16+(含 pgvector 扩展),SQLite 已不支持。 + +--- + +## 方案一:Docker Compose(推荐,本地开发) + +适合本地开发与测试,一条命令启动 PostgreSQL + pgvector。 + +### 1. 创建 `docker-compose.yml` + +在项目根目录或任意位置新建: + +```yaml +version: '3.8' + +services: + postgres: + image: pgvector/pgvector:pg16 + container_name: resume-agent-db + environment: + POSTGRES_USER: resume_agent + POSTGRES_PASSWORD: change-me-in-production + POSTGRES_DB: resume_agent + ports: + - "5435:5432" + volumes: + - resume_agent_data:/var/lib/postgresql/data + restart: unless-stopped + +volumes: + resume_agent_data: +``` + +### 2. 启动 + +```bash +docker-compose up -d +``` + +### 3. 配置 `backend/.env` + +```bash +DATABASE_URL=postgresql+psycopg://resume_agent:change-me-in-production@127.0.0.1:5435/resume_agent +RESUME_AGENT_TEST_DATABASE_URL=postgresql+psycopg://resume_agent:change-me-in-production@127.0.0.1:5435/resume_agent_test +``` + +### 4. 初始化数据库 + +```bash +cd backend +alembic upgrade head +``` + +**停止与清理**: +```bash +docker-compose down # 停止(保留数据) +docker-compose down -v # 停止并删除数据卷(重置数据库) +``` + +--- + +## 方案二:生产环境 PostgreSQL + +适合公司已有 PostgreSQL 集群或需要独立部署的场景。 + +### 1. 安装 PostgreSQL 16+ + +**Ubuntu/Debian**: +```bash +sudo apt install postgresql-16 postgresql-contrib-16 +``` + +**CentOS/RHEL**: +```bash +sudo dnf install postgresql16-server postgresql16-contrib +sudo postgresql-16-setup initdb +sudo systemctl enable --now postgresql-16 +``` + +**macOS(Homebrew)**: +```bash +brew install postgresql@16 +brew services start postgresql@16 +``` + +**Windows**:下载官方安装包 https://www.postgresql.org/download/windows/ + +### 2. 安装 pgvector 扩展 + +pgvector 用于向量存储(未来扩展知识库功能时需要,当前轻度优化不依赖)。 + +**Ubuntu/Debian**: +```bash +sudo apt install postgresql-16-pgvector +``` + +**从源码安装**(如包管理器无 pgvector): +```bash +git clone https://github.com/pgvector/pgvector.git +cd pgvector +make PG_CONFIG=/usr/pgsql-16/bin/pg_config # 路径按实际调整 +sudo make install PG_CONFIG=/usr/pgsql-16/bin/pg_config +``` + +### 3. 创建用户与数据库 + +以 `postgres` 管理员身份执行: + +```sql +CREATE USER resume_agent WITH PASSWORD 'your-strong-password'; +CREATE DATABASE resume_agent OWNER resume_agent; +CREATE DATABASE resume_agent_test OWNER resume_agent; + +-- 启用 pgvector 扩展(当前可选,未来知识库功能需要) +\c resume_agent +CREATE EXTENSION IF NOT EXISTS vector; +\c resume_agent_test +CREATE EXTENSION IF NOT EXISTS vector; + +-- 授权(如果数据库归属已设为 resume_agent 则自动有权限,此行可跳过) +GRANT ALL PRIVILEGES ON DATABASE resume_agent TO resume_agent; +GRANT ALL PRIVILEGES ON DATABASE resume_agent_test TO resume_agent; +``` + +### 4. 配置 `backend/.env` + +将 `host`、`port`、密码替换为实际值: + +```bash +DATABASE_URL=postgresql+psycopg://resume_agent:your-strong-password@your-db-host:5432/resume_agent +RESUME_AGENT_TEST_DATABASE_URL=postgresql+psycopg://resume_agent:your-strong-password@your-db-host:5432/resume_agent_test +``` + +**注意**:生产环境**必须**修改默认密码 `change-me-in-production`。 + +### 5. 初始化数据库 + +```bash +cd backend +alembic upgrade head +``` + +--- + +## 验证安装 + +### 检查连接 + +```bash +cd backend +python -c "from app.postgres_database import PostgresDatabase; db = PostgresDatabase('your-DATABASE_URL-here', 'resume_agent'); db.initialize(); print('✓ 连接成功')" +``` + +### 运行测试(需要测试库) + +```bash +cd backend +pytest tests/test_postgres_environment.py -v +``` + +--- + +## 常见问题 + +### Q1: `ModuleNotFoundError: No module named 'psycopg'` + +安装 Python 驱动: +```bash +pip install psycopg[binary] +``` + +### Q2: `FATAL: password authentication failed` + +- 检查 `.env` 中的密码是否正确 +- PostgreSQL 默认可能只允许本地 Unix socket 连接,需修改 `pg_hba.conf`: + ``` + # 允许密码认证(开发环境) + host all all 127.0.0.1/32 md5 + ``` + 修改后重启 PostgreSQL:`sudo systemctl restart postgresql-16` + +### Q3: `FATAL: database "resume_agent" does not exist` + +执行方案二第 3 步创建数据库。 + +### Q4: `could not open extension control file ".../vector.control"` + +pgvector 未安装或路径不对,执行方案二第 2 步。当前轻度优化功能可暂不安装(但测试套件会跳过 pgvector 相关测试)。 + +--- + +## 从 SQLite 迁移到 PostgreSQL + +如果你有旧的 SQLite 数据库(`backend/data/resume_agent.db`),可一键迁移: + +```bash +cd backend +# 确保 PostgreSQL 已启动且 alembic upgrade head 已执行 +python scripts/migrate_sqlite_to_postgres.py \ + --sqlite-path data/resume_agent.db \ + --postgres-url "postgresql+psycopg://resume_agent:password@127.0.0.1:5435/resume_agent" +``` + +迁移完成后 SQLite 文件可归档备份(不要删除,以防回滚)。 + +--- + +## 多环境 Schema 隔离(可选) + +如果多个开发者或环境共用一个 PostgreSQL 实例,可用不同 schema 隔离: + +```bash +# 开发者 A +export RESUME_AGENT_DATABASE_SCHEMA=dev_alice + +# 开发者 B +export RESUME_AGENT_DATABASE_SCHEMA=dev_bob + +# 测试 CI +export RESUME_AGENT_DATABASE_SCHEMA=ci_test +``` + +每个 schema 自动创建独立表,互不影响。默认 schema 是 `resume_agent`。 + +--- + +## ⚠️ 为什么不要打包现有数据库镜像 + +如果你已在本地运行过项目并考虑"把我的数据库导出给其他人用",**请不要这样做**: + +| 问题 | 后果 | +|---|---| +| **本地库含测试 PII** | 测试用的真实简历、手机号会随镜像泄露到其他环境 | +| **schema 版本分裂** | 如果本地库含未发布的表结构(如深度优化功能的实验性迁移),其他人拿到的库与代码不匹配 | +| **无法追踪变更** | 镜像是"某一时刻的快照",后续表结构变更无法增量同步,只能重新导出(覆盖生产数据)或手写 SQL 补丁 | +| **违反 Alembic 设计** | Alembic 迁移链才是 schema 的唯一事实来源;绕过它会导致 `alembic current` 显示错误版本,后续 `upgrade` 失败 | + +**正确做法**:每个环境独立执行 `alembic upgrade head`(从零建表),通过**迁移文件**而非**数据库快照**同步 schema。 + +--- + +## 多仓库协作:如何同步 Schema 变更(Alembic 迁移) + +适用场景:原始开发仓库(含深度优化等未发布功能)与交付仓库(resume-agent-offerpai)分离,需定期同步表结构。 + +### 原则 + +- **Alembic 迁移文件是 schema 的唯一事实来源**,不传数据库镜像 +- 每个环境通过 `alembic upgrade head` 应用迁移,保证 schema 一致 +- 新功能的表结构变更先在开发仓库测试,稳定后再合并进交付仓库 + +### 工作流 + +#### 1. 开发仓库添加新功能(如深度优化) + +当你在原始仓库开发深度优化功能并需要新增表时: + +```bash +# 在开发仓库 backend/ +alembic revision -m "add deep optimization knowledge tables" +``` + +Alembic 会生成新迁移文件,例如 `backend/alembic/versions/20260806_06_add_deep_knowledge.py`。 + +编辑该文件实现表结构变更: + +```python +def upgrade() -> None: + op.create_table( + 'knowledge_entries', + sa.Column('id', sa.Integer(), primary_key=True), + sa.Column('content', sa.Text(), nullable=False), + # ... 其他列 + ) + +def downgrade() -> None: + op.drop_table('knowledge_entries') +``` + +在本地测试: + +```bash +alembic upgrade head # 应用迁移 +alembic downgrade -1 # 回滚测试 +alembic upgrade head # 重新应用 +pytest tests/test_deep_optimization.py # 功能测试 +``` + +#### 2. 决定是否合并进交付仓库 + +开发完成后,根据发布计划决定: + +**情况 A:深度优化暂不发布** +→ 迁移文件留在开发仓库,交付仓库不同步(两个仓库的 schema 暂时分叉) + +**情况 B:深度优化已稳定,准备发布** +→ 将新迁移文件复制进交付仓库: + +```bash +# 复制迁移文件 +cp resume-agent/backend/alembic/versions/20260806_06_*.py \ + resume-agent-offerpai/backend/alembic/versions/ + +# 同时复制相关代码模块 +cp -r resume-agent/backend/app/deep_optimization \ + resume-agent-offerpai/backend/app/ +``` + +#### 3. 交付仓库用户升级数据库 + +其他开发者或生产环境拉取最新代码后: + +```bash +cd backend +alembic upgrade head +``` + +Alembic 会**自动检测本地数据库版本**,只应用新增的迁移(如 `06_add_deep_knowledge.py`),已有的表结构不受影响。 + +**验证迁移成功**: + +```bash +alembic current +# 输出:06 (head), add deep optimization knowledge tables +``` + +#### 4. 回滚(如果新功能有问题) + +```bash +alembic downgrade -1 # 回退一个版本 +# 或指定目标版本 +alembic downgrade 05 +``` + +### 注意事项 + +1. **迁移文件命名保持顺序**:Alembic 按文件名前缀排序(`20260806_06_`),不要手动改编号 +2. **不要修改已发布的迁移**:已在生产环境执行的迁移文件禁止编辑;如需修正,写新的迁移 +3. **复制迁移时检查依赖**:如果新迁移引用了其他未发布的表,需一并复制依赖的迁移 +4. **测试先行**:新迁移在开发环境验证通过后再合并;生产环境升级前先在预发环境测试 + +### 查看迁移历史 + +```bash +alembic history --verbose +# 显示完整迁移链与当前版本 +``` + +### 如果两个仓库的迁移链已分叉 + +如果长期未同步导致迁移编号冲突(例如两边都有 `06_` 开头的迁移但内容不同): + +```bash +# 在交付仓库重新编号新迁移 +cd resume-agent-offerpai/backend +alembic revision -m "sync: merge deep optimization from main repo" +# 手动编辑生成的文件,将开发仓库的迁移内容复制进来 +``` + +**最佳实践**:定期(如每次发版)同步迁移文件,避免分叉。 + +--- + +## 示例:完整的多仓库协作流程 + +**场景**:你在开发仓库完成了深度优化功能,需要同步到交付仓库供公司团队使用。 + +### Step 1:开发仓库提交迁移 + +```bash +cd resume-agent/backend +alembic revision -m "add deep optimization tables" +# 编辑生成的迁移文件,实现 upgrade/downgrade +alembic upgrade head +pytest # 验证功能 +git add alembic/versions/20260806_06_*.py app/deep_optimization/ +git commit -m "feat: add deep optimization module with knowledge tables" +``` + +### Step 2:同步到交付仓库 + +```bash +cd ../resume-agent-offerpai +cp ../resume-agent/backend/alembic/versions/20260806_06_*.py \ + backend/alembic/versions/ +cp -r ../resume-agent/backend/app/deep_optimization \ + backend/app/ +git add backend/alembic/versions/ backend/app/deep_optimization/ +git commit -m "feat: sync deep optimization from main repo" +git push origin master +``` + +### Step 3:公司团队升级 + +```bash +# 其他开发者拉取最新代码 +git pull origin master +cd backend +alembic upgrade head +# 输出: +# INFO [alembic.runtime.migration] Running upgrade 05 -> 06, add deep optimization tables +pytest # 验证本地环境 +``` + +### Step 4:生产环境升级(零停机) + +```bash +# 生产服务器 +cd /opt/resume-agent/backend +git pull +alembic upgrade head # Alembic 自动只应用新迁移,已有数据不受影响 +sudo systemctl restart resume-agent +``` + +--- + +## 总结 + +| 场景 | 推荐方案 | +|---|---| +| 首次部署 | 方案一(Docker Compose)或方案二(独立 PG),然后 `alembic upgrade head` | +| 多人协作 | 每人独立建库 + 共享迁移文件(通过 Git),不传数据库镜像 | +| Schema 升级 | 开发仓库写迁移 → 测试 → 复制到交付仓库 → 其他人 `alembic upgrade` | +| 数据迁移 | 用迁移文件的 `op.execute("INSERT ...")` 或独立脚本(如 `scripts/seed_demo_data.py`) | +| 回滚 | `alembic downgrade ` | + +**禁止操作**:`pg_dump` 整个库然后 `psql < dump.sql` 覆盖他人数据库 —— 会破坏 Alembic 版本追踪。