mirror of
https://github.com/rnvm9wjdtj-bot/myaps_api.git
synced 2026-06-02 05:54:40 +00:00
bf42299ead
- 新增 globalobjects/logger/ 模块化日志系统 - 支持异步写入、多目标输出、敏感信息脱敏 - 完全向后兼容原有logger API - 备份旧版本为 logger_v1_backup.py 和 logger_v2_backup.py - 更新 .env.example 和 AGENTS.md 文档
548 lines
14 KiB
Markdown
548 lines
14 KiB
Markdown
# MyAPS API - 开发者指南
|
||
|
||
本文档为代码助手(如华为云CodeArts代码智能体)提供项目开发所需的关键信息,包括构建命令、代码风格指南和最佳实践。
|
||
|
||
## 项目概述
|
||
|
||
MyAPS API 是一个基于FastAPI的企业级数据操作平台,支持数据清洗、监控、WebSocket通信和定时任务调度。
|
||
|
||
**技术栈:**
|
||
- **后端框架**: FastAPI (>=0.110.0)
|
||
- **异步服务器**: Uvicorn (>=0.29.0)
|
||
- **数据库ORM**: Tortoise-ORM (>=1.1.7)
|
||
- **数据验证**: Pydantic (>=2.0.0)
|
||
- **前端**: 原生HTML/JS + Bootstrap CSS
|
||
|
||
## 统一日志系统
|
||
|
||
项目使用统一的日志系统(`globalobjects/logger/`),替代原有的logger.py和logger_v2.py。
|
||
|
||
### 特性
|
||
- 异步写入,不阻塞业务线程
|
||
- 多目标输出(控制台、文件、数据库、WebSocket)
|
||
- 敏感信息自动脱敏
|
||
- 日期前缀文件轮转
|
||
- API完全向后兼容
|
||
|
||
### 使用方法
|
||
```python
|
||
from globalobjects import logger
|
||
|
||
# 基本日志
|
||
logger.debug("调试信息")
|
||
logger.info("普通信息")
|
||
logger.warning("警告信息")
|
||
logger.error("错误信息")
|
||
logger.exception("异常信息") # 自动捕获异常堆栈
|
||
|
||
# 业务便捷方法
|
||
logger.success("推送数据", "单号001", "共5条")
|
||
logger.fail("查询失败", "表A", "连接超时")
|
||
logger.start("同步任务", "账套A01")
|
||
logger.stop("同步任务", "账套A01")
|
||
logger.query("用户表", count=100)
|
||
logger.insert("日志表", count=50)
|
||
|
||
# 配置
|
||
logger.set_level("DEBUG")
|
||
logger.set_db_initialized(True)
|
||
```
|
||
|
||
### 环境变量配置
|
||
```bash
|
||
LOG_LEVEL=INFO # 日志级别
|
||
LOG_DIR=logs # 日志目录
|
||
TO_CONSOLE=true # 输出到控制台
|
||
TO_FILE=true # 输出到文件
|
||
TO_DATABASE=true # 写入数据库
|
||
LOG_STACK_TRACE=false # 是否启用调用栈追踪
|
||
```
|
||
|
||
### 旧版本备份
|
||
- `logger_v1_backup.py` - 原logger.py备份
|
||
- `logger_v2_backup.py` - 原logger_v2.py备份
|
||
|
||
## 构建和运行命令
|
||
|
||
### 开发环境运行
|
||
```bash
|
||
# 启动开发服务器(默认端口8001)
|
||
./scripts/dev_server.sh start
|
||
|
||
# 查看状态
|
||
./scripts/dev_server.sh status
|
||
|
||
# 停止服务
|
||
./scripts/dev_server.sh stop
|
||
|
||
# 重启服务
|
||
./scripts/dev_server.sh restart
|
||
|
||
# 查看日志
|
||
./scripts/dev_server.sh logs
|
||
./scripts/dev_server.sh logs -f # 实时查看
|
||
|
||
# 清除Python缓存
|
||
./scripts/dev_server.sh clear_cache
|
||
```
|
||
|
||
### 直接运行
|
||
```bash
|
||
# 使用uvicorn
|
||
uvicorn main:app --host 0.0.0.0 --port 8000
|
||
|
||
# 带热重载
|
||
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
|
||
```
|
||
|
||
### Docker运行
|
||
```bash
|
||
# 使用Docker Compose(包含Redis)
|
||
docker-compose up -d
|
||
|
||
# 单独构建
|
||
docker build -t myaps-api .
|
||
docker run -p 8000:8000 myaps-api
|
||
```
|
||
|
||
### 生产部署
|
||
```bash
|
||
# 使用Gunicorn
|
||
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000
|
||
|
||
# 使用配置文件
|
||
gunicorn -c scripts/deploy/gunicorn.conf.py main:app
|
||
```
|
||
|
||
## 测试命令
|
||
|
||
### 运行所有测试
|
||
```bash
|
||
# 在项目根目录运行
|
||
python -m pytest tests/ -v
|
||
|
||
# 或直接使用pytest
|
||
pytest tests/ -v
|
||
```
|
||
|
||
### 运行单个测试文件
|
||
```bash
|
||
# 测试统一数据入口
|
||
python -m pytest tests/test_unified_router.py -v
|
||
|
||
# 测试业务规则
|
||
python -m pytest tests/test_business_rules.py -v
|
||
|
||
# 测试日志系统
|
||
python -m pytest tests/test_logger.py -v
|
||
```
|
||
|
||
### 运行单个测试类
|
||
```bash
|
||
# 测试特定的测试类
|
||
python -m pytest tests/test_unified_router.py::TestIsStagingMode -v
|
||
python -m pytest tests/test_unified_router.py::TestMapStagingResponseToDirect -v
|
||
```
|
||
|
||
### 运行单个测试方法
|
||
```bash
|
||
# 测试特定的测试方法
|
||
python -m pytest tests/test_unified_router.py::TestIsStagingMode::test_staging_mode_with_reserved_value -v
|
||
```
|
||
|
||
### 测试标记
|
||
项目使用pytest标记:
|
||
- `@pytest.mark.asyncio` - 异步测试标记
|
||
- 无其他特殊标记
|
||
|
||
### 测试覆盖率(如需要)
|
||
```bash
|
||
# 安装pytest-cov
|
||
pip install pytest-cov
|
||
|
||
# 运行测试并计算覆盖率
|
||
pytest --cov=. --cov-report=html tests/
|
||
```
|
||
|
||
## 代码风格指南
|
||
|
||
### Python代码风格
|
||
项目遵循PEP 8标准,但没有配置正式的lint工具。建议遵循以下约定:
|
||
|
||
#### 导入顺序
|
||
```python
|
||
# 1. 标准库导入
|
||
import os
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
# 2. 第三方库导入
|
||
from fastapi import FastAPI, APIRouter
|
||
from pydantic import BaseModel
|
||
import pandas as pd
|
||
|
||
# 3. 本地应用导入
|
||
from core.app import create_app
|
||
from core.settings import PORT
|
||
from apps.io_api.routers import rt as io_rt
|
||
```
|
||
|
||
#### 命名约定
|
||
- **变量/函数**: `snake_case`
|
||
- **常量**: `UPPER_CASE_WITH_UNDERSCORES`
|
||
- **类名**: `PascalCase`
|
||
- **模块/包**: `snake_case`
|
||
- **私有成员**: `_private_variable` 或 `__really_private`
|
||
|
||
#### 类型提示
|
||
使用Python类型提示:
|
||
```python
|
||
from typing import Optional, List, Dict, Any
|
||
|
||
def process_data(
|
||
data: List[Dict[str, Any]],
|
||
config: Optional[Dict] = None
|
||
) -> Dict[str, Any]:
|
||
"""处理数据的函数文档字符串"""
|
||
pass
|
||
```
|
||
|
||
#### FastAPI特定约定
|
||
1. **路由函数**: 使用异步(async/await)
|
||
2. **Pydantic模型**: 使用BaseModel派生
|
||
3. **API响应**: 统一返回JSON格式
|
||
4. **错误处理**: 使用FastAPI异常处理器
|
||
|
||
#### 数据库相关
|
||
- **表名**: `snake_case` (如 `t_material_staging`)
|
||
- **列名**: `PascalCase` (如 `MaterialNo`)
|
||
- **注意**: 数据库字段名大小写敏感
|
||
|
||
### API设计规范
|
||
|
||
#### 路由定义
|
||
```python
|
||
from fastapi import APIRouter, Depends, HTTPException
|
||
|
||
router = APIRouter(prefix="/api", tags=["materials"])
|
||
|
||
@router.post("/upload", response_model=UploadResponse)
|
||
async def upload_materials(
|
||
data: UploadRequest,
|
||
db_name: str = Query(..., description="数据库名称")
|
||
):
|
||
"""上传物料数据"""
|
||
pass
|
||
```
|
||
|
||
#### 请求/响应模型
|
||
```python
|
||
from pydantic import BaseModel
|
||
from typing import Optional
|
||
|
||
class UploadRequest(BaseModel):
|
||
file_content: str
|
||
file_name: str
|
||
overwrite: bool = False
|
||
|
||
class UploadResponse(BaseModel):
|
||
success: bool
|
||
message: str
|
||
data: Optional[Dict] = None
|
||
meta: Optional[Dict] = None
|
||
```
|
||
|
||
#### API字段名
|
||
- **POST字段名**: 使用小写格式 (如 `file_content`, `db_name`)
|
||
- **Query参数**: 使用snake_case (如 `db_name`, `overwrite`)
|
||
- **路径参数**: 使用snake_case (如 `{material_id}`)
|
||
|
||
### 错误处理
|
||
|
||
#### HTTP状态码
|
||
- `200`: 成功
|
||
- `400`: 请求参数错误
|
||
- `401`: 未授权
|
||
- `403`: 禁止访问
|
||
- `404`: 资源不存在
|
||
- `500`: 服务器内部错误
|
||
|
||
#### 错误响应格式
|
||
```json
|
||
{
|
||
"success": false,
|
||
"error": {
|
||
"code": "VALIDATION_ERROR",
|
||
"message": "字段验证失败",
|
||
"details": {
|
||
"field_name": "具体错误信息"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 日志记录
|
||
项目使用loguru或原生logging:
|
||
```python
|
||
from globalobjects import logger
|
||
|
||
logger.info("操作成功")
|
||
logger.warning("警告信息")
|
||
logger.error("错误信息", exc_info=True)
|
||
```
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
myaps_api/
|
||
├── apps/ # 应用模块
|
||
│ ├── common/ # 通用模块(监控、帮助)
|
||
│ ├── data_opt/ # 数据操作模块
|
||
│ └── io_api/ # I/O API模块
|
||
├── core/ # 核心组件
|
||
│ ├── app.py # FastAPI应用工厂
|
||
│ ├── database.py # 数据库配置
|
||
│ ├── settings.py # 应用设置
|
||
│ └── middleware.py # 中间件
|
||
├── globalobjects/ # 全局对象管理
|
||
├── scripts/ # 脚本目录
|
||
│ ├── dev_server.sh # 开发服务器管理
|
||
│ ├── deploy/ # 部署配置
|
||
│ └── migrate/ # 数据库迁移
|
||
├── static/ # 静态文件
|
||
├── storage/ # 数据存储
|
||
├── tests/ # 测试文件
|
||
├── .env # 环境变量配置
|
||
├── main.py # 应用入口
|
||
└── requirements.txt # 依赖包
|
||
```
|
||
|
||
## 开发工作流
|
||
|
||
### 1. 环境设置
|
||
```bash
|
||
# 创建虚拟环境(如不存在)
|
||
python -m venv venv
|
||
|
||
# 激活虚拟环境
|
||
source venv/bin/activate # Linux/Mac
|
||
venv\Scripts\activate # Windows
|
||
|
||
# 安装依赖
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
### 2. 代码规范检查
|
||
项目目前没有配置lint工具,建议添加以下工具:
|
||
|
||
**可选配置(如需要):**
|
||
```bash
|
||
# 安装格式化工具
|
||
pip install black isort ruff
|
||
|
||
# 代码格式化
|
||
black .
|
||
isort .
|
||
ruff check --fix
|
||
|
||
# 类型检查(如需)
|
||
pip install mypy
|
||
mypy .
|
||
```
|
||
|
||
### 3. 运行测试
|
||
```bash
|
||
# 运行所有测试
|
||
pytest tests/
|
||
|
||
# 运行特定模块测试
|
||
pytest tests/test_unified_router.py
|
||
|
||
# 运行带详细输出
|
||
pytest -v
|
||
|
||
# 运行并输出覆盖率
|
||
pytest --cov=. --cov-report=html
|
||
```
|
||
|
||
### 4. 代码提交前检查
|
||
1. 确保测试通过
|
||
2. 检查代码格式(如配置了lint工具)
|
||
3. 更新相关文档
|
||
4. 验证API接口
|
||
|
||
## 数据库操作
|
||
|
||
### 迁移脚本
|
||
```bash
|
||
# 数据库迁移
|
||
python scripts/migrate/auto_migrate.py
|
||
|
||
# Tortoise-ORM迁移
|
||
python scripts/migrate/migrate_with_tortoise.py
|
||
```
|
||
|
||
### 模型定义
|
||
```python
|
||
from tortoise.models import Model
|
||
from tortoise import fields
|
||
|
||
class MaterialStaging(Model):
|
||
"""物料暂存表"""
|
||
id = fields.IntField(pk=True)
|
||
MaterialNo = fields.CharField(max_length=50)
|
||
MaterialName = fields.CharField(max_length=255)
|
||
# 注意:列名使用PascalCase
|
||
|
||
class Meta:
|
||
table = "t_material_staging" # 表名使用snake_case
|
||
```
|
||
|
||
## 前端约定
|
||
|
||
### HTML/JS约定
|
||
1. **样式**: 使用Bootstrap 5.x
|
||
2. **图标**: 使用Bootstrap Icons (`bi-*`)
|
||
3. **字体**: 整个页面统一使用等宽字体
|
||
4. **布局**: 偏好卡片布局而非列表布局
|
||
5. **颜色**: 特定颜色使用十六进制值(如`#ff9300`)
|
||
|
||
### 错误提示
|
||
1. **布局**: 横版布局,错误类型横向排列
|
||
2. **样式**: 统一错误高亮提示样式
|
||
3. **交互**: 手型光标用于可交互元素,插入光标用普通指针
|
||
|
||
### 验证规则显示
|
||
- 必填字段、枚举字段、业务规则块左右排列
|
||
- 内容在每个块内垂直分布
|
||
- 必填星号紧贴字段名右侧
|
||
|
||
## 部署配置
|
||
|
||
### 环境变量
|
||
复制`.env.example`(如存在)或创建`.env`文件:
|
||
```bash
|
||
# 应用配置
|
||
PORT=8000
|
||
HOST=0.0.0.0
|
||
LOG_LEVEL=INFO
|
||
|
||
# 数据库配置
|
||
DB_HOST=localhost
|
||
DB_PORT=3306
|
||
DB_USER=root
|
||
DB_PASSWORD=password
|
||
DB_NAME=myaps
|
||
|
||
# 功能开关
|
||
TURNON_BINLOG_LISTENER=False
|
||
TRUNON_SCHEDULER=False
|
||
|
||
# Staging模式配置
|
||
# 用于数据清洗模式的特殊数据库名称标识(默认--s)
|
||
STAGING_DB_NAME=--s
|
||
```
|
||
|
||
### Gunicorn配置
|
||
生产环境使用Gunicorn多进程配置:
|
||
```python
|
||
# scripts/deploy/gunicorn.conf.py
|
||
workers = 4
|
||
worker_class = "uvicorn.workers.UvicornWorker"
|
||
bind = "0.0.0.0:8000"
|
||
```
|
||
|
||
## 监控和调试
|
||
|
||
### 监控功能
|
||
- HTTP请求监控(`HTTPMonitorMiddleware`)
|
||
- 资源使用监控
|
||
- 数据库监控(binlog监听)
|
||
- 定时任务监控
|
||
|
||
### 调试技巧
|
||
1. 使用`scripts/dev_server.sh logs -f`实时查看日志
|
||
2. 检查`logs/`目录下的日志文件
|
||
3. 使用FastAPI自动生成的API文档(`/docs`和`/redoc`)
|
||
|
||
## 华为云CodeArts集成
|
||
|
||
项目已配置华为云CodeArts Doer:
|
||
- 配置文件位于`.codeartsdoer/`
|
||
- 技能配置在`.codeartsdoer/skills/`
|
||
- 规范配置在`.codeartsdoer/specs/`
|
||
|
||
## 注意事项
|
||
|
||
1. **代码质量**: 确保新代码遵循项目现有模式
|
||
2. **API兼容性**: 修改API时保持向后兼容
|
||
3. **错误处理**: 所有API端点应有适当的错误处理
|
||
4. **日志记录**: 重要操作需记录日志
|
||
5. **测试覆盖**: 新功能应包含单元测试
|
||
6. **配置管理**: 避免硬编码,使用环境变量和配置对象
|
||
7. **数据库命名**: 表名用snake_case,列名用PascalCase,注意大小写敏感
|
||
|
||
## 故障排除
|
||
|
||
### 常见问题
|
||
1. **端口占用**: 修改`.env`中的`PORT`配置
|
||
2. **数据库连接失败**: 检查数据库配置和环境变量
|
||
3. **依赖安装失败**: 使用离线包或调整pip源
|
||
4. **权限问题**: 确保`logs/`和`storage/`目录可写
|
||
|
||
### Tortoise ORM 初始化竞态条件
|
||
|
||
**问题描述**:
|
||
启动时偶尔出现"Tortoise ORM 初始化超时"错误,即使数据库可连接。
|
||
|
||
**根本原因**:
|
||
FastAPI启动时,`register_tortoise`异步初始化与`lifespan`检查存在竞态条件:
|
||
- PostgreSQL首次连接可能需要3-5秒
|
||
- 启动事件和lifespan并行执行
|
||
- 早期请求到达时,ORM可能未完全初始化
|
||
|
||
**解决方案**(已实施):
|
||
使用**事件驱动的智能等待机制**(非硬编码等待):
|
||
|
||
1. **DatabaseInitManager** (`core/db_init_manager.py`)
|
||
- 事件驱动:初始化完成后主动通知等待者
|
||
- 精确计时:记录实际初始化耗时
|
||
- 状态追踪:监控初始化进度
|
||
|
||
2. **启动事件通知** (`core/database.py`)
|
||
- `@app.on_event("startup")` 中标记初始化完成
|
||
- 通知所有等待的协程
|
||
|
||
3. **智能等待** (`core/lifespan.py`, `apps/common/utils/db_helpers.py`)
|
||
- 使用`asyncio.Event`而非轮询
|
||
- 实际等待时间 = 数据库真实初始化时间
|
||
- 超时保护:最多等待30秒
|
||
|
||
**对比传统方案**:
|
||
```python
|
||
# ❌ 旧方案:硬编码轮询
|
||
for i in range(20): # 固定等待10秒
|
||
await asyncio.sleep(0.5)
|
||
if Tortoise._inited:
|
||
break
|
||
|
||
# ✅ 新方案:事件驱动
|
||
result = await db_init_manager.wait_for_init(max_wait=30.0)
|
||
# 实际等待时间 = 数据库初始化实际耗时(通常1-3秒)
|
||
```
|
||
|
||
**相关配置**:
|
||
- `STAGING_DB_NAME`: 清洗模式数据库标识(默认`--s`)
|
||
- `THIS_DB_*`: PostgreSQL连接配置
|
||
|
||
### 调试指南
|
||
如需调试指导(如断点设置),请参考:
|
||
1. VS Code调试配置在`.vscode/`
|
||
2. 使用Python内置`pdb`模块
|
||
3. 或使用更高级的调试器如`debugpy`
|
||
|
||
---
|
||
|
||
**最后更新**: 2026-05-21
|
||
**维护者**: MyAPS开发团队
|
||
**版本**: 1.0.0 |