docs(dev): update contribution guide & agent instructions
This commit is contained in:
166
.github/copilot-instructions.md
vendored
Normal file
166
.github/copilot-instructions.md
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
# copilot-instruction
|
||||
|
||||
> 此文件是 AGENTS.md 的复制。一切以 AGENTS.md 为主。
|
||||
|
||||
> 使用自动化与 AI 代理(GitHub Copilot、依赖/CI 机器人,以及仓库中的运行时调度器/worker)的指导原则,适用于 g0v0-server 仓库。
|
||||
|
||||
---
|
||||
|
||||
## API 参考
|
||||
|
||||
本项目必须保持与公开的 osu! API 兼容。在添加或映射端点时请参考:
|
||||
|
||||
- **v1(旧版):** [https://github.com/ppy/osu-api/wiki](https://github.com/ppy/osu-api/wiki)
|
||||
- **v2(OpenAPI):** [https://osu.ppy.sh/docs/openapi.yaml](https://osu.ppy.sh/docs/openapi.yaml)
|
||||
|
||||
任何在 `app/router/v1/`、`app/router/v2/` 或 `app/router/notification/` 中的实现必须与官方规范保持一致。自定义或实验性的端点应放在 `app/router/private/` 中。
|
||||
|
||||
---
|
||||
|
||||
## 代理类别
|
||||
|
||||
允许的代理分为三类:
|
||||
|
||||
- **代码生成/补全代理**(如 GitHub Copilot 或其他 LLM)—— **仅当** 有维护者审核并批准输出时允许使用。
|
||||
- **自动维护代理**(如 Dependabot、Renovate、pre-commit.ci)—— 允许使用,但必须遵守严格的 PR 和 CI 政策。
|
||||
- **运行时/后台代理**(调度器、worker)—— 属于产品代码的一部分;必须遵守生命周期、并发和幂等性规范。
|
||||
|
||||
所有由代理生成或建议的更改必须遵守以下规则。
|
||||
|
||||
---
|
||||
|
||||
## 所有代理的规则
|
||||
|
||||
1. **单一职责的 PR。** 代理的 PR 必须只解决一个问题(一个功能、一个 bug 修复或一次依赖更新)。提交信息应使用 Angular 风格(如 `feat(api): add ...`)。
|
||||
2. **通过 Lint 与 CI 检查。** 每个 PR(包括代理创建的)在合并前必须通过 `pyright`、`ruff`、`pre-commit` 钩子和仓库 CI。PR 中应附带 CI 运行结果链接。
|
||||
3. **绝不可提交敏感信息。** 代理不得提交密钥、密码、token 或真实 `.env` 值。如果检测到可能的敏感信息,代理必须中止并通知指定的维护者。
|
||||
4. **API 位置限制。** 不得在 `app/router/v1` 或 `app/router/v2` 下添加新的公开端点,除非该端点在官方 v1/v2 规范中存在。自定义或实验性端点必须放在 `app/router/private/`。
|
||||
5. **保持公共契约稳定。** 未经批准的迁移计划,不得随意修改响应 schema、路由前缀或其他公共契约。若有变更,PR 中必须包含明确的兼容性说明。
|
||||
|
||||
---
|
||||
|
||||
## Copilot / LLM 使用
|
||||
|
||||
> 关于在本仓库中使用 GitHub Copilot 和其他基于 LLM 的辅助工具的统一指导。
|
||||
|
||||
### 关键项目结构(需要了解的内容)
|
||||
|
||||
- **应用入口:** `main.py` —— FastAPI 应用,包含启动/关闭生命周期管理(fetchers、GeoIP、调度器、缓存与健康检查、Redis 消息、统计、成就系统)。
|
||||
|
||||
- **路由:** `app/router/` 包含所有路由组。主要的路由包括:
|
||||
- `v1/`(v1 端点)
|
||||
- `v2/`(v2 端点)
|
||||
- `notification/` 路由(聊天/通知子系统)
|
||||
- `auth.py`(认证/token 流程)
|
||||
- `private/`(自定义或实验性的端点)
|
||||
|
||||
**规则:** `v1/` 和 `v2/` 必须与官方 API 对应。仅内部或实验端点应放在 `app/router/private/`。
|
||||
|
||||
- **模型与数据库工具:**
|
||||
- SQLModel/ORM 模型在 `app/database/`。
|
||||
- 非数据库模型在 `app/models/`。
|
||||
- 修改模型/schema 时必须生成 Alembic 迁移,并手动检查生成的 SQL 与索引。
|
||||
|
||||
- **服务层:** `app/service/` 保存领域逻辑(如缓存工具、通知/邮件逻辑)。复杂逻辑应放在 service,而不是路由处理器中。
|
||||
|
||||
- **任务:** `app/tasks/` 保存任务(定时任务、启动任务、关闭任务)。
|
||||
- 均在 `__init__.py` 进行导出。
|
||||
- 对于启动任务/关闭任务,在 `main.py` 的 `lifespan` 调用。
|
||||
- 定时任务使用 APScheduler
|
||||
|
||||
- **缓存与依赖:** 使用 `app/dependencies/` 提供的 Redis 依赖和缓存服务(遵循现有 key 命名约定,如 `user:{id}:...`)。
|
||||
|
||||
- **日志:** 使用 `app/log` 提供的日志工具。
|
||||
|
||||
### 实用工作流(提示模式)
|
||||
|
||||
- **添加 v2 端点(正确方式):** 在 `app/router/v2/` 下添加文件,导出路由,实现基于数据库与缓存依赖的异步处理函数。**不得**在 v1/v2 添加非官方端点。
|
||||
- **添加内部端点:** 放在 `app/router/private/`,保持处理器精简,将业务逻辑放入 `app/service/`。
|
||||
- **添加后台任务:** 将任务逻辑写在 `app/service/_job.py`(幂等、可重试)。调度器入口放在 `app/scheduler/_scheduler.py`,并在应用生命周期注册。
|
||||
- **数据库 schema 变更:** 修改 `app/models/` 中的 SQLModel 模型,运行 `alembic revision --autogenerate`,检查迁移并本地测试 `alembic upgrade head` 后再提交。
|
||||
- **缓存写入与响应:** 使用现有的 `UserResp` 模式和 `UserCacheService`;异步缓存写入应使用后台任务。
|
||||
|
||||
### 提示指导(给 LLM/Copilot 的输入)
|
||||
|
||||
- 明确文件位置和限制(如:`Add an async endpoint under app/router/private/... DO NOT add to app/router/v1 or v2`)。
|
||||
- 要求异步处理函数、依赖注入 DB/Redis、复用已有服务/工具、加上类型注解,并生成最小化 pytest 测试样例。
|
||||
|
||||
### 约定与质量要求
|
||||
|
||||
- **使用 Annotated-style 依赖注入** 在路由处理器中。
|
||||
- **提交信息风格:** `type(scope): subject`(Angular 风格)。
|
||||
- **优先异步:** 路由必须为异步函数;避免阻塞事件循环。
|
||||
- **关注点分离:** 业务逻辑应放在 service,而不是路由中。
|
||||
- **错误处理:** 客户端错误用 `HTTPException`,服务端错误使用结构化日志。
|
||||
- **类型与 lint:** 在请求评审前,代码必须通过 `pyright` 和 `ruff` 检查。
|
||||
- **注释:** 避免过多注释,仅为晦涩逻辑添加简洁的“魔法注释”。
|
||||
- **日志:** 使用 `app.log` 提供的 `log` 函数获取 logger 实例。(服务、任务除外)
|
||||
|
||||
### 工具参考
|
||||
|
||||
```
|
||||
uv sync
|
||||
pre-commit install
|
||||
pre-commit run --all-files
|
||||
pyright
|
||||
ruff .
|
||||
alembic revision --autogenerate -m "feat(db): ..."
|
||||
alembic upgrade head
|
||||
uvicorn main:app --reload --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
### PR 范围指导
|
||||
|
||||
- 保持 PR 专注:一次只做一件事(如端点或重构,不要混合)。
|
||||
- 不确定时,请参考现有服务,并添加简短说明性注释。
|
||||
|
||||
### PR 审核规则
|
||||
|
||||
> GitHub Copilot PR review 可参考。
|
||||
|
||||
1. 如果 PR 修改了端点,简要说明端点的用途和预期行为。同时检查是否满足上述的 API 位置限制。
|
||||
2. 如果 PR 修改了数据库模型,必须包含 Alembic 迁移。检查迁移的 SQL 语句和索引是否合理。
|
||||
3. 修改的其他功能需要提供简短的说明。
|
||||
4. 提供性能优化的建议(见下文)。
|
||||
|
||||
---
|
||||
|
||||
## 性能优化提示
|
||||
|
||||
以下为结合本仓库架构(FastAPI + SQLModel/SQLAlchemy、Redis 缓存、后台调度器)总结的性能优化建议:
|
||||
|
||||
### 数据库
|
||||
|
||||
- **仅选择必要字段。** 使用 `select(Model.col1, Model.col2)`,避免 `select(Model)`。
|
||||
|
||||
```py
|
||||
stmt = select(User.id, User.username).where(User.active == True)
|
||||
rows = await session.execute(stmt)
|
||||
```
|
||||
|
||||
- **使用 `select(exists())` 检查存在性。** 避免加载整行:
|
||||
|
||||
```py
|
||||
from sqlalchemy import select, exists
|
||||
exists_stmt = select(exists().where(User.id == some_id))
|
||||
found = await session.scalar(exists_stmt)
|
||||
```
|
||||
|
||||
- **避免 N+1 查询。** 需要关联对象时用 `selectinload`、`joinedload`。
|
||||
|
||||
- **批量操作。** 插入/更新时应批量执行,并放在一个事务中,而不是多个小事务。
|
||||
|
||||
|
||||
### 耗时任务
|
||||
|
||||
- 如果这个任务来自 API Router,请使用 FastAPI 提供的 [`BackgroundTasks`](https://fastapi.tiangolo.com/tutorial/background-tasks)
|
||||
- 其他情况,使用 `app.utils` 的 `bg_tasks`,它提供了与 FastAPI 的 `BackgroundTasks` 类似的功能。
|
||||
|
||||
---
|
||||
|
||||
## 部分 LLM 的额外要求
|
||||
|
||||
### Claude Code
|
||||
|
||||
- 禁止创建额外的测试脚本。
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -222,7 +222,6 @@ newrelic.ini
|
||||
logs/
|
||||
osu-server-spectator-master/*
|
||||
spectator-server/
|
||||
.github/copilot-instructions.md
|
||||
osu-web-master/*
|
||||
osu-web-master/.env.dusk.local.example
|
||||
osu-web-master/.env.example
|
||||
|
||||
195
AGENTS.md
195
AGENTS.md
@@ -1,117 +1,100 @@
|
||||
# AGENTS.md
|
||||
# AGENTS
|
||||
|
||||
> Guidelines for using automation and AI agents (GitHub Copilot, dependency/CI bots, and in-repo runtime schedulers/workers) with the g0v0-server repository.
|
||||
> 使用自动化与 AI 代理(GitHub Copilot、依赖/CI 机器人,以及仓库中的运行时调度器/worker)的指导原则,适用于 g0v0-server 仓库。
|
||||
|
||||
---
|
||||
|
||||
## API References
|
||||
## API 参考
|
||||
|
||||
This project must stay compatible with the public osu! APIs. Use these references when adding or mapping endpoints:
|
||||
本项目必须保持与公开的 osu! API 兼容。在添加或映射端点时请参考:
|
||||
|
||||
- **v1 (legacy):** [https://github.com/ppy/osu-api/wiki](https://github.com/ppy/osu-api/wiki)
|
||||
- **v2 (OpenAPI):** [https://osu.ppy.sh/docs/openapi.yaml](https://osu.ppy.sh/docs/openapi.yaml)
|
||||
- **v1(旧版):** [https://github.com/ppy/osu-api/wiki](https://github.com/ppy/osu-api/wiki)
|
||||
- **v2(OpenAPI):** [https://osu.ppy.sh/docs/openapi.yaml](https://osu.ppy.sh/docs/openapi.yaml)
|
||||
|
||||
Any implementation in `app/router/v1/`, `app/router/v2/`, or `app/router/notification/` must match official endpoints from the corresponding specification above. Custom or experimental endpoints belong in `app/router/private/`.
|
||||
任何在 `app/router/v1/`、`app/router/v2/` 或 `app/router/notification/` 中的实现必须与官方规范保持一致。自定义或实验性的端点应放在 `app/router/private/` 中。
|
||||
|
||||
---
|
||||
|
||||
## Agent Categories
|
||||
## 代理类别
|
||||
|
||||
Agents are allowed in three categories:
|
||||
允许的代理分为三类:
|
||||
|
||||
- **Code authoring / completion agents** (e.g. GitHub Copilot or other LLMs) — allowed **only** when a human maintainer reviews and approves the output.
|
||||
- **Automated maintenance agents** (e.g. Dependabot, Renovate, pre-commit.ci) — allowed but must follow strict PR and CI policies.
|
||||
- **Runtime / background agents** (schedulers, workers) — part of the product code; must follow lifecycle, concurrency, and idempotency conventions.
|
||||
- **代码生成/补全代理**(如 GitHub Copilot 或其他 LLM)—— **仅当** 有维护者审核并批准输出时允许使用。
|
||||
- **自动维护代理**(如 Dependabot、Renovate、pre-commit.ci)—— 允许使用,但必须遵守严格的 PR 和 CI 政策。
|
||||
- **运行时/后台代理**(调度器、worker)—— 属于产品代码的一部分;必须遵守生命周期、并发和幂等性规范。
|
||||
|
||||
All changes produced or suggested by agents must comply with the rules below.
|
||||
所有由代理生成或建议的更改必须遵守以下规则。
|
||||
|
||||
---
|
||||
|
||||
## Rules for All Agents
|
||||
## 所有代理的规则
|
||||
|
||||
1. **Human review required.** Any code, configuration, or documentation generated by an AI or automation agent must be reviewed and approved by a human maintainer familiar with g0v0-server. Do not merge agent PRs without explicit human approval.
|
||||
2. **Single-responsibility PRs.** Agent PRs must address one concern only (one feature, one bugfix, or one dependency update). Use Angular-style commit messages (e.g. `feat(api): add ...`).
|
||||
3. **Lint & CI compliance.** Every PR (including agent-created ones) must pass `pyright`, `ruff`, `pre-commit` hooks, and the repository CI before merging. Include links to CI runs in the PR.
|
||||
4. **Never commit secrets.** Agents must not add keys, passwords, tokens, or real `.env` values. If a suspected secret is detected, the agent must abort and notify a designated human.
|
||||
5. **API location constraints.** Do not add new public endpoints under `app/router/v1` or `app/router/v2` unless the endpoints exist in the official v1/v2 specs. Custom or experimental endpoints must go under `app/router/private/`.
|
||||
6. **Stable public contracts.** Avoid changing response schemas, route prefixes, or other public contracts without an approved migration plan and explicit compatibility notes in the PR.
|
||||
1. **单一职责的 PR。** 代理的 PR 必须只解决一个问题(一个功能、一个 bug 修复或一次依赖更新)。提交信息应使用 Angular 风格(如 `feat(api): add ...`)。
|
||||
2. **通过 Lint 与 CI 检查。** 每个 PR(包括代理创建的)在合并前必须通过 `pyright`、`ruff`、`pre-commit` 钩子和仓库 CI。PR 中应附带 CI 运行结果链接。
|
||||
3. **绝不可提交敏感信息。** 代理不得提交密钥、密码、token 或真实 `.env` 值。如果检测到可能的敏感信息,代理必须中止并通知指定的维护者。
|
||||
4. **API 位置限制。** 不得在 `app/router/v1` 或 `app/router/v2` 下添加新的公开端点,除非该端点在官方 v1/v2 规范中存在。自定义或实验性端点必须放在 `app/router/private/`。
|
||||
5. **保持公共契约稳定。** 未经批准的迁移计划,不得随意修改响应 schema、路由前缀或其他公共契约。若有变更,PR 中必须包含明确的兼容性说明。
|
||||
|
||||
---
|
||||
|
||||
## Copilot / LLM Usage
|
||||
## Copilot / LLM 使用
|
||||
|
||||
> Consolidated guidance for using GitHub Copilot and other LLM-based helpers with this repository.
|
||||
> 关于在本仓库中使用 GitHub Copilot 和其他基于 LLM 的辅助工具的统一指导。
|
||||
|
||||
### Key project structure (what you should know)
|
||||
### 关键项目结构(需要了解的内容)
|
||||
|
||||
- **App entry:** `main.py` — FastAPI application with lifespan startup/shutdown orchestration (fetchers, GeoIP, schedulers, cache and health checks, Redis messaging, stats, achievements).
|
||||
- **应用入口:** `main.py` —— FastAPI 应用,包含启动/关闭生命周期管理(fetchers、GeoIP、调度器、缓存与健康检查、Redis 消息、统计、成就系统)。
|
||||
|
||||
- **Routers:** `app/router/` contains route groups. Important routers exposed by the project include:
|
||||
- **路由:** `app/router/` 包含所有路由组。主要的路由包括:
|
||||
- `v1/`(v1 端点)
|
||||
- `v2/`(v2 端点)
|
||||
- `notification/` 路由(聊天/通知子系统)
|
||||
- `auth.py`(认证/token 流程)
|
||||
- `private/`(自定义或实验性的端点)
|
||||
|
||||
- `api_v1_router` (v1 endpoints)
|
||||
- `api_v2_router` (v2 endpoints)
|
||||
- `notification` routers (chat/notification subsystems)
|
||||
- `auth_router` (authentication/token flows)
|
||||
- `private_router` (internal or server-specific endpoints)
|
||||
**规则:** `v1/` 和 `v2/` 必须与官方 API 对应。仅内部或实验端点应放在 `app/router/private/`。
|
||||
|
||||
**Rules:** `v1/` and `v2/` must mirror the official APIs. Put internal-only or experimental endpoints under `app/router/private/`.
|
||||
- **模型与数据库工具:**
|
||||
- SQLModel/ORM 模型在 `app/database/`。
|
||||
- 非数据库模型在 `app/models/`。
|
||||
- 修改模型/schema 时必须生成 Alembic 迁移,并手动检查生成的 SQL 与索引。
|
||||
|
||||
- **Models & DB helpers:**
|
||||
- **服务层:** `app/service/` 保存领域逻辑(如缓存工具、通知/邮件逻辑)。复杂逻辑应放在 service,而不是路由处理器中。
|
||||
|
||||
- SQLModel/ORM models live in `app/models/`.
|
||||
- DB access helpers and table-specific helpers live in `app/database/`.
|
||||
- For model/schema changes, draft an Alembic migration and manually review the generated SQL and indexes before applying.
|
||||
- **任务:** `app/tasks/` 保存任务(定时任务、启动任务、关闭任务)。
|
||||
- 均在 `__init__.py` 进行导出。
|
||||
- 对于启动任务/关闭任务,在 `main.py` 的 `lifespan` 调用。
|
||||
- 定时任务使用 APScheduler
|
||||
|
||||
- **Services:** `app/service/` holds domain logic (e.g., user ranking calculation, caching helpers, notification/email logic). Heavy logic belongs in services rather than in route handlers.
|
||||
- **缓存与依赖:** 使用 `app/dependencies/` 提供的 Redis 依赖和缓存服务(遵循现有 key 命名约定,如 `user:{id}:...`)。
|
||||
|
||||
- **Schedulers:** `app/scheduler/` contains scheduler starters; implement `start_*_scheduler()` and `stop_*_scheduler()` and register them in `main.py` lifespan handlers.
|
||||
- **日志:** 使用 `app/log` 提供的日志工具。
|
||||
|
||||
- **Caching & dependencies:** Use injected Redis dependencies from `app/dependencies/` and shared cache services (follow existing key naming conventions such as `user:{id}:...`).
|
||||
### 实用工作流(提示模式)
|
||||
|
||||
- **Rust/native extensions:** `packages/msgpack_lazer_api` is a native MessagePack encoder/decoder. When changing native code, run `maturin develop -R` and validate compatibility with Python bindings.
|
||||
- **添加 v2 端点(正确方式):** 在 `app/router/v2/` 下添加文件,导出路由,实现基于数据库与缓存依赖的异步处理函数。**不得**在 v1/v2 添加非官方端点。
|
||||
- **添加内部端点:** 放在 `app/router/private/`,保持处理器精简,将业务逻辑放入 `app/service/`。
|
||||
- **添加后台任务:** 将任务逻辑写在 `app/service/_job.py`(幂等、可重试)。调度器入口放在 `app/scheduler/_scheduler.py`,并在应用生命周期注册。
|
||||
- **数据库 schema 变更:** 修改 `app/models/` 中的 SQLModel 模型,运行 `alembic revision --autogenerate`,检查迁移并本地测试 `alembic upgrade head` 后再提交。
|
||||
- **缓存写入与响应:** 使用现有的 `UserResp` 模式和 `UserCacheService`;异步缓存写入应使用后台任务。
|
||||
|
||||
### Practical playbooks (prompt patterns)
|
||||
### 提示指导(给 LLM/Copilot 的输入)
|
||||
|
||||
- **Add a v2 endpoint (correct):** Add files under `app/router/v2/`, export the router, implement async path operations using DB and injected caching dependencies. Do **not** add non-official endpoints to v1/v2.
|
||||
- **Add an internal endpoint:** Add under `app/router/private/`; keep route handlers thin and move business logic into `app/service/`.
|
||||
- **Add a background job:** Put pure job logic in `app/service/_job.py` (idempotent, retry-safe). Add scheduler start/stop functions in `app/scheduler/_scheduler.py`, and register them in the app lifespan.
|
||||
- **DB schema changes:** Update SQLModel models in `app/models/`, run `alembic revision --autogenerate`, inspect the migration, and validate locally with `alembic upgrade head` before committing.
|
||||
- **Cache writes & responses:** Use existing `UserResp` patterns and `UserCacheService` where applicable; use background tasks for asynchronous cache writes.
|
||||
- 明确文件位置和限制(如:`Add an async endpoint under app/router/private/... DO NOT add to app/router/v1 or v2`)。
|
||||
- 要求异步处理函数、依赖注入 DB/Redis、复用已有服务/工具、加上类型注解,并生成最小化 pytest 测试样例。
|
||||
|
||||
### Prompt guidance (what to include for LLMs/Copilot)
|
||||
### 约定与质量要求
|
||||
|
||||
- Specify the exact file location and constraints (e.g. `Add an async endpoint under app/router/private/ ... DO NOT add to app/router/v1 or v2`).
|
||||
- Ask for asynchronous handlers, dependency injection for DB/Redis, reuse of existing services/helpers, type annotations, and a minimal pytest skeleton.
|
||||
- For native edits, require build instructions, ABI compatibility notes, and import validation steps.
|
||||
- **使用 Annotated-style 依赖注入** 在路由处理器中。
|
||||
- **提交信息风格:** `type(scope): subject`(Angular 风格)。
|
||||
- **优先异步:** 路由必须为异步函数;避免阻塞事件循环。
|
||||
- **关注点分离:** 业务逻辑应放在 service,而不是路由中。
|
||||
- **错误处理:** 客户端错误用 `HTTPException`,服务端错误使用结构化日志。
|
||||
- **类型与 lint:** 在请求评审前,代码必须通过 `pyright` 和 `ruff` 检查。
|
||||
- **注释:** 避免过多注释,仅为晦涩逻辑添加简洁的“魔法注释”。
|
||||
- **日志:** 使用 `app.log` 提供的 `log` 函数获取 logger 实例。(服务、任务除外)
|
||||
|
||||
### Conventions & quality expectations
|
||||
|
||||
- **Commit message style:** `type(scope): subject` (Angular-style).
|
||||
- **Async-first:** Route handlers must be async; avoid blocking the event loop.
|
||||
- **Separation of concerns:** Business logic should live in services, not inside route handlers.
|
||||
- **Error handling:** Use `HTTPException` for client errors and structured logging for server-side issues.
|
||||
- **Types & linting:** Aim for `pyright`-clean, `ruff`-clean code before requesting review.
|
||||
- **Comments:** Avoid excessive inline comments. Add short, targeted comments to explain non-obvious or "magical" behavior.
|
||||
|
||||
### Human reviewer checklist
|
||||
|
||||
- Is the code async and non-blocking, with heavy logic in `app/service/`?
|
||||
- Are DB and Redis dependencies injected via the project's dependency utilities?
|
||||
- Are existing cache keys and services reused consistently?
|
||||
- Are tests or test skeletons present and runnable?
|
||||
- If models changed: is an Alembic migration drafted, reviewed, and applied locally?
|
||||
- If native code changed: was `maturin develop -R` executed and validated?
|
||||
- Do `pyright` and `ruff` pass locally?
|
||||
|
||||
### Merge checklist
|
||||
|
||||
- Run `uv sync` to install/update dependencies.
|
||||
- Run `pre-commit` hooks and fix any failures.
|
||||
- Run `pyright` and `ruff` locally and resolve issues.
|
||||
- If native modules changed: run `maturin develop -R`.
|
||||
- If DB migrations changed: run `alembic upgrade head` locally to validate.
|
||||
|
||||
### Tooling reference
|
||||
### 工具参考
|
||||
|
||||
```
|
||||
uv sync
|
||||
@@ -119,34 +102,41 @@ pre-commit install
|
||||
pre-commit run --all-files
|
||||
pyright
|
||||
ruff .
|
||||
maturin develop -R # when native modules changed
|
||||
alembic revision --autogenerate -m "feat(db): ..."
|
||||
alembic upgrade head
|
||||
uvicorn main:app --reload --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
### PR scope guidance
|
||||
### PR 范围指导
|
||||
|
||||
- Keep PRs focused: one concern per PR (e.g., endpoint OR refactor, not both).
|
||||
- Update README/config docs when adding new environment variables.
|
||||
- If unsure about conventions, align with the closest existing service and leave a clarifying comment.
|
||||
- 保持 PR 专注:一次只做一件事(如端点或重构,不要混合)。
|
||||
- 不确定时,请参考现有服务,并添加简短说明性注释。
|
||||
|
||||
### PR 审核规则
|
||||
|
||||
> GitHub Copilot PR review 可参考。
|
||||
|
||||
1. 如果 PR 修改了端点,简要说明端点的用途和预期行为。同时检查是否满足上述的 API 位置限制。
|
||||
2. 如果 PR 修改了数据库模型,必须包含 Alembic 迁移。检查迁移的 SQL 语句和索引是否合理。
|
||||
3. 修改的其他功能需要提供简短的说明。
|
||||
4. 提供性能优化的建议(见下文)。
|
||||
|
||||
---
|
||||
|
||||
## Performance Tips
|
||||
## 性能优化提示
|
||||
|
||||
Below are practical, project-specific performance tips derived from this repository's architecture (FastAPI + SQLModel/SQLAlchemy, Redis caching, background schedulers, and a Rust-native messagepack module).
|
||||
以下为结合本仓库架构(FastAPI + SQLModel/SQLAlchemy、Redis 缓存、后台调度器)总结的性能优化建议:
|
||||
|
||||
### Database
|
||||
### 数据库
|
||||
|
||||
- **Select only required fields.** Fetch only the columns you need using `select(Model.col1, Model.col2)` instead of `select(Model)`.
|
||||
- **仅选择必要字段。** 使用 `select(Model.col1, Model.col2)`,避免 `select(Model)`。
|
||||
|
||||
```py
|
||||
stmt = select(User.id, User.username).where(User.active == True)
|
||||
rows = await session.execute(stmt)
|
||||
```
|
||||
|
||||
- **Use **``** for existence checks.** This avoids loading full rows:
|
||||
- **使用 `select(exists())` 检查存在性。** 避免加载整行:
|
||||
|
||||
```py
|
||||
from sqlalchemy import select, exists
|
||||
@@ -154,34 +144,21 @@ exists_stmt = select(exists().where(User.id == some_id))
|
||||
found = await session.scalar(exists_stmt)
|
||||
```
|
||||
|
||||
- **Avoid N+1 queries.** Use relationship loading strategies (`selectinload`, `joinedload`) when you need related objects.
|
||||
- **避免 N+1 查询。** 需要关联对象时用 `selectinload`、`joinedload`。
|
||||
|
||||
- **Batch operations.** For inserts/updates, use bulk or batched statements inside a single transaction rather than many small transactions.
|
||||
- **批量操作。** 插入/更新时应批量执行,并放在一个事务中,而不是多个小事务。
|
||||
|
||||
- **Indexes & EXPLAIN.** Add indexes on frequently filtered columns and use `EXPLAIN ANALYZE` to inspect slow queries.
|
||||
|
||||
- **Cursor / keyset pagination.** Prefer keyset pagination for large result sets instead of `OFFSET`/`LIMIT` to avoid high-cost scans.
|
||||
### 耗时任务
|
||||
|
||||
### Caching & Redis
|
||||
- 如果这个任务来自 API Router,请使用 FastAPI 提供的 [`BackgroundTasks`](https://fastapi.tiangolo.com/tutorial/background-tasks)
|
||||
- 其他情况,使用 `app.utils` 的 `bg_tasks`,它提供了与 FastAPI 的 `BackgroundTasks` 类似的功能。
|
||||
|
||||
- **Cache hot reads.** Use `UserCacheService` to cache heavy or frequently-requested responses and store compact serialized forms (e.g., messagepack via the native module).
|
||||
---
|
||||
|
||||
- **Use pipelines and multi/exec.** When performing multiple Redis commands, pipeline them to reduce roundtrips.
|
||||
## 部分 LLM 的额外要求
|
||||
|
||||
- **Set appropriate TTLs.** Avoid never-expiring keys; choose TTLs that balance freshness and read amplification.
|
||||
### Claude Code
|
||||
|
||||
- **Prevent cache stampedes.** Use early recompute with jitter or distributed locks (Redis `SET NX` or a small lock library) to avoid many processes rebuilding the same cache.
|
||||
- 禁止创建额外的测试脚本。
|
||||
|
||||
- **Atomic operations with Lua.** For complex multi-step Redis changes, consider a Lua script to keep operations atomic and fast.
|
||||
|
||||
### Background & Long-running Tasks
|
||||
|
||||
- **BackgroundTasks for lightweight work.** FastAPI's `BackgroundTasks` is fine for quick follow-up work (send email, async cache write). For heavy or long tasks, use a scheduler/worker (e.g., a dedicated async worker or job queue).
|
||||
|
||||
- **Use schedulers or workers for heavy jobs.** For expensive recalculations, use the repository's `app/scheduler/` pattern or an external worker system. Keep request handlers responsive — return quickly and delegate.
|
||||
|
||||
- **Throttling & batching.** When processing many items, batch them and apply concurrency limits (semaphore) to avoid saturating DB/Redis.
|
||||
|
||||
### API & Response Performance
|
||||
|
||||
- **Compress large payloads.** Enable gzip/deflate for large JSON responses
|
||||
|
||||
168
CONTRIBUTING.md
168
CONTRIBUTING.md
@@ -54,9 +54,123 @@ dotnet run --project osu.Server.Spectator --urls "http://0.0.0.0:8086"
|
||||
uv sync
|
||||
```
|
||||
|
||||
## 代码质量和代码检查
|
||||
## 开发规范
|
||||
|
||||
我们使用 `pre-commit` 在提交之前执行代码质量标准。这确保所有代码都通过 `ruff`(用于代码检查和格式化)和 `pyright`(用于类型检查)的检查。
|
||||
### 项目结构
|
||||
|
||||
以下是项目主要目录和文件的结构说明:
|
||||
|
||||
- `main.py`: FastAPI 应用的主入口点,负责初始化和启动服务器。
|
||||
- `pyproject.toml`: 项目配置文件,用于管理依赖项 (uv)、代码格式化 (Ruff) 和类型检查 (Pyright)。
|
||||
- `alembic.ini`: Alembic 数据库迁移工具的配置文件。
|
||||
- `app/`: 存放所有核心应用代码。
|
||||
- `router/`: 包含所有 API 端点的定义,根据 API 版本和功能进行组织。
|
||||
- `service/`: 存放核心业务逻辑,例如用户排名计算、每日挑战处理等。
|
||||
- `database/`: 定义数据库模型 (SQLModel) 和会话管理。
|
||||
- `models/`: 定义非数据库模型和其他模型。
|
||||
- `tasks/`: 包含由 APScheduler 调度的后台任务和启动/关闭任务。
|
||||
- `dependencies/`: 管理 FastAPI 的依赖项注入。
|
||||
- `achievements/`: 存放与成就相关的逻辑。
|
||||
- `storage/`: 存储服务代码。
|
||||
- `fetcher/`: 用于从外部服务(如 osu! 官网)获取数据的模块。
|
||||
- `middleware/`: 定义中间件,例如会话验证。
|
||||
- `helpers/`: 存放辅助函数和工具类。
|
||||
- `config.py`: 应用配置,使用 pydantic-settings 管理。
|
||||
- `calculator.py`: 存放所有的计算逻辑,例如 pp 和等级。
|
||||
- `log.py`: 日志记录模块,提供统一的日志接口。
|
||||
- `const.py`: 定义常量。
|
||||
- `path.py`: 定义跨文件使用的常量。
|
||||
- `migrations/`: 存放 Alembic 生成的数据库迁移脚本。
|
||||
- `static/`: 存放静态文件,如 `mods.json`。
|
||||
|
||||
### 数据库模型定义
|
||||
|
||||
所有的数据库模型定义在 `app.database` 里,并且在 `__init__.py` 中导出。
|
||||
|
||||
如果这个模型的数据表结构和响应不完全相同,遵循 `Base` - `Table` - `Resp` 结构:
|
||||
|
||||
```python
|
||||
class ModelBase(SQLModel):
|
||||
# 定义共有内容
|
||||
...
|
||||
|
||||
|
||||
class Model(ModelBase, table=True):
|
||||
# 定义数据库表内容
|
||||
...
|
||||
|
||||
|
||||
class ModelResp(ModelBase):
|
||||
# 定义响应内容
|
||||
...
|
||||
|
||||
@classmethod
|
||||
def from_db(cls, db: Model) -> "ModelResp":
|
||||
# 从数据库模型转换
|
||||
...
|
||||
```
|
||||
|
||||
数据库模块名应与表名相同,定义了多个模型的除外。
|
||||
|
||||
如果你需要使用 Session,使用 `app.dependencies.database` 提供的 `with_db`,注意手动使用 `COMMIT`。
|
||||
|
||||
```python
|
||||
from app.dependencies.database import with_db
|
||||
|
||||
async with with_db() as session:
|
||||
...
|
||||
```
|
||||
|
||||
### Redis
|
||||
|
||||
根据你需要的用途选择对应的 Redis 客户端。如果你的用途较为复杂或趋向一个较大的系统,考虑再创建一个 Redis 连接。
|
||||
|
||||
- `redis_client` (db0):标准用途,存储字符串、哈希等常规数据。
|
||||
- `redis_message_client` (db1):用于消息缓存,存储聊天记录等。
|
||||
- `redis_binary_client` (db2):用于存储二进制数据,如音频文件等。
|
||||
- `redis_rate_limit_client` (db3):仅用于 FastAPI-Limiter 使用。
|
||||
|
||||
### API Router
|
||||
|
||||
所有的 API Router 定义在 `app.router` 里:
|
||||
|
||||
- `app/router/v2` 存放所有 osu! v2 API 实现,**不允许添加额外的,原 v2 API 不存在的 Endpoint**
|
||||
- `app/router/notification` **存放所有 osu! v2 API 聊天、通知和 BanchoBot 的实现,不允许添加额外的,原 v2 API 不存在的 Endpoint**
|
||||
- `app/router/v1` 存放所有 osu! v1 API 实现,**不允许添加额外的,原 v1 API 不存在的 Endpoint**
|
||||
- `app/router/auth.py` 存放账户鉴权/登录的 API
|
||||
- `app/router/private` 存放服务器自定义 API (g0v0 API),供其他服务使用
|
||||
|
||||
任何 Router 需要满足:
|
||||
|
||||
- 使用 Annotated-style 的依赖注入
|
||||
- 对于已经存在的依赖注入如 Database 和 Redis,使用 `app.dependencies` 中的实现
|
||||
- 需要拥有文档
|
||||
- 如果返回需要资源代理,使用 `app.helpers.asset_proxy_helper` 的 `asset_proxy_response` 装饰器。
|
||||
- 如果需要记录日志,请使用 `app.log` 提供的 `log` 函数获取一个 logger 实例
|
||||
|
||||
### Service
|
||||
|
||||
所有的核心业务逻辑放在 `app.service` 里:
|
||||
|
||||
- 业务逻辑需要要以类实现
|
||||
- 日志只需要使用 `app.log` 中的 `logger` 即可。服务器会对 Service 的日志进行包装。
|
||||
|
||||
### 定时任务/启动任务/关闭任务
|
||||
|
||||
均定义在 `app.tasks` 里。
|
||||
|
||||
- 均在 `__init__.py` 进行导出
|
||||
- 对于启动任务/关闭任务,在 `main.py` 的 `lifespan` 调用。
|
||||
- 定时任务使用 APScheduler
|
||||
|
||||
### 耗时任务
|
||||
|
||||
- 如果这个任务来自 API Router,请使用 FastAPI 提供的 [`BackgroundTasks`](https://fastapi.tiangolo.com/tutorial/background-tasks)
|
||||
- 其他情况,使用 `app.utils` 的 `bg_tasks`,它提供了与 FastAPI 的 `BackgroundTasks` 类似的功能。
|
||||
|
||||
### 代码质量和代码检查
|
||||
|
||||
使用 `pre-commit` 在提交之前执行代码质量标准。这确保所有代码都通过 `ruff`(用于代码检查和格式化)和 `pyright`(用于类型检查)的检查。
|
||||
|
||||
### 设置
|
||||
|
||||
@@ -70,19 +184,9 @@ pre-commit install
|
||||
|
||||
pre-commit 不提供 pyright 的 hook,您需要手动运行 `pyright` 检查类型错误。
|
||||
|
||||
## 提交信息指南
|
||||
### 提交信息指南
|
||||
|
||||
我们遵循 [AngularJS 提交规范](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commit-message-format) 来编写提交信息。这使得在查看项目历史记录时,信息更加可读且易于理解。
|
||||
|
||||
每条提交信息由 **标题**、**主体**和 **页脚** 三部分组成。
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
<BLANK LINE>
|
||||
<body>
|
||||
<BLANK LINE>
|
||||
<footer>
|
||||
```
|
||||
遵循 [AngularJS 提交规范](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commit-message-format) 来编写提交信息。
|
||||
|
||||
**类型** 必须是以下之一:
|
||||
|
||||
@@ -97,40 +201,16 @@ pre-commit 不提供 pyright 的 hook,您需要手动运行 `pyright` 检查
|
||||
* **ci**:持续集成相关的更改
|
||||
* **deploy**: 部署相关的更改
|
||||
|
||||
**范围** 可以是任何指定提交更改位置的内容。例如 `api`、`db`、`auth` 等等。
|
||||
**范围** 可以是任何指定提交更改位置的内容。例如 `api`、`db`、`auth` 等等。对整个项目的更改使用 `project`。
|
||||
|
||||
**主题** 包含对更改的简洁描述。
|
||||
|
||||
## 项目结构
|
||||
### 持续集成检查
|
||||
|
||||
以下是项目主要目录和文件的结构说明:
|
||||
所有提交应该通过以下 CI 检查:
|
||||
|
||||
- `main.py`: FastAPI 应用的主入口点,负责初始化和启动服务器。
|
||||
- `pyproject.toml`: 项目配置文件,用于管理依赖项 (uv)、代码格式化 (Ruff) 和类型检查 (Pyright)。
|
||||
- `alembic.ini`: Alembic 数据库迁移工具的配置文件。
|
||||
- `app/`: 存放所有核心应用代码。
|
||||
- `router/`: 包含所有 API 端点的定义,根据 API 版本和功能进行组织。
|
||||
- `service/`: 存放核心业务逻辑,例如用户排名计算、每日挑战处理等。
|
||||
- `database/`: 定义数据库模型 (SQLModel) 和会话管理。
|
||||
- `models/`: 定义非数据库模型和其他模型。
|
||||
- `scheduler/`: 包含由 APScheduler 调度的后台任务。
|
||||
- `dependencies/`: 管理 FastAPI 的依赖项注入。
|
||||
- `achievement.py`: 存放与成就相关的逻辑。
|
||||
- `storage/`: 存储服务代码。
|
||||
- `fetcher/`: 用于从外部服务(如 osu! 官网)获取数据的模块。
|
||||
- `config.py`: 应用配置,使用 pydantic-settings 管理。
|
||||
- `calculator.py`: 存放所有的计算逻辑,例如 pp 和等级。
|
||||
- `migrations/`: 存放 Alembic 生成的数据库迁移脚本。
|
||||
- `packages/`: 包含项目相关的独立包。
|
||||
- `msgpack_lazer_api/`: 基于 Rust 的高性能支持 lazer APIMod 的 MessagePack 解析模块,用于与 osu!lazer 客户端通信。
|
||||
- `static/`: 存放静态文件,如 `mods.json`。
|
||||
|
||||
## API Router 规范
|
||||
|
||||
- `app/router/v2` 存放所有 osu! v2 API 实现,不允许添加额外的,原 v2 API 不存在的 Endpoint
|
||||
- `app/router/notification` 存放所有 osu! v2 API 聊天和通知的实现,不允许添加额外的,原 v2 API 不存在的 Endpoint
|
||||
- `app/router/v1` 存放所有 osu! v1 API 实现,不允许添加额外的,原 v1 API 不存在的 Endpoint
|
||||
- `app/router/auth.py` 存放账户鉴权/登录的 API
|
||||
- `app/router/private` 存放服务器自定义 API,供其他服务使用
|
||||
- Ruff Lint
|
||||
- Pyright Lint
|
||||
- pre-commit
|
||||
|
||||
感谢您的贡献!
|
||||
|
||||
Reference in New Issue
Block a user