Skip to content

开发规范

框架版本要求

当前后端运行基线:

组件要求
Python>=3.10,<3.14
Node.js22.23.1(以仓库 .nvmrc 为准)
FastAPI>=0.109.2
Pydanticpydantic>=1.10.26,<2(v1 钉死;兼容层见 tg_signer/pydantic_compat.py
SQLAlchemy当前使用 1.x 风格 API
APScheduler进程内调度器,单后端实例运行

新增代码必须兼容 Python 3.10,不使用 3.11+ 专属语法。

Pydantic 使用规范

当前项目仍运行在 Pydantic v1:

  • 使用 BaseModelFieldvalidator 等 v1 API。
  • 不要在生产代码中直接引入 v2 专属的 field_validatorConfigDictmodel_validate,除非同时提供兼容层。
  • 对外 API schema 保持字段名稳定,新增字段优先设为可选并提供默认值。
  • 输入模型必须做边界校验,例如空字符串、超长文本、非法 URL 和非法枚举值。

如果后续迁移到 Pydantic v2:

  • 用兼容模块集中封装 model_dump / dictmodel_validate / parse_obj 差异。
  • 先迁移测试覆盖充分的边界模型,再迁移核心任务配置模型。
  • 不在业务服务中散落版本判断。

当前状态:依赖钉死为 pydantic>=1.10.26,<2(v1 路径)。统一使用 tg_signer.pydantic_compatmodel_validate / model_dump / try_import_field_validator)。业务模型与路由逐步迁入 compat,为后续放宽到 <3 预留兼容层。

SQLAlchemy 使用规范

当前项目使用 SQLAlchemy 1.x 风格:

  • 路由层通过依赖注入获取 Session
  • 服务函数接收显式 Session,不要在深层函数里隐式创建连接。
  • 写操作必须提交或回滚清晰,异常路径不要留下未关闭 session。
  • 查询结果对外返回前转换为 Pydantic / dict,不直接暴露 ORM 对象给前端。

新增索引或约束时需要同时说明查询场景、影响的写入路径和对已有数据的兼容性。

日志规范

  • 使用模块级 logger,例如 logging.getLogger("backend.tasks")
  • 不记录明文 token、密码、API key、session string、验证码。
  • 面向用户的任务日志写清楚动作、目标和失败原因。
  • 异常日志保留上下文,但避免把完整请求体或密钥写入日志。
  • 日志级别遵循:调试细节用 DEBUG,状态变化用 INFO,可恢复异常用 WARNING,功能失败用 ERROR

类型注解规范

  • 新增函数必须标注参数和返回值。
  • Python 3.10 使用内置泛型:dict[str, Any]list[str]
  • 可空值使用 Optional[T]T | None,同一文件内保持一致。
  • 对 JSON-like 配置使用 dict[str, Any],不要用裸 dict 扩散到新代码。
  • 公共服务方法的返回类型要表达失败语义,例如 Optional[dict[str, Any]] 或显式结果对象。

代码变更原则

  • 优先保持现有模块边界,避免把路由、持久化和执行逻辑混在一起。
  • 文件写入使用原子写入或明确锁保护,避免损坏用户配置。
  • 后台任务必须记录异常,不能让 asyncio.create_task 的异常静默丢失。
  • 新增环境变量必须同步更新 docs/reference/configuration.md
  • 涉及部署行为的变更必须同步更新 docs/deploy/docker.mddocs/reference/ops.md

测试规范

测试基础设施

测试目录 tests/ 下包含完整的测试基础设施:

目录/文件说明
conftest.py全局 fixtures(数据库会话、测试客户端、Mock 对象)
fixtures/预定义测试数据(账号、任务、消息)
mocks/Mock 对象(Telegram 客户端、数据库会话、AI 服务)
factories/测试数据工厂(AccountFactory、TaskFactory 等)
utils/测试辅助函数(时间工具、环境管理、断言增强)

运行测试

bash
# 运行全部测试
pytest

# 运行指定模块
pytest tests/test_core.py -v

# 运行并查看覆盖率
pytest --cov=tg_signer --cov-report=term-missing

# 跳过覆盖率阈值检查(用于新增 backend/ 模块测试)
pytest --no-cov

前端测试

前端使用 Vitest 进行单元测试:

bash
nvm use
cd frontend

# 运行全部测试
npm test

# 监听模式
npm run test:watch

测试文件位于 frontend/src/test/ 目录。

本地、GitHub Actions 和 Docker 前端构建统一使用 .nvmrc 指定的 Node.js 22.23.1。不要使用其他 Node 主版本验证后直接提交;升级 Node 时必须同步更新 .nvmrc、两个 package.jsonengines、Dockerfile,并重新运行完整前端测试与构建。

jsdom 与 Node Web API 测试约束

Vitest 的 jsdom 环境和 Node/Undici 可能分别提供 BlobFileResponseReadableStream 等 Web API。不同 realm 的对象即使名称相同,也不保证可以互相传递。

  • 构造真实 Response 测试夹具时,正文优先使用字符串或字节数组,再通过 response.blob() 验证 Blob 消费路径。
  • 不要把 jsdom 创建的 Blob 直接传给 Node/Undici 的 Response;这在部分平台会因 缺少兼容的 stream() 方法而失败。
  • 必须测试流异常时,使用 ReadableStream 明确触发 controller.error(),不要伪造可重复 读取的简化响应对象。
  • fake timer 与异步断言应放入同一个已等待的 Promise.all(),避免留下未等待的 expect(...).resolves
  • 涉及 Node Web API 的测试在提交前至少执行 nvm use && cd frontend && npm test,并运行 npm run typechecknpm run build

覆盖率配置

pyproject.toml 中配置了 pytest-cov:

  • fail_under 阈值为 40%,同时统计 tg_signerbackend 两个包(addopts--cov=tg_signer --cov=backend
  • 新增测试用例时,优先覆盖核心逻辑和边界条件

新增依赖

近期新增的运行时依赖:

依赖用途
aiofiles异步文件读写(历史/配置等可选非阻塞 IO)
psutil>=5.9.0内存监控(backend/utils/memory_monitor.py

前端新增依赖:

依赖用途
vue-i18n@9多语言支持(中英文切换)

前端 API 请求超时

统一入口:frontend/src/lib/api/core.ts

常量默认用途
DEFAULT_TIMEOUT_MS30s普通 JSON API;覆盖发起到 body 读完
MEDIUM_TIMEOUT_MS120sWebDAV 探测/列表、设备保活、会话检测、聊天列表等
LONG_TIMEOUT_MS600s完整备份、WebDAV 下载、配置导入导出、同步 run

说明:

  • request / requestBlob / requestText:整段墙钟超时(headers + body)。
  • 直接 fetchWithAuth:仅 TTFB;长任务应外层 createRequestAbort 覆盖 body。
  • 超时 → NETWORK_TIMEOUT;调用方 AbortSignal 取消 → NETWORK_ABORTED
  • 页面轮询优先用 startChainPoll,避免 setInterval + async 叠请求。

基于 VitePress 构建 · 默认 SQLite,可选 PostgreSQL