Explorar el Código

数据库变更指南

liuq hace 3 meses
padre
commit
a62fb054f8
Se han modificado 3 ficheros con 169 adiciones y 4 borrados
  1. 36 0
      README.md
  2. 42 4
      docker-compose.wsl.yml
  3. 91 0
      docs/AI_DB_GUIDE.md

+ 36 - 0
README.md

@@ -48,6 +48,7 @@
 
 ```text
 Unified_Authentication_Platform/
+├── sql/                  # 数据库迁移脚本 (Flyway)
 ├── backend/                  # 后端项目 (FastAPI)
 │   ├── app/                  # 应用源码
 │   │   ├── api/v1/           # API 接口层
@@ -247,6 +248,41 @@ npm install
 npm run dev
 ```
 
+### 6.3 数据库运维 (自动升级与恢复)
+
+本项目集成了 **Flyway** 和 **Backup Sidecar**,实现了企业级的数据库运维能力。
+
+#### 1. 自动升级数据库 (Flyway)
+- **原理**: `db-migration` 容器启动时会自动比对 `sql/` 目录下的脚本与数据库状态,自动执行增量更新。
+- **操作步骤**:
+  1. 在项目根目录的 `sql/` 文件夹中创建 SQL 文件。
+  2. 命名需遵循 Flyway 规范:`V<版本号>__<描述>.sql` (**注意是双下划线**)。
+     - 示例: `sql/V1__init_schema.sql`, `sql/V2__add_phone_field.sql`
+  3. 执行 `docker-compose up -d`。容器会自动检测并应用新的 SQL 变更。
+
+#### 2. 灾难恢复 (Disaster Recovery)
+- **自动备份**: `db-backup` 容器每天凌晨 3:00 自动将数据库备份至 `backups/` 目录 (保留7天)。
+- **手动恢复步骤**:
+  假设需要从 `backups/uap_db_xxxx.sql.gz` 恢复数据:
+  
+  ```bash
+  # 1. 停止应用服务,防止写入
+  docker-compose stop
+
+  # 2. 仅启动数据库
+  docker-compose up -d mysql
+
+  # 3. 执行恢复 (使用 Docker 临时容器执行导入,无需本地安装 MySQL 客户端)
+  # 注意:替换下方文件名
+  docker run --rm -i \
+    --network container:uap_mysql \
+    mysql:8.0 \
+    sh -c 'exec mysql -h mysql -u root -proot_password uap_db' < <(gzip -dc ./backups/uap_db_xxxx.sql.gz)
+
+  # 4. 恢复完成后重启所有服务
+  docker-compose restart
+  ```
+
 ---
 
 ## 7. 常见问题 (FAQ)

+ 42 - 4
docker-compose.wsl.yml

@@ -70,6 +70,7 @@ services:
   # ==========================================
   db:
     image: mysql:8.0
+    container_name: uap_mysql
     command: --default-authentication-plugin=mysql_native_password
     restart: always
     environment:
@@ -82,12 +83,49 @@ services:
       - "3308:3306"
     volumes:
       - db_data:/var/lib/mysql
+      # - ./config/my.cnf:/etc/mysql/conf.d/my.cnf
     healthcheck:
-      test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost", "-u", "uap_user", "-p$$MYSQL_PASSWORD"]
+      test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
       interval: 10s
       timeout: 5s
-      retries: 10
-      start_period: 10s
+      retries: 5
+
+  # ==========================================
+  # Database Version Migration (Flyway)
+  # ==========================================
+  db-migration:
+    image: flyway/flyway:9-alpine
+    container_name: uap_migration
+    depends_on:
+      db:
+        condition: service_healthy
+    command: -connectRetries=60 -baselineOnMigrate=true migrate
+    environment:
+      FLYWAY_URL: jdbc:mysql://db:3306/uap_db
+      FLYWAY_USER: root
+      FLYWAY_PASSWORD: root_password
+    volumes:
+      - ./sql:/flyway/sql
+
+  # ==========================================
+  # Database Auto Backup (Sidecar)
+  # ==========================================
+  db-backup:
+    image: fradelg/mysql-cron-backup
+    container_name: uap_backup
+    restart: always
+    depends_on:
+      - db
+    environment:
+      - MYSQL_HOST=db
+      - MYSQL_PORT=3306
+      - MYSQL_USER=root
+      - MYSQL_PASS=root_password
+      - CRON_TIME=0 3 * * *
+      - MAX_BACKUPS=7
+      - GZIP_COMPRESSION=true
+    volumes:
+      - ./backups:/backup
 
   # ==========================================
   # Redis
@@ -126,7 +164,7 @@ services:
       - "4444:4444"
       - "4445:4445"
       - "5555:5555"
-    command: serve -c /etc/config/hydra/hydra.yml all --dev
+    command: serve all --dev
     environment:
       - TZ=Asia/Shanghai
       - DSN=postgres://hydra:secret@postgresd:5432/hydra?sslmode=disable&max_conns=20&max_idle_conns=4

+ 91 - 0
docs/AI_DB_GUIDE.md

@@ -0,0 +1,91 @@
+# AI 开发规范:数据库变更指南 (Database Migration Guide)
+
+## 1. 核心原则 (Core Principles)
+
+本项目的数据库管理采用 **"Schema as Code"** 模式,由 **Flyway** 和 **SQLAlchemy** 共同管理。
+AI 在执行任何涉及数据库结构(Schema)的变更时,**必须**严格遵循以下流程。
+
+**🚫 禁止行为:**
+1. **禁止** 直接告诉用户去数据库执行 SQL 语句。
+2. **禁止** 仅修改 Python `models` 代码而不创建 SQL 迁移脚本(这会导致代码与数据库不一致)。
+3. **禁止** 修改已经存在的/旧的 `V` 开头的 SQL 文件(历史记录不可篡改)。
+
+---
+
+## 2. 变更流程 (Workflow)
+
+当用户提出需求(如:“给用户表加一个手机号字段”)时,AI 需按顺序执行以下步骤:
+
+### 第一步:确定版本号
+1. 扫描项目根目录下的 `sql/` 文件夹。
+2. 找到当前最大的版本号(例如当前是 `V4__xxx.sql`)。
+3. 新文件的版本号 = 当前最大版本号 + 1(即 `V5`)。
+
+### 第二步:创建迁移脚本 (Migration Script)
+在 `sql/` 目录下创建新文件。
+
+* **命名规则**:`V{Version}__{Description}.sql`
+    * 注意:`V` 大写。
+    * 注意:版本号与描述之间是 **双下划线 (`__`)**。
+    * 示例:`sql/V2__add_phone_column.sql`
+
+* **内容规范**:
+    * 使用标准 MySQL 8.0 语法。
+    * 尽量保证操作的可重入性(虽然 Flyway 会保证只执行一次,但写法上推荐防御性编程)。
+    
+    ```sql
+    -- 示例内容
+    ALTER TABLE users ADD COLUMN phone_number VARCHAR(20) DEFAULT NULL COMMENT '用户手机号';
+    -- 如果是创建表
+    CREATE TABLE IF NOT EXISTS new_table (...);
+    ```
+
+### 第三步:同步 SQLAlchemy 模型 (Sync Models)
+修改后端代码以匹配新的数据库结构。
+
+* **目标路径**:`backend/app/models/`
+* **操作**:找到对应的 Python 模型文件(如 `user.py`),添加或修改对应的 `Column` 定义。
+    
+    ```python
+    # backend/app/models/user.py
+    class User(Base):
+        # ... 原有字段
+        phone_number = Column(String(20), nullable=True, comment="用户手机号") # 新增
+    ```
+
+### 第四步:同步 Pydantic Schema (Optional)
+如果该字段需要通过 API 暴露或接收,需同步修改 Schema。
+
+* **目标路径**:`backend/app/schemas/`
+* **操作**:在 `UserBase` 或 `UserCreate`/`UserUpdate` 模型中添加字段。
+
+---
+
+## 3. 示例场景 (Example Scenario)
+
+**用户指令**:
+> "帮我增加一个功能,记录用户的最后登录IP。"
+
+**AI 应执行的操作**:
+
+1. **读取文件列表**:检查 `sql/`,发现最新是 `V1__init.sql`。
+2. **创建文件**:`sql/V2__add_last_login_ip.sql`。
+    ```sql
+    ALTER TABLE users ADD COLUMN last_login_ip VARCHAR(50) DEFAULT NULL;
+    ```
+3. **修改模型**:`backend/app/models/user.py`。
+    ```python
+    last_login_ip = Column(String(50), nullable=True)
+    ```
+4. **修改 Schema**:`backend/app/schemas/user.py` (视情况而定)。
+5. **回复用户**:
+    > "已为您创建了数据库迁移脚本 `V2` 并更新了后端模型。请执行 `docker-compose up -d` 以应用变更。"
+
+---
+
+## 4. 故障排查 (Troubleshooting)
+
+如果 Flyway 启动失败(校验和错误):
+* **原因**:有人修改了已经执行过的 SQL 文件。
+* **AI 建议**:不要尝试通过 AI 修复历史文件的 checksum。建议用户进入 `uap_migration` 容器手动运行 `flyway repair`,或者在开发环境中清理 `flyway_schema_history` 表中的失败记录。
+