后端 FastAPI 六层结构(api/services/repositories/models/schemas/core), 统一响应信封、全局异常、日志脱敏;6 张表经 Alembic 迁移建库,SQL 留存 db/migration;登录鉴权含图形验证码(Redis GETDEL 防重放)、JWT、登录限流、 登出黑名单(TTL=令牌剩余有效期)、登录日志。 前端 Vue3 + TS + Element Plus 骨架,含登录页、路由守卫、请求封装与 Vite 代理。 工程配置:uv 锁定 Python 3.12、ruff 检查与格式化、editorconfig、gitattributes。 测试 184 项(单元 155 / 集成 29)全绿,浏览器端到端 8 项通过。 Co-Authored-By: Claude Code <noreply@anthropic.com>
108 lines
4.3 KiB
TOML
108 lines
4.3 KiB
TOML
[project]
|
||
name = "payroll-backend"
|
||
version = "0.1.0"
|
||
description = "衍水集团营销人员工资管理系统 —— 后端服务"
|
||
readme = "README.md"
|
||
# 锁定 3.12:系统默认是 3.14,第三方库轮子覆盖不如 3.12 完备
|
||
requires-python = ">=3.12,<3.13"
|
||
|
||
dependencies = [
|
||
"fastapi>=0.115",
|
||
# starlette 已进入 1.x(当前 1.7.0)。FastAPI 对它的约束是 `starlette>=0.46.0`,
|
||
# **没有上界** —— uv lock --upgrade 时可能漂移到未验证的大版本。
|
||
# 我们的异常处理器与 TestClient 直接依赖其 API,故显式限定主版本。
|
||
# 当前组合(fastapi 0.143 + starlette 1.7.0)已实测通过全部用例。
|
||
"starlette>=1.7,<2",
|
||
"uvicorn[standard]>=0.32",
|
||
"pydantic>=2.9",
|
||
"pydantic-settings>=2.6",
|
||
# ORM 与驱动:采用同步 —— 本项目并发极低,异步无吞吐收益;
|
||
# 而重活(绩效批量核算、pandas 报表、Excel 导出)全是同步阻塞代码,
|
||
# 在异步路由里跑会卡死事件循环。同步路由由 FastAPI 自动放入线程池执行。
|
||
"sqlalchemy>=2.0.36",
|
||
# 必须带 [rsa]:MySQL 8.0 默认 caching_sha2_password,容器重启后首次连接走
|
||
# 全量认证需要 cryptography 做 RSA 交换,缺失时 PyMySQL 直接抛 RuntimeError
|
||
# (报错出现在建连阶段,极易被误读成"密码错误")
|
||
"pymysql[rsa]>=1.2.3",
|
||
"alembic>=1.14",
|
||
# 验证码、登录限流、Token 黑名单
|
||
"redis[hiredis]>=5.2",
|
||
# 鉴权与密码哈希
|
||
# 注意:不用 passlib —— 它与 bcrypt>=4.1 存在 __about__ 属性缺失的不兼容问题
|
||
"pyjwt>=2.10",
|
||
"pwdlib[bcrypt]>=0.2",
|
||
# 图形验证码(纯 Python,依赖 Pillow)
|
||
"captcha>=0.6",
|
||
"pillow>=11.0",
|
||
]
|
||
|
||
[dependency-groups]
|
||
dev = [
|
||
"pytest>=8.3",
|
||
"pytest-cov>=7",
|
||
"httpx>=0.28,<1.0",
|
||
# 用假 Redis 做单测,无需起容器即可覆盖 GETDEL 一次性语义
|
||
"fakeredis>=2.30",
|
||
# lint + format 二合一,替代 flake8 + isort + black
|
||
"ruff>=0.14",
|
||
]
|
||
|
||
# 本项目按应用而非库来管理,不打包安装自身
|
||
[tool.uv]
|
||
package = false
|
||
|
||
[tool.pytest.ini_options]
|
||
testpaths = ["tests"]
|
||
markers = [
|
||
"integration: 需要 MySQL/Redis 容器或完整应用实例的测试",
|
||
]
|
||
|
||
# ==================== 代码检查与格式化 ====================
|
||
|
||
[tool.ruff]
|
||
# 与项目根 .editorconfig 保持一致:Python 用 4 空格(缩进由 formatter 控制)
|
||
target-version = "py312"
|
||
line-length = 100
|
||
src = ["app", "tests"]
|
||
|
||
[tool.ruff.lint]
|
||
select = [
|
||
"E", # pycodestyle 错误
|
||
"W", # pycodestyle 警告
|
||
"F", # pyflakes:未使用的导入、未定义的名称等
|
||
"I", # isort:导入顺序
|
||
"B", # flake8-bugbear:常见陷阱(可变默认参数、循环引用等)
|
||
"C4", # flake8-comprehensions:推导式可简化处
|
||
"UP", # pyupgrade:按目标 Python 版本升级旧写法
|
||
"SIM", # flake8-simplify:可简化的分支与判断
|
||
"RUF", # ruff 自有规则
|
||
]
|
||
ignore = [
|
||
# 行宽已由 formatter 控制,lint 不再重复报——长中文注释很容易触发
|
||
"E501",
|
||
# FastAPI 的依赖注入要求在参数默认值处调用 Depends(),是框架约定而非缺陷。
|
||
# 项目内已尽量改用 Annotated 形式(见 api/deps.py),此处兜底。
|
||
"B008",
|
||
# RUF001/002/003 检查「易混淆的 Unicode 字符」,分别针对字符串字面量、
|
||
# 文档字符串、注释 —— 这套规则的默认前提是英文文本。
|
||
# 对中文会把全角逗号、句号、括号、冒号全部判定为混淆字符(本项目实测 800+ 条),
|
||
# 而中文里全角标点正是规范写法,故一并关闭。
|
||
"RUF001",
|
||
"RUF002",
|
||
"RUF003",
|
||
]
|
||
|
||
[tool.ruff.lint.isort]
|
||
# 必须显式声明:本项目 `[tool.uv] package = false`(不作为包安装),
|
||
# ruff 无法从项目布局推断出 `app` 是第一方包,否则会把第三方依赖
|
||
# 排到 `app.*` 之后(按字母序把两者当成同一组)。
|
||
known-first-party = ["app", "tests"]
|
||
|
||
[tool.ruff.lint.per-file-ignores]
|
||
# Alembic 自动生成的迁移脚本不按手写代码的标准要求。
|
||
# 这些文件由 `alembic revision --autogenerate` 产出,手工修 lint 会在下次生成时被覆盖。
|
||
"alembic/versions/*.py" = ["E501", "I001", "W291"]
|
||
|
||
[tool.ruff.format]
|
||
quote-style = "double"
|