Files
meida_backend/pyproject.toml
T
xsl d5f366fa4c chore(prep): shared groundwork for the Sprint-2 parallel batch
第二批(T6~T11)协调提交:
- 迁移 0005:kb 七表(entity/relation/rule/chunk vector1024+tsv 生成列/
  asset/color/gap),HNSW+GIN 索引,FK 级联
- ORM:七个 Kb* 模型(pgvector Vector/TSVECTOR/Computed)
- 配置:检索与 embedding、华为 JWKS、短信全参数组
- 错误码:40110/40111/42910/42911/61000
- 骨架路由:kb.py + auth_sms.py(已注册);依赖:tencentcloud-sdk-python-sms
  + spike extra(onnxruntime/opencv);gitignore:models/ 与 spike 输出
2026-08-14 17:01:43 +08:00

165 lines
5.6 KiB
TOML
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
[project]
name = "meida-backend"
version = "0.1.0"
description = "美搭 · 智能穿搭美学助手服务端"
requires-python = ">=3.12"
dependencies = [
"fastapi>=0.115",
"uvicorn[standard]>=0.32",
"pydantic>=2.9",
"pydantic-settings>=2.6",
"sqlalchemy[asyncio]>=2.0.36",
"asyncpg>=0.30",
"alembic>=1.14",
"pgvector>=0.3.6",
"redis>=5.2",
"celery>=5.4",
"httpx>=0.28",
"tenacity>=9.0",
"pyjwt[crypto]>=2.9",
"structlog>=24.4",
"orjson>=3.10",
"prometheus-client>=0.21",
"cos-python-sdk-v5>=1.9.44",
"tencentcloud-sdk-python-sms>=3.1.153",
]
[project.optional-dependencies]
spike = [
# 算法验证 SPIKE(T-P0-10/12/16)专用;模型文件在 models/(已 gitignore)
"onnxruntime>=1.20",
"opencv-python-headless>=4.10",
]
dev = [
"pytest>=8.3",
"pytest-asyncio>=0.24",
"pytest-cov>=6.0",
"respx>=0.22",
"ruff>=0.8",
"mypy>=1.13",
"import-linter>=2.1",
"detect-secrets>=1.5",
"pre-commit>=4.0",
]
[build-system]
requires = ["setuptools>=75"]
build-backend = "setuptools.build_meta"
[tool.setuptools.packages.find]
include = ["apps*", "packages*", "services*"]
# ── ruff ────────────────────────────────────────────────────────────────────
[tool.ruff]
line-length = 100
target-version = "py312"
extend-exclude = ["migrations/versions"]
[tool.ruff.lint]
select = ["E", "F", "I", "N", "UP", "B", "SIM", "ASYNC", "C4", "RUF"]
# B008 与 FastAPI 的 Depends() 默认值写法直接冲突
ignore = ["B008", "RUF001", "RUF002", "RUF003"]
[tool.ruff.lint.per-file-ignores]
"tests/**" = ["SLF001"]
# ── pytest ──────────────────────────────────────────────────────────────────
[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
# 集成用例需要真实 PostgreSQL/Redis,默认不跑:`make test-integration` 显式开启
addopts = "-q --strict-markers --strict-config -m 'not integration' --cov=packages --cov=apps"
markers = ["integration: 需要真实 PostgreSQL / Redis(默认跳过)"]
[tool.coverage.run]
branch = true
source = ["packages", "apps"]
omit = ["*/__init__.py"]
[tool.coverage.report]
show_missing = true
skip_covered = true
# ── mypy ────────────────────────────────────────────────────────────────────
[tool.mypy]
python_version = "3.12"
plugins = ["pydantic.mypy"]
ignore_missing_imports = true
warn_unused_configs = true
warn_redundant_casts = true
warn_unused_ignores = true
no_implicit_reexport = true
disallow_untyped_defs = true
check_untyped_defs = true
# 领域层与 LLM 网关是钱与正确性的所在,按 strict 要求;外层逐步收紧。
[[tool.mypy.overrides]]
module = ["packages.domain.*", "packages.llm.*"]
strict = true
[[tool.mypy.overrides]]
module = ["tests.*", "migrations.*"]
disallow_untyped_defs = false
# ── import-linter:分层依赖(架构文档 §4.2)────────────────────────────────
# 这些契约用机器代替 code review 来守住依赖方向。没有它,
# "domain 不许 import 框架" 这类约定会在第一次赶工时悄悄破掉。
[tool.importlinter]
root_packages = ["apps", "packages", "services"]
include_external_packages = true
[[tool.importlinter.contracts]]
name = "分层:apps → packages → domain,不得逆向"
type = "layers"
# 配额(billing)、账号(identity)、任务中心(task)是被各业务域共用的能力,
# 因此排在业务域下方一层 —— Agent 要预扣配额、报告要建任务,这些依赖是正当的。
# 反向不成立:billing 不该知道 Agent 的存在。
layers = [
"apps",
"packages.agent | packages.report | packages.tryon | packages.wardrobe",
"packages.identity | packages.billing | packages.task | packages.compliance | packages.notify | packages.analytics | packages.storage",
"packages.kb | packages.retrieval | packages.rules | packages.memory | packages.profile",
"packages.llm",
"packages.shared",
"packages.domain",
]
[[tool.importlinter.contracts]]
name = "domain 层不依赖任何框架与 I/O"
type = "forbidden"
source_modules = ["packages.domain"]
forbidden_modules = [
"fastapi",
"starlette",
"sqlalchemy",
"alembic",
"celery",
"redis",
"httpx",
"pydantic_settings",
]
[[tool.importlinter.contracts]]
name = "业务包不得绕过网关直连大模型"
type = "forbidden"
source_modules = [
"packages.agent",
"packages.report",
"packages.identity",
"packages.billing",
"packages.task",
"packages.compliance",
]
forbidden_modules = ["packages.llm.providers"]
# 只禁直接 import。经由 packages.llm.gateway 的间接依赖是正常的 ——
# 要拦的是"业务代码自己拼 HTTP 请求",那样成本归因与熔断都会被绕过。
allow_indirect_imports = "true"
[[tool.importlinter.contracts]]
name = "apps 之间互不依赖"
type = "independence"
modules = ["apps.api", "apps.worker", "apps.admin"]
# 例外:API 投递异步任务需要 worker 的任务签名。这是投递方向(api → worker),
# 反向不允许 —— worker 不得 import apps.api,否则 worker 会被迫加载整个 HTTP 层。
ignore_imports = ["apps.api.routers.tasks -> apps.worker.tasks"]