按 2026-11-02 需求补齐计划交付后端能力: - 角色授权:权限目录化,接口统一准入校验,未登记默认拒绝; 管理员判断改为按数据库角色重新判定,防止权限码持有者绕过 - 系统监控:单进程采集资源、请求与异常指标,分钟级聚合, 阈值配置化;敏感配置增加 repr 保护,Redis 密码 URL 转义 - 试用期计提:按回款日判定并写入快照,年度结清与调整单联动; 人员模型补试用期、离职日期与工资版本历史字段 - 计提模板:公式骨架受控,页面维护名称与参数绑定 - T+ 采集:自动化配置表与进度查询 内置角色禁停用保护对齐模块注释;核算规则版本提为常量并 补充批量核算失败堆栈日志。 影响范围:后端全部模块、数据库迁移 V22-V28 验证:uv run ruff check 通过;922 个单元测试全部通过; 集成测试因本机 MySQL 数据卷被其他容器锁定暂未运行
116 lines
4.4 KiB
TOML
116 lines
4.4 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",
|
||
"openpyxl>=3.1.5",
|
||
"python-multipart>=0.0.32",
|
||
"psutil>=7.2,<8",
|
||
]
|
||
|
||
[project.optional-dependencies]
|
||
tplus = [
|
||
"pyodbc>=5.2,<6",
|
||
]
|
||
|
||
[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"
|