> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fim.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 贡献指南

> FIM One 贡献者的开发规范、类型安全、测试和代码质量标准。

<Tip>
  本页面涵盖开发规范和代码质量标准。如需完整的贡献指南——包括先锋计划、现场测试、PR 流程和社区链接——请参阅 [GitHub 上的 CONTRIBUTING.md](https://github.com/fim-ai/fim-one/blob/master/CONTRIBUTING.md)。
</Tip>

## 设置

前置条件：Python 3.11+、[uv](https://docs.astral.sh/uv/)、Node.js 18+、pnpm。

```bash theme={null}
git clone https://github.com/fim-ai/fim-one.git && cd fim-one
cp example.env .env                        # LLM_API_KEY is optional for contributors
uv sync --all-extras                       # Python dependencies
cd frontend && pnpm install && cd ..       # frontend dependencies
bash scripts/setup-hooks.sh                # pre-commit hooks (required)
```

<Note>
  `LLM_API_KEY` 仅在本地运行后端或在提交时预览自动翻译的区域设置输出时需要。没有密钥的贡献者仍然可以提交英文更改 — GitHub Actions 工作流在 PR 合并后在 `master` 上进行翻译。请参阅下面的 [i18n](#i18n)。
</Note>

验证一切正常：

```bash theme={null}
uv run pytest tests/ -x -q                # tests
uv run mypy src/fim_one/                   # type check
uv run ruff check src/                     # lint
cd frontend && pnpm build && cd ..         # frontend build
```

***

## 类型安全

mypy 严格模式已启用。整个代码库通过零错误检查，预提交钩子在每个暂存的 `.py` 文件上运行 mypy，并进行完整的导入链检查。

**规则：**

* 所有公共函数都需要类型提示。
* 除了 `import-untyped`（没有存根的第三方库）外，不允许使用 `# type: ignore`。
* 使用 `from __future__ import annotations` 来处理前向引用。
* 修复实际类型——永远不要通过抑制错误来让 CI 通过。

## 测试

每个新模块**必须**有对应的测试文件。每个功能提交**必须**包含测试。

| 约定 | 模式                           |
| -- | ---------------------------- |
| 文件 | `tests/test_{module}.py`     |
| 类  | `Test{Feature}`              |
| 方法 | `test_{behavior_under_test}` |

**规则：**

* 提交前所有现有测试必须通过：`uv run pytest tests/ -x -q`。
* 测试不得依赖外部服务 -- 使用 `unittest.mock` / `AsyncMock` 模拟数据库、MCP 服务器、HTTP 端点和 LLM 调用。
* 运行带覆盖率的测试：`uv run pytest --cov=fim_one`。

***

## 代码风格

* **异步优先。** 对于 I/O 绑定操作使用 `async def`。用 `asyncio.to_thread()` 包装同步调用，而不是阻塞事件循环。
* **使用 Ruff 进行代码检查。** `uv run ruff check src/` -- 行长度为 100 个字符。
* **最小化 `__init__.py` 导出。** 仅重新导出公共 API；保持内部符号私有。
* **包管理器。** Python 使用 `uv`，前端使用 `pnpm`。永远不要使用 `pip` 或 `npm`。

***

## Git 约定

**原子提交。** 每次提交包含一个逻辑变更。即使是一起开发的无关变更也要分开提交。

**提交信息格式：** `type: description`

| Type       | 何时使用       |
| ---------- | ---------- |
| `feat`     | 新的面向用户的功能  |
| `fix`      | 错误修复       |
| `refactor` | 代码重构，无行为变更 |
| `docs`     | 仅文档更新      |
| `test`     | 添加或更新测试    |
| `chore`    | 构建、CI、依赖更新 |

**不要跳过钩子** 使用 `--no-verify`。预提交管道的存在是为了在错误进入仓库之前捕获它们。

***

## 预提交钩子管道

钩子在每次提交时自动运行。它只处理与每个步骤相关的暂存文件——如果你只修改了Python文件，i18n步骤会被跳过，反之亦然。

| 顺序 | 步骤            | 触发条件                                                                           | 功能                                                  |
| -- | ------------- | ------------------------------------------------------------------------------ | --------------------------------------------------- |
| 0  | 语言环境编辑保护      | 任何`messages/{locale}/`、`docs/{locale}/`或`README.{locale}.md`下的暂存文件             | 中止提交——无法覆盖。通过`scripts/translation-glossary.md`修复翻译。 |
| 1  | OpenAPI规范重新生成 | `src/fim_one/web/**/*.py`已更改                                                   | 从FastAPI路由重新导出`docs/openapi.json`                   |
| 2  | i18n翻译        | `messages/en/*.json`、`docs/*.mdx`或`README.md`已更改（需要本地`LLM_API_KEY`，否则CI在合并后处理） | 将新增/更改的键翻译为所有目标语言                                   |
| 3  | mypy类型检查      | 任何`src/fim_one/**/*.py`已更改                                                     | 在暂存文件上运行mypy及完整导入链                                  |
| 4  | MDX验证         | 任何`.mdx`文件已暂存                                                                  | 在到达Mintlify之前验证JSX/MDX语法                            |

如果任何步骤失败，提交将被中止。修复报告的错误并重试。

## 国际化

FIM One 支持 6 种语言环境（EN、ZH、JA、KO、DE、FR）。翻译完全自动化。

**仅编辑英文源文件：**

* `frontend/messages/en/{namespace}.json` -- UI 字符串
* `docs/*.mdx`（根目录，不是语言环境子目录）-- 文档
* `README.md` -- 项目自述文件

其他语言环境文件（`messages/zh/`、`docs/zh/`、`README.zh.md` 等）是**自动生成的**，预提交钩子无条件拒绝手动编辑这些文件的提交。要修复翻译错误，请编辑 [`scripts/translation-glossary.md`](https://github.com/fim-ai/fim-one/blob/master/scripts/translation-glossary.md)——每个翻译规则的提示词注入单一信息源——然后使用 `uv run scripts/translate.py --files <en-sources> --force` 重新生成受影响的文件。每个词汇表修复都会永久应用于所有五种语言环境。

**生成语言环境文件的两条路径：**

1. **本地预提交钩子** -- 如果在 `.env` 中设置了 `LLM_API_KEY`，则运行。翻译在推送前进行，因此你可以预览输出。
2. **CI 备选方案** -- 如果本地钩子没有密钥并跳过，[`.github/workflows/i18n-sync.yml`](https://github.com/fim-ai/fim-one/blob/master/.github/workflows/i18n-sync.yml) 会在合并后在 `master` 上进行翻译，并自动提交结果。

没有 API 密钥的贡献者可以自由提交英文更改——CI 路径确保语言环境文件正确生成。

**添加新的国际化命名空间：** 创建 `messages/en/{ns}.json` -- 其他语言环境文件会在下次提交或合并后的 CI 上生成。

**强制完全重新翻译：** `uv run scripts/translate.py --all`（需要本地 `LLM_API_KEY`）。

## 数据库迁移

开发环境使用 SQLite，生产环境使用 PostgreSQL。一套 Alembic 迁移文件必须在两者上都能工作。

**关键规则：**

* 每个新的 ORM 模型或列**必须**有一个迁移 -- 永远不要依赖 `metadata.create_all()`。
* 所有迁移**必须**是幂等的 -- 使用 `fim_one.migrations.helpers` 中的辅助函数（`table_exists`、`table_has_column`、`index_exists`）。
* 布尔默认值：`server_default=sa.text("FALSE")` / `sa.text("TRUE")`。永远不要使用 `"0"` / `"1"` -- PostgreSQL 拒绝为布尔列使用整数字面量。
* SQLite 无法执行 `ALTER COLUMN` -- 对于列约束更改，使用 `op.batch_alter_table()`。
* 编写迁移后，立即运行 `uv run alembic upgrade head` 来应用它。

***

## 快速参考

```bash theme={null}
# Development
./start.sh dev                            # hot reload (Python + Next.js HMR)
./start.sh dev:api                        # API only, dev mode (hot reload)
./start.sh dev:ui                         # Frontend only, dev mode (HMR)
./start.sh api                            # FastAPI only (headless)

# Quality checks
uv run pytest tests/ -x -q               # tests (stop on first failure)
uv run pytest --cov=fim_one              # tests with coverage
uv run mypy src/fim_one/                  # type check
uv run ruff check src/                    # lint

# i18n
uv run scripts/translate.py --all         # force full retranslation

# Database
uv run alembic upgrade head               # apply migrations
uv run alembic revision -m "description"  # create new migration
```
