diff --git a/docs/de/reference/translation-status.md b/docs/de/reference/translation-status.md
index f63f9ee..0473b62 100644
--- a/docs/de/reference/translation-status.md
+++ b/docs/de/reference/translation-status.md
@@ -21,12 +21,12 @@ Die unten stehenden Zahlen zählen die Markdown-Seiten im Verzeichnisbaum jeder
| 🇬🇧 Englisch (`en`) | ✅ Maßgebliche Referenz | 26 / 26 | Maßgeblich. |
| 🇰🇷 Koreanisch (`ko`) | ✅ Vollständig | 26 / 26 | Alle Seiten dieser Sprachversion sind vorhanden. Phase 1: oberste Ebene + Kern des Benutzerhandbuchs; Phase 2: restliches Benutzerhandbuch + alle Tutorials; Phase 3: Beiträge + Referenzseiten. `docs/ko/changelog.md` verweist bewusst auf das kanonische englische `CHANGELOG.md`. |
| 🇯🇵 Japanisch (`ja`) | ✅ Vollständig | 26 / 26 | Alle Seiten dieser Sprachversion sind vorhanden. Phase 1: oberste Ebene + Kern des Benutzerhandbuchs; Phase 2: restliches Benutzerhandbuch + alle Tutorials; Phase 3: Beiträge + Referenzseiten. `docs/ja/changelog.md` verweist bewusst auf das kanonische englische `CHANGELOG.md`. |
-| 🇨🇳 Chinesisch (`zh`) | 🔴 Skelett | 0 / 26 | Nur als Sprach-Build-Ziel vorhanden. Jede Seite fällt auf Englisch zurück. |
+| 🇨🇳 Chinesisch (`zh`) | ✅ Vollständig | 26 / 26 | Alle Seiten dieser Sprachversion sind vorhanden. Phase 1: oberste Ebene + Kern des Benutzerhandbuchs; Phase 2: restliches Benutzerhandbuch + alle Tutorials; Phase 3: Beiträge + Referenzseiten. `docs/zh/changelog.md` verweist bewusst auf das kanonische englische `CHANGELOG.md`. |
| 🇪🇸 Spanisch (`es`) | ✅ Vollständig | 26 / 26 | Alle Seiten dieser Sprachversion sind vorhanden. Phase 1: oberste Ebene + Kern des Benutzerhandbuchs; Phase 2: restliches Benutzerhandbuch + alle Tutorials; Phase 3: Beiträge + Referenzseiten. `docs/es/changelog.md` verweist bewusst auf das kanonische englische `CHANGELOG.md`. |
| 🇫🇷 Französisch (`fr`) | ✅ Vollständig | 26 / 26 | Alle Seiten dieser Sprachversion sind vorhanden. Phase 1: oberste Ebene + Kern des Benutzerhandbuchs; Phase 2: restliches Benutzerhandbuch + alle Tutorials; Phase 3: Beiträge + Referenzseiten. `docs/fr/changelog.md` verweist bewusst auf das kanonische englische `CHANGELOG.md`. |
| 🇩🇪 Deutsch (`de`) | ✅ Vollständig | 26 / 26 | Alle Seiten dieser Sprachversion sind vorhanden. Phase 1: oberste Ebene + Kern des Benutzerhandbuchs; Phase 2: restliches Benutzerhandbuch + alle Tutorials; Phase 3: Beiträge + Referenzseiten. `docs/de/changelog.md` verweist bewusst auf das kanonische englische `CHANGELOG.md`. |
-*Stand verifiziert am 2026-05-17; die Zeile `de` wurde für den aktuellen Branch nach dem Abschluss von Phase 3 (Beiträge + Referenzseiten) neu gezählt. Deutsch umfasst nun alle Seiten dieser Sprachversion, und `docs/de/changelog.md` verweist auf den kanonischen englischen Changelog.* Diese Zahlen werden manuell gepflegt; um den aktuellen Stand vom Repo-Root neu zu zählen, führen Sie aus:
+*Stand verifiziert am 2026-06-18; die Zeile `zh` wurde für den aktuellen Branch nach dem Abschluss von Phase 3 (Beiträge + Referenzseiten) neu gezählt. Chinesisch hat nun alle 26 Locale-Seiten und wird als ✅ Vollständig geführt.* Diese Zahlen werden manuell gepflegt; um den aktuellen Stand vom Repo-Root neu zu zählen, führen Sie aus:
```console
$ for loc in en ko ja zh es fr de; do
diff --git a/docs/en/reference/translation-status.md b/docs/en/reference/translation-status.md
index 2627235..49d4861 100644
--- a/docs/en/reference/translation-status.md
+++ b/docs/en/reference/translation-status.md
@@ -36,12 +36,12 @@ next section explains).
| 🇬🇧 English (`en`) | ✅ Source of truth | 26 / 26 | Authoritative. |
| 🇰🇷 Korean (`ko`) | ✅ Complete | 26 / 26 | All locale pages are present. Phase 1: top-level + core user-guide; Phase 2: remaining user-guide + all tutorials; Phase 3: contributing + reference. `docs/ko/changelog.md` intentionally reuses the canonical English `CHANGELOG.md`. |
| 🇯🇵 Japanese (`ja`) | ✅ Complete | 26 / 26 | All locale pages are present. Phase 1: top-level + core user-guide; Phase 2: remaining user-guide + all tutorials; Phase 3: contributing + reference. `docs/ja/changelog.md` intentionally reuses the canonical English `CHANGELOG.md`. |
-| 🇨🇳 Chinese (`zh`) | 🔴 Skeleton | 0 / 26 | Build target only. Every page falls back to English. |
+| 🇨🇳 Chinese (`zh`) | ✅ Complete | 26 / 26 | All locale pages are present. Phase 1: top-level + core user-guide; Phase 2: remaining user-guide + all tutorials; Phase 3: contributing + reference. `docs/zh/changelog.md` intentionally reuses the canonical English `CHANGELOG.md`. |
| 🇪🇸 Spanish (`es`) | ✅ Complete | 26 / 26 | All locale pages are present. Phase 1: top-level + core user-guide; Phase 2: remaining user-guide + all tutorials; Phase 3: contributing + reference. `docs/es/changelog.md` intentionally reuses the canonical English `CHANGELOG.md`. |
| 🇫🇷 French (`fr`) | ✅ Complete | 26 / 26 | All locale pages are present. Phase 1: top-level + core user-guide; Phase 2: remaining user-guide + all tutorials; Phase 3: contributing + reference. `docs/fr/changelog.md` intentionally reuses the canonical English `CHANGELOG.md`. |
| 🇩🇪 German (`de`) | ✅ Complete | 26 / 26 | All locale pages are present. Phase 1: top-level + core user-guide; Phase 2: remaining user-guide + all tutorials; Phase 3: contributing + reference. `docs/de/changelog.md` intentionally reuses the canonical English `CHANGELOG.md`. |
-*Snapshot verified 2026-05-17; de row recounted for the current branch after Phase 3 (contributing + reference) landed. German now has all locale pages present, while `docs/de/changelog.md` intentionally points to the canonical English changelog.* These counts are maintained by hand;
+*Snapshot verified 2026-06-18; zh row recounted for the current branch after Phase 3 (contributing + reference) landed. Chinese now has all 26 locale pages present and is tracked at ✅ Complete.* These counts are maintained by hand;
to recount the current state from the repo root, run:
```console
diff --git a/docs/es/reference/translation-status.md b/docs/es/reference/translation-status.md
index c456dd2..3c897d5 100644
--- a/docs/es/reference/translation-status.md
+++ b/docs/es/reference/translation-status.md
@@ -22,11 +22,11 @@ Los números siguientes cuentan páginas Markdown presentes en el árbol de cada
| 🇰🇷 Coreano (`ko`) | ✅ Completo | 26 / 26 | Todas las páginas del idioma están presentes. Phase 1: nivel superior + user-guide principal; Phase 2: user-guide restante + todos los tutorials; Phase 3: contributing + reference. `docs/ko/changelog.md` reutiliza intencionadamente el `CHANGELOG.md` canónico en inglés. |
| 🇯🇵 Japonés (`ja`) | ✅ Completo | 26 / 26 | Todas las páginas del idioma están presentes. Phase 1: nivel superior + user-guide principal; Phase 2: user-guide restante + todos los tutorials; Phase 3: contributing + reference. `docs/ja/changelog.md` reutiliza intencionadamente el `CHANGELOG.md` canónico en inglés. |
| 🇪🇸 Español (`es`) | ✅ Completo | 26 / 26 | Todas las páginas del idioma están presentes. Phase 1: nivel superior + user-guide principal; Phase 2: user-guide restante + todos los tutorials; Phase 3: contributing + reference. `docs/es/changelog.md` reutiliza intencionadamente el `CHANGELOG.md` canónico en inglés. |
-| 🇨🇳 Chino (`zh`) | 🔴 Esqueleto | 0 / 26 | Solo está configurado como destino de compilación. Cada página muestra la versión en inglés. |
+| 🇨🇳 Chino (`zh`) | ✅ Completo | 26 / 26 | Todas las páginas del idioma están presentes. Phase 1: nivel superior + user-guide principal; Phase 2: user-guide restante + todos los tutorials; Phase 3: contributing + reference. `docs/zh/changelog.md` reutiliza intencionadamente el `CHANGELOG.md` canónico en inglés. |
| 🇫🇷 Francés (`fr`) | ✅ Completo | 26 / 26 | Todas las páginas del idioma están presentes. Phase 1: nivel superior + núcleo del user-guide; Phase 2: resto del user-guide + todos los tutoriales; Phase 3: contributing + reference. `docs/fr/changelog.md` reutiliza intencionadamente el `CHANGELOG.md` canónico en inglés. |
| 🇩🇪 Alemán (`de`) | ✅ Completo | 26 / 26 | Todas las páginas del idioma están presentes. Phase 1: nivel superior + núcleo del user-guide; Phase 2: resto del user-guide + todos los tutoriales; Phase 3: contributing + reference. `docs/de/changelog.md` reutiliza intencionadamente el `CHANGELOG.md` canónico en inglés. |
-*Verificado el 2026-05-17; la fila de `de` se volvió a contar para la rama actual tras completar Phase 3 (contributing + reference). El alemán ya tiene todas las páginas del idioma presentes, mientras que `docs/de/changelog.md` apunta al changelog canónico en inglés.* Esta cuenta se mantiene a mano; para volver a contar el estado actual desde la raíz del repositorio, ejecuta:
+*Verificado el 2026-06-18; la fila de `zh` se volvió a contar para la rama actual tras completar Phase 3 (contributing + reference). El chino ya tiene las 26 páginas del idioma presentes y se sigue con el estado ✅ Completo.* Esta cuenta se mantiene a mano; para volver a contar el estado actual desde la raíz del repositorio, ejecuta:
```console
$ for loc in en ko ja zh es fr de; do
diff --git a/docs/fr/reference/translation-status.md b/docs/fr/reference/translation-status.md
index 7722be9..fc06101 100644
--- a/docs/fr/reference/translation-status.md
+++ b/docs/fr/reference/translation-status.md
@@ -21,12 +21,12 @@ Les nombres ci-dessous comptent les pages Markdown dans l'arborescence de chaque
| 🇬🇧 Anglais (`en`) | ✅ Source de vérité | 26 / 26 | Référence. |
| 🇰🇷 Coréen (`ko`) | ✅ Complet | 26 / 26 | Toutes les pages de la locale sont présentes. Phase 1 : top-level + cœur du guide de l'utilisateur ; Phase 2 : reste du guide de l'utilisateur + tous les tutoriels ; Phase 3 : pages de contribution + de référence. `docs/ko/changelog.md` réutilise intentionnellement le `CHANGELOG.md` canonique en anglais. |
| 🇯🇵 Japonais (`ja`) | ✅ Complet | 26 / 26 | Toutes les pages de la locale sont présentes. Phase 1 : top-level + cœur du guide de l'utilisateur ; Phase 2 : reste du guide de l'utilisateur + tous les tutoriels ; Phase 3 : pages de contribution + de référence. `docs/ja/changelog.md` réutilise intentionnellement le `CHANGELOG.md` canonique en anglais. |
-| 🇨🇳 Chinois (`zh`) | 🔴 Squelette | 0 / 26 | Cible de build uniquement. Toutes les pages retombent sur l'anglais. |
+| 🇨🇳 Chinois (`zh`) | ✅ Complet | 26 / 26 | Toutes les pages de la locale sont présentes. Phase 1 : top-level + cœur du guide de l'utilisateur ; Phase 2 : reste du guide de l'utilisateur + tous les tutoriels ; Phase 3 : pages de contribution + de référence. `docs/zh/changelog.md` réutilise intentionnellement le `CHANGELOG.md` canonique en anglais. |
| 🇪🇸 Espagnol (`es`) | ✅ Complet | 26 / 26 | Toutes les pages de la locale sont présentes. Phase 1 : top-level + cœur du guide de l'utilisateur ; Phase 2 : reste du guide de l'utilisateur + tous les tutoriels ; Phase 3 : pages de contribution + de référence. `docs/es/changelog.md` réutilise intentionnellement le `CHANGELOG.md` canonique en anglais. |
| 🇫🇷 Français (`fr`) | ✅ Complet | 26 / 26 | Toutes les pages de la locale sont présentes. Phase 1 : top-level + cœur du guide de l'utilisateur ; Phase 2 : reste du guide de l'utilisateur + tous les tutoriels ; Phase 3 : pages de contribution + de référence. `docs/fr/changelog.md` réutilise intentionnellement le `CHANGELOG.md` canonique en anglais. |
| 🇩🇪 Allemand (`de`) | ✅ Complet | 26 / 26 | Toutes les pages de la locale sont présentes. Phase 1 : top-level + cœur du guide de l'utilisateur ; Phase 2 : reste du guide de l'utilisateur + tous les tutoriels ; Phase 3 : contributing + reference. `docs/de/changelog.md` réutilise intentionnellement le `CHANGELOG.md` canonique en anglais. |
-*Instantané vérifié le 2026-05-17 ; la ligne `de` a été recomptée sur la branche actuelle après la fin de la Phase 3 (contributing + reference). L'allemand comporte désormais toutes les pages de la locale et `docs/de/changelog.md` pointe vers le changelog canonique en anglais.* Ces compteurs sont maintenus à la main ; pour recompter l'état actuel depuis la racine du dépôt, exécutez :
+*Instantané vérifié le 2026-06-18 ; la ligne `zh` a été recomptée sur la branche actuelle après la fin de la Phase 3 (pages de contribution + de référence). Le chinois comporte désormais l'ensemble des 26 pages traduites et est suivi en ✅ Complet.* Ces compteurs sont maintenus à la main ; pour recompter l'état actuel depuis la racine du dépôt, exécutez :
```console
$ for loc in en ko ja zh es fr de; do
diff --git a/docs/ja/reference/translation-status.md b/docs/ja/reference/translation-status.md
index 41223fb..279ada4 100644
--- a/docs/ja/reference/translation-status.md
+++ b/docs/ja/reference/translation-status.md
@@ -21,12 +21,12 @@ FastAPI-fastkit のドキュメントは複数の言語でビルドされます
| 🇬🇧 English (`en`) | ✅ 原典 (Source of truth) | 26 / 26 | すべての基準になる原文です。 |
| 🇰🇷 Korean (`ko`) | ✅ 完了 | 26 / 26 | ロケール側のページはすべてそろっています。Phase 1: トップレベル + コアの user-guide、Phase 2: 残りの user-guide + すべての tutorial、Phase 3: contributing + reference。`docs/ko/changelog.md` は英語の `CHANGELOG.md` を意図的に再利用しています。 |
| 🇯🇵 Japanese (`ja`) | ✅ 完了 | 26 / 26 | ロケール側のページはすべて存在します。Phase 1: トップレベル + コアの user-guide、Phase 2: 残りの user-guide + すべての tutorial、Phase 3: contributing + reference。`docs/ja/changelog.md` は英語の `CHANGELOG.md` を意図的に再利用しています。 |
-| 🇨🇳 Chinese (`zh`) | 🔴 スケルトン | 0 / 26 | ビルドターゲットのみ。すべてのページが英語にフォールバックします。 |
+| 🇨🇳 Chinese (`zh`) | ✅ 完了 | 26 / 26 | ロケール側のページはすべて存在します。Phase 1: トップレベル + コアの user-guide、Phase 2: 残りの user-guide + すべての tutorial、Phase 3: contributing + reference。`docs/zh/changelog.md` は英語の `CHANGELOG.md` を意図的に再利用しています。 |
| 🇪🇸 Spanish (`es`) | ✅ 完了 | 26 / 26 | ロケール側のページはすべて存在します。Phase 1: トップレベル + コアの user-guide、Phase 2: 残りの user-guide + すべての tutorial、Phase 3: contributing + reference。`docs/es/changelog.md` は英語の `CHANGELOG.md` を意図的に再利用しています。 |
| 🇫🇷 French (`fr`) | ✅ 完了 | 26 / 26 | ロケール側のページはすべて存在します。Phase 1: トップレベル + コアの user-guide、Phase 2: 残りの user-guide + すべての tutorial、Phase 3: contributing + reference。`docs/fr/changelog.md` は英語の `CHANGELOG.md` を意図的に再利用しています。 |
| 🇩🇪 German (`de`) | ✅ 完了 | 26 / 26 | ロケール側のページはすべて存在します。Phase 1: トップレベル + コアの user-guide、Phase 2: 残りの user-guide + すべての tutorial、Phase 3: contributing + reference。`docs/de/changelog.md` は英語の `CHANGELOG.md` を意図的に再利用しています。 |
-*スナップショット検証日: 2026-05-17。Phase 3 (contributing + reference) を反映した現在のブランチを基準に `de` 行を再集計しました。ドイツ語はロケール側のページがすべてそろっており、`docs/de/changelog.md` は英語版 changelog をそのまま指しています。* この表は手動で管理されています。リポジトリルートで現在の状態を再カウントしたい場合は、次のコマンドを実行してください:
+*スナップショット検証日: 2026-06-18。Phase 3 (contributing + reference) を反映した現在のブランチを基準に `zh` 行を再集計しました。中国語はロケール側のページが 26 件すべて存在し、✅ 完了として追跡されます。* この表は手動で管理されています。リポジトリルートで現在の状態を再カウントしたい場合は、次のコマンドを実行してください:
```console
$ for loc in en ko ja zh es fr de; do
diff --git a/docs/ko/reference/translation-status.md b/docs/ko/reference/translation-status.md
index da1e35f..0f8c8fc 100644
--- a/docs/ko/reference/translation-status.md
+++ b/docs/ko/reference/translation-status.md
@@ -21,12 +21,12 @@ FastAPI-fastkit 문서는 여러 언어로 빌드되지만, 모든 번역이 **
| 🇬🇧 English (`en`) | ✅ 원본 | 26 / 26 | 기준이 되는 원문입니다. |
| 🇰🇷 한국어 (`ko`) | ✅ 완료 | 26 / 26 | 언어별 페이지는 모두 존재합니다. Phase 1: 최상위 + 핵심 user-guide, Phase 2: 나머지 user-guide + 모든 tutorial, Phase 3: contributing + reference. `docs/ko/changelog.md` 는 영문 기준 `CHANGELOG.md` 를 그대로 사용합니다. |
| 🇯🇵 일본어 (`ja`) | ✅ 완료 | 26 / 26 | 언어별 페이지는 모두 존재합니다. Phase 1: 최상위 + 핵심 user-guide, Phase 2: 나머지 user-guide + 모든 tutorial, Phase 3: contributing + reference. `docs/ja/changelog.md` 는 영문 기준 `CHANGELOG.md` 를 그대로 사용합니다. |
-| 🇨🇳 중국어 (`zh`) | 🔴 기본 구조만 있음 | 0 / 26 | 빌드 대상만 설정되어 있으며, 모든 페이지는 영어 원문으로 표시됩니다. |
+| 🇨🇳 중국어 (`zh`) | ✅ 완료 | 26 / 26 | 언어별 페이지는 모두 존재합니다. Phase 1: 최상위 + 핵심 user-guide, Phase 2: 나머지 user-guide + 모든 tutorial, Phase 3: contributing + reference. `docs/zh/changelog.md` 는 영문 기준 `CHANGELOG.md` 를 그대로 사용합니다. |
| 🇪🇸 스페인어 (`es`) | ✅ 완료 | 26 / 26 | 언어별 페이지는 모두 존재합니다. Phase 1: 최상위 + 핵심 user-guide, Phase 2: 나머지 user-guide + 모든 tutorial, Phase 3: contributing + reference. `docs/es/changelog.md` 는 영문 기준 `CHANGELOG.md` 를 그대로 사용합니다. |
| 🇫🇷 프랑스어 (`fr`) | ✅ 완료 | 26 / 26 | 모든 로케일 페이지가 존재합니다. Phase 1: 최상위 + 핵심 user-guide; Phase 2: 나머지 user-guide + 모든 tutorial; Phase 3: contributing + reference. `docs/fr/changelog.md` 는 영문 기준 `CHANGELOG.md` 를 그대로 재사용합니다. |
| 🇩🇪 독일어 (`de`) | ✅ 완료 | 26 / 26 | 모든 로케일 페이지가 존재합니다. Phase 1: 최상위 + 핵심 user-guide; Phase 2: 나머지 user-guide + 모든 tutorial; Phase 3: contributing + reference. `docs/de/changelog.md` 는 영문 기준 `CHANGELOG.md` 를 그대로 재사용합니다. |
-*스냅샷 검증 시점: 2026-05-17. Phase 3(contributing + reference) 작업이 반영된 현재 브랜치 기준으로 `de` 행을 다시 집계했습니다. 독일어는 이제 모든 로케일 페이지를 보유하며 `docs/de/changelog.md` 는 영문 기준 changelog를 그대로 가리킵니다.* 이 표는 수동으로 관리됩니다. 리포지토리 루트에서 현재 상태를 다시 세고 싶다면 다음 명령을 실행하세요:
+*스냅샷 검증 시점: 2026-06-18. Phase 3(contributing + reference) 작업이 반영된 현재 브랜치 기준으로 `zh` 행을 다시 집계했습니다. 중국어는 이제 26개 로케일 페이지를 모두 보유하며 ✅ 완료 상태로 추적됩니다.* 이 표는 수동으로 관리됩니다. 리포지토리 루트에서 현재 상태를 다시 세고 싶다면 다음 명령을 실행하세요:
```console
$ for loc in en ko ja zh es fr de; do
diff --git a/docs/zh/changelog.md b/docs/zh/changelog.md
new file mode 100644
index 0000000..f4d16fd
--- /dev/null
+++ b/docs/zh/changelog.md
@@ -0,0 +1 @@
+{!CHANGELOG.md!}
diff --git a/docs/zh/contributing/code-guidelines.md b/docs/zh/contributing/code-guidelines.md
new file mode 100644
index 0000000..2a90636
--- /dev/null
+++ b/docs/zh/contributing/code-guidelines.md
@@ -0,0 +1,748 @@
+# 代码规范
+
+为参与 FastAPI-fastkit 贡献而准备的完整编码标准与最佳实践。
+
+## 总览
+
+这些规范用于保证 FastAPI-fastkit 项目在代码质量、一致性与可维护性上的水准。遵循这些标准,可以让代码库更易于阅读、维护与扩展。
+
+## Python 代码风格
+
+### PEP 8 一致性
+
+遵循 [PEP 8](https://www.python.org/dev/peps/pep-0008/),并按以下具体约定:
+
+- **行宽**:88 字符(Black 默认)
+- **缩进**:4 空格(不要使用 tab)
+- **末尾逗号**:多行结构必须保留末尾逗号
+- **字符串引号**:优先使用双引号
+
+### 代码格式化
+
+我们使用 **Black** 进行自动格式化:
+
+```python
+# Good ✅
+def create_project(
+ name: str,
+ template: str,
+ options: Dict[str, Any],
+) -> ProjectResult:
+ """Create a new FastAPI project."""
+ return ProjectResult(name=name, template=template)
+
+# Bad ❌
+def create_project(name: str, template: str, options: Dict[str,Any])->ProjectResult:
+ """Create a new FastAPI project."""
+ return ProjectResult(name=name,template=template)
+```
+
+### Import 组织
+
+使用 **isort** 组织 import:
+
+```python
+# Standard library imports
+import os
+import sys
+from pathlib import Path
+from typing import Dict, List, Optional, Union
+
+# Third-party imports
+import click
+import pydantic
+from fastapi import FastAPI
+
+# Local imports
+from fastapi_fastkit.commands import BaseCommand
+from fastapi_fastkit.utils import validation
+from fastapi_fastkit.templates.manager import TemplateManager
+```
+
+## 类型注解
+
+### 必备的类型注解
+
+所有公共函数与方法必须带有类型注解:
+
+```python
+# Good ✅
+def validate_project_name(name: str) -> bool:
+ """Validate project name format."""
+ return name.isidentifier() and not name.startswith('_')
+
+def create_files(
+ files: List[Path],
+ template_data: Dict[str, Any]
+) -> List[Path]:
+ """Create files from template data."""
+ created_files = []
+ for file_path in files:
+ # Implementation...
+ created_files.append(file_path)
+ return created_files
+
+# Bad ❌
+def validate_project_name(name):
+ return name.isidentifier() and not name.startswith('_')
+```
+
+### 复杂类型注解
+
+对复杂结构使用合适的类型注解:
+
+```python
+from typing import Dict, List, Optional, Union, Tuple, Any
+from pathlib import Path
+
+# Type aliases for complex types
+ProjectConfig = Dict[str, Union[str, bool, List[str]]]
+FileMapping = Dict[Path, str]
+ValidationResult = Tuple[bool, Optional[str]]
+
+def process_template(
+ template_path: Path,
+ config: ProjectConfig,
+ output_dir: Optional[Path] = None,
+) -> ValidationResult:
+ """Process template with configuration."""
+ # Implementation...
+ return True, None
+```
+
+## 命名约定
+
+### 变量与函数
+
+- 变量与函数使用 **snake_case**
+- 名称应**有描述性**,清晰表达用途
+- **避免缩写**,除非该缩写已被广泛接受
+
+```python
+# Good ✅
+project_name = "my-api"
+template_directory = Path("templates")
+user_input_data = get_user_input()
+
+def validate_email_address(email: str) -> bool:
+ """Validate email address format."""
+ return "@" in email and "." in email
+
+# Bad ❌
+proj_nm = "my-api"
+temp_dir = Path("templates")
+usr_data = get_input()
+
+def validate_email(e):
+ return "@" in e and "." in e
+```
+
+### 类
+
+- 类名使用 **PascalCase**
+- 名称要**具体且具描述性**
+
+```python
+# Good ✅
+class SomeClass:
+ """Represents example class of FastAPI-fastkit."""
+ pass
+
+class SomeClassValidationError(Exception):
+ """Raised when example class validation fails."""
+ pass
+
+class UserInputHandler:
+ """Handles user input validation and processing."""
+ pass
+
+# Bad ❌
+class Class:
+ pass
+
+class Error(Exception):
+ pass
+
+class Handler:
+ pass
+```
+
+### 常量
+
+- 使用带下划线的 **UPPER_CASE**
+- 仅在**模块级**定义常量
+
+```python
+# Good ✅
+DEFAULT_TEMPLATE_NAME = "fastapi-default"
+MAX_PROJECT_NAME_LENGTH = 50
+SUPPORTED_PYTHON_VERSIONS = ["3.8", "3.9", "3.10", "3.11", "3.12"]
+
+# Bad ❌
+default_template = "fastapi-default"
+maxLength = 50
+versions = ["3.8", "3.9", "3.10", "3.11", "3.12"]
+```
+
+## 文档标准
+
+### Docstring
+
+所有公共 API 使用 **Google 风格 docstring**:
+
+```python
+def create_project_structure(
+ project_name: str,
+ template_path: Path,
+ output_directory: Optional[Path] = None,
+ overwrite: bool = False,
+) -> List[Path]:
+ """Create project structure from template.
+
+ Creates a new FastAPI project structure by copying and processing
+ template files. Supports variable substitution and file customization.
+
+ Args:
+ project_name: Name of the project to create. Must be a valid
+ Python identifier.
+ template_path: Path to the template directory containing
+ source files and configuration.
+ output_directory: Directory where project will be created.
+ Defaults to current working directory.
+ overwrite: Whether to overwrite existing files. If False,
+ raises error when files exist.
+
+ Returns:
+ List of created file paths in order of creation.
+
+ Raises:
+ ValueError: If project_name is invalid or empty.
+ FileExistsError: If output directory exists and overwrite is False.
+ TemplateNotFoundError: If template_path doesn't exist.
+ PermissionError: If insufficient permissions to create files.
+
+ Example:
+ ```python
+ template_path = Path("templates/fastapi-default")
+ created_files = create_project_structure(
+ project_name="my-api",
+ template_path=template_path,
+ output_directory=Path("./projects"),
+ overwrite=False
+ )
+ print(f"Created {len(created_files)} files")
+ ```
+ """
+ # Implementation here...
+ pass
+```
+
+### 注释
+
+- **解释 WHY,而不是 WHAT**
+- **节制使用** —— 代码本身应具有自解释性
+- 代码改动后**同步更新注释**
+
+```python
+# Good ✅
+def validate_dependencies(requirements: List[str]) -> bool:
+ """Validate project dependencies."""
+ # Skip validation in development mode to allow experimental packages
+ if os.getenv("FASTKIT_DEV_MODE"):
+ return True
+
+ # Check each requirement against known security vulnerabilities
+ for requirement in requirements:
+ if is_vulnerable_package(requirement):
+ return False
+
+ return True
+
+# Bad ❌
+def validate_dependencies(requirements: List[str]) -> bool:
+ """Validate project dependencies."""
+ # Check if dev mode
+ if os.getenv("FASTKIT_DEV_MODE"):
+ return True
+
+ # Loop through requirements
+ for requirement in requirements:
+ # Check if vulnerable
+ if is_vulnerable_package(requirement):
+ return False
+
+ # Return true
+ return True
+```
+
+## 错误处理
+
+### 异常处理
+
+- 尽量**捕获具体异常**
+- **提供有意义的错误信息**
+- **合理地记录错误日志**
+
+```python
+# Good ✅
+def load_template_config(template_path: Path) -> Dict[str, Any]:
+ """Load template configuration from file."""
+ config_file = template_path / "template.yaml"
+
+ try:
+ with open(config_file, 'r') as f:
+ return yaml.safe_load(f)
+ except FileNotFoundError:
+ raise TemplateNotFoundError(
+ f"Template configuration not found: {config_file}"
+ )
+ except yaml.YAMLError as e:
+ raise TemplateConfigError(
+ f"Invalid YAML syntax in {config_file}: {e}"
+ )
+ except PermissionError:
+ raise TemplateAccessError(
+ f"Permission denied reading {config_file}"
+ )
+
+# Bad ❌
+def load_template_config(template_path: Path) -> Dict[str, Any]:
+ """Load template configuration from file."""
+ config_file = template_path / "template.yaml"
+
+ try:
+ with open(config_file, 'r') as f:
+ return yaml.safe_load(f)
+ except Exception as e:
+ raise Exception(f"Error loading config: {e}")
+```
+
+### 自定义异常
+
+为不同错误场景定义具体的异常类:
+
+```python
+class FastKitError(Exception):
+ """Base exception for FastAPI-fastkit errors."""
+ pass
+
+class ProjectCreationError(FastKitError):
+ """Raised when project creation fails."""
+ pass
+
+class TemplateNotFoundError(FastKitError):
+ """Raised when template is not found."""
+ pass
+
+class ValidationError(FastKitError):
+ """Raised when input validation fails."""
+
+ def __init__(self, message: str, field: str = None):
+ super().__init__(message)
+ self.field = field
+```
+
+## 测试标准
+
+### 测试结构
+
+测试要有清晰的结构与命名:
+
+```python
+class TestProjectCreation:
+ """Test project creation functionality."""
+
+ def test_create_project_with_valid_name(self, tmp_path):
+ """Test project creation with valid project name."""
+ project_name = "test-project"
+ result = create_project(project_name, template="minimal", output=tmp_path)
+
+ assert result.success is True
+ assert (tmp_path / project_name).exists()
+ assert (tmp_path / project_name / "src" / "main.py").exists()
+
+ def test_create_project_with_invalid_name(self):
+ """Test project creation fails with invalid name."""
+ with pytest.raises(ValueError, match="Invalid project name"):
+ create_project("invalid-project-name!", template="minimal")
+
+ def test_create_project_overwrites_existing(self, tmp_path):
+ """Test project creation overwrites existing directory when forced."""
+ project_name = "existing-project"
+ project_dir = tmp_path / project_name
+ project_dir.mkdir()
+
+ result = create_project(
+ project_name,
+ template="minimal",
+ output=tmp_path,
+ overwrite=True
+ )
+
+ assert result.success is True
+ assert project_dir.exists()
+```
+
+### 测试覆盖率
+
+- 对新代码,**目标覆盖率 90% 以上**
+- **覆盖边界情况**与异常路径
+- 对外部依赖使用 **mock**
+
+```python
+def test_template_download_with_network_error(mock_requests):
+ """Test template download handles network errors gracefully."""
+ mock_requests.get.side_effect = requests.ConnectionError("Network unreachable")
+
+ with pytest.raises(TemplateDownloadError, match="Network error"):
+ download_template("https://example.com/template.zip")
+
+def test_file_creation_with_permission_error(mock_open):
+ """Test file creation handles permission errors."""
+ mock_open.side_effect = PermissionError("Permission denied")
+
+ with pytest.raises(FileCreationError, match="Permission denied"):
+ create_file(Path("/restricted/file.py"), content="test")
+```
+
+## Import 规范
+
+### Import 组织
+
+!!! note
+
+ `isort` 格式化器会自动组织 import,只需运行 `bash scripts/format.sh` 即可。
+
+1. **标准库** import 在最前
+2. **第三方** import 在中间
+3. **本地应用** import 在最后
+4. 每组之间用**空行**分隔
+
+```python
+# Standard library
+import os
+import sys
+from pathlib import Path
+from typing import Dict, List, Optional
+
+# Third-party
+import click
+import pydantic
+import yaml
+from fastapi import FastAPI
+
+# Local application
+from fastapi_fastkit.commands.base import BaseCommand
+from fastapi_fastkit.utils.validation import validate_project_name
+from fastapi_fastkit.templates import TemplateManager
+```
+
+### Import 最佳实践
+
+- **避免通配 import**(`from module import *`)
+- 使用**绝对 import**,保持清晰
+- 当需要导入许多项时,**优先导入模块本身**
+
+```python
+# Good ✅
+from fastapi_fastkit.utils import validation, files, formatting
+
+# Good ✅ (when importing few items)
+from fastapi_fastkit.utils.validation import validate_email, validate_project_name
+
+# Bad ❌
+from fastapi_fastkit.utils.validation import *
+
+# Bad ❌ (when importing many items)
+from fastapi_fastkit.utils.validation import (
+ validate_email, validate_project_name, validate_template_name,
+ validate_dependencies, validate_python_version, validate_directory
+)
+```
+
+## 安全规范
+
+### 输入校验
+
+始终对用户输入进行校验与净化:
+
+```python
+def validate_project_name(name: str) -> str:
+ """Validate and sanitize project name."""
+ if not name:
+ raise ValueError("Project name cannot be empty")
+
+ if not name.isidentifier():
+ raise ValueError("Project name must be a valid Python identifier")
+
+ if name.startswith('_'):
+ raise ValueError("Project name cannot start with underscore")
+
+ if len(name) > 50:
+ raise ValueError("Project name too long (max 50 characters)")
+
+ # Sanitize by removing dangerous characters
+ sanitized = re.sub(r'[^a-zA-Z0-9_-]', '', name)
+
+ return sanitized
+```
+
+### 文件操作
+
+谨慎处理文件路径与文件操作:
+
+```python
+def create_file_safely(file_path: Path, content: str, base_dir: Path) -> None:
+ """Create file safely within base directory."""
+ # Resolve to prevent directory traversal attacks
+ resolved_path = file_path.resolve()
+ resolved_base = base_dir.resolve()
+
+ # Ensure file is within base directory
+ try:
+ resolved_path.relative_to(resolved_base)
+ except ValueError:
+ raise SecurityError(f"File path outside base directory: {file_path}")
+
+ # Create parent directories safely
+ resolved_path.parent.mkdir(parents=True, exist_ok=True)
+
+ # Write file with appropriate permissions
+ resolved_path.write_text(content, encoding='utf-8')
+ resolved_path.chmod(0o644) # Read/write for owner, read for others
+```
+
+## 性能规范
+
+### 高效的代码写法
+
+- 对大数据集**使用生成器**
+- **避免过早优化**
+- **先剖析,再优化**
+
+```python
+# Good ✅ - Generator for memory efficiency
+def process_large_template(template_files: List[Path]) -> Iterator[ProcessedFile]:
+ """Process template files efficiently."""
+ for file_path in template_files:
+ content = file_path.read_text()
+ processed_content = process_template_content(content)
+ yield ProcessedFile(path=file_path, content=processed_content)
+
+# Bad ❌ - Loads everything into memory
+def process_large_template(template_files: List[Path]) -> List[ProcessedFile]:
+ """Process template files."""
+ results = []
+ for file_path in template_files:
+ content = file_path.read_text()
+ processed_content = process_template_content(content)
+ results.append(ProcessedFile(path=file_path, content=processed_content))
+ return results
+```
+
+### 缓存
+
+对开销大的操作使用缓存:
+
+```python
+from functools import lru_cache
+
+@lru_cache(maxsize=128)
+def get_template_metadata(template_path: Path) -> TemplateMetadata:
+ """Get template metadata with caching."""
+ config_file = template_path / "template.yaml"
+
+ if not config_file.exists():
+ return TemplateMetadata(name=template_path.name)
+
+ config = yaml.safe_load(config_file.read_text())
+ return TemplateMetadata.from_config(config)
+```
+
+## Git 提交规范
+
+### 提交信息格式
+
+使用约定式提交(Conventional Commits)格式:
+
+```
+type(scope): description
+
+[optional body]
+
+[optional footer]
+```
+
+### 提交类型
+
+- **feat**:新特性
+- **fix**:bug 修复
+- **docs**:文档相关改动
+- **style**:代码风格改动(格式化等)
+- **refactor**:代码重构
+- **test**:增加或调整测试
+- **chore**:维护性任务
+
+### 示例
+
+```bash
+# Good ✅
+feat(cli): add template validation command
+
+Add new command to validate template structure and configuration.
+The command checks for required files, validates YAML syntax,
+and ensures template follows conventions.
+
+Closes #123
+
+# Good ✅
+fix(templates): handle missing dependency files gracefully
+
+When a template references a requirements file that doesn't exist,
+show a clear error message instead of crashing.
+
+# Bad ❌
+update stuff
+
+# Bad ❌
+Fixed bug
+```
+
+## 代码评审规范
+
+### 对作者而言
+
+提交评审前请确认:
+
+1. **运行全部测试**,且全部通过
+2. **核查测试覆盖率**未下滑
+3. **必要时更新文档**
+4. **遵循提交信息**规范
+5. **保持 PR 聚焦且小**
+
+### 对评审者而言
+
+评审时请关注:
+
+1. **功能是否正确** —— 行为是否符合预期?
+2. **测试是否完善** —— 是否覆盖边界情况?
+3. **文档是否同步** —— 描述是否清晰、最新?
+4. **代码风格** —— 是否遵循项目约定?
+5. **是否考虑安全** —— 是否存在潜在漏洞?
+
+### 评审清单
+
+- [ ] 代码符合风格规范
+- [ ] 测试齐备且全部通过
+- [ ] 文档已更新
+- [ ] 无安全漏洞
+- [ ] 已考虑性能问题
+- [ ] 错误处理得当
+- [ ] 提交信息符合规范
+
+## 工具与自动化
+
+### Pre-commit 钩子
+
+我们使用 pre-commit 钩子来强制执行标准:
+
+```yaml
+# .pre-commit-config.yaml
+repos:
+- repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v6.0.0
+ hooks:
+ - id: trailing-whitespace
+ - id: end-of-file-fixer
+ - id: check-yaml
+ - id: check-toml
+
+- repo: local
+ hooks:
+ - id: format
+ name: format
+ entry: black --config pyproject.toml --check .
+ language: python
+ types: [python]
+ additional_dependencies: ['black>=24.10.0']
+ pass_filenames: false
+
+ - id: isort-check
+ name: isort check
+ entry: isort --sp pyproject.toml --check-only --diff .
+ language: python
+ types: [python]
+ additional_dependencies: ['isort>=5.13.2']
+ pass_filenames: false
+
+ - id: isort-fix
+ name: isort fix
+ entry: isort --sp pyproject.toml .
+ language: python
+ types: [python]
+ additional_dependencies: ['isort>=5.13.2']
+ pass_filenames: false
+
+ - id: black-fix
+ name: black fix
+ entry: black --config pyproject.toml .
+ language: python
+ types: [python]
+ additional_dependencies: ['black>=24.10.0']
+ pass_filenames: false
+
+ - id: mypy
+ name: mypy
+ entry: mypy --config-file pyproject.toml src
+ language: python
+ types: [python]
+ additional_dependencies:
+ - mypy>=1.12.0
+ - rich>=13.9.2
+ - click>=8.1.7
+ - pyyaml>=6.0.0
+ - types-PyYAML>=6.0.12
+ pass_filenames: false
+
+ci:
+ autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
+ autoupdate_commit_msg: ⬆ [pre-commit.ci] pre-commit autoupdate
+```
+
+!!! note
+
+ Pre-commit 钩子使用隔离的 Python 环境(`language: python`)。
+
+### IDE 配置
+
+推荐的 VS Code 设置:
+
+```json
+{
+ "python.linting.enabled": true,
+ "python.linting.mypyEnabled": true,
+ "python.formatting.provider": "black",
+ "python.sortImports.path": "isort",
+ "editor.formatOnSave": true,
+ "editor.codeActionsOnSave": {
+ "source.organizeImports": true
+ }
+}
+```
+
+## 下一步
+
+读完这些规范后:
+
+1. **配置开发环境**,参见 [开发环境配置](development-setup.md)
+2. **从小贡献开始练手**,熟悉流程
+3. **在 GitHub Discussions 提问**,有不明之处随时问
+4. **阅读已有代码**,看看这些规范在实践中的样子
+
+!!! tip "速查"
+ - 用 `make check-all` 验证您的代码是否满足全部规范
+ - 配置 pre-commit 钩子,尽早发现问题
+ - 拿不准时,看现有代码作为示例
+ - 评审中遇到问题,不要犹豫,主动求助
+
+遵循这些规范有助于让 FastAPI-fastkit 保持高水准的代码质量,并让所有人协作起来更轻松!🚀
diff --git a/docs/zh/contributing/development-setup.md b/docs/zh/contributing/development-setup.md
new file mode 100644
index 0000000..96aed02
--- /dev/null
+++ b/docs/zh/contributing/development-setup.md
@@ -0,0 +1,816 @@
+# 开发环境配置
+
+为参与 FastAPI-fastkit 贡献而准备开发环境的完整指南。
+
+## 前置条件
+
+开始之前,请确认您已具备:
+
+- 已安装 **Python 3.12 及以上**
+- 已安装并配置 **Git**
+- 具备 **Python 与 FastAPI 的基础知识**
+- 一个 **文本编辑器或 IDE**(VS Code、PyCharm 等)
+
+## 借助 Makefile 快速配置
+
+FastAPI-fastkit 提供了用于简化开发环境配置的 Makefile:
+
+
+
+```console
+$ git clone https://github.com/bnbong/FastAPI-fastkit.git
+$ cd FastAPI-fastkit
+$ make install-dev
+Setting up development environment...
+Creating virtual environment...
+Installing dependencies...
+Installing pre-commit hooks...
+✅ Development environment ready!
+```
+
+
+
+这一条命令会:
+
+- 以可编辑模式安装包及其开发依赖
+- 安装 pre-commit 钩子
+- 配置开发工具
+
+!!! note
+
+ 在运行该命令前,建议先创建并激活虚拟环境。
+
+## 手动配置
+
+如果您倾向于手动配置,或 Makefile 在您的系统上无法正常工作:
+
+### 1. 克隆仓库
+
+
+
+```console
+$ git clone https://github.com/bnbong/FastAPI-fastkit.git
+$ cd FastAPI-fastkit
+```
+
+
+
+### 2. 创建虚拟环境
+
+
+
+```console
+$ python -m venv .venv
+$ source .venv/bin/activate # On Windows: .venv\Scripts\activate
+```
+
+
+
+### 3. 安装依赖
+
+
+
+```console
+# Install package in editable mode with development dependencies
+$ pip install -e ".[dev]"
+
+# Or install from requirements files
+$ pip install -r requirements.txt
+$ pip install -r requirements-dev.txt
+```
+
+
+
+### 4. 配置 pre-commit 钩子
+
+
+
+```console
+$ pre-commit install
+pre-commit installed at .git/hooks/pre-commit
+```
+
+
+
+### 5. 验证安装
+
+
+
+```console
+$ fastkit --version
+fastapi-fastkit, version 1.2.1
+
+$ python -m pytest tests/
+======================== test session starts ========================
+collected 45 items
+tests/test_cli.py::test_init_command PASSED
+tests/test_templates.py::test_template_listing PASSED
+...
+======================== 45 passed in 2.34s ========================
+```
+
+
+
+## 开发工具
+
+开发环境包含多种工具,用于维护代码质量:
+
+### 一行命令
+
+使用 Makefile:
+
+```console
+$ make format lint
+Running isort...
+Running black...
+Running mypy...
+✅ All checks passed!
+```
+
+使用项目自带脚本:
+
+```console
+$ ./scripts/format.sh
+$ ./scripts/lint.sh
+```
+
+### 代码格式化
+
+**Black** —— 代码格式化器:
+
+
+
+```console
+$ black src/ tests/
+reformatted src/main.py
+reformatted tests/test_cli.py
+All done! ✨ 🍰 ✨
+```
+
+
+
+**isort** —— import 排序:
+
+
+
+```console
+$ isort src/ tests/
+Fixing import order in src/main.py
+```
+
+
+
+### 代码静态检查
+
+**mypy** —— 类型检查:
+
+
+
+```console
+$ mypy src/
+Success: no issues found in 12 source files
+```
+
+
+
+## 可用的 Make 命令
+
+项目的 Makefile 为常见的开发任务提供了便捷命令:
+
+### 安装命令
+
+| 命令 | 描述 |
+|---------|-------------|
+| `make install` | 以生产模式安装包 |
+| `make install-dev` | 以包含开发依赖的方式安装包 |
+| `make install-test` | 为测试用途安装包(卸载并重新安装) |
+| `make uninstall` | 卸载包 |
+| `make clean` | 清理构建产物与缓存文件 |
+
+### 代码质量命令
+
+| 命令 | 描述 |
+|---------|-------------|
+| `make format` | 使用 black 与 isort 格式化代码 |
+| `make format-check` | 检查代码格式,但不做修改 |
+| `make lint` | 运行所有静态检查(isort、black、mypy) |
+
+### 测试命令
+
+| 命令 | 描述 |
+|---------|-------------|
+| `make test` | 运行全部测试 |
+| `make test-verbose` | 以详细模式运行测试 |
+| `make test-coverage` | 运行测试并生成覆盖率报告 |
+| `make coverage-report` | 生成详细的覆盖率报告(FORMAT=html/xml/json/all) |
+
+### 模板检查命令
+
+| 命令 | 描述 |
+|---------|-------------|
+| `make inspect-templates` | 对所有模板执行模板检查 |
+| `make inspect-templates-verbose` | 以详细输出运行模板检查 |
+| `make inspect-template` | 检查指定模板(TEMPLATES 参数) |
+
+### 文档命令
+
+| 命令 | 描述 |
+|---------|-------------|
+| `make serve-docs` | 在本地启动文档服务 |
+| `make build-docs` | 构建文档 |
+
+### 翻译命令
+
+| 命令 | 描述 |
+|---------|-----------|
+| `make translate` | 翻译文档(LANG、PROVIDER、MODEL 参数) |
+
+### 示例
+
+
+
+```console
+# Format code and run all checks
+$ make format lint
+Running isort...
+Running black...
+Running mypy...
+✅ All checks passed!
+
+# Run tests with coverage
+$ make test-coverage
+======================== test session starts ========================
+collected 45 items
+tests/test_cli.py::test_init_command PASSED
+...
+======================== 45 passed in 2.34s ========================
+
+---------- coverage: platform darwin, python 3.12.1-final-0 ----------
+Name Stmts Miss Cover
+--------------------------------------------
+src/main.py 45 2 96%
+src/cli.py 89 5 94%
+src/templates.py 67 3 96%
+--------------------------------------------
+TOTAL 201 10 95%
+
+# Generate HTML coverage report
+$ make coverage-report FORMAT=html
+🌐 Opening HTML coverage report in browser...
+
+# Translate documentation to Korean
+$ make translate LANG=ko PROVIDER=github MODEL=gpt-4o-mini
+Starting translation...
+Running: python scripts/translate.py --target-lang ko --api-provider github --model gpt-4o-mini
+```
+
+
+
+## 项目结构
+
+理解项目结构对开发工作至关重要:
+
+```bash
+FastAPI-fastkit/
+├── src/
+│ ├── fastapi_fastkit/
+│ │ ├── __main__.py # Entry point of the application
+│ │ ├── backend/
+│ │ │ ├── inspector.py # FastAPI-fastkit template inspector
+│ │ │ ├── interactive/
+│ │ │ │ ├── config_builder.py # Configuration builder for interactive mode
+│ │ │ │ ├── prompts.py # Prompts for interactive mode
+│ │ │ │ ├── selectors.py # Selectors logic for interactive mode
+│ │ │ │ └── validators.py # User input validators for interactive mode
+│ │ │ ├── main.py # Backend's logic entry point
+│ │ │ ├── package_managers/
+│ │ │ │ ├── base.py # Base class for package managers
+│ │ │ │ ├── factory.py # Factory for package managers
+│ │ │ │ ├── pdm_manager.py # PDM package manager
+│ │ │ │ ├── pip_manager.py # pip package manager
+│ │ │ │ ├── poetry_manager.py # Poetry package manager
+│ │ │ │ └── uv_manager.py # uv package manager
+│ │ │ ├── project_builder/
+│ │ │ │ ├── config_generator.py # Configuration generator for project builder
+│ │ │ │ └── dependency_collector.py # Dependency collector for project builder
+│ │ │ └── transducer.py # Transducer for project builder
+│ │ ├── cli.py # FastAPI-fastkit main CLI entry point
+│ │ ├── core/
+│ │ │ ├── exceptions.py # Exception handling
+│ │ │ └── settings.py # Settings configuration
+│ │ ├── fastapi_project_template/
+│ │ │ ├── PROJECT_README_TEMPLATE.md # fastkit template project base README file
+│ │ │ ├── README.md # fastkit template README
+│ │ │ ├── fastapi-async-crud/
+│ │ │ ├── fastapi-custom-response/
+│ │ │ ├── fastapi-default/
+│ │ │ ├── fastapi-dockerized/
+│ │ │ ├── fastapi-empty/
+│ │ │ ├── fastapi-mcp/
+│ │ │ ├── fastapi-psql-orm/
+│ │ │ ├── fastapi-single-module/
+│ │ │ └── modules/
+│ │ │ ├── api/
+│ │ │ │ └── routes/
+│ │ │ ├── crud/
+│ │ │ └── schemas/
+│ │ ├── py.typed
+│ │ └── utils/
+│ │ ├── logging.py # Logging configuration
+│ │ └── main.py # FastAPI-fastkit main entry point
+│ └── logs
+├── tests
+│ ├── conftest.py # pytest configuration
+│ ├── test_backends/
+│ ├── test_cli_operations/
+│ ├── test_core.py
+│ ├── test_rich/
+│ ├── test_templates/
+│ └── test_utils.py
+├── uv.lock
+├── docs/ # Documentation
+├── scripts/ # Development scripts
+├── mkdocs.yml
+├── overrides/ # mkdocs overrides
+├── pdm.lock
+├── pyproject.toml
+├── requirements-docs.txt # requirements for documentation
+├── requirements.txt # requirements for development
+├── CHANGELOG.md
+├── CITATION.cff
+├── CODE_OF_CONDUCT.md
+├── CONTRIBUTING.md
+├── LICENSE
+├── MANIFEST.in
+├── Makefile
+├── README.md
+├── SECURITY.md
+└── env.example # environment example(configures translation AI model env vars)
+```
+
+### 关键目录
+
+- **`src/fastapi_fastkit/`** —— 主包源码
+ - **`cli.py`** —— 主 CLI 入口
+ - **`backend/`** —— 核心后端逻辑
+ - **`inspector.py`** —— 模板检查器
+ - **`interactive/`** —— 交互模式相关组件(提示、选择器、校验器)
+ - **`package_managers/`** —— 包管理器实现(pip、uv、pdm、poetry)
+ - **`project_builder/`** —— 项目构建工具
+ - **`transducer.py`** —— 模板 transducer
+ - **`core/`** —— 核心配置与异常
+ - **`fastapi_project_template/`** —— 项目模板(fastapi-default、fastapi-async-crud 等)
+ - **`utils/`** —— 共享工具函数
+- **`tests/`** —— 测试套件
+ - **`test_backends/`** —— 针对后端的测试
+ - **`test_cli_operations/`** —— CLI 操作的测试
+ - **`test_templates/`** —— 模板系统的测试
+- **`docs/`** —— 文档(MkDocs)
+ - 用户指南、教程与 API 参考
+
+## 开发工作流
+
+### 1. 创建特性分支
+
+
+
+```console
+$ git checkout -b feature/add-new-template
+Switched to a new branch 'feature/add-new-template'
+```
+
+
+
+### 2. 进行改动
+
+编辑代码、添加特性、修复 bug……
+
+### 3. 运行测试与检查
+
+
+
+```console
+$ make dev-check
+Running all quality checks...
+Running all tests...
+✅ All tests passed!
+```
+
+
+
+### 4. 提交改动
+
+pre-commit 钩子会自动运行:
+
+
+
+```console
+$ git add .
+$ git commit -m "Add new FastAPI template with authentication"
+format...................................................................Passed
+isort-check..............................................................Passed
+black-fix................................................................Passed
+mypy.....................................................................Passed
+[feature/add-new-template abc1234] Add new FastAPI template with authentication
+```
+
+
+
+### 5. 推送并创建 Pull Request
+
+
+
+```console
+$ git push origin feature/add-new-template
+$ gh pr create --title "Add new FastAPI template with authentication"
+```
+
+
+
+## 测试
+
+### 运行测试
+
+**全部测试:**
+
+
+
+```console
+$ make test
+# or
+$ python -m pytest
+```
+
+
+
+**指定测试文件:**
+
+
+
+```console
+$ python -m pytest tests/test_cli.py -v
+```
+
+
+
+**带覆盖率:**
+
+
+
+```console
+$ make test-coverage
+# or
+$ python -m pytest --cov=src --cov-report=html
+```
+
+
+
+### 编写测试
+
+新增特性时,务必同步编写测试:
+
+```python
+# tests/test_commands/test_new_feature.py
+import pytest
+from fastapi_fastkit.commands.new_feature import NewFeatureCommand
+
+class TestNewFeatureCommand:
+ def test_command_success(self):
+ """Test successful command execution"""
+ command = NewFeatureCommand()
+ result = command.execute(valid_args)
+ assert result.success is True
+ assert result.message == "Feature executed successfully"
+
+ def test_command_validation_error(self):
+ """Test command with invalid arguments"""
+ command = NewFeatureCommand()
+ with pytest.raises(ValueError, match="Invalid argument"):
+ command.execute(invalid_args)
+
+ def test_command_edge_case(self):
+ """Test edge case handling"""
+ command = NewFeatureCommand()
+ result = command.execute(edge_case_args)
+ assert result.success is True
+ assert "warning" in result.message.lower()
+```
+
+### 测试分类
+
+**单元测试** —— 测试单个函数与类:
+
+```python
+def test_validate_project_name():
+ assert validate_project_name("valid-name") is True
+ assert validate_project_name("invalid name!") is False
+```
+
+**集成测试** —— 测试命令之间的交互:
+
+```python
+def test_init_command_creates_project(tmp_path):
+ result = runner.invoke(cli, ['init'], input='test-project\n...')
+ assert result.exit_code == 0
+ assert (tmp_path / "test-project").exists()
+```
+
+**端到端测试** —— 测试完整的工作流:
+
+```python
+def test_full_project_creation_workflow(tmp_path):
+ # Create project
+ result = runner.invoke(cli, ['init'], input='...')
+ assert result.exit_code == 0
+
+ # Add route
+ result = runner.invoke(cli, ['addroute', 'test-project', 'users'])
+ assert result.exit_code == 0
+
+ # Verify files exist
+ assert (tmp_path / "test-project" / "src" / "api" / "routes" / "users.py").exists()
+```
+
+## 文档
+
+### 在本地启动文档服务
+
+
+
+```console
+$ make serve-docs
+INFO - Building documentation...
+INFO - Cleaning site directory
+INFO - Documentation built in 0.43 seconds
+INFO - [14:30:00] Serving on http://127.0.0.1:8000/
+```
+
+
+
+### 构建文档
+
+
+
+```console
+$ make build-docs
+INFO - Building documentation...
+INFO - Documentation built in 0.43 seconds
+```
+
+
+
+### 编写文档
+
+文档使用 Markdown 编写,由 MkDocs 构建。以下是示例结构:
+
+**特性指南模板:**
+
+````markdown
+# New Feature Guide
+
+This guide explains how to use the new feature.
+
+## Prerequisites
+
+- FastAPI-fastkit installed
+- Basic Python knowledge
+
+## Usage
+
+
+
+```console
+$ fastkit new-feature --option value
+✅ Feature executed successfully!
+```
+
+
+
+!!! tip "Pro Tip"
+ Use `--help` to see all available options.
+````
+
+要了解 `mkdocs-material` 的详细参考,请查看 [mkdocs-material 文档](https://squidfunk.github.io/mkdocs-material/reference/admonitions/)。
+
+## 代码风格指南
+
+### Python 代码风格
+
+遵循 [PEP 8](https://www.python.org/dev/peps/pep-0008/),并附加以下具体约定:
+
+- **行宽**:88 字符(Black 默认)
+- **import**:由 isort 组织
+- **类型注解**:所有公共函数都必须提供
+- **docstring**:所有公共 API 使用 Google 风格
+
+### 示例
+
+```python
+from typing import List, Optional
+from pathlib import Path
+
+def create_project_structure(
+ project_name: str,
+ template_path: Path,
+ output_dir: Optional[Path] = None,
+) -> List[Path]:
+ """Create project structure from template.
+
+ Args:
+ project_name: Name of the project to create
+ template_path: Path to the template directory
+ output_dir: Output directory, defaults to current directory
+
+ Returns:
+ List of created file paths
+
+ Raises:
+ ValueError: If project_name is invalid
+ FileNotFoundError: If template_path doesn't exist
+ """
+ if not project_name.isidentifier():
+ raise ValueError(f"Invalid project name: {project_name}")
+
+ if not template_path.exists():
+ raise FileNotFoundError(f"Template not found: {template_path}")
+
+ # Implementation here...
+ return created_files
+```
+
+## 环境变量
+
+进行开发时,您可以设置以下环境变量:
+
+| 变量 | 描述 | 默认值 |
+|----------|-------------|---------|
+| `FASTKIT_DEBUG` | 启用调试日志 | `False` |
+| `FASTKIT_DEV_MODE` | 启用开发模式特性 | `False` |
+| `FASTKIT_TEMPLATE_DIR` | 自定义模板目录 | 内置模板 |
+| `FASTKIT_CONFIG_DIR` | 配置目录 | `~/.fastkit` |
+| `TRANSLATION_API_KEY` | 翻译 API key(使用 [Github AI 模型提供方](https://github.com/marketplace/models/azure-openai) 时填写 Github PAT) | `None` |
+
+
+
+```console
+$ export FASTKIT_DEBUG=true
+$ export FASTKIT_DEV_MODE=true
+$ fastkit init
+DEBUG: Loading configuration from /home/user/.fastkit/
+DEBUG: Available templates: ['fastapi-default', ...]
+```
+
+
+
+其他环境变量设置请参阅 [@settings.py](https://github.com/bnbong/FastAPI-fastkit/blob/main/src/fastapi_fastkit/core/settings.py) 模块。
+
+## 故障排查
+
+### 常见问题
+
+**1. pre-commit 钩子失败:**
+
+
+
+```console
+$ git commit -m "Fix bug"
+black....................................................................Failed
+hookid: black
+
+Files were modified by this hook. Additional output:
+
+would reformat src/cli.py
+```
+
+
+
+**解决办法:** 运行格式化器后再次提交:
+
+
+
+```console
+$ make format
+$ git add .
+$ git commit -m "Fix bug"
+```
+
+
+
+**2. 在不同 Python 版本上测试失败:**
+
+**解决办法:** 使用 tox 在多个 Python 版本上测试:
+
+
+
+```console
+$ pip install tox
+$ tox
+py38: commands succeeded
+py39: commands succeeded
+py310: commands succeeded
+py311: commands succeeded
+py312: commands succeeded
+```
+
+
+
+**3. 开发时出现 import 错误:**
+
+**解决办法:** 以可编辑模式安装包:
+
+
+```console
+$ pip install -e .
+```
+
+
+
+### 获取帮助
+
+- **[GitHub Issues](https://github.com/bnbong/FastAPI-fastkit/issues)**:报告 bug 与请求特性
+- **[GitHub Discussions](https://github.com/bnbong/FastAPI-fastkit/discussions)**:提问与分享想法
+- **文档**:查看 [用户指南](../user-guide/installation.md)
+
+## 贡献指南
+
+### 提交 PR 之前
+
+1. **运行所有检查:** `make dev-check`
+2. **必要时更新文档**
+3. **为新特性增加测试**
+4. **遵循提交信息规范**
+
+### 提交信息格式
+
+```
+type(scope): brief description
+
+Longer description if needed
+
+Fixes #123
+```
+
+**类型(type):**
+
+- `feat`:新特性
+- `fix`:bug 修复
+- `docs`:文档相关改动
+- `style`:代码风格改动
+- `refactor`:代码重构
+- `test`:增加 / 调整测试
+- `chore`:维护性任务
+
+**示例:**
+
+```
+feat(cli): add new template command
+
+Add support for creating projects from custom templates.
+The command accepts a template path and creates a new
+project with the specified configuration.
+
+Fixes #45
+
+fix(templates): handle missing template files gracefully
+
+When a template file is missing, show a clear error message
+instead of crashing with a stack trace.
+
+Fixes #67
+```
+
+## 发布流程
+
+对维护者而言,发布流程如下:
+
+1. **更新版本号**(`setup.py` 与 `__init__.py`)
+2. **更新 CHANGELOG.md**
+3. **创建发布 PR**
+4. **合并后打 tag**
+5. **GitHub Actions** 自动构建并发布
+
+
+
+```console
+$ git tag v1.2.0
+$ git push origin v1.2.0
+```
+
+
+
+## 下一步
+
+开发环境已就绪后:
+
+1. **[浏览代码库](https://github.com/bnbong/FastAPI-fastkit/tree/main/src/fastapi_fastkit)** —— 理解整体架构
+2. **运行测试套件**,确认一切正常
+3. **从 GitHub 上挑选一个 [issue](https://github.com/bnbong/FastAPI-fastkit/issues)** 着手开发
+4. **加入 [discussions](https://github.com/bnbong/FastAPI-fastkit/discussions)**,与其他贡献者交流
+
+祝您编码愉快!🚀
+
+!!! tip "开发小贴士"
+ - 提交前先运行 `make dev-check`
+ - 优先编写测试(TDD 方式)
+ - 让每次提交保持小而聚焦
+ - 新特性同时更新文档
diff --git a/docs/zh/contributing/template-creation-guide.md b/docs/zh/contributing/template-creation-guide.md
new file mode 100644
index 0000000..ae3ebe9
--- /dev/null
+++ b/docs/zh/contributing/template-creation-guide.md
@@ -0,0 +1,575 @@
+# FastAPI 模板创建指南
+
+为 FastAPI-fastkit 添加新 FastAPI 项目模板的完整指南。
+
+## 🎯 总览
+
+添加新模板分为 5 个步骤:
+
+1. **📋 规划与设计** —— 明确模板用途与结构
+2. **🏗️ 模板实现** —— 创建必需的结构与文件
+3. **🔍 本地校验** —— 用 inspector 校验模板
+4. **📚 文档** —— 编写 README 与使用指南
+5. **🚀 提交与评审** —— 创建 PR 并由社区评审
+
+## 📋 第 1 步:规划与设计
+
+### 明确模板用途
+
+在创建新模板之前,请回答以下问题:
+
+- **该模板的独特价值是什么?**
+- **它与现有模板的差异在哪里?**
+- **目标用户群体是谁?**
+- **会包含怎样的技术栈?**
+
+### 模板命名规范
+
+```
+fastapi-{purpose}-{stack}
+```
+
+示例:
+
+- `fastapi-microservice`(微服务模板)
+- `fastapi-graphql`(GraphQL 集成模板)
+- `fastapi-auth-jwt`(JWT 认证模板)
+
+### 技术栈规划
+
+事先定义好要包含的主要技术:
+
+```yaml
+# Example: fastapi-microservice template
+core_dependencies:
+ - fastapi
+ - uvicorn
+ - pydantic
+ - pydantic-settings
+
+additional_features:
+ - sqlalchemy (ORM)
+ - alembic (migrations)
+ - redis (caching)
+ - celery (background tasks)
+ - pytest (testing)
+
+development_tools:
+ - black (code formatting)
+ - isort (import sorting)
+ - mypy (type checking)
+ - pre-commit (Git hooks)
+```
+
+## 🏗️ 第 2 步:模板实现
+
+### 必需的目录结构
+
+```
+fastapi-{template-name}/
+├── src/ # Application source code
+│ ├── main.py-tpl # ✅ FastAPI app entry point (required)
+│ ├── __init__.py-tpl
+│ ├── api/ # API routers
+│ │ ├── __init__.py-tpl
+│ │ ├── api.py-tpl # Main API router
+│ │ └── routes/ # Individual routes
+│ │ ├── __init__.py-tpl
+│ │ └── items.py-tpl # Example route
+│ ├── core/ # Core configuration
+│ │ ├── __init__.py-tpl
+│ │ └── config.py-tpl # Settings management
+│ ├── crud/ # CRUD logic
+│ │ ├── __init__.py-tpl
+│ │ └── items.py-tpl
+│ ├── schemas/ # Pydantic models
+│ │ ├── __init__.py-tpl
+│ │ └── items.py-tpl
+│ └── utils/ # Utility functions
+│ ├── __init__.py-tpl
+│ └── helpers.py-tpl
+├── tests/ # ✅ Tests (required)
+│ ├── __init__.py-tpl
+│ ├── conftest.py-tpl # pytest configuration
+│ └── test_items.py-tpl # Example tests
+├── scripts/ # Scripts
+│ ├── format.sh-tpl # Code formatting
+│ ├── lint.sh-tpl # Linting
+│ ├── run-server.sh-tpl # Server execution
+│ └── test.sh-tpl # Test execution
+├── pyproject.toml-tpl # ✅ Primary metadata (PEP 621, preferred)
+├── setup.py-tpl # 🟡 Legacy metadata (accepted for back-compat)
+├── requirements.txt-tpl # 🟡 Optional when pyproject declares deps
+├── setup.cfg-tpl # Development tools configuration
+├── README.md-tpl # ✅ Project documentation (required)
+├── .env-tpl # Environment variables template
+└── .gitignore-tpl # Git ignore file
+```
+
+**最少必备文件。** 一个模板至少要提供:
+
+- `tests/` 目录
+- `README.md-tpl`
+- 至少一份元数据文件:`pyproject.toml-tpl`(推荐,PEP 621)或 `setup.py-tpl`(遗留,仍可接受)
+- 在以下至少一个位置声明 `fastapi` 依赖:`pyproject.toml-tpl` 的 `[project].dependencies`、`requirements.txt-tpl`,或 `setup.py-tpl` 的 `install_requires`
+
+当 `pyproject.toml-tpl` 已声明 `[project].dependencies` 时,`requirements.txt-tpl` 不再是严格必需的。新模板**建议**采用 `pyproject.toml-tpl` 作为主要元数据文件。
+
+### 文件编写指南
+
+#### 1. 编写 main.py-tpl
+
+```python
+"""
+FastAPI application entry point
+
+This file is the main application for the project created with FastAPI-fastkit.
+"""
+from fastapi import FastAPI
+from fastapi.middleware.cors import CORSMiddleware
+
+from api.api import api_router
+from core.config import settings
+
+# Create FastAPI app (required for inspector validation)
+app = FastAPI(
+ title="",
+ description="Project created with FastAPI-fastkit",
+ version="1.0.0",
+)
+
+# CORS middleware configuration
+app.add_middleware(
+ CORSMiddleware,
+ allow_origins=["*"],
+ allow_credentials=True,
+ allow_methods=["*"],
+ allow_headers=["*"],
+)
+
+# Register API router
+app.include_router(api_router, prefix="/api/v1")
+
+@app.get("/")
+async def root():
+ """Root endpoint"""
+ return {"message": "Hello from !"}
+
+@app.get("/health")
+async def health_check():
+ """Health check endpoint"""
+ return {"status": "healthy"}
+
+if __name__ == "__main__":
+ import uvicorn
+ uvicorn.run(app, host="0.0.0.0", port=8000)
+```
+
+#### 2. 编写 pyproject.toml-tpl(推荐)
+
+新模板应使用 PEP 621 的 `pyproject.toml-tpl` 来声明元数据与依赖。该文件至少要有一个 `[project]` 段,内含 `name`、`version`、`description`,以及包含 `fastapi` 的 `dependencies` 列表。模板还必须携带两个 FastAPI-fastkit 身份标识,这样 `is_fastkit_project()` 才能在用户工作区中把生成的项目与无关的 FastAPI 项目区分开:
+
+- 在 `description` 中带 `[FastAPI-fastkit templated]` 前缀
+- 专门提供 `[tool.fastapi-fastkit]` 表,并设置 `managed = true`
+
+识别时只需任一标识匹配即可(不区分大小写)。若模板遗漏了它们,元数据注入会在项目生成时自动补上,但作者**应当显式包含**它们。
+
+```toml
+[project]
+name = ""
+version = "0.1.0"
+description = "[FastAPI-fastkit templated] "
+authors = [
+ {name = "", email = ""},
+]
+readme = "README.md"
+requires-python = ">=3.12"
+dependencies = [
+ "fastapi>=0.115.0",
+ "uvicorn[standard]>=0.34.0",
+ "pydantic>=2.10.0",
+ "pydantic-settings>=2.7.0",
+ "python-dotenv>=1.0.0",
+]
+
+[project.optional-dependencies]
+dev = [
+ "pytest>=8.0.0",
+ "httpx>=0.28.0",
+]
+
+[tool.fastapi-fastkit]
+managed = true
+
+[build-system]
+requires = ["hatchling"]
+build-backend = "hatchling.build"
+```
+
+#### 3. 编写 requirements.txt-tpl(可选)
+
+当 `pyproject.toml-tpl` 已经声明 `[project].dependencies` 时为可选。对于偏好纯 `pip` 工作流的模板,仍然有用。
+
+```txt
+# FastAPI core dependencies (required)
+fastapi==0.104.1
+uvicorn[standard]==0.24.0
+
+# Data validation
+pydantic==2.5.0
+pydantic-settings==2.1.0
+
+# Environment variable management
+python-dotenv==1.0.0
+
+# Database (if needed)
+sqlalchemy==2.0.23
+alembic==1.13.0
+
+# Development tools
+pytest==7.4.3
+pytest-asyncio==0.21.1
+httpx==0.25.2
+
+# Code quality
+black==23.11.0
+isort==5.12.0
+mypy==1.7.1
+```
+
+#### 4. 编写 setup.py-tpl(遗留 —— 在已有 pyproject 时为可选)
+
+保留它是为了兼容遗留模板。如果新模板已附带 `pyproject.toml-tpl`,则无需此文件。
+
+```python
+"""
+ package setup
+
+Project created with FastAPI-fastkit.
+"""
+from setuptools import find_packages, setup
+
+# Dependencies list (type annotation required)
+install_requires: list[str] = [
+ "fastapi>=0.104.0",
+ "uvicorn[standard]>=0.24.0",
+ "pydantic>=2.5.0",
+ "pydantic-settings>=2.1.0",
+ "python-dotenv>=1.0.0",
+]
+
+setup(
+ name="",
+ version="1.0.0",
+ description="[FastAPI-fastkit templated] ", # Identity marker used by is_fastkit_project()
+ long_description=open("README.md").read(),
+ long_description_content_type="text/markdown",
+ author="",
+ author_email="",
+ packages=find_packages(),
+ install_requires=install_requires,
+ python_requires=">=3.8",
+ classifiers=[
+ "Development Status :: 4 - Beta",
+ "Intended Audience :: Developers",
+ "License :: OSI Approved :: MIT License",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
+ ],
+)
+```
+
+#### 5. 编写测试文件
+
+```python
+# tests/test_items.py-tpl
+"""
+Items API test module
+"""
+import pytest
+from fastapi.testclient import TestClient
+from main import app
+
+client = TestClient(app)
+
+def test_read_root():
+ """Test root endpoint"""
+ response = client.get("/")
+ assert response.status_code == 200
+ assert "message" in response.json()
+
+def test_health_check():
+ """Test health check"""
+ response = client.get("/health")
+ assert response.status_code == 200
+ assert response.json() == {"status": "healthy"}
+
+def test_create_item():
+ """Test item creation"""
+ item_data = {
+ "name": "Test Item",
+ "description": "Test Description"
+ }
+ response = client.post("/api/v1/items/", json=item_data)
+ assert response.status_code == 200
+ data = response.json()
+ assert data["name"] == item_data["name"]
+ assert data["description"] == item_data["description"]
+
+def test_read_items():
+ """Test reading items list"""
+ response = client.get("/api/v1/items/")
+ assert response.status_code == 200
+ assert isinstance(response.json(), list)
+```
+
+## 🔍 第 3 步:本地校验
+
+### 运行自动校验脚本
+
+新模板准备好后,用以下命令进行校验:
+
+```bash
+# Validate all templates
+make inspect-templates
+
+# Validate specific template only
+make inspect-template TEMPLATES="fastapi-your-template"
+
+# Validate with verbose output
+python scripts/inspect-templates.py --templates "fastapi-your-template" --verbose
+```
+
+!!! note
+
+ 您提交 PR 后,**Template PR Inspection** 工作流会自动运行并校验您的模板改动,反馈会直接出现在 PR 上。
+
+### 校验清单
+
+inspector 会自动校验以下项目:
+
+#### ✅ 文件结构校验
+
+- [ ] 存在 `tests/` 目录
+- [ ] 存在 `README.md-tpl` 文件
+- [ ] 至少存在 `pyproject.toml-tpl`(推荐)或 `setup.py-tpl`(遗留)之一
+
+#### ✅ 文件扩展名校验
+
+- [ ] 所有 Python 文件使用 `.py-tpl` 扩展名
+- [ ] 不存在 `.py` 扩展名的文件
+
+#### ✅ 依赖校验
+
+- [ ] `fastapi` 至少声明于以下其一:
+ - [ ] `pyproject.toml-tpl` 的 `[project].dependencies`(推荐)
+ - [ ] `requirements.txt-tpl`
+ - [ ] `setup.py-tpl` 的 `install_requires`
+
+#### ✅ FastAPI 实现校验
+
+- [ ] `main.py-tpl` 中存在 `FastAPI` 的 import
+- [ ] `main.py-tpl` 中存在形如 `app = FastAPI()` 的应用创建
+
+#### ✅ 测试执行校验
+
+- [ ] 成功创建虚拟环境
+- [ ] 成功安装依赖
+- [ ] 所有 pytest 测试通过
+
+#### ✅ 自动化模板测试
+
+FastAPI-fastkit 自带**自动化模板测试**,会对所有模板执行完整测试:
+
+**测试覆盖范围:**
+
+- ✅ 模板创建过程
+- ✅ 项目元数据注入
+- ✅ 虚拟环境搭建
+- ✅ 依赖安装(覆盖所有包管理器)
+- ✅ 基本项目结构校验
+- ✅ FastAPI 项目识别
+
+**测试执行:**
+```console
+# Test all templates automatically
+$ pytest tests/test_templates/test_all_templates.py -v
+
+# Test specific template
+$ pytest tests/test_templates/test_all_templates.py::TestAllTemplates::test_template_creation[your-template-name] -v
+```
+
+**模板测试自动发现:**
+新模板会被**自动发现**并测试,无需手动配置:
+
+1. ✅ **零配置**:加入模板即可自动测试
+2. ✅ **一致的测试**:对所有模板使用相同的质量标准
+3. ✅ **多种包管理器**:覆盖 UV、PDM、Poetry 与 PIP
+4. ✅ **全面校验**:结构、元数据与功能性都会检查
+
+**这对您意味着什么:**
+
+- 🚀 **`FastAPI-fastkit` 主源码中无需新增测试**:您的模板会被自动测试
+- ⚡ **开发更快**:专注模板内容,而不是测试配置
+- 🛡️ **质量保证**:所有模板拥有一致的测试体验
+- 🔄 **CI/CD 集成**:Pull Request 中自动测试
+
+**仍需手动测试的内容:**
+
+- 🧪 **模板特有的功能**:业务逻辑与定制特性
+- 🔧 **集成测试**:外部服务与复杂工作流
+- 📱 **端到端场景**:完整的用户流程
+
+**测试最佳实践:**
+```console
+# 1. Test your template locally
+$ fastkit startdemo your-template-name
+
+# 2. Run automated tests
+$ pytest tests/test_templates/test_all_templates.py::TestAllTemplates::test_template_creation[your-template-name] -v
+
+# 3. Test with different package managers
+$ fastkit startdemo your-template-name --package-manager poetry
+$ fastkit startdemo your-template-name --package-manager pdm
+$ fastkit startdemo your-template-name --package-manager uv
+```
+
+### 手动校验清单
+
+在自动校验之外,还要手动检查以下项:
+
+#### 🔧 代码质量
+
+- [ ] 代码遵循 PEP 8 风格指南
+- [ ] 合理使用类型注解
+- [ ] 变量与函数命名有意义
+- [ ] 注释与 docstring 得当
+
+#### 🏗️ 架构
+
+- [ ] 关注点分离(API、业务逻辑、数据访问相互独立)
+- [ ] 组件设计可复用
+- [ ] 结构便于扩展
+- [ ] 落实安全最佳实践
+
+#### 📚 文档
+
+- [ ] README.md-tpl 遵循 PROJECT_README_TEMPLATE.md 的格式
+- [ ] 明确说明安装与运行方式
+- [ ] 提供 API 文档(OpenAPI / Swagger)
+- [ ] 解释环境变量
+
+## 📚 第 4 步:文档
+
+### 编写 README.md-tpl
+
+参照 [PROJECT_README_TEMPLATE.md](https://github.com/bnbong/FastAPI-fastkit/blob/main/src/fastapi_fastkit/fastapi_project_template/PROJECT_README_TEMPLATE.md) 指南编写。
+
+### 编写模板说明文档
+
+在 `src/fastapi_fastkit/fastapi_project_template/README.md` 中加入对新模板的说明:
+
+```markdown
+## fastapi-your-template
+
+Write a brief description and use cases for your new template here.
+
+### Features:
+- Feature 1
+- Feature 2
+- Feature 3
+
+### Use Cases:
+- Use case 1
+- Use case 2
+```
+
+## 🚀 第 5 步:提交与评审
+
+### 创建 PR 前的清单
+
+- [ ] 全部自动校验通过(`make inspect-templates`)
+- [ ] 完成代码格式化(`make format`)
+- [ ] 静态检查通过(`make lint`)
+- [ ] 所有测试通过(`make test`)
+- [ ] 文档已完成
+- [ ] 遵循 CONTRIBUTING.md 的规范
+
+### PR 标题与描述
+
+```
+[TEMPLATE] Add fastapi-{template-name} template
+
+## Overview
+Adds a new {purpose} template.
+
+## Key Features
+- Feature 1
+- Feature 2
+- Feature 3
+
+## Validation Results
+- [ ] Inspector validation passed
+- [ ] All tests passed
+- [ ] Documentation completed
+
+## Usage Example
+\```bash
+fastkit startdemo
+# Select template: fastapi-{template-name}
+\```
+
+## Related Issues
+Closes #issue-number
+```
+
+### 评审流程
+
+1. **自动校验**:GitHub Actions 自动校验模板
+ - **Template PR Inspection**:对修改模板的 PR 运行 `inspect-changed-templates.py`
+ - **Weekly Inspection**:每周三对所有模板进行完整校验
+2. **代码评审**:维护者与社区评审代码
+3. **测试**:在不同环境中测试模板
+4. **文档评审**:核对文档的准确性与完整性
+5. **批准与合并**:所有要求满足后合并到 main 分支
+
+!!! note
+
+ 您会自动收到带有校验结果的 PR 评论。在请求评审前先确认这些结果!
+
+## 🎯 最佳实践
+
+### 安全考量
+
+- 用环境变量管理敏感信息
+- 合理配置 CORS
+- 校验输入数据
+- 预防 SQL 注入
+
+### 性能优化
+
+- 善用异步处理
+- 优化数据库查询
+- 合理的缓存策略
+- 配置响应压缩
+
+### 可维护性
+
+- 代码结构清晰
+- 测试覆盖全面
+- 文档详尽
+- 配置日志与监控
+
+## 🆘 需要帮助?
+
+- 📖 [开发环境配置指南](development-setup.md)
+- 📋 [代码规范](code-guidelines.md)
+- 💬 [GitHub Discussions](https://github.com/bnbong/FastAPI-fastkit/discussions)
+- 📧 [联系维护者](mailto:bbbong9@gmail.com)
+
+为 FastAPI-fastkit 社区添加新模板是非常宝贵的贡献。
+您的创意与付出会对其他开发者大有帮助!🚀
diff --git a/docs/zh/contributing/translation-guide.md b/docs/zh/contributing/translation-guide.md
new file mode 100644
index 0000000..14ad7dd
--- /dev/null
+++ b/docs/zh/contributing/translation-guide.md
@@ -0,0 +1,367 @@
+# 翻译指南
+
+本指南说明如何为 FastAPI-fastkit 文档贡献翻译。
+
+## 权威来源与翻译政策
+
+> **英文(`en`)是 FastAPI-fastkit 文档的权威来源。** 其他所有语言都是翻译目标,可能在某个版本或单个页面上落后于英文。
+>
+> 当翻译页面与英文页面不一致时,**请以英文页面为准**,直到翻译跟上为止。翻译以贡献者达到的进度发布 —— 部分覆盖是正常且符合预期的。
+
+与该政策相对应的用户视角说明是 [翻译状态](../reference/translation-status.md) 页面,它会列出每个语言的实际完成度,以及尚未翻译时 MkDocs 的呈现方式(简而言之:回退到英文)。
+
+仓库根目录的 `CHANGELOG.md` 也保持英文,作为权威发布历史。如果某个语言提供了 `changelog.md` 页面,该页面应当链接或包含规范的英文 changelog,而不要单独维护一份翻译过的 changelog —— 除非将来项目政策做出明确调整。
+
+每次贡献翻译时,也请同步更新状态页中的表格,这样用户无需从语言切换器中猜测就能知道有哪些可用内容。
+
+## 总览
+
+FastAPI-fastkit 使用一套基于 AI 的自动化翻译系统,把文档翻译成多种语言。该系统会:
+
+- 读取英文源文档
+- 使用 AI API(OpenAI 或 Anthropic)翻译内容
+- 将翻译结果保存到对应语言目录
+- 创建 GitHub Pull Request 以供评审
+
+自动化只提供起点,合并前**仍需人工评审**。AI 生成的翻译在 PR 中应标记为「draft」,并由该语言的熟练使用者评审后再合入。
+
+## 支持的语言
+
+以下是文档站当前**会构建**的语言。仅仅配置了构建目标**并不**意味着该语言已被翻译 —— 真实完成度请参阅 [翻译状态](../reference/translation-status.md)。
+
+- 🇰🇷 韩文(ko)
+- 🇯🇵 日文(ja)
+- 🇨🇳 中文(zh)
+- 🇪🇸 西班牙文(es)
+- 🇫🇷 法文(fr)
+- 🇩🇪 德文(de)
+
+## 前置条件
+
+### 1. 安装翻译相关依赖
+
+```bash
+# Install using pip
+pip install openai anthropic
+
+# Or using pdm
+pdm install -G translation
+```
+
+### 2. 配置 API key
+
+您需要 OpenAI 或 Anthropic 任一家的 API key:
+
+```bash
+# For OpenAI
+export TRANSLATION_API_KEY="sk-..."
+
+# Or for Anthropic
+export TRANSLATION_API_KEY="sk-ant-..."
+```
+
+### 3. 安装 GitHub CLI(可选)
+
+用于自动创建 PR:
+
+```bash
+# macOS
+brew install gh
+
+# Linux
+curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
+echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
+sudo apt update
+sudo apt install gh
+
+# Authenticate
+gh auth login
+```
+
+## 使用方式
+
+### 使用 Make 命令(推荐)
+
+运行翻译最便捷的方式:
+
+```bash
+# Translate all docs to all languages
+make translate
+
+# Translate to specific language
+make translate LANG=ko
+
+# Specify API provider and model
+make translate LANG=ko PROVIDER=openai MODEL=gpt-4
+make translate LANG=ko PROVIDER=github MODEL=gpt-4o-mini
+```
+
+### 直接使用脚本
+
+#### 翻译全部文档
+
+把全部文档翻译为所有支持的语言:
+
+```bash
+python scripts/translate.py --api-provider openai
+```
+
+### 翻译为指定语言
+
+仅翻译为韩文:
+
+```bash
+python scripts/translate.py --target-lang ko --api-provider openai
+```
+
+### 翻译指定文件
+
+只翻译特定的文档文件:
+
+```bash
+python scripts/translate.py \
+ --target-lang ko \
+ --files user-guide/installation.md user-guide/quick-start.md \
+ --api-provider openai
+```
+
+### 跳过 PR 创建
+
+翻译但不创建 GitHub PR:
+
+```bash
+python scripts/translate.py --target-lang ko --no-pr --api-provider openai
+```
+
+### 使用 Anthropic Claude
+
+使用 Anthropic 的 Claude 代替 OpenAI:
+
+```bash
+python scripts/translate.py \
+ --target-lang ko \
+ --api-provider anthropic \
+ --api-key "sk-ant-..."
+```
+
+## 目录结构
+
+完成翻译后,文档结构形如:
+
+```
+docs/
+├── en/ # English (original)
+│ ├── index.md
+│ ├── user-guide/
+│ │ ├── installation.md
+│ │ ├── quick-start.md
+│ │ └── ...
+│ ├── tutorial/
+│ └── ...
+├── ko/ # Korean
+│ ├── index.md
+│ ├── user-guide/
+│ └── ...
+├── ja/ # Japanese
+├── zh/ # Chinese
+├── es/ # Spanish
+├── fr/ # French
+├── de/ # German
+├── css/ # Shared assets
+├── js/ # Shared assets
+└── img/ # Shared assets
+```
+
+## 翻译工作流
+
+### 1. 用英文撰写文档
+
+所有文档都应先用英文写在 `docs/` 目录:
+
+```bash
+# Create new documentation
+vim docs/user-guide/new-feature.md
+```
+
+### 2. 运行翻译
+
+英文文档完成后,运行翻译脚本:
+
+```bash
+python scripts/translate.py --target-lang ko
+```
+
+### 3. 评审 Pull Request
+
+脚本会创建包含翻译结果的 Pull Request。评审时请:
+
+1. 检查 markdown 格式是否保留
+2. 核对技术术语是否处理得当
+3. 确认代码示例未被改动
+4. 检查与目标语言相关的具体问题
+
+### Changelog 政策
+
+- 仓库根目录的 `CHANGELOG.md` 保持英文。
+- 不要开启「把根 changelog 中的发布历史改写成其他语言」的翻译 PR。
+- 如果某个语言需要 changelog 页面,请把 `docs//changelog.md` 视为规范英文 changelog 的包装页或入口页。
+
+### 4. 批准并合并(面向维护者)
+
+翻译核对完毕后:
+
+```bash
+gh pr review --approve
+gh pr merge
+```
+
+### 5. 部署文档
+
+文档站会自动重建,新增的翻译会随之上线。
+
+## 翻译配置
+
+编辑 `scripts/translation_config.json` 进行定制:
+
+```json
+{
+ "source_language": "en",
+ "target_languages": [
+ {
+ "code": "ko",
+ "name": "Korean",
+ "native_name": "한국어",
+ "enabled": true
+ }
+ ],
+ "translation_settings": {
+ "default_api_provider": "openai",
+ "batch_size": 5,
+ "preserve_formatting": true
+ },
+ "github_settings": {
+ "create_pr_by_default": true,
+ "branch_prefix": "translation"
+ }
+}
+```
+
+## 最佳实践
+
+### 源文档相关
+
+1. **使用清晰的语言**:让英文表达清楚、简洁,便于翻译
+2. **术语一致**:对技术术语保持一致
+3. **正确使用代码块**:始终在代码块上标明语言
+4. **链接核对**:内部链接都使用相对路径
+
+### 翻译评审相关
+
+1. **技术术语**:确认这些术语在目标语言下是否恰当
+2. **文化语境**:判断示例是否需要本地化
+3. **格式**:保留全部 markdown 格式
+4. **代码完整性**:确认代码块未被改动
+
+## 故障排查
+
+### 触发 API 限流
+
+如果触发 API 限流,可按更小的批次翻译:
+
+```bash
+# Translate only user guide
+python scripts/translate.py \
+ --target-lang ko \
+ --files user-guide/*.md
+```
+
+### 翻译质量问题
+
+若翻译质量不佳:
+
+1. 检查 API key 是否有效
+2. 换一家 AI provider 试试
+3. 把复杂文档拆成更小的章节
+4. 手动评审并修订翻译
+
+### GitHub PR 创建失败
+
+如果 PR 创建失败:
+
+```bash
+# Translate without PR
+python scripts/translate.py --target-lang ko --no-pr
+
+# Manually create PR
+git checkout -b translation/ko
+git add docs/ko/
+git commit -m "Add Korean translations"
+git push -u origin translation/ko
+gh pr create --title "Add Korean translations"
+```
+
+## 手动翻译
+
+也可以完全手动翻译:
+
+1. 把英文文件复制到目标语言目录:
+```bash
+mkdir -p docs/ko/user-guide
+cp docs/en/user-guide/installation.md docs/ko/user-guide/installation.md
+```
+
+2. 用您喜欢的编辑器编辑该文件
+3. 提交并创建 PR
+
+## 语言切换
+
+文档站顶部导航中包含语言切换器,用户可以:
+
+1. 点击语言选择器
+2. 选择心仪的语言
+3. 在翻译过的文档间浏览
+
+## 贡献新语言
+
+要新增一种语言:
+
+1. 编辑 `scripts/translation_config.json`:
+```json
+{
+ "code": "pt",
+ "name": "Portuguese",
+ "native_name": "Português",
+ "enabled": true
+}
+```
+
+2. 更新 `mkdocs.yml`:
+```yaml
+- locale: pt
+ name: Português
+ build: true
+```
+
+3. 运行翻译:
+```bash
+python scripts/translate.py --target-lang pt
+```
+
+## 需要帮助?
+
+- **Issues**:在 [GitHub Issues](https://github.com/bnbong/FastAPI-fastkit/issues) 反馈翻译问题
+- **Discussions**:在 [GitHub Discussions](https://github.com/bnbong/FastAPI-fastkit/discussions) 提问
+- **Contributing**:参见 [CONTRIBUTING.md](https://github.com/bnbong/FastAPI-fastkit/blob/main/CONTRIBUTING.md)
+
+## 翻译质量标准
+
+所有翻译都必须达到以下标准:
+
+- ✅ 保留全部 markdown 格式
+- ✅ 保持代码块原样不动
+- ✅ 妥善处理技术术语
+- ✅ 语法与拼写正确
+- ✅ 遵循目标语言的约定
+- ✅ 验证所有链接可用
+
+感谢您为 FastAPI-fastkit 的翻译工作贡献力量!🌍
diff --git a/docs/zh/index.md b/docs/zh/index.md
new file mode 100644
index 0000000..4df9647
--- /dev/null
+++ b/docs/zh/index.md
@@ -0,0 +1,577 @@
+
+
+
+
+FastAPI-fastkit:面向 Python 与 FastAPI 新手的快速、易用启动套件
+
+
+
+
+
+
+
+
+
+
+
+
+
+---
+
+本项目旨在帮助 Python 与 [FastAPI](https://github.com/fastapi/fastapi) 新手更快完成基于 Python 的 Web 应用开发环境配置。
+
+本项目的灵感来自 `Spring Boot Initializr` 以及 Django 的 `django-admin` CLI 工具。
+
+!!! info "翻译状态"
+ 英文是本文档的权威来源。语言切换器中的其他语言可能尚未完整翻译,缺失页面会按页回退到英文。请参阅 [翻译状态](reference/translation-status.md) 了解各语言版本的实际覆盖情况。
+
+## 主要特性
+
+- **⚡ 即时创建 FastAPI 项目**:通过 CLI 快速创建 FastAPI 工作区与项目,灵感来自 [Django](https://github.com/django/django) 的 `django-admin`
+- **✨ 交互式项目构建器**:对数据库、认证、缓存、监控等进行分步引导式选择,并自动生成代码
+- **🎨 更美观的 CLI 输出**:基于 [rich](https://github.com/Textualize/rich) 提供更好的 CLI 体验
+- **📋 基于标准的 FastAPI 项目模板**:所有 FastAPI-fastkit 模板都遵循 Python 标准与 FastAPI 常见实践
+- **🔍 自动化的模板质量保障**:通过每周自动化测试,确保所有模板始终可用并保持更新
+- **🚀 多种项目模板**:提供多种预配置模板,覆盖 async CRUD、Docker、PostgreSQL 等不同使用场景
+- **📦 支持多种包管理器**:可选用您偏好的 Python 包管理器(pip、uv、pdm、poetry)管理依赖
+
+## 安装
+
+请在您的 Python 环境中安装 `FastAPI-fastkit`。
+
+
+
+```console
+$ pip install FastAPI-fastkit
+---> 100%
+```
+
+
+
+
+## 使用方法
+
+### 立即创建新的 FastAPI 项目工作区
+
+现在您可以使用 FastAPI-fastkit 快速启动一个新的 FastAPI 项目。
+
+使用下面的命令即可创建新的 FastAPI 项目工作区:
+
+
+
+```console
+$ fastkit init
+Enter the project name: my-awesome-project
+Enter the author name: John Doe
+Enter the author email: john@example.com
+Enter the project description: My awesome FastAPI project
+
+ Project Information
+┌──────────────┬────────────────────────────┐
+│ Project Name │ my-awesome-project │
+│ Author │ John Doe │
+│ Author Email │ john@example.com │
+│ Description │ My awesome FastAPI project │
+└──────────────┴────────────────────────────┘
+
+Available Stacks and Dependencies:
+ MINIMAL Stack
+┌──────────────┬───────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ pydantic │
+│ Dependency 4 │ pydantic-settings │
+└──────────────┴───────────────────┘
+
+ STANDARD Stack
+┌──────────────┬───────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ sqlalchemy │
+│ Dependency 4 │ alembic │
+│ Dependency 5 │ pytest │
+│ Dependency 6 │ pydantic │
+│ Dependency 7 │ pydantic-settings │
+└──────────────┴───────────────────┘
+
+ FULL Stack
+┌──────────────┬───────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ sqlalchemy │
+│ Dependency 4 │ alembic │
+│ Dependency 5 │ pytest │
+│ Dependency 6 │ redis │
+│ Dependency 7 │ celery │
+│ Dependency 8 │ pydantic │
+│ Dependency 9 │ pydantic-settings │
+└──────────────┴───────────────────┘
+
+Select stack (minimal, standard, full): minimal
+
+Available Package Managers:
+ Package Managers
+┌────────┬────────────────────────────────────────────┐
+│ PIP │ Standard Python package manager │
+│ UV │ Fast Python package manager │
+│ PDM │ Modern Python dependency management │
+│ POETRY │ Python dependency management and packaging │
+└────────┴────────────────────────────────────────────┘
+
+Select package manager (pip, uv, pdm, poetry) [uv]: uv
+Do you want to proceed with project creation? [y/N]: y
+FastAPI project will deploy at '~your-project-path~'
+
+╭──────────────────────── Info ────────────────────────╮
+│ ℹ Injected metadata into setup.py │
+╰──────────────────────────────────────────────────────╯
+╭──────────────────────── Info ────────────────────────╮
+│ ℹ Injected metadata into config file │
+╰──────────────────────────────────────────────────────╯
+
+ Creating Project:
+ my-awesome-project
+┌───────────────────┬───────────┐
+│ Component │ Collected │
+│ fastapi │ ✓ │
+│ uvicorn │ ✓ │
+│ pydantic │ ✓ │
+│ pydantic-settings │ ✓ │
+└───────────────────┴───────────┘
+
+Creating virtual environment...
+
+╭──────────────────────── Info ────────────────────────╮
+│ ℹ venv created at │
+│ ~your-project-path~/my-awesome-project/.venv │
+│ To activate the virtual environment, run: │
+│ │
+│ source │
+│ ~your-project-path~/my-awesome-project/.venv/bin/act │
+│ ivate │
+╰──────────────────────────────────────────────────────╯
+
+Installing dependencies...
+⠙ Setting up project environment...Collecting
+
+---> 100%
+
+╭─────────────────────── Success ───────────────────────╮
+│ ✨ Dependencies installed successfully │
+╰───────────────────────────────────────────────────────╯
+╭─────────────────────── Success ───────────────────────╮
+│ ✨ FastAPI project 'my-awesome-project' has been │
+│ created successfully and saved to │
+│ ~your-project-path~! │
+╰───────────────────────────────────────────────────────╯
+╭──────────────────────── Info ────────────────────────╮
+│ ℹ To start your project, run 'fastkit runserver' at │
+│ newly created FastAPI project directory │
+╰──────────────────────────────────────────────────────╯
+```
+
+
+
+该命令将创建一个包含 Python 虚拟环境的新 FastAPI 项目工作区。
+
+### 使用交互模式创建项目 ✨ 新功能
+
+如果项目需求更复杂,可以使用 **交互模式** 通过功能选择一步步搭建 FastAPI 应用:
+
+
+
+```console
+$ fastkit init --interactive
+
+⚡ FastAPI-fastkit Interactive Project Setup ⚡
+
+📋 Basic Project Information
+Enter the project name: my-fullstack-project
+Enter the author name: John Doe
+Enter the author email: john@example.com
+Enter the project description: Full-stack FastAPI project with PostgreSQL and JWT
+
+🧱 Architecture Preset
+Pick a project layout. Press Enter to accept the recommended default.
+ 1. minimal - Smallest viable FastAPI app
+ 2. single-module - Everything in one module (prototypes / scripts)
+ 3. classic-layered - api/routes + crud + schemas + core (à la fastapi-default)
+ 4. domain-starter - Domain-oriented src/app/domains// (recommended)
+
+Select architecture preset: [4]
+
+🗄️ Database Selection
+Select database (PostgreSQL, MySQL, MongoDB, Redis, SQLite, None):
+ 1. PostgreSQL - PostgreSQL database with SQLAlchemy
+ 2. MySQL - MySQL database with SQLAlchemy
+ 3. MongoDB - MongoDB with motor async driver
+ 4. Redis - Redis for caching and session storage
+ 5. SQLite - SQLite database for development
+ 6. None - No database
+
+Select database: 1
+
+🔐 Authentication Selection
+Select authentication (JWT, OAuth2, FastAPI-Users, Session-based, None):
+ 1. JWT - JSON Web Token authentication
+ 2. OAuth2 - OAuth2 with password flow
+ 3. FastAPI-Users - Full featured user management
+ 4. Session-based - Cookie-based sessions
+ 5. None - No authentication
+
+Select authentication: 1
+
+⚙️ Background Tasks Selection
+Select background tasks (Celery, Dramatiq, None):
+ 1. Celery - Distributed task queue
+ 2. Dramatiq - Fast and reliable task processing
+ 3. None - No background tasks
+
+Select background tasks: 1
+
+💾 Caching Selection
+Select caching (Redis, fastapi-cache2, None):
+ 1. Redis - Redis caching
+ 2. fastapi-cache2 - Simple caching for FastAPI
+ 3. None - No caching
+
+Select caching: 1
+
+📊 Monitoring Selection
+Select monitoring (Loguru, OpenTelemetry, Prometheus, None):
+ 1. Loguru - Simple and powerful logging
+ 2. OpenTelemetry - Observability framework
+ 3. Prometheus - Metrics and monitoring
+ 4. None - No monitoring
+
+Select monitoring: 3
+
+🧪 Testing Framework Selection
+Select testing framework (Basic, Coverage, Advanced, None):
+ 1. Basic - pytest + httpx for API testing
+ 2. Coverage - Basic + code coverage
+ 3. Advanced - Coverage + faker + factory-boy for fixtures
+ 4. None - No testing framework
+
+Select testing framework: 2
+
+🛠️ Additional Utilities
+Select utilities (comma-separated numbers, e.g., 1,3,4):
+ 1. CORS - Cross-Origin Resource Sharing
+ 2. Rate-Limiting - Request rate limiting
+ 3. Pagination - Pagination support
+ 4. WebSocket - WebSocket support
+
+Select utilities: 1
+
+🚀 Deployment Configuration
+Select deployment option:
+ 1. Docker - Generate Dockerfile
+ 2. docker-compose - Generate docker-compose.yml (includes Docker)
+ 3. None - No deployment configuration
+
+Select deployment option: 2
+
+📦 Package Manager Selection
+Select package manager (pip, uv, pdm, poetry): uv
+
+📝 Custom Packages (optional)
+Enter custom package names (comma-separated, press Enter to skip):
+
+📋 Project Configuration Summary
+┌─────────────────────┬───────────────────────────────────────────────────────────────────────────┐
+│ Setting │ Value │
+├─────────────────────┼───────────────────────────────────────────────────────────────────────────┤
+│ Project Name │ my-fullstack-project │
+│ Author │ John Doe │
+│ Email │ john@example.com │
+│ Description │ Full-stack FastAPI project with PostgreSQL and JWT │
+│ Architecture Preset │ domain-starter — Domain-oriented: src/app/domains// (recommended)│
+│ Database │ PostgreSQL │
+│ Authentication │ JWT │
+│ Async Tasks │ Celery │
+│ Caching │ Redis │
+│ Monitoring │ Prometheus │
+│ Testing │ Coverage │
+│ Utilities │ CORS │
+│ Package Manager │ uv │
+└─────────────────────┴───────────────────────────────────────────────────────────────────────────┘
+
+Total dependencies to install: 18
+
+Proceed with project creation? [Y/n]: y
+
+╭──────────────────────── Info ────────────────────────╮
+│ ℹ Injected metadata into pyproject.toml │
+╰──────────────────────────────────────────────────────╯
+╭─────────────────────── Success ───────────────────────╮
+│ ✨ Generated dependency file with 18 packages │
+╰───────────────────────────────────────────────────────╯
+╭──────────────────────── Info ────────────────────────╮
+│ ℹ Preserving template-shipped main.py for preset │
+│ 'domain-starter'. │
+╰──────────────────────────────────────────────────────╯
+╭─────────────────────── Success ───────────────────────╮
+│ ✨ Generated Docker deployment files │
+╰───────────────────────────────────────────────────────╯
+╭────────────────────── Warning ────────────────────────╮
+│ ⚠ Preset compatibility │
+│ fastapi-domain-starter's shipped src/app/main.py is │
+│ preserved. The selections below need manual wiring │
+│ there (CORS is already wired — set │
+│ BACKEND_CORS_ORIGINS in .env to activate it). │
+│ Affected selections (packages installed, but no │
+│ dynamic main.py edits applied for the │
+│ 'domain-starter' preset): Prometheus │
+╰───────────────────────────────────────────────────────╯
+╭─────────────────────── Success ───────────────────────╮
+│ ✨ Generated configuration files for selected stack │
+╰───────────────────────────────────────────────────────╯
+
+Creating virtual environment...
+Installing dependencies...
+
+----> 100%
+
+╭─────────────────────── Success ───────────────────────╮
+│ ✨ FastAPI project 'my-fullstack-project' from │
+│ 'fastapi-domain-starter' has been created! │
+╰───────────────────────────────────────────────────────╯
+```
+
+
+
+交互模式提供:
+
+- **架构预设选择**(`minimal` / `single-module` / `classic-layered` / `domain-starter`),用于决定基础模板与项目布局
+- **引导式功能选择**,覆盖数据库、认证、后台任务、缓存、监控等配置
+- **自动生成代码** —— 会根据预设行为有所不同(`minimal` / `single-module` 会重新生成 `main.py`;`classic-layered` / `domain-starter` 会保留模板自带的 `main.py` 并补充配置模块)
+- **感知预设的 Docker 生成** —— 生成的 `Dockerfile` 中 `CMD` 会指向当前预设真正的入口点(`src.main:app` 或 `src.app.main:app`)
+- **智能依赖管理**,自动兼容 pip
+- **功能校验**,当预设无法自动完成接入时会给出手动处理提示
+- **项目身份标识** 会写入生成的 `pyproject.toml`(description 标识 + `[tool.fastapi-fastkit]` 节),便于后续由 `is_fastkit_project()` 识别生成的项目
+
+### 向 FastAPI 项目添加新路由
+
+`FastAPI-fastkit` 让扩展 FastAPI 项目变得更简单。
+
+使用以下命令向您的 FastAPI 项目添加一个新的路由端点:
+
+
+
+```console
+$ fastkit addroute user my-awesome-project
+ Adding New Route
+┌──────────────────┬──────────────────────────────────────────┐
+│ Project │ my-awesome-project │
+│ Route Name │ user │
+│ Target Directory │ ~your-project-path~ │
+└──────────────────┴──────────────────────────────────────────┘
+
+Do you want to add route 'user' to project 'my-awesome-project'? [Y/n]: y
+
+╭──────────────────────── Info ────────────────────────╮
+│ ℹ Updated main.py to include the API router │
+╰──────────────────────────────────────────────────────╯
+╭─────────────────────── Success ───────────────────────╮
+│ ✨ Successfully added new route 'user' to project │
+│ `my-awesome-project` │
+╰───────────────────────────────────────────────────────╯
+```
+
+
+
+### 立即部署一个结构化的 FastAPI 示例项目
+
+您也可以从一个结构完整的 FastAPI 示例项目开始。
+
+这些示例项目覆盖不同技术栈,并内置了简单的 item CRUD 端点实现。
+
+使用下面的命令即可创建一个结构完整的 FastAPI 示例项目:
+
+
+
+```console
+$ fastkit startdemo
+Enter the project name: my-awesome-demo
+Enter the author name: John Doe
+Enter the author email: john@example.com
+Enter the project description: My awesome FastAPI demo
+Deploying FastAPI project using 'fastapi-default' template
+Template path:
+/~fastapi_fastkit-package-path~/fastapi_project_template/fastapi-default
+
+ Project Information
+┌──────────────┬─────────────────────────┐
+│ Project Name │ my-awesome-demo │
+│ Author │ John Doe │
+│ Author Email │ john@example.com │
+│ Description │ My awesome FastAPI demo │
+└──────────────┴─────────────────────────┘
+
+ Template Dependencies
+┌──────────────┬───────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ pydantic │
+│ Dependency 4 │ pydantic-settings │
+│ Dependency 5 │ python-dotenv │
+└──────────────┴───────────────────┘
+
+Available Package Managers:
+ Package Managers
+┌────────┬────────────────────────────────────────────┐
+│ PIP │ Standard Python package manager │
+│ UV │ Fast Python package manager │
+│ PDM │ Modern Python dependency management │
+│ POETRY │ Python dependency management and packaging │
+└────────┴────────────────────────────────────────────┘
+
+Select package manager (pip, uv, pdm, poetry) [uv]: uv
+Do you want to proceed with project creation? [y/N]: y
+FastAPI template project will deploy at '~your-project-path~'
+
+---> 100%
+
+╭─────────────────────── Success ───────────────────────╮
+│ ✨ Dependencies installed successfully │
+╰───────────────────────────────────────────────────────╯
+╭─────────────────────── Success ───────────────────────╮
+│ ✨ FastAPI project 'my-awesome-demo' from │
+│ 'fastapi-default' has been created and saved to │
+│ ~your-project-path~! │
+╰───────────────────────────────────────────────────────╯
+```
+
+
+
+如需查看可用的 FastAPI 示例列表,请运行:
+
+
+
+```console
+$ fastkit list-templates
+ Available Templates
+┌────────────────────────┬───────────────────────────────────────────────────────┐
+│ fastapi-custom-response│ Async Item Management API with Custom Response System │
+│ fastapi-mcp │ FastAPI MCP Project │
+│ fastapi-domain-starter │ FastAPI Domain Starter │
+│ fastapi-dockerized │ Dockerized FastAPI Item Management API │
+│ fastapi-empty │ Minimal FastAPI Template │
+│ fastapi-async-crud │ Async Item Management API Server │
+│ fastapi-psql-orm │ Dockerized FastAPI Item Management API with │
+│ │ PostgreSQL │
+│ fastapi-default │ Simple FastAPI Project │
+│ fastapi-single-module │ FastAPI Single Module Template │
+└────────────────────────┴───────────────────────────────────────────────────────┘
+```
+
+
+
+## 文档
+
+如需更完整的指南与详细使用说明,请查阅我们的文档:
+
+- 📚 **[用户指南](user-guide/quick-start.md)** —— 详细的安装与使用指南
+- 🎯 **[教程](tutorial/getting-started.md)** —— 面向新手的分步教程
+- 📖 **[CLI 参考](user-guide/cli-reference.md)** —— 完整的命令参考
+- 🔍 **[模板质量保障](reference/template-quality-assurance.md)** —— 自动化测试与质量标准
+
+## 🚀 基于模板的教程
+
+通过我们的预构建模板,在实际用例中学习 FastAPI 开发:
+
+### 📖 核心教程
+
+- **[构建基础 API 服务器](tutorial/basic-api-server.md)** —— 使用 `fastapi-default` 模板创建您的第一个 FastAPI 服务器
+- **[构建异步 CRUD API](tutorial/async-crud-api.md)** —— 使用 `fastapi-async-crud` 模板开发高性能异步 API
+- **[领域驱动项目(Domain Starter)](tutorial/domain-starter.md)** —— 使用 `fastapi-domain-starter` 模板构建中型规模的 API,这是推荐的现代默认选项
+
+### 🗄️ 数据库与基础设施
+
+- **[集成数据库](tutorial/database-integration.md)** —— 借助 `fastapi-psql-orm` 模板使用 PostgreSQL + SQLAlchemy
+- **[Docker 化与部署](tutorial/docker-deployment.md)** —— 借助 `fastapi-dockerized` 模板搭建生产部署环境
+
+### ⚡ 高级功能
+
+- **[自定义响应处理与高级 API 设计](tutorial/custom-response-handling.md)** —— 借助 `fastapi-custom-response` 模板构建企业级 API
+- **[集成 MCP](tutorial/mcp-integration.md)** —— 借助 `fastapi-mcp` 模板创建与 AI 模型集成的 API 服务器
+
+每个教程包含:
+
+- ✅ **实用示例** —— 可直接用于真实项目的代码
+- ✅ **分步指南** —— 详细的说明,易于新手跟随
+- ✅ **最佳实践** —— 行业标准模式与安全考量
+- ✅ **拓展方法** —— 帮助您将项目推向新阶段
+
+## 贡献
+
+我们欢迎社区的贡献!FastAPI-fastkit 旨在帮助 Python 与 FastAPI 的新手,而您的贡献能带来巨大的影响。
+
+### 您可以贡献什么
+
+- 🚀 **新的 FastAPI 模板** —— 为不同的场景添加模板
+- 🐛 **修复缺陷** —— 帮助我们提升稳定性与可靠性
+- 📚 **文档** —— 改进指南、示例与翻译
+- 🧪 **测试** —— 提高测试覆盖率,补充集成测试
+- 💡 **功能** —— 提议并实现新的 CLI 功能
+
+### 如何开始贡献
+
+要开始为 FastAPI-fastkit 贡献,请参考我们的完整指南:
+
+- **[开发环境设置](contributing/development-setup.md)** —— 配置开发环境的完整指南
+- **[代码规范](contributing/code-guidelines.md)** —— 编码标准与最佳实践
+- **[CONTRIBUTING.md](https://github.com/bnbong/FastAPI-fastkit/blob/main/CONTRIBUTING.md)** —— 完整的贡献指南
+- **[CODE_OF_CONDUCT.md](https://github.com/bnbong/FastAPI-fastkit/blob/main/CODE_OF_CONDUCT.md)** —— 项目原则与社区准则
+- **[SECURITY.md](https://github.com/bnbong/FastAPI-fastkit/blob/main/SECURITY.md)** —— 安全指引与上报方式
+
+## FastAPI-fastkit 的意义
+
+FastAPI-fastkit 的目标是为 Python 与 FastAPI 的新手提供一个快速、易用的启动套件。
+
+这个想法的初衷,是帮助 FastAPI 新手从一开始就轻松上手 —— 这与 [FastAPI 0.111.0 版本更新](https://github.com/fastapi/fastapi/releases/tag/0.111.0) 中加入的 FastAPI-cli 包对生产环境的意义不谋而合。
+
+作为一名长期使用并热爱 FastAPI 的开发者,我希望开发一个项目,可以帮助实现 FastAPI 开发者 [tiangolo](https://github.com/tiangolo) 所表达的 [那份美好初衷](https://github.com/fastapi/fastapi/pull/11522#issuecomment-2264639417)。
+
+FastAPI-fastkit 通过以下几点,在「快速上手」与「构建生产级应用」之间架起桥梁:
+
+- **新手即可立刻获得生产力**,不再被复杂的配置流程吓退
+- **每个模板内置最佳实践**,帮助使用者学习正确的 FastAPI 模式
+- **可扩展的基础**,陪伴使用者从新手成长为专家
+- **社区驱动的模板**,反映真实世界的 FastAPI 使用模式
+
+## 下一步
+
+准备好开始使用 FastAPI-fastkit 了吗?请按以下步骤继续:
+
+### 🚀 快速开始
+
+1. **[安装](user-guide/installation.md)**:安装 FastAPI-fastkit
+2. **[快速上手](user-guide/quick-start.md)**:5 分钟内创建您的第一个项目
+3. **[入门教程](tutorial/getting-started.md)**:分步详细教程
+
+### 📚 进阶学习
+
+- **[创建项目](user-guide/creating-projects.md)**:使用不同的技术栈创建项目
+- **[添加路由](user-guide/adding-routes.md)**:为您的项目添加 API 端点
+- **[使用模板](user-guide/using-templates.md)**:使用预构建的项目模板
+
+### 🛠️ 参与贡献
+
+想要为 FastAPI-fastkit 做贡献?
+
+- **[开发环境设置](contributing/development-setup.md)**:配置您的开发环境
+- **[代码规范](contributing/code-guidelines.md)**:遵循我们的编码标准与最佳实践
+- **[贡献指南](https://github.com/bnbong/FastAPI-fastkit/blob/main/CONTRIBUTING.md)**:完整的贡献指南
+
+### 🔍 参考
+
+- **[CLI 参考](user-guide/cli-reference.md)**:完整的 CLI 命令参考
+- **[模板质量保障](reference/template-quality-assurance.md)**:自动化测试与质量标准
+- **[FAQ](reference/faq.md)**:常见问题解答
+- **[GitHub 仓库](https://github.com/bnbong/FastAPI-fastkit)**:源代码与问题跟踪
+
+## 许可证
+
+本项目采用 MIT 许可证 —— 详细信息见 [LICENSE](https://github.com/bnbong/FastAPI-fastkit/blob/main/LICENSE) 文件。
diff --git a/docs/zh/reference/faq.md b/docs/zh/reference/faq.md
new file mode 100644
index 0000000..c9c9f21
--- /dev/null
+++ b/docs/zh/reference/faq.md
@@ -0,0 +1,784 @@
+# 常见问题
+
+围绕 FastAPI-fastkit 的常见问答。
+
+## 安装与配置
+
+### 问:支持哪些 Python 版本?
+
+**答:** FastAPI-fastkit 需要 **Python 3.12 及以上**。我们建议使用最新的稳定版 Python,以获得最佳体验。
+
+
+
+```console
+$ python --version
+Python 3.12.1
+
+$ pip install fastapi-fastkit
+```
+
+
+
+### 问:如何安装 FastAPI-fastkit?
+
+**答:** 使用 pip 即可安装:
+
+
+
+```console
+# Latest stable version
+$ pip install fastapi-fastkit
+
+# Development version from GitHub
+$ pip install git+https://github.com/bnbong/FastAPI-fastkit.git
+
+# Specific version
+$ pip install fastapi-fastkit==1.0.0
+```
+
+
+
+### 问:安装时出现权限错误失败
+
+**答:** 请尝试在虚拟环境中安装,或以当前用户身份安装:
+
+
+
+```console
+# Create virtual environment
+$ python -m venv fastapi-env
+$ source fastapi-env/bin/activate # On Windows: fastapi-env\Scripts\activate
+
+# Install in virtual environment
+$ pip install fastapi-fastkit
+
+# Or install for current user only
+$ pip install --user fastapi-fastkit
+```
+
+
+
+### 问:安装后找不到 `fastkit` 命令
+
+**答:** 这通常意味着安装目录不在您的 PATH 中:
+
+
+
+```console
+# Check if installed
+$ pip show fastapi-fastkit
+
+# Find installation location
+$ python -c "import fastapi_fastkit; print(fastapi_fastkit.__file__)"
+
+# Try running directly
+$ python -m fastapi_fastkit --version
+
+# Or add to PATH (Linux/macOS)
+$ export PATH="$HOME/.local/bin:$PATH"
+```
+
+
+
+## 创建项目
+
+### 问:可选哪些依赖栈?
+
+**答:** FastAPI-fastkit 提供三种依赖栈:
+
+- **MINIMAL**:FastAPI、Uvicorn、Pydantic、Pydantic-Settings(基础 Web API)
+- **STANDARD**:再加上 SQLAlchemy、Alembic、pytest(数据库支持)
+- **FULL**:再加上 Redis、Celery(后台任务)
+
+!!! tip "默认包管理器"
+ 默认包管理器是 `uv`,依赖安装更快。您也可以选择 `pip`、`pdm` 或 `poetry`。
+
+
+
+```console
+$ fastkit init
+# Select your preferred stack during project creation
+```
+
+
+
+### 问:可以自定义项目模板吗?
+
+**答:** 可以!您可以:
+
+1. **使用现有模板**(`fastkit startdemo`)
+2. **创建自定义模板** —— 在现有模板基础上复制并修改
+3. **逐步添加路由**(`fastkit addroute`)
+
+
+
+```console
+# Use pre-built templates
+$ fastkit list-templates
+$ fastkit startdemo
+
+# Add routes to existing project
+$ fastkit addroute users . # Add 'users' route to current directory
+$ fastkit addroute users my-project # Add 'users' route to 'my-project'
+```
+
+
+
+### 问:项目名称有什么格式要求?
+
+**答:** 项目名称必须是合法的 Python 标识符:
+
+- ✅ `my-api`、`blog_system`、`UserService`
+- ❌ `my api`、`123project`、`project-name!`
+
+
+
+```console
+$ fastkit init
+Enter the project name: my_awesome_api # Valid
+Enter the project name: my-awesome-api # Valid (hyphens converted to underscores)
+```
+
+
+
+### 问:创建项目失败,提示「directory already exists」
+
+**答:** 项目目录已经存在。处理方式:
+
+1. **换一个名字**
+2. **删除已有目录**(确认安全后)
+3. **使用其他输出位置**
+
+
+
+```console
+# Check if directory exists
+$ ls my-project
+
+# Remove if safe (CAUTION!)
+$ rm -rf my-project
+
+# Or create in different location
+$ mkdir projects
+$ cd projects
+$ fastkit init
+```
+
+
+
+### 问:如何用交互模式创建项目?
+
+**答:** 使用 `fastkit init --interactive` 进入引导式逐步项目创建,并自动智能选择功能:
+
+
+
+```console
+$ fastkit init --interactive
+```
+
+
+
+交互模式会依次带您完成以下步骤:
+
+1. **项目信息** —— 名称、作者、邮箱、描述。
+2. **架构预设** —— 选定项目布局。推荐默认是 `domain-starter`;直接回车即可接受。每种预设的具体布局,以及哪些功能组合需要手动接入,详见 [架构预设矩阵](preset-feature-matrix.md)。
+3. **功能选择** —— 数据库、认证、后台任务、缓存、监控、测试、工具、部署。
+4. **包管理器与自定义包** —— pip / uv / pdm / poetry,以及您想固定下来的额外依赖。
+5. **确认** —— 在项目创建之前展示一张总结表,列出全部选择(包含架构预设)。
+
+交互模式提供丰富的功能目录可选:
+
+| 类别 | 可选项 |
+|----------|-------------------|
+| **架构** | minimal、single-module、classic-layered、**domain-starter**(推荐默认) |
+| **数据库** | PostgreSQL、MySQL、MongoDB、Redis、SQLite |
+| **认证** | JWT、OAuth2、FastAPI-Users、基于会话 |
+| **后台任务** | Celery、Dramatiq |
+| **测试** | Basic(pytest)、Coverage、Advanced(附带 faker、factory-boy) |
+| **缓存** | 基于 fastapi-cache2 的 Redis |
+| **监控** | Loguru、OpenTelemetry、Prometheus |
+| **工具** | CORS、限流、分页、WebSocket |
+| **部署** | Docker、docker-compose,自动生成配置 |
+
+交互模式会自动生成:
+
+- 一个集成所选功能的 `main.py`
+- 当所选选项支持代码生成时,会生成数据库与认证的配置文件(例如数据库选 PostgreSQL/MySQL/SQLite/MongoDB,认证选 JWT/FastAPI-Users);其他选项仅安装必要的包
+- 与所选部署选项匹配的部署文件(选了 `Docker` 会生成 `Dockerfile`,选了 `docker-compose` 会生成 `docker-compose.yml`)
+- 基于所选测试选项的测试配置(只有选择 `Coverage` 或 `Advanced` 时才会包含覆盖率设置)
+
+### 问:如何查看交互模式可用的功能?
+
+**答:** 使用 `list-features` 命令,可以展示所有可用功能及其包:
+
+
+
+```console
+$ fastkit list-features
+# Shows all available features organized by category
+# with their associated packages
+```
+
+
+
+这可以帮助您理解每个功能选择会安装哪些包。
+
+## 路由开发
+
+### 问:如何为路由加上认证?
+
+**答:** 创建一个用于认证的依赖:
+
+```python
+# src/api/deps.py
+from fastapi import Depends, HTTPException, status
+from fastapi.security import HTTPBearer
+
+security = HTTPBearer()
+
+def get_current_user(token: str = Depends(security)):
+ # Verify token and return user
+ if not verify_token(token):
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Invalid authentication credentials"
+ )
+ return get_user_from_token(token)
+
+# src/api/routes/users.py
+@router.get("/me")
+def get_current_user_profile(user = Depends(get_current_user)):
+ return user
+```
+
+### 问:如何为项目添加数据库模型?
+
+**答:** 在 STANDARD 或 FULL 栈中,创建 SQLAlchemy 模型:
+
+```python
+# src/models/users.py
+from sqlalchemy import Column, Integer, String, Boolean
+from sqlalchemy.ext.declarative import declarative_base
+
+Base = declarative_base()
+
+class User(Base):
+ __tablename__ = "users"
+
+ id = Column(Integer, primary_key=True, index=True)
+ email = Column(String, unique=True, index=True)
+ username = Column(String, unique=True, index=True)
+ hashed_password = Column(String)
+ is_active = Column(Boolean, default=True)
+```
+
+### 问:如何为请求数据加校验?
+
+**答:** 在 schema 中使用 Pydantic 模型:
+
+```python
+# src/schemas/users.py
+from pydantic import BaseModel, EmailStr, Field
+
+class UserCreate(BaseModel):
+ email: EmailStr
+ username: str = Field(..., min_length=3, max_length=50)
+ password: str = Field(..., min_length=8)
+
+ @validator('username')
+ def validate_username(cls, v):
+ if not v.isalnum():
+ raise ValueError('Username must be alphanumeric')
+ return v
+```
+
+### 问:如何处理文件上传?
+
+**答:** 使用 FastAPI 的 `UploadFile`:
+
+```python
+from fastapi import UploadFile, File
+
+@router.post("/upload")
+async def upload_file(file: UploadFile = File(...)):
+ contents = await file.read()
+
+ # Save file
+ with open(f"uploads/{file.filename}", "wb") as f:
+ f.write(contents)
+
+ return {"filename": file.filename, "size": len(contents)}
+```
+
+## 模板
+
+### 问:有哪些可用模板?
+
+**答:** FastAPI-fastkit 自带多个预制模板:
+
+
+
+```console
+$ fastkit list-templates
+ Available Templates
+┌─────────────────────────┬───────────────────────────────────┐
+│ fastapi-default │ Simple FastAPI Project │
+│ fastapi-async-crud │ Async Item Management API Server │
+│ fastapi-custom-response │ Custom Response System │
+│ fastapi-dockerized │ Dockerized FastAPI API │
+│ fastapi-empty │ Minimal FastAPI Project │
+│ fastapi-mcp │ MCP (Model Context Protocol) API │
+│ fastapi-psql-orm │ PostgreSQL FastAPI API │
+│ fastapi-single-module │ Single-file FastAPI Project │
+└─────────────────────────┴───────────────────────────────────┘
+```
+
+
+
+### 问:如何使用指定模板?
+
+**答:** 使用 `startdemo` 命令:
+
+
+
+```console
+$ fastkit startdemo
+Enter the project name: my-blog
+Select template: fastapi-psql-orm
+```
+
+
+
+### 问:可以创建自定义模板吗?
+
+**答:** 可以!创建目录结构并使用模板变量:
+
+```
+my-template/
+├── src/
+│ └── main.py-tpl
+├── requirements.txt-tpl
+└── template.yaml
+```
+
+```python
+# main.py-tpl
+from fastapi import FastAPI
+
+app = FastAPI(title="{{PROJECT_NAME}}")
+
+@app.get("/")
+def read_root():
+ return {"message": "Hello from {{PROJECT_NAME}}!"}
+```
+
+### 问:如何修改已有模板?
+
+**答:** 模板位于 `fastapi_project_template` 目录,您可以:
+
+1. **fork 仓库** 并修改模板
+2. **基于现有模板创建自定义模板**
+3. **在创建项目后覆盖特定文件**
+
+## 开发服务器
+
+### 问:如何启动开发服务器?
+
+**答:** 在项目目录中使用 `runserver` 命令:
+
+
+
+```console
+$ cd my-project
+$ source .venv/bin/activate # Activate virtual environment
+$ fastkit runserver
+INFO: Uvicorn running on http://127.0.0.1:8000
+```
+
+
+
+### 问:服务器无法启动 —— 「Address already in use」
+
+**答:** 8000 端口被占用。换一个端口,或结束已有进程:
+
+
+
+```console
+# Use different port
+$ fastkit runserver --port 8080
+
+# Or find and kill existing process
+$ lsof -ti:8000 | xargs kill -9
+
+# On Windows
+$ netstat -ano | findstr :8000
+$ taskkill /PID
/F
+```
+
+
+
+### 问:自动重载不生效
+
+**答:** 确认您处在项目目录中,并已激活虚拟环境:
+
+
+
+```console
+# Check current directory
+$ pwd
+/path/to/my-project
+
+# Check virtual environment
+$ which python
+/path/to/my-project/.venv/bin/python
+
+# Start with explicit reload
+$ fastkit runserver --reload
+```
+
+
+
+### 问:生产环境下如何配置服务器?
+
+**答:** **不要**在生产环境使用开发服务器,而应:
+
+```python
+# Use gunicorn or similar WSGI server
+$ pip install gunicorn
+$ gunicorn src.main:app -w 4 -k uvicorn.workers.UvicornWorker
+
+# Or use Docker with the fastapi-dockerized template
+$ fastkit startdemo # Select fastapi-dockerized
+$ docker build -t my-app .
+$ docker run -p 8000:8000 my-app
+```
+
+## 性能与优化
+
+### 问:如何提升 API 性能?
+
+**答:** 多种优化策略:
+
+1. 对 I/O 操作使用 **async/await**
+2. 为开销大的操作**加缓存**
+3. **优化数据库查询**
+4. 用**后台任务**处理重活
+
+```python
+# Async endpoint
+@router.get("/users/{user_id}")
+async def get_user(user_id: int):
+ user = await users_service.get_user_async(user_id)
+ return user
+
+# Background task
+from fastapi import BackgroundTasks
+
+@router.post("/send-email")
+def send_email(background_tasks: BackgroundTasks, email: str):
+ background_tasks.add_task(send_notification_email, email)
+ return {"message": "Email will be sent in background"}
+```
+
+### 问:如何加入缓存?
+
+**答:** 使用 Redis 做缓存:
+
+```python
+import redis
+from functools import wraps
+
+redis_client = redis.Redis(host='localhost', port=6379, db=0)
+
+def cache_result(expiration: int = 300):
+ def decorator(func):
+ @wraps(func)
+ async def wrapper(*args, **kwargs):
+ cache_key = f"{func.__name__}:{hash(str(args) + str(kwargs))}"
+
+ # Try to get from cache
+ cached = redis_client.get(cache_key)
+ if cached:
+ return json.loads(cached)
+
+ # Execute function and cache result
+ result = await func(*args, **kwargs)
+ redis_client.setex(cache_key, expiration, json.dumps(result))
+ return result
+ return wrapper
+ return decorator
+
+@cache_result(expiration=600)
+async def get_expensive_data():
+ # Expensive operation
+ return complex_calculation()
+```
+
+### 问:如何处理大量并发请求?
+
+**答:** 使用合适的服务器配置:
+
+
+
+```console
+# Development
+$ fastkit runserver --workers 1 # Single worker for development
+
+# Production
+$ gunicorn src.main:app -w 4 -k uvicorn.workers.UvicornWorker
+$ uvicorn src.main:app --workers 4 --host 0.0.0.0 --port 8000
+```
+
+
+
+## 测试
+
+### 问:如何运行测试?
+
+**答:** 在项目目录中使用 pytest:
+
+
+
+```console
+$ cd my-project
+$ source .venv/bin/activate
+$ python -m pytest
+
+# With coverage
+$ python -m pytest --cov=src
+
+# Specific test file
+$ python -m pytest tests/test_users.py
+
+# With verbose output
+$ python -m pytest -v
+```
+
+
+
+### 问:如何编写 API 测试?
+
+**答:** 使用 FastAPI 的 test client:
+
+```python
+from fastapi.testclient import TestClient
+from src.main import app
+
+client = TestClient(app)
+
+def test_create_user():
+ response = client.post(
+ "/api/v1/users/",
+ json={"email": "test@example.com", "username": "testuser"}
+ )
+ assert response.status_code == 201
+ assert response.json()["email"] == "test@example.com"
+
+def test_get_user():
+ response = client.get("/api/v1/users/1")
+ assert response.status_code == 200
+```
+
+### 问:如何对外部依赖进行 mock?
+
+**答:** 使用 pytest fixture 与 mock:
+
+```python
+import pytest
+from unittest.mock import Mock, patch
+
+@pytest.fixture
+def mock_database():
+ with patch('src.database.get_db') as mock_db:
+ mock_db.return_value = Mock()
+ yield mock_db
+
+def test_user_creation_with_mock_db(mock_database):
+ # Test with mocked database
+ response = client.post("/api/v1/users/", json=user_data)
+ assert response.status_code == 201
+```
+
+## 参与贡献
+
+### 问:如何为 FastAPI-fastkit 做贡献?
+
+**答:** 按以下步骤即可:
+
+1. 在 GitHub 上 **fork 仓库**
+2. **配置开发环境**
+3. **创建特性分支**
+4. **进行改动**并附上测试
+5. **提交 Pull Request**
+
+
+
+```console
+$ git clone https://github.com/yourusername/FastAPI-fastkit.git
+$ cd FastAPI-fastkit
+$ make dev-setup # Set up development environment
+$ git checkout -b feature/my-feature
+# Make changes...
+$ make dev-check # Format, lint, and test
+$ git commit -m "feat: add new feature"
+$ git push origin feature/my-feature
+```
+
+
+
+### 问:Pull Request 应当包含什么?
+
+**答:** 每个 Pull Request 都应包含:
+
+- [ ] **对改动的清晰描述**
+- [ ] 新功能对应的**测试**
+- [ ] 必要时更新**文档**
+- [ ] **遵循代码规范**
+- [ ] **所有检查通过**
+
+### 问:如何报告 bug?
+
+**答:** 在 GitHub 上创建 issue,包含:
+
+1. **bug 描述**与预期行为
+2. **复现步骤**
+3. **环境信息**(操作系统、Python 版本等)
+4. **错误信息**或日志
+5. **最小可复现示例**(如可能)
+
+### 问:如何提交新特性请求?
+
+**答:** 打开一个特性请求 issue,包含:
+
+1. 对特性的**清晰描述**
+2. **使用场景**与动机
+3. **建议的实现方式**(可选)
+4. **类似特性的例子**
+
+## 故障排查
+
+### 问:出现 import 错误
+
+**答:** 检查您的 Python path 与虚拟环境:
+
+
+
+```console
+# Check virtual environment is activated
+$ which python
+/path/to/project/.venv/bin/python
+
+# Check Python path
+$ python -c "import sys; print(sys.path)"
+
+# Reinstall in editable mode (for development)
+$ pip install -e .
+```
+
+
+
+### 问:数据库连接问题
+
+**答:** 对于带数据库的模板,请确认数据库已运行:
+
+
+
+```console
+# PostgreSQL template
+$ docker-compose up -d postgres # Start database
+$ alembic upgrade head # Run migrations
+
+# Check connection
+$ docker-compose logs postgres
+```
+
+
+
+### 问:找不到模板文件
+
+**答:** 这通常意味着模板路径有问题:
+
+
+
+```console
+# Check available templates
+$ fastkit list-templates
+
+# Check template directory
+$ python -c "import fastapi_fastkit; print(fastapi_fastkit.__path__)"
+
+# Reinstall if templates missing
+$ pip uninstall fastapi-fastkit
+$ pip install fastapi-fastkit
+```
+
+
+
+### 问:pre-commit 钩子失败
+
+**答:** 安装并运行钩子:
+
+
+
+```console
+$ pip install pre-commit
+$ pre-commit install
+$ pre-commit run --all-files
+
+# Fix formatting issues
+$ black src/ tests/
+$ isort src/ tests/
+```
+
+
+
+### 问:CI 测试失败,但本地通过
+
+**答:** 常见原因与解决办法:
+
+1. **环境差异**:核对 Python 版本是否一致
+2. **缺少依赖**:确认测试依赖已安装
+3. **路径问题**:使用绝对 import
+4. **时序问题**:在异步测试中加入合理的等待
+
+
+
+```console
+# Test with same Python version as CI
+$ python3.12 -m pytest
+
+# Check for missing dependencies
+$ pip install -r requirements-dev.txt
+
+# Run tests in isolated environment
+$ tox
+```
+
+
+
+## 获取帮助
+
+### 问:在哪里获取帮助?
+
+**答:** 多种渠道:
+
+- **GitHub Issues**:报告 bug 与请求特性
+- **GitHub Discussions**:提问与社区交流
+- **文档**:用户指南与教程
+- **代码示例**:查看已有模板与测试
+
+### 问:如何掌握最新动态?
+
+**答:** 关注项目更新:
+
+- 在 GitHub 上 **watch 仓库**
+- 通过 **releases** 了解新特性
+- 阅读 **changelog**,关注破坏性变更
+- 在文档中**遵循最佳实践**
+
+!!! tip "进阶小贴士"
+ - 始终在 Python 项目中使用虚拟环境
+ - 保持 FastAPI-fastkit 安装为最新
+ - 用 `fastkit --help` 查看可用命令
+ - 卡住时回到文档查阅
+ - 不要犹豫,在 GitHub Discussions 上多多提问
diff --git a/docs/zh/reference/preset-feature-matrix.md b/docs/zh/reference/preset-feature-matrix.md
new file mode 100644
index 0000000..46fc712
--- /dev/null
+++ b/docs/zh/reference/preset-feature-matrix.md
@@ -0,0 +1,60 @@
+# 架构预设 / 功能矩阵
+
+交互式的 `fastkit init --interactive` 在收集功能选择之前,会先询问一个 **架构预设**([issue #44](https://github.com/bnbong/FastAPI-fastkit/issues/44))。预设决定了生成项目的整体布局 —— 不同的预设会使用不同的基础模板,并把生成的配置文件落到不同位置,使其与已有结构相邻,而不是放进平行的 `src/config/` 子树中。
+
+本页是关于「每个预设的作用、文件落地位置、哪些功能组合需要手动接入」的权威说明。
+
+## 预设 → 基础模板
+
+| 预设 | 基础模板 | 描述 |
+|---|---|---|
+| `minimal` | `fastapi-empty` | 最小可运行的 FastAPI 应用 —— 占位的 `main.py` 会根据您的功能选择重新生成。 |
+| `single-module` | `fastapi-single-module` | 单文件 FastAPI 应用 —— `main.py` 会被重新生成。 |
+| `classic-layered` | `fastapi-default` | 分层布局(`api/routes`、`crud`、`schemas`、`core`)。自带的 `main.py` 会被保留。 |
+| `domain-starter` | `fastapi-domain-starter` | 领域驱动布局(`src/app/domains//`)。自带的 `main.py` 会被保留。**推荐默认选项。** |
+
+## 生成文件的落地位置
+
+| 预设 | `main.py` 覆盖策略 | 数据库配置落点 | 认证配置落点 |
+|---|---|---|---|
+| `minimal` | 在 `src/main.py` 处重新生成 | `src/config/database.py` | `src/config/auth.py` |
+| `single-module` | 在 `src/main.py` 处重新生成 | `src/config/database.py` | `src/config/auth.py` |
+| `classic-layered` | 保留(模板自带) | `src/core/database.py` | `src/core/auth.py` |
+| `domain-starter` | 保留(模板自带) | `src/app/core/database.py` | `src/app/core/auth.py` |
+
+## 各预设对数据库 / 认证功能的支持
+
+下列功能在**所有**预设中都支持 —— 包安装都会成功;差别只在于动态的 `main.py` 覆盖是否会自动接入它们。
+
+| 功能 | `minimal` / `single-module` | `classic-layered` / `domain-starter` |
+|---|---|---|
+| **数据库**(PostgreSQL、MySQL、SQLite、MongoDB) | 生成配置模块,**并且**在重新生成的 `main.py` 中插入 `await init_db()` 调用。 | 在预设对应路径生成配置模块。自带的 `main.py` 会**保留**,因此需要手动把 `get_db()` 接入路由器。 |
+| **认证**(JWT、FastAPI-Users、OAuth2、基于会话) | 生成认证配置模块。JWT 还会在重新生成的 `main.py` 中导入 `HTTPBearer`。 | 在预设对应路径生成认证配置模块。不会向 `main.py` 添加 import —— 需要手动接入依赖。 |
+| **后台任务**(Celery、Dramatiq) | 安装相应包;目前没有 main.py 覆盖。 | 同上。 |
+| **缓存**(Redis) | 安装相应包;目前没有 main.py 覆盖。 | 同上。 |
+| **CORS**(工具类) | 在重新生成的 `main.py` 中加入 `CORSMiddleware`,`allow_origins=['*']`。 | 自带的 `main.py` 中**已接入**(以 `settings.all_cors_origins` 作为条件)。只需在 `.env` 中设置 `BACKEND_CORS_ORIGINS` 即可启用 —— 无需修改代码。 |
+| **测试**(基础 / 覆盖率 / 进阶) | 在项目根生成 `pytest.ini`。 | 同上。 |
+| **部署**(Docker、docker-compose) | 在项目根写入 `Dockerfile` 和/或 `docker-compose.yml`。 | 同上。 |
+
+## 何时会出现「Preset compatibility」警告
+
+对于**保留自带 `main.py`** 的预设(`classic-layered`、`domain-starter`),某些功能选择不会被自动接入到应用。CLI 会在生成结束时一次性给出警告,列出哪些选择需要手动接入:
+
+| 选择的功能 | 在 `classic-layered` / `domain-starter` 下是否触发警告? |
+|---|---|
+| `CORS`(工具类) | ❌ —— 自带的 `main.py` 已接入。只需在 `.env` 中填好 `BACKEND_CORS_ORIGINS`。 |
+| `Rate-Limiting`(工具类) | ✅ —— 不会加入 `slowapi` 限流器的初始化 |
+| `Prometheus`(监控) | ✅ —— 不会调用 `Instrumentator().instrument(app)` |
+| 任意数据库 / 认证选择 | ⚠️ —— 配置文件已生成,但需要您手动在路由器中通过 `Depends()` 接入 |
+
+对 `minimal` 与 `single-module` 预设,动态的 `main.py` 覆盖会自动处理 CORS、限流与 Prometheus 监控,因此不会触发警告。
+
+## 不支持的组合(安全起见)
+
+策略设计者**刻意不会**尝试把生成的代码拼接进模板自带的 `main.py`。这样做有可能产生坏掉的 import 或重复的路由器。整体契约是:
+
+- 所选的包总是会被安装(这样 `pip freeze` 与用户意图匹配)。
+- 生成的配置模块总是落到对应预设的路径。
+- 对于保留 main 的预设,会告知用户哪些选择仍需手动接入,而不是产出悄无声息坏掉的代码。
+
+如果您需要对所有功能都进行自动接入,请选择 `minimal` 或 `single-module` —— 它们会基于功能开关重新生成 `main.py`。
diff --git a/docs/zh/reference/template-quality-assurance.md b/docs/zh/reference/template-quality-assurance.md
new file mode 100644
index 0000000..f6ffa83
--- /dev/null
+++ b/docs/zh/reference/template-quality-assurance.md
@@ -0,0 +1,219 @@
+# 模板质量保障
+
+FastAPI-fastkit 提供了完善的自动化模板校验,确保所有模板在不同环境与包管理器下都保持高质量且可正常工作。
+
+## 多层质量保障
+
+FastAPI-fastkit 同时使用**两套互补的质量保障系统**:
+
+### 1. 静态模板检查
+**对模板结构与语法的每周自动校验**
+
+### 2. 动态模板测试
+**包含真实项目创建的完整端到端测试**
+
+## 自动化的每周检查
+
+每周三午夜(UTC),我们的 GitHub Actions 工作流会自动检查所有 FastAPI 模板,确保它们达到质量标准:
+
+- ✅ **文件结构校验** —— 确保所有必备文件与目录都存在
+- ✅ **文件扩展名核对** —— 确认模板文件使用正确的 `.py-tpl` 扩展名
+- ✅ **依赖检查** —— 确认 FastAPI 及必要依赖被正确声明
+- ✅ **FastAPI 实现** —— 确认模板包含合规的 FastAPI 应用初始化
+- ✅ **测试执行** —— 运行模板的测试以确认功能正常
+
+## 自动化模板测试系统
+
+FastAPI-fastkit 自带一套**革新性的自动化测试系统**,对每个模板进行完整校验:
+
+### 动态模板发现
+
+测试系统会**自动发现所有模板**,无需手动配置:
+
+```console
+# Test all templates automatically
+$ pytest tests/test_templates/test_all_templates.py -v
+
+# Results show all discovered templates
+PASSED tests/test_templates/test_all_templates.py::TestAllTemplates::test_template_creation[fastapi-default]
+PASSED tests/test_templates/test_all_templates.py::TestAllTemplates::test_template_creation[fastapi-async-crud]
+PASSED tests/test_templates/test_all_templates.py::TestAllTemplates::test_template_creation[fastapi-dockerized]
+PASSED tests/test_templates/test_all_templates.py::TestAllTemplates::test_template_creation[fastapi-psql-orm]
+```
+
+### 全面的测试覆盖
+
+每个模板都会经历**完整的端到端测试**:
+
+#### ✅ 项目创建过程
+- 模板复制与文件转换
+- 项目元数据注入(名称、作者、描述)
+- 文件结构校验
+
+#### ✅ 包管理器兼容性
+- **UV**(默认):基于 Rust 的高速包管理器
+- **PDM**:现代 Python 依赖管理工具
+- **Poetry**:成熟的依赖管理工具
+- **PIP**:传统的 Python 包管理器
+
+#### ✅ 虚拟环境管理
+- 为每种包管理器创建对应环境
+- 校验依赖安装
+- 处理包管理器特有的工作流
+
+#### ✅ 依赖解析
+- 生成 `pyproject.toml`(UV、PDM、Poetry)
+- 生成 `requirements.txt`(PIP)
+- 元数据合规(PEP 621)
+- 构建系统配置
+
+#### ✅ 项目结构校验
+- FastAPI 项目识别
+- 必备文件存在性
+- 目录结构核对
+
+### 测试执行示例
+
+**运行全部模板测试:**
+```console
+$ pytest tests/test_templates/test_all_templates.py -v
+```
+
+**测试指定模板:**
+```console
+$ pytest tests/test_templates/test_all_templates.py::TestAllTemplates::test_template_creation[fastapi-default] -v
+```
+
+**在 PDM 环境中运行测试:**
+```console
+$ pdm run pytest tests/test_templates/test_all_templates.py -v
+```
+
+### 持续集成
+
+自动化测试系统在 **CI/CD 流水线**中运行:
+
+- ✅ **Pull Request 校验**:每个 PR 都会测试受影响的模板
+- ✅ **每日夜间测试**:对完整模板套件进行校验
+- ✅ **包管理器测试**:覆盖所有包管理器的交叉校验
+- ✅ **环境测试**:覆盖多个 Python 版本与平台
+
+### 对贡献者的好处
+
+**零配置测试:**
+
+- 🚀 添加新模板 → 自动测试
+- ⚡ 无需手动创建测试文件
+- 🛡️ 一致的质量标准
+
+**全面覆盖:**
+
+- 🔍 端到端项目创建测试
+- 📦 多包管理器校验
+- 🏗️ 完整的依赖解析测试
+- ✅ 模拟真实使用场景
+
+**开发体验:**
+
+- 🎯 **专注模板内容**:测试由系统自动完成
+- 🔄 **即时反馈**:测试执行迅速
+- 📊 **结果清晰**:报告信息详尽
+- 🚫 **零样板代码**:无需任何测试配置
+
+## 手动模板检查
+
+为开发与调试之便,您可以通过本地检查脚本或 Makefile 命令手动检查模板:
+
+### 直接使用检查脚本
+
+```console
+# Inspect all templates
+$ python scripts/inspect-templates.py
+
+# Inspect specific templates
+$ python scripts/inspect-templates.py --templates fastapi-default,fastapi-async-crud
+
+# Verbose output with detailed information
+$ python scripts/inspect-templates.py --verbose
+
+# Save results to custom file
+$ python scripts/inspect-templates.py --output my_results.json
+```
+
+### 使用 Makefile 命令
+
+```console
+# Inspect all templates
+$ make inspect-templates
+
+# Inspect with verbose output
+$ make inspect-templates-verbose
+
+# Inspect specific templates
+$ make inspect-template TEMPLATES="fastapi-default,fastapi-async-crud"
+```
+
+## 检查结果
+
+- **成功的检查**会被记录在工作流输出与产物中
+- **失败的检查**会自动创建 GitHub issue,附带详细的错误报告
+- **检查历史**在 GitHub Actions 产物中保留 30 天
+
+## 理解检查输出
+
+运行模板检查时,您会看到类似输出:
+
+```console
+📋 Found 6 templates to inspect: fastapi-async-crud, fastapi-custom-response, fastapi-default, fastapi-dockerized, fastapi-empty, fastapi-psql-orm
+============================================================
+🔍 Inspecting template: fastapi-async-crud
+ Path: /path/to/src/fastapi_fastkit/fastapi_project_template/fastapi-async-crud
+✅ fastapi-async-crud: PASSED
+----------------------------------------
+🔍 Inspecting template: fastapi-custom-response
+ Path: /path/to/src/fastapi_fastkit/fastapi_project_template/fastapi-custom-response
+✅ fastapi-custom-response: PASSED
+----------------------------------------
+...
+============================================================
+📊 INSPECTION SUMMARY
+ Total templates: 6
+ ✅ Passed: 6
+ ❌ Failed: 0
+🎉 All templates passed inspection!
+📄 Results saved to: template_inspection_results.json
+```
+
+## 模板要求
+
+要让模板通过检查,必须满足以下要求:
+
+### 文件结构
+- 必须包含一个带 Python 源文件的 `src/` 目录
+- Python 文件必须使用 `.py-tpl` 扩展名
+- 必须包含 `tests/` 目录与 `README.md-tpl` 文件
+- 必须至少包含**一份**元数据文件:
+ - `pyproject.toml-tpl`(推荐,PEP 621),或
+ - `setup.py-tpl`(遗留,仍可接受)
+- 当 `pyproject.toml-tpl` 已声明 `[project].dependencies` 时,`requirements.txt-tpl` 为可选
+
+### FastAPI 要求
+- 必须包含 FastAPI 应用初始化
+- 必须在以下至少一个位置把 `fastapi` 声明为依赖:`pyproject.toml-tpl` 的 `[project].dependencies`、`requirements.txt-tpl`,或 `setup.py-tpl` 的 `install_requires`
+- 所有模板文件必须具有有效的 Python 语法
+
+### 身份标识
+
+模板应携带 FastAPI-fastkit 的身份标识,这样生成的项目在用户工作区中可以与无关的 FastAPI 项目区分开:
+
+- `pyproject.toml-tpl` —— 在 `description` 中带 `[FastAPI-fastkit templated]` 前缀,并提供带 `managed = true` 的 `[tool.fastapi-fastkit]` 表。
+- `setup.py-tpl` —— 在 `setup()` 的 `description` 参数中带 `[FastAPI-fastkit templated]` 前缀。
+
+`is_fastkit_project()` 接受其中任一标识(pyproject 优先,setup.py 是遗留回退;匹配不区分大小写)。即使模板遗漏了它们,元数据注入也能确保生成的项目带上这些标识。
+
+### 质量标准
+- 所有模板文件必须语法正确
+- 依赖必须正确声明
+- 模板结构必须遵循 FastAPI-fastkit 的约定
+
+这套自动化的质量保障可以让所有模板保持可靠,并随时可用于生产。
diff --git a/docs/zh/reference/translation-status.md b/docs/zh/reference/translation-status.md
new file mode 100644
index 0000000..ea9d6ef
--- /dev/null
+++ b/docs/zh/reference/translation-status.md
@@ -0,0 +1,82 @@
+# 翻译状态
+
+FastAPI-fastkit 以多种语言发布文档,但这些翻译**并不总是完全同步**。本页面会说明哪些内容已经翻译、未翻译时会显示什么,以及您可以如何参与补充。
+
+## 权威来源
+
+> **英文(`en`)是权威来源。** 文档中描述的所有产品、CLI 与 API 行为,都先在英文文件中编写。其他语言是这些英文源的翻译,可能落后于某个版本。
+>
+> 如果某个翻译页面与英文页面不一致,**请以英文页面为准**,直到翻译跟上为止。
+
+英文文件位于 [`docs/en/`](https://github.com/bnbong/FastAPI-fastkit/tree/main/docs/en)。所有其他语言(`docs/ko/`、`docs/ja/`,……)都是翻译目标。
+
+仓库根目录的 `CHANGELOG.md` 也属于这份英文权威来源。各语言的 `changelog.md` 页面可以作为入口页或包装页存在,但会刻意复用规范的英文版本历史,而不是维护一份独立的翻译版本。
+
+## 各语言的完成度
+
+下表中的数字是各语言目录中的 Markdown 页面数,相对于英文源的比例。它们反映的是仓库中实际存在的内容 —— 而不是语言切换器中显示的样子(下一节会解释)。
+
+| 语言 | 状态 | Markdown 页面数 | 备注 |
+|---|---|---:|---|
+| 🇬🇧 英文(`en`) | ✅ 权威来源 | 26 / 26 | 标准来源。 |
+| 🇰🇷 韩文(`ko`) | ✅ 完成 | 26 / 26 | 该语言的所有页面都已存在。Phase 1:顶层页面 + 核心用户指南;Phase 2:其余用户指南 + 全部教程;Phase 3:贡献文档 + 参考文档。`docs/ko/changelog.md` 刻意复用规范的英文 `CHANGELOG.md`。 |
+| 🇯🇵 日文(`ja`) | ✅ 完成 | 26 / 26 | 该语言的所有页面都已存在。Phase 1:顶层页面 + 核心用户指南;Phase 2:其余用户指南 + 全部教程;Phase 3:贡献文档 + 参考文档。`docs/ja/changelog.md` 刻意复用规范的英文 `CHANGELOG.md`。 |
+| 🇨🇳 中文(`zh`) | ✅ 完成 | 26 / 26 | 该语言的所有页面都已存在。Phase 1:顶层页面 + 核心用户指南;Phase 2:其余用户指南 + 全部教程;Phase 3:贡献文档 + 参考文档。`docs/zh/changelog.md` 刻意复用规范的英文 `CHANGELOG.md`。 |
+| 🇪🇸 西班牙文(`es`) | ✅ 完成 | 26 / 26 | 该语言的所有页面都已存在。Phase 1:顶层页面 + 核心用户指南;Phase 2:其余用户指南 + 全部教程;Phase 3:贡献文档 + 参考文档。`docs/es/changelog.md` 刻意复用规范的英文 `CHANGELOG.md`。 |
+| 🇫🇷 法文(`fr`) | ✅ 完成 | 26 / 26 | 该语言的所有页面都已存在。Phase 1:顶层页面 + 核心用户指南;Phase 2:其余用户指南 + 全部教程;Phase 3:贡献文档 + 参考文档。`docs/fr/changelog.md` 刻意复用规范的英文 `CHANGELOG.md`。 |
+| 🇩🇪 德文(`de`) | ✅ 完成 | 26 / 26 | 该语言的所有页面都已存在。Phase 1:顶层页面 + 核心用户指南;Phase 2:其余用户指南 + 全部教程;Phase 3:贡献文档 + 参考文档。`docs/de/changelog.md` 刻意复用规范的英文 `CHANGELOG.md`。 |
+
+*快照验证时间:2026-06-18;在 Phase 3(贡献文档 + 参考文档)完成后,已基于当前分支重新统计 `zh` 这一行。中文目前 26 个本地化页面全部就位,状态记为 ✅ 完成。* 此表通过人工维护;如需在仓库根目录重新统计当前状态,请运行:
+
+```console
+$ for loc in en ko ja zh es fr de; do
+ echo "$loc: $(find docs/$loc -name '*.md' 2>/dev/null | wc -l | tr -d ' ')"
+ done
+```
+
+若重新统计的结果与表格不一致,说明表格已过时 —— 请更新它(或开 PR / issue 报告差异)。
+
+图例:
+
+- ✅ **权威来源** —— 我们以此语言为基准撰写。
+- 🟡 **部分翻译** —— 已翻译部分页面;缺失的页面会回退到英文。
+- 🔴 **骨架** —— 语言切换器中存在该入口,但尚未提交任何翻译过的页面。站点会在翻译后的导航标签下渲染英文内容。
+
+## 回退机制如何工作
+
+文档站点使用 [`mkdocs-static-i18n`](https://github.com/ultrabug/mkdocs-static-i18n) 并开启 `fallback_to_default: true`。这意味着:
+
+- 对每个翻译语言,MkDocs 只为该语言目录中存在的页面生成输出。
+- 对每个**不存在于**某语言的页面,构建会回退到该页面的英文版本。
+- 全站语言切换器始终列出所有已配置的语言,而不论每个语言实际包含多少页面 —— 因为构建会为每种情况生成可访问的 URL(本语言页面 → 必要时回退到英文)。
+
+所以,语言切换器中的 🔴 骨架条目**并不**意味着文档已经翻译完成 —— 它只表示该语言的构建目标已经配置好。这样设计是有意为之(外部贡献者可以逐页翻译,而不会破坏链接结构),但也确实会让语言切换器看起来比实际内容更完整。
+
+## 如何阅读站点
+
+- **默认使用英文**,若您希望获得最准确、最新的信息。
+- **先查看本页确认状态,再决定是否使用翻译语言**。如果状态是 🟡 或 🔴,而您打开了尚未翻译的主题,实际看到的会是英文回退内容,只是外层仍显示翻译后的导航标签。
+
+## 如何提供帮助
+
+当前的推进方式是:**每种语言对应一个跟踪 issue**,再把工作拆成若干**阶段(phase)**。例如 `ko` 会分为 Phase 1(顶层页面 + 核心用户指南)、Phase 2(其余用户指南 + 全部教程)和 Phase 3(贡献文档 + 参考文档)。每个阶段都会以独立 PR 落地,这样审阅者可以聚焦于一个完整的小范围,不必等到整套翻译全部完成。
+
+如果您想贡献:
+
+1. 阅读 [翻译指南](../contributing/translation-guide.md),了解工作流程、工具与风格约定。
+2. **优先查找或创建对应语言的跟踪 issue。** 若该语言已有一个开放的跟踪 issue,请在其中认领某个 phase(或 phase 内某个具体页面),以避免重复工作。如果尚不存在跟踪 issue,请创建一个,列出每个 phase 所属的页面,然后从 Phase 1 开始。
+3. **首选每个 phase 对应一份 PR**。更小的“只修这一页”PR 同样欢迎 —— 尤其适合修复与英文不同步的内容 —— 但对于全新的语言翻译工作,按 phase 打包更有利于保持术语和交叉链接措辞的一致性。
+4. 提交 PR,将文件加入 `docs//<相同路径>` 下。请保持文件名与英文源完全一致,这样 MkDocs 才会自动识别。
+5. 将本地化的 changelog 页面视作规范英文 `CHANGELOG.md` 的包装页或入口页,除非项目政策以后明确调整。
+6. 更新本页表格以反映新的完成度(可使用本页顶部的重新统计片段),并同步更新“快照验证时间”,方便审阅者确认上次对齐的时间点。如果该语言仍处于部分翻译状态,请在“备注”列注明已经完成到哪个 phase。
+
+也欢迎报告翻译页面与英文源失同步的缺陷 —— 请同时附上英文页面与翻译页面的链接,便于分流。
+
+## 为何还要保留 🔴 骨架语言
+
+两个原因:
+
+1. **可预测的 URL 结构。** 每种语言的 `//` 子树都已可访问,这样翻译页面一旦落地,链接从第一天起就是稳定的 —— 包括本指南里已经发布过的链接。
+2. **降低贡献门槛。** 只翻译单页的贡献者无需再去修改 MkDocs 配置接入新的语言构建目标 —— 直接把文件放到对应位置即可。
+
+如果某个语言长期处于 🔴 骨架且没有任何贡献,我们会重新评估是否保留它的构建目标。该决定会单独跟踪,**不会**由这个状态页面悄悄改变。
diff --git a/docs/zh/tutorial/async-crud-api.md b/docs/zh/tutorial/async-crud-api.md
new file mode 100644
index 0000000..a183ca9
--- /dev/null
+++ b/docs/zh/tutorial/async-crud-api.md
@@ -0,0 +1,665 @@
+# 构建异步 CRUD API
+
+学习如何利用 FastAPI 的异步处理能力构建高性能的 CRUD API。本教程中我们会使用 `fastapi-async-crud` 模板实现异步文件 I/O 与高效的数据处理。
+
+## 您将学到的内容
+
+- 理解异步 FastAPI 应用
+- 使用 `async/await` 语法的异步 CRUD 操作
+- 使用 aiofiles 处理异步文件
+- 编写并运行异步测试
+- 性能优化技巧
+
+## 前置条件
+
+- 完成 [基础 API 服务器教程](basic-api-server.md)
+- 理解 Python `async/await` 的基本概念
+- 已安装 FastAPI-fastkit
+
+## 为什么需要异步处理
+
+让我们先理解同步与异步处理之间的差异:
+
+### 同步处理
+
+```python
+def process_items():
+ item1 = read_file("item1.json") # Wait 2 seconds
+ item2 = read_file("item2.json") # Wait 2 seconds
+ item3 = read_file("item3.json") # Wait 2 seconds
+ return [item1, item2, item3] # Total: 6 seconds
+```
+
+### 异步处理
+
+```python
+async def process_items():
+ item1_task = read_file_async("item1.json") # Start concurrently
+ item2_task = read_file_async("item2.json") # Start concurrently
+ item3_task = read_file_async("item3.json") # Start concurrently
+
+ items = await asyncio.gather(item1_task, item2_task, item3_task)
+ return items # Total: 2 seconds
+```
+
+## 第 1 步:创建异步 CRUD 项目
+
+使用 `fastapi-async-crud` 模板创建项目:
+
+
+
+```console
+$ fastkit startdemo fastapi-async-crud
+Enter the project name: async-todo-api
+Enter the author name: Developer Kim
+Enter the author email: developer@example.com
+Enter the project description: Asynchronous todo management API
+Deploying FastAPI project using 'fastapi-async-crud' template
+
+ Project Information
+┌──────────────┬─────────────────────────────────────────┐
+│ Project Name │ async-todo-api │
+│ Author │ Developer Kim │
+│ Author Email │ developer@example.com │
+│ Description │ Asynchronous todo management API │
+└──────────────┴─────────────────────────────────────────┘
+
+ Template Dependencies
+┌──────────────┬───────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ pydantic │
+│ Dependency 4 │ pydantic-settings │
+│ Dependency 5 │ aiofiles │
+│ Dependency 6 │ pytest-asyncio │
+└──────────────┴───────────────────┘
+
+Select package manager (pip, uv, pdm, poetry) [uv]: uv
+Do you want to proceed with project creation? [y/N]: y
+
+✨ FastAPI project 'async-todo-api' from 'fastapi-async-crud' has been created successfully!
+```
+
+
+
+## 第 2 步:分析项目结构
+
+来看看生成后的项目有哪些关键差异:
+
+```
+async-todo-api/
+├── src/
+│ ├── main.py # 异步 FastAPI 应用入口
+│ ├── api/
+│ │ └── routes/
+│ │ └── items.py # 异步 CRUD 端点
+│ ├── crud/
+│ │ └── items.py # 异步数据处理逻辑
+│ ├── schemas/
+│ │ └── items.py # 数据模型(结构相同)
+│ ├── mocks/
+│ │ └── mock_items.json # JSON 文件数据库
+│ └── core/
+│ └── config.py # 配置文件
+└── tests/
+ ├── conftest.py # 异步测试配置
+ └── test_items.py # 异步测试用例
+```
+
+### 关键差异
+
+1. **aiofiles**:异步文件 I/O 处理
+2. **pytest-asyncio**:对异步测试的支持
+3. **async/await 模式**:所有 CRUD 操作都用异步方式实现
+
+## 第 3 步:理解异步 CRUD 逻辑
+
+### 异步数据处理(`src/crud/items.py`)
+
+```python
+import json
+import asyncio
+from typing import List, Optional
+from aiofiles import open as aio_open
+from pathlib import Path
+
+from src.schemas.items import Item, ItemCreate, ItemUpdate
+
+class AsyncItemCRUD:
+ def __init__(self, data_file: str = "src/mocks/mock_items.json"):
+ self.data_file = Path(data_file)
+
+ async def _read_data(self) -> List[dict]:
+ """异步读取 JSON 文件中的数据"""
+ try:
+ async with aio_open(self.data_file, 'r', encoding='utf-8') as f:
+ content = await f.read()
+ return json.loads(content)
+ except FileNotFoundError:
+ return []
+
+ async def _write_data(self, data: List[dict]) -> None:
+ """异步将数据写入 JSON 文件"""
+ async with aio_open(self.data_file, 'w', encoding='utf-8') as f:
+ await f.write(json.dumps(data, indent=2, ensure_ascii=False))
+
+ async def get_items(self) -> List[Item]:
+ """异步获取所有 items"""
+ data = await self._read_data()
+ return [Item(**item) for item in data]
+
+ async def get_item(self, item_id: int) -> Optional[Item]:
+ """异步获取指定 item"""
+ data = await self._read_data()
+ item_data = next((item for item in data if item["id"] == item_id), None)
+ return Item(**item_data) if item_data else None
+
+ async def create_item(self, item: ItemCreate) -> Item:
+ """异步创建新 item"""
+ data = await self._read_data()
+ new_id = max([item["id"] for item in data], default=0) + 1
+
+ new_item = Item(id=new_id, **item.dict())
+ data.append(new_item.dict())
+
+ await self._write_data(data)
+ return new_item
+
+ async def update_item(self, item_id: int, item_update: ItemUpdate) -> Optional[Item]:
+ """Update item (asynchronous)"""
+ data = await self._read_data()
+
+ for i, item in enumerate(data):
+ if item["id"] == item_id:
+ update_data = item_update.dict(exclude_unset=True)
+ data[i].update(update_data)
+ await self._write_data(data)
+ return Item(**data[i])
+
+ return None
+
+ async def delete_item(self, item_id: int) -> bool:
+ """Delete item (asynchronous)"""
+ data = await self._read_data()
+ original_length = len(data)
+
+ data = [item for item in data if item["id"] != item_id]
+
+ if len(data) < original_length:
+ await self._write_data(data)
+ return True
+
+ return False
+```
+
+### 异步 API 端点(`src/api/routes/items.py`)
+
+```python
+from typing import List
+from fastapi import APIRouter, HTTPException, status
+
+from src.schemas.items import Item, ItemCreate, ItemUpdate
+from src.crud.items import AsyncItemCRUD
+
+router = APIRouter()
+crud = AsyncItemCRUD()
+
+@router.get("/", response_model=List[Item])
+async def read_items():
+ """Retrieve all items (asynchronous)"""
+ return await crud.get_items()
+
+@router.get("/{item_id}", response_model=Item)
+async def read_item(item_id: int):
+ """Retrieve specific item (asynchronous)"""
+ item = await crud.get_item(item_id)
+ if item is None:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail=f"Item with id {item_id} not found"
+ )
+ return item
+
+@router.post("/", response_model=Item, status_code=status.HTTP_201_CREATED)
+async def create_item(item: ItemCreate):
+ """Create new item (asynchronous)"""
+ return await crud.create_item(item)
+
+@router.put("/{item_id}", response_model=Item)
+async def update_item(item_id: int, item_update: ItemUpdate):
+ """Update item (asynchronous)"""
+ updated_item = await crud.update_item(item_id, item_update)
+ if updated_item is None:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail=f"Item with id {item_id} not found"
+ )
+ return updated_item
+
+@router.delete("/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
+async def delete_item(item_id: int):
+ """Delete item (asynchronous)"""
+ deleted = await crud.delete_item(item_id)
+ if not deleted:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail=f"Item with id {item_id} not found"
+ )
+```
+
+## 第 4 步:运行服务器并测试
+
+进入项目目录运行服务器:
+
+
+
+```console
+$ cd async-todo-api
+$ fastkit runserver
+Starting FastAPI server at 127.0.0.1:8000...
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+INFO: Started reloader process [12345] using WatchFiles
+INFO: Started server process [12346]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+```
+
+
+
+### 性能测试
+
+我们来验证异步处理的性能,尝试同时发出多个请求:
+
+**并发请求测试(Python 脚本)**
+
+```python
+import asyncio
+import aiohttp
+import time
+
+async def create_item(session, item_data):
+ async with session.post("http://127.0.0.1:8000/items/", json=item_data) as response:
+ return await response.json()
+
+async def test_concurrent_requests():
+ start_time = time.time()
+
+ items_to_create = [
+ {"name": f"Item {i}", "description": f"Description {i}", "price": i * 10, "tax": i}
+ for i in range(1, 11) # Create 10 items concurrently
+ ]
+
+ async with aiohttp.ClientSession() as session:
+ tasks = [create_item(session, item) for item in items_to_create]
+ results = await asyncio.gather(*tasks)
+
+ end_time = time.time()
+ print(f"Created 10 items in: {end_time - start_time:.2f} seconds")
+ print(f"Number of items created: {len(results)}")
+
+# Run test
+# asyncio.run(test_concurrent_requests())
+```
+
+## 第 5 步:编写异步测试
+
+### 测试配置(`tests/conftest.py`)
+
+```python
+import pytest
+import asyncio
+from httpx import AsyncClient
+from src.main import app
+
+@pytest.fixture(scope="session")
+def event_loop():
+ """Event loop configuration"""
+ loop = asyncio.get_event_loop_policy().new_event_loop()
+ yield loop
+ loop.close()
+
+@pytest.fixture
+async def async_client():
+ """Asynchronous test client"""
+ async with AsyncClient(app=app, base_url="http://test") as client:
+ yield client
+```
+
+### 异步测试用例(`tests/test_items.py`)
+
+```python
+import pytest
+from httpx import AsyncClient
+
+@pytest.mark.asyncio
+async def test_create_item_async(async_client: AsyncClient):
+ """Asynchronous item creation test"""
+ item_data = {
+ "name": "Test Item",
+ "description": "Item for asynchronous testing",
+ "price": 100.0,
+ "tax": 10.0
+ }
+
+ response = await async_client.post("/items/", json=item_data)
+
+ assert response.status_code == 201
+ data = response.json()
+ assert data["name"] == item_data["name"]
+ assert data["price"] == item_data["price"]
+ assert "id" in data
+
+@pytest.mark.asyncio
+async def test_read_items_async(async_client: AsyncClient):
+ """Asynchronous item list retrieval test"""
+ response = await async_client.get("/items/")
+
+ assert response.status_code == 200
+ items = response.json()
+ assert isinstance(items, list)
+
+@pytest.mark.asyncio
+async def test_concurrent_operations(async_client: AsyncClient):
+ """Concurrent operations test"""
+ import asyncio
+
+ # Create multiple items concurrently
+ tasks = []
+ for i in range(5):
+ item_data = {
+ "name": f"ConcurrentItem{i}",
+ "description": f"Description{i}",
+ "price": i * 10,
+ "tax": i
+ }
+ task = async_client.post("/items/", json=item_data)
+ tasks.append(task)
+
+ responses = await asyncio.gather(*tasks)
+
+ # Verify all requests succeeded
+ for response in responses:
+ assert response.status_code == 201
+
+ # Verify created items
+ response = await async_client.get("/items/")
+ items = response.json()
+ assert len(items) >= 5
+```
+
+### 运行测试
+
+
+
+```console
+$ pytest tests/ -v --asyncio-mode=auto
+======================== test session starts ========================
+collected 8 items
+
+tests/test_items.py::test_create_item_async PASSED [ 12%]
+tests/test_items.py::test_read_items_async PASSED [ 25%]
+tests/test_items.py::test_read_item_async PASSED [ 37%]
+tests/test_items.py::test_update_item_async PASSED [ 50%]
+tests/test_items.py::test_delete_item_async PASSED [ 62%]
+tests/test_items.py::test_concurrent_operations PASSED [ 75%]
+tests/test_items.py::test_item_not_found_async PASSED [ 87%]
+tests/test_items.py::test_invalid_item_data_async PASSED [100%]
+
+======================== 8 passed in 0.24s ========================
+```
+
+
+
+## 第 6 步:性能监控与优化
+
+### 添加响应耗时测量中间件
+
+在 `src/main.py` 中加入性能监控:
+
+```python
+import time
+from fastapi import FastAPI, Request
+from src.api.api import api_router
+from src.core.config import settings
+
+app = FastAPI(
+ title=settings.PROJECT_NAME,
+ version=settings.VERSION,
+ description=settings.DESCRIPTION,
+)
+
+@app.middleware("http")
+async def add_process_time_header(request: Request, call_next):
+ """Add request processing time to headers"""
+ start_time = time.time()
+ response = await call_next(request)
+ process_time = time.time() - start_time
+ response.headers["X-Process-Time"] = str(process_time)
+ return response
+
+app.include_router(api_router)
+
+@app.get("/")
+async def read_root():
+ return {"message": "Welcome to the Asynchronous Todo API!"}
+```
+
+### 实现异步批量处理
+
+我们加上批量端点,以便一次处理多个 item:
+
+```python
+# Add to src/api/routes/items.py
+
+@router.post("/batch", response_model=List[Item])
+async def create_items_batch(items: List[ItemCreate]):
+ """Create multiple items concurrently (batch processing)"""
+ import asyncio
+
+ # Execute all item creation tasks concurrently
+ tasks = [crud.create_item(item) for item in items]
+ created_items = await asyncio.gather(*tasks)
+
+ return created_items
+
+@router.get("/batch/{item_ids}")
+async def read_items_batch(item_ids: str):
+ """Retrieve multiple items concurrently (batch processing)"""
+ import asyncio
+
+ # Parse comma-separated IDs
+ ids = [int(id.strip()) for id in item_ids.split(",")]
+
+ # Execute all item retrieval tasks concurrently
+ tasks = [crud.get_item(item_id) for item_id in ids]
+ items = await asyncio.gather(*tasks)
+
+ # Return only non-None items
+ return [item for item in items if item is not None]
+```
+
+### 批量处理测试
+
+
+
+```console
+# Batch creation test
+$ curl -X POST "http://127.0.0.1:8000/items/batch" \
+ -H "Content-Type: application/json" \
+ -d '[
+ {"name": "Item1", "description": "Description1", "price": 10.0, "tax": 1.0},
+ {"name": "Item2", "description": "Description2", "price": 20.0, "tax": 2.0},
+ {"name": "Item3", "description": "Description3", "price": 30.0, "tax": 3.0}
+ ]'
+
+# Batch retrieval test
+$ curl -X GET "http://127.0.0.1:8000/items/batch/1,2,3"
+```
+
+
+
+## 第 7 步:进阶异步模式
+
+### 实现限流
+
+```python
+import asyncio
+from collections import defaultdict
+from fastapi import HTTPException, Request
+from datetime import datetime, timedelta
+
+class AsyncRateLimiter:
+ def __init__(self, max_requests: int = 100, window_seconds: int = 60):
+ self.max_requests = max_requests
+ self.window_seconds = window_seconds
+ self.requests = defaultdict(list)
+
+ async def is_allowed(self, client_ip: str) -> bool:
+ now = datetime.now()
+ cutoff = now - timedelta(seconds=self.window_seconds)
+
+ # remove old request records
+ self.requests[client_ip] = [
+ req_time for req_time in self.requests[client_ip]
+ if req_time > cutoff
+ ]
+
+ # check current request count
+ if len(self.requests[client_ip]) >= self.max_requests:
+ return False
+
+ # add current request record
+ self.requests[client_ip].append(now)
+ return True
+
+# global rate limiter instance
+rate_limiter = AsyncRateLimiter()
+
+@app.middleware("http")
+async def rate_limit_middleware(request: Request, call_next):
+ client_ip = request.client.host
+
+ if not await rate_limiter.is_allowed(client_ip):
+ raise HTTPException(
+ status_code=429,
+ detail="Too many requests"
+ )
+
+ response = await call_next(request)
+ return response
+```
+
+### 实现异步缓存
+
+```python
+import asyncio
+from typing import Optional, Any
+from datetime import datetime, timedelta
+
+class AsyncCache:
+ def __init__(self):
+ self._cache = {}
+ self._expiry = {}
+
+ async def get(self, key: str) -> Optional[Any]:
+ # remove expired items
+ if key in self._expiry and datetime.now() > self._expiry[key]:
+ del self._cache[key]
+ del self._expiry[key]
+ return None
+
+ return self._cache.get(key)
+
+ async def set(self, key: str, value: Any, ttl_seconds: int = 300):
+ self._cache[key] = value
+ self._expiry[key] = datetime.now() + timedelta(seconds=ttl_seconds)
+
+ async def delete(self, key: str):
+ self._cache.pop(key, None)
+ self._expiry.pop(key, None)
+
+# global cache instance
+cache = AsyncCache()
+
+# modify CRUD methods to use cache
+async def get_items_cached(self) -> List[Item]:
+ """Retrieve items using cache"""
+ cache_key = "all_items"
+ cached_items = await cache.get(cache_key)
+
+ if cached_items:
+ return cached_items
+
+ # if cache is not found, read from file
+ items = await self.get_items()
+ await cache.set(cache_key, items, ttl_seconds=60) # 1 minute cache
+
+ return items
+```
+
+## 第 8 步:生产环境考量
+
+### 管理连接池
+
+```python
+# add to src/core/config.py
+class Settings(BaseSettings):
+ # ... existing settings ...
+
+ # asynchronous processing related settings
+ MAX_CONCURRENT_REQUESTS: int = 100
+ REQUEST_TIMEOUT: int = 30
+ CONNECTION_POOL_SIZE: int = 20
+
+settings = Settings()
+```
+
+### 改进错误处理
+
+```python
+import logging
+from fastapi import HTTPException
+from typing import Union
+
+logger = logging.getLogger(__name__)
+
+async def safe_async_operation(operation, *args, **kwargs) -> Union[Any, None]:
+ """Execute safe asynchronous operation"""
+ try:
+ return await operation(*args, **kwargs)
+ except asyncio.TimeoutError:
+ logger.error(f"Timeout in {operation.__name__}")
+ raise HTTPException(status_code=504, detail="Request timeout")
+ except Exception as e:
+ logger.error(f"Error in {operation.__name__}: {str(e)}")
+ raise HTTPException(status_code=500, detail="Internal server error")
+
+# usage example
+@router.get("/safe/{item_id}")
+async def read_item_safe(item_id: int):
+ return await safe_async_operation(crud.get_item, item_id)
+```
+
+## 下一步
+
+恭喜您完成了异步 CRUD API 的构建!接下来可以尝试:
+
+1. **[数据库集成](database-integration.md)** —— 使用 PostgreSQL 与异步 SQLAlchemy
+2. **[Docker 容器化](docker-deployment.md)** —— 把异步应用容器化
+3. **[自定义响应处理](custom-response-handling.md)** —— 进阶的响应格式与错误处理
+
+
+
+## 小结
+
+在本教程中,我们用异步 FastAPI 完成了:
+
+- ✅ 实现异步 CRUD 操作
+- ✅ 用 aiofiles 优化文件 I/O
+- ✅ 处理并发请求并进行性能测试
+- ✅ 编写并运行异步测试
+- ✅ 实现批量处理与进阶异步模式
+- ✅ 处理生产环境的考量(缓存、错误处理、连接管理)
+
+掌握异步处理,您就能构建出高性能的 API 服务器!
diff --git a/docs/zh/tutorial/basic-api-server.md b/docs/zh/tutorial/basic-api-server.md
new file mode 100644
index 0000000..cb1c9a0
--- /dev/null
+++ b/docs/zh/tutorial/basic-api-server.md
@@ -0,0 +1,398 @@
+# 构建一个基础 API 服务器
+
+学习如何使用 FastAPI-fastkit 快速构建一个简单的 REST API 服务器。本教程面向 FastAPI 初学者,覆盖基础 CRUD API 的创建。
+
+## 您将学到的内容
+
+- 使用 `fastkit startdemo` 命令创建基础 API 服务器
+- 理解 FastAPI 项目结构
+- 使用基础的 CRUD 端点
+- API 测试与文档
+- 项目的扩展方式
+
+## 前置条件
+
+- 已安装 Python 3.12 及以上
+- 已安装 FastAPI-fastkit(`pip install fastapi-fastkit`)
+- 具备 Python 基础知识
+
+## 第 1 步:创建基础 API 项目
+
+使用 `fastapi-default` 模板创建基础 API 服务器。
+
+
+
+```console
+$ fastkit startdemo fastapi-default
+Enter the project name: my-first-api
+Enter the author name: Developer Kim
+Enter the author email: developer@example.com
+Enter the project description: My first FastAPI server
+Deploying FastAPI project using 'fastapi-default' template
+
+ Project Information
+┌──────────────┬────────────────────────────┐
+│ Project Name │ my-first-api │
+│ Author │ Developer Kim │
+│ Author Email │ developer@example.com │
+│ Description │ My first FastAPI server │
+└──────────────┴────────────────────────────┘
+
+ Template Dependencies
+┌──────────────┬───────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ pydantic │
+│ Dependency 4 │ pydantic-settings │
+│ Dependency 5 │ python-dotenv │
+└──────────────┴───────────────────┘
+
+Select package manager (pip, uv, pdm, poetry) [uv]: uv
+Do you want to proceed with project creation? [y/N]: y
+
+✨ FastAPI project 'my-first-api' from 'fastapi-default' has been created successfully!
+```
+
+
+
+## 第 2 步:理解生成的项目结构
+
+先来看看生成后的项目结构:
+
+```
+my-first-api/
+├── README.md # 项目文档
+├── requirements.txt # 依赖列表
+├── setup.py # 包配置
+├── scripts/
+│ └── run-server.sh # 启动服务器脚本
+├── src/ # Main source code
+│ ├── main.py # FastAPI 应用入口
+│ ├── core/
+│ │ └── config.py # 配置管理
+│ ├── api/
+│ │ ├── api.py # API 路由汇总
+│ │ └── routes/
+│ │ └── items.py # items 相关端点
+│ ├── schemas/
+│ │ └── items.py # 数据模型定义
+│ ├── crud/
+│ │ └── items.py # 数据处理逻辑
+│ └── mocks/
+│ └── mock_items.json # 测试数据
+└── tests/ # 测试代码
+ ├── __init__.py
+ ├── conftest.py
+ └── test_items.py
+```
+
+### 关键文件说明
+
+- **`src/main.py`**:FastAPI 应用入口
+- **`src/api/routes/items.py`**:item 相关的 API 端点定义
+- **`src/schemas/items.py`**:请求 / 响应数据结构定义
+- **`src/crud/items.py`**:数据库操作逻辑
+- **`src/mocks/mock_items.json`**:开发用的示例数据
+
+## 第 3 步:运行服务器
+
+进入生成的项目目录,运行服务器。
+
+
+
+```console
+$ cd my-first-api
+$ fastkit runserver
+Starting FastAPI server at 127.0.0.1:8000...
+
+INFO: Will watch for changes in these directories: ['/path/to/my-first-api']
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+INFO: Started reloader process [12345] using WatchFiles
+INFO: Started server process [12346]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+```
+
+
+
+服务器成功运行后,您可以在浏览器中访问:
+
+- **API 服务器**:http://127.0.0.1:8000
+- **Swagger UI 文档**:http://127.0.0.1:8000/docs
+- **ReDoc 文档**:http://127.0.0.1:8000/redoc
+
+## 第 4 步:探索 API 端点
+
+生成的 API 默认提供以下端点:
+
+| 方法 | 端点 | 描述 |
+|--------|----------|-------------|
+| GET | `/items/` | 获取所有 item |
+| GET | `/items/{item_id}` | 获取指定 item |
+| POST | `/items/` | 创建新 item |
+| PUT | `/items/{item_id}` | 更新 item |
+| DELETE | `/items/{item_id}` | 删除 item |
+
+### 测试 API
+
+**1. 获取所有 item**
+
+
+
+```console
+$ curl -X GET "http://127.0.0.1:8000/items/"
+[
+ {
+ "id": 1,
+ "name": "Laptop",
+ "description": "High-performance laptop",
+ "price": 999.99,
+ "tax": 99.99
+ },
+ {
+ "id": 2,
+ "name": "Mouse",
+ "description": "Wireless mouse",
+ "price": 29.99,
+ "tax": 2.99
+ }
+]
+```
+
+
+
+**2. 创建新 item**
+
+
+
+```console
+$ curl -X POST "http://127.0.0.1:8000/items/" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "Keyboard",
+ "description": "Mechanical keyboard",
+ "price": 150.00,
+ "tax": 15.00
+ }'
+
+{
+ "id": 3,
+ "name": "Keyboard",
+ "description": "Mechanical keyboard",
+ "price": 150.0,
+ "tax": 15.0
+}
+```
+
+
+
+**3. 获取指定 item**
+
+
+
+```console
+$ curl -X GET "http://127.0.0.1:8000/items/1"
+{
+ "id": 1,
+ "name": "Laptop",
+ "description": "High-performance laptop",
+ "price": 999.99,
+ "tax": 99.99
+}
+```
+
+
+
+## 第 5 步:用 Swagger UI 测试 API
+
+在浏览器中访问 http://127.0.0.1:8000/docs,查看自动生成的 API 文档。
+
+借助 Swagger UI 您可以:
+
+1. **查看 API 端点**:以可视化方式查看所有可用端点
+2. **核对请求 / 响应模式**:查看每个端点的输入输出格式
+3. **直接测试 API**:点击「Try it out」实际调用 API
+4. **查看示例数据**:浏览各端点的请求 / 响应示例
+
+### 如何使用 Swagger UI
+
+1. 点击 `/items/` GET 端点
+2. 点击「Try it out」按钮
+3. 点击「Execute」按钮
+4. 查看服务器响应
+
+## 第 6 步:理解代码结构
+
+### 主应用(`src/main.py`)
+
+```python
+from fastapi import FastAPI
+from src.api.api import api_router
+from src.core.config import settings
+
+app = FastAPI(
+ title=settings.PROJECT_NAME,
+ version=settings.VERSION,
+ description=settings.DESCRIPTION,
+)
+
+app.include_router(api_router)
+
+@app.get("/")
+def read_root():
+ return {"message": "Hello World"}
+```
+
+### Item 模式(`src/schemas/items.py`)
+
+```python
+from pydantic import BaseModel
+from typing import Optional
+
+class ItemBase(BaseModel):
+ name: str
+ description: Optional[str] = None
+ price: float
+ tax: Optional[float] = None
+
+class ItemCreate(ItemBase):
+ pass
+
+class ItemUpdate(ItemBase):
+ name: Optional[str] = None
+ price: Optional[float] = None
+
+class Item(ItemBase):
+ id: int
+
+ class Config:
+ from_attributes = True
+```
+
+### CRUD 逻辑(`src/crud/items.py`)
+
+```python
+from typing import List, Optional
+from src.schemas.items import Item, ItemCreate, ItemUpdate
+
+class ItemCRUD:
+ def __init__(self):
+ self.items: List[Item] = []
+ self.next_id = 1
+
+ def create_item(self, item: ItemCreate) -> Item:
+ new_item = Item(id=self.next_id, **item.dict())
+ self.items.append(new_item)
+ self.next_id += 1
+ return new_item
+
+ def get_items(self) -> List[Item]:
+ return self.items
+
+ def get_item(self, item_id: int) -> Optional[Item]:
+ return next((item for item in self.items if item.id == item_id), None)
+```
+
+## 第 7 步:扩展项目
+
+### 添加新路由
+
+可以使用 `fastkit addroute` 命令添加新端点:
+
+
+
+```console
+$ fastkit addroute user
+ Adding New Route
+┌──────────────────┬──────────────────────────────────────────┐
+│ Project │ my-first-api │
+│ Route Name │ user │
+│ Target Directory │ /path/to/my-first-api │
+└──────────────────┴──────────────────────────────────────────┘
+
+Do you want to add route 'user' to the current project? [Y/n]: y
+
+✨ Successfully added new route 'user' to the current project!
+```
+
+
+
+该命令会创建以下文件:
+
+- `src/api/routes/user.py` —— 用户相关端点
+- `src/schemas/user.py` —— 用户数据模型
+- `src/crud/user.py` —— 用户数据处理逻辑
+
+### 自定义环境配置
+
+可以修改 `src/core/config.py` 文件来调整项目设置:
+
+```python
+from pydantic_settings import BaseSettings
+
+class Settings(BaseSettings):
+ PROJECT_NAME: str = "My First API"
+ VERSION: str = "1.0.0"
+ DESCRIPTION: str = "My first FastAPI server"
+ API_V1_STR: str = "/api/v1"
+
+ class Config:
+ env_file = ".env"
+
+settings = Settings()
+```
+
+## 第 8 步:运行测试
+
+项目自带基础测试:
+
+
+
+```console
+$ pytest tests/ -v
+======================== test session starts ========================
+collected 4 items
+
+tests/test_items.py::test_create_item PASSED [ 25%]
+tests/test_items.py::test_read_items PASSED [ 50%]
+tests/test_items.py::test_read_item PASSED [ 75%]
+tests/test_items.py::test_update_item PASSED [100%]
+
+======================== 4 passed in 0.15s ========================
+```
+
+
+
+## 下一步
+
+恭喜您完成了基础 API 服务器的构建!接下来可以尝试:
+
+1. **[构建异步 CRUD API](async-crud-api.md)** —— 学习更复杂的异步处理
+2. **[数据库集成](database-integration.md)** —— 使用 PostgreSQL 与 SQLAlchemy
+3. **[Docker 容器化](docker-deployment.md)** —— 为生产部署做准备
+4. **[自定义响应处理](custom-response-handling.md)** —— 进阶的响应格式配置
+
+## 故障排查
+
+### 常见问题
+
+**问:服务器无法启动**
+答:确认虚拟环境已激活,依赖已正确安装。
+
+**问:无法访问 API 端点**
+答:确认服务器在正常运行,端口号(默认 8000)正确。
+
+**问:API 没有出现在 Swagger UI 中**
+答:确认路由器已正确包含在 `src/main.py` 中。
+
+## 小结
+
+在本教程中,您使用 FastAPI-fastkit 完成了:
+
+- ✅ 创建基础 FastAPI 项目
+- ✅ 理解项目结构
+- ✅ 使用 CRUD API 端点
+- ✅ API 文档与测试
+- ✅ 项目扩展方式
+
+既然您已经掌握了 FastAPI 的基础,不妨挑战更复杂的项目!
diff --git a/docs/zh/tutorial/custom-response-handling.md b/docs/zh/tutorial/custom-response-handling.md
new file mode 100644
index 0000000..af5d910
--- /dev/null
+++ b/docs/zh/tutorial/custom-response-handling.md
@@ -0,0 +1,1393 @@
+# 自定义响应处理与进阶 API 设计
+
+学习如何利用 FastAPI 的进阶特性,实现一致的响应格式、错误处理、分页与自定义 OpenAPI 文档。本节我们将通过 `fastapi-custom-response` 模板实现企业级 API 设计模式。
+
+## 您将学到的内容
+
+- 设计标准化的 API 响应格式
+- 全局异常处理与自定义错误响应
+- 实现分页系统
+- 过滤与排序功能
+- 自定义 OpenAPI 文档
+- API 版本管理
+- 响应缓存与优化
+
+## 前置条件
+
+- 完成 [Docker 容器化教程](docker-deployment.md)
+- 理解 REST API 设计原则
+- 熟悉 HTTP 状态码
+- 对 OpenAPI / Swagger 有基础认识
+
+## 标准化 API 响应的重要性
+
+### 不一致 vs 标准化的响应
+
+**有问题的响应格式:**
+```json
+// Success
+{"id": 1, "name": "item"}
+
+// Error
+{"detail": "Not found"}
+
+// List retrieval
+[{"id": 1}, {"id": 2}]
+```
+
+**标准化的响应格式:**
+```json
+// Success
+{
+ "success": true,
+ "data": {"id": 1, "name": "item"},
+ "message": "Item retrieved successfully",
+ "timestamp": "2024-01-01T12:00:00Z"
+}
+
+// Error
+{
+ "success": false,
+ "error": {
+ "code": "ITEM_NOT_FOUND",
+ "message": "Item not found",
+ "details": {"item_id": 123}
+ },
+ "timestamp": "2024-01-01T12:00:00Z"
+}
+```
+
+## 第 1 步:创建自定义响应项目
+
+使用 `fastapi-custom-response` 模板创建项目:
+
+
+
+```console
+$ fastkit startdemo fastapi-custom-response
+Enter the project name: advanced-api-server
+Enter the author name: Developer Kim
+Enter the author email: developer@example.com
+Enter the project description: API server with advanced response handling
+Deploying FastAPI project using 'fastapi-custom-response' template
+
+ Project Information
+┌──────────────┬─────────────────────────────────────────────┐
+│ Project Name │ advanced-api-server │
+│ Author │ Developer Kim │
+│ Author Email │ developer@example.com │
+│ Description │ API server with advanced response handling │
+└──────────────┴─────────────────────────────────────────────┘
+
+ Template Dependencies
+┌──────────────┬───────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ pydantic │
+│ Dependency 4 │ pydantic-settings │
+│ Dependency 5 │ aiofiles │
+│ Dependency 6 │ python-multipart │
+└──────────────┴───────────────────┘
+
+Select package manager (pip, uv, pdm, poetry) [uv]: uv
+Do you want to proceed with project creation? [y/N]: y
+
+✨ FastAPI project 'advanced-api-server' from 'fastapi-custom-response' has been created successfully!
+```
+
+
+
+## 第 2 步:分析项目结构
+
+让我们看看生成项目中的进阶特性:
+
+```
+advanced-api-server/
+├── src/
+│ ├── main.py # FastAPI application
+│ ├── schemas/
+│ │ ├── base.py # Base response schemas
+│ │ ├── items.py # Item schemas
+│ │ └── responses.py # Response format definitions
+│ ├── helper/
+│ │ ├── exceptions.py # Custom exception classes
+│ │ └── pagination.py # Pagination helpers
+│ ├── utils/
+│ │ ├── responses.py # 响应工具
+│ │ └── documents.py # OpenAPI 文档定制
+│ ├── api/
+│ │ └── routes/
+│ │ └── items.py # 进阶 API 端点
+│ ├── crud/
+│ │ └── items.py # CRUD 逻辑
+│ └── core/
+│ └── config.py # 配置
+└── tests/
+ └── test_responses.py # 响应格式测试
+```
+
+## 第 3 步:实现标准化的响应模式
+
+### 基础响应模式(`src/schemas/base.py`)
+
+```python
+from typing import Generic, TypeVar, Optional, Any, Dict, List
+from pydantic import BaseModel, Field
+from datetime import datetime
+from enum import Enum
+
+T = TypeVar('T')
+
+class ResponseStatus(str, Enum):
+ """响应状态"""
+ SUCCESS = "success"
+ ERROR = "error"
+ WARNING = "warning"
+
+class ErrorDetail(BaseModel):
+ """错误详情信息"""
+ code: str = Field(..., description="错误代码")
+ message: str = Field(..., description="错误信息")
+ field: Optional[str] = Field(None, description="发生错误的字段")
+ details: Optional[Dict[str, Any]] = Field(None, description="附加错误信息")
+
+class BaseResponse(BaseModel, Generic[T]):
+ """基础响应格式"""
+ success: bool = Field(..., description="请求是否成功")
+ status: ResponseStatus = Field(..., description="响应状态")
+ data: Optional[T] = Field(None, description="响应数据")
+ message: Optional[str] = Field(None, description="响应消息")
+ timestamp: datetime = Field(default_factory=datetime.utcnow, description="响应时间戳")
+ request_id: Optional[str] = Field(None, description="请求追踪 ID")
+
+class ErrorResponse(BaseModel):
+ """错误响应格式"""
+ success: bool = Field(False, description="请求是否成功")
+ status: ResponseStatus = Field(ResponseStatus.ERROR, description="响应状态")
+ error: ErrorDetail = Field(..., description="错误信息")
+ timestamp: datetime = Field(default_factory=datetime.utcnow, description="响应时间戳")
+ request_id: Optional[str] = Field(None, description="请求追踪 ID")
+
+class PaginationMeta(BaseModel):
+ """分页元数据"""
+ page: int = Field(..., ge=1, description="当前页码")
+ size: int = Field(..., ge=1, le=100, description="每页条数")
+ total: int = Field(..., ge=0, description="总条目数")
+ pages: int = Field(..., ge=0, description="总页数")
+ has_next: bool = Field(..., description="是否存在下一页")
+ has_prev: bool = Field(..., description="是否存在上一页")
+
+class PaginatedResponse(BaseModel, Generic[T]):
+ """分页响应格式"""
+ success: bool = Field(True, description="请求是否成功")
+ status: ResponseStatus = Field(ResponseStatus.SUCCESS, description="响应状态")
+ data: List[T] = Field(..., description="数据列表")
+ meta: PaginationMeta = Field(..., description="分页信息")
+ message: Optional[str] = Field(None, description="响应消息")
+ timestamp: datetime = Field(default_factory=datetime.utcnow, description="响应时间")
+ request_id: Optional[str] = Field(None, description="请求追踪 ID")
+
+class ValidationErrorDetail(BaseModel):
+ """校验错误详情"""
+ field: str = Field(..., description="校验失败的字段")
+ message: str = Field(..., description="错误信息")
+ invalid_value: Any = Field(..., description="无效值")
+
+class ValidationErrorResponse(BaseModel):
+ """校验错误响应格式"""
+ success: bool = Field(False, description="请求是否成功")
+ status: ResponseStatus = Field(ResponseStatus.ERROR, description="响应状态")
+ error: ErrorDetail = Field(..., description="错误信息")
+ validation_errors: List[ValidationErrorDetail] = Field(..., description="校验错误列表")
+ timestamp: datetime = Field(default_factory=datetime.utcnow, description="响应时间")
+ request_id: Optional[str] = Field(None, description="请求追踪 ID")
+```
+
+### 响应工具函数(`src/utils/responses.py`)
+
+```python
+from typing import Any, Optional, List, TypeVar
+from fastapi import Request
+from fastapi.responses import JSONResponse
+import uuid
+
+from src.schemas.base import (
+ BaseResponse, ErrorResponse, PaginatedResponse,
+ ResponseStatus, ErrorDetail, PaginationMeta
+)
+
+T = TypeVar('T')
+
+def generate_request_id() -> str:
+ """生成请求追踪 ID"""
+ return str(uuid.uuid4())
+
+def success_response(
+ data: Any = None,
+ message: Optional[str] = None,
+ request_id: Optional[str] = None,
+ status_code: int = 200
+) -> JSONResponse:
+ """生成成功响应"""
+ response_data = BaseResponse[Any](
+ success=True,
+ status=ResponseStatus.SUCCESS,
+ data=data,
+ message=message or "Request processed successfully",
+ request_id=request_id or generate_request_id()
+ )
+
+ return JSONResponse(
+ status_code=status_code,
+ content=response_data.dict(exclude_none=True)
+ )
+
+def error_response(
+ error_code: str,
+ error_message: str,
+ details: Optional[dict] = None,
+ status_code: int = 400,
+ request_id: Optional[str] = None
+) -> JSONResponse:
+ """生成错误响应"""
+ error_detail = ErrorDetail(
+ code=error_code,
+ message=error_message,
+ details=details
+ )
+
+ response_data = ErrorResponse(
+ error=error_detail,
+ request_id=request_id or generate_request_id()
+ )
+
+ return JSONResponse(
+ status_code=status_code,
+ content=response_data.dict(exclude_none=True)
+ )
+
+def paginated_response(
+ data: List[T],
+ page: int,
+ size: int,
+ total: int,
+ message: Optional[str] = None,
+ request_id: Optional[str] = None
+) -> JSONResponse:
+ """Generate paginated response"""
+ pages = (total + size - 1) // size # round up calculation
+ has_next = page < pages
+ has_prev = page > 1
+
+ meta = PaginationMeta(
+ page=page,
+ size=size,
+ total=total,
+ pages=pages,
+ has_next=has_next,
+ has_prev=has_prev
+ )
+
+ response_data = PaginatedResponse[T](
+ data=data,
+ meta=meta,
+ message=message or f"Page {page}/{pages} data retrieved",
+ request_id=request_id or generate_request_id()
+ )
+
+ return JSONResponse(
+ status_code=200,
+ content=response_data.dict(exclude_none=True)
+ )
+
+class ResponseHelper:
+ """Response helper class"""
+
+ @staticmethod
+ def created(data: Any, message: str = "Resource created successfully") -> JSONResponse:
+ return success_response(data=data, message=message, status_code=201)
+
+ @staticmethod
+ def updated(data: Any, message: str = "Resource updated successfully") -> JSONResponse:
+ return success_response(data=data, message=message, status_code=200)
+
+ @staticmethod
+ def deleted(message: str = "Resource deleted successfully") -> JSONResponse:
+ return success_response(data=None, message=message, status_code=204)
+
+ @staticmethod
+ def not_found(resource: str = "Resource") -> JSONResponse:
+ return error_response(
+ error_code="RESOURCE_NOT_FOUND",
+ error_message=f"{resource} not found",
+ status_code=404
+ )
+
+ @staticmethod
+ def bad_request(message: str = "Bad request") -> JSONResponse:
+ return error_response(
+ error_code="BAD_REQUEST",
+ error_message=message,
+ status_code=400
+ )
+
+ @staticmethod
+ def unauthorized(message: str = "Authentication required") -> JSONResponse:
+ return error_response(
+ error_code="UNAUTHORIZED",
+ error_message=message,
+ status_code=401
+ )
+
+ @staticmethod
+ def forbidden(message: str = "Permission denied") -> JSONResponse:
+ return error_response(
+ error_code="FORBIDDEN",
+ error_message=message,
+ status_code=403
+ )
+
+ @staticmethod
+ def server_error(message: str = "Server internal error occurred") -> JSONResponse:
+ return error_response(
+ error_code="INTERNAL_SERVER_ERROR",
+ error_message=message,
+ status_code=500
+ )
+```
+
+## 第 4 步:自定义异常处理体系
+
+### 自定义异常类(`src/helper/exceptions.py`)
+
+```python
+from typing import Optional, Dict, Any
+from fastapi import HTTPException
+
+class BaseAPIException(HTTPException):
+ """Base API exception class"""
+
+ def __init__(
+ self,
+ error_code: str,
+ message: str,
+ status_code: int = 400,
+ details: Optional[Dict[str, Any]] = None
+ ):
+ self.error_code = error_code
+ self.message = message
+ self.details = details or {}
+ super().__init__(status_code=status_code, detail=message)
+
+class ValidationException(BaseAPIException):
+ """Validation exception"""
+
+ def __init__(self, message: str, field: Optional[str] = None, details: Optional[Dict] = None):
+ super().__init__(
+ error_code="VALIDATION_ERROR",
+ message=message,
+ status_code=422,
+ details=details or {"field": field} if field else None
+ )
+
+class ResourceNotFoundException(BaseAPIException):
+ """Resource not found exception"""
+
+ def __init__(self, resource: str, resource_id: Any):
+ super().__init__(
+ error_code="RESOURCE_NOT_FOUND",
+ message=f"{resource}(ID: {resource_id}) not found",
+ status_code=404,
+ details={"resource": resource, "id": resource_id}
+ )
+
+class DuplicateResourceException(BaseAPIException):
+ """Duplicate resource exception"""
+
+ def __init__(self, resource: str, field: str, value: Any):
+ super().__init__(
+ error_code="DUPLICATE_RESOURCE",
+ message=f"{resource} {field} '{value}' already exists",
+ status_code=409,
+ details={"resource": resource, "field": field, "value": value}
+ )
+
+class BusinessLogicException(BaseAPIException):
+ """Business logic exception"""
+
+ def __init__(self, message: str, error_code: str = "BUSINESS_LOGIC_ERROR"):
+ super().__init__(
+ error_code=error_code,
+ message=message,
+ status_code=422
+ )
+
+class RateLimitException(BaseAPIException):
+ """Request limit exception"""
+
+ def __init__(self, retry_after: int = 60):
+ super().__init__(
+ error_code="RATE_LIMIT_EXCEEDED",
+ message="Request limit exceeded. Please try again later",
+ status_code=429,
+ details={"retry_after": retry_after}
+ )
+
+class AuthenticationException(BaseAPIException):
+ """Authentication exception"""
+
+ def __init__(self, message: str = "Authentication required"):
+ super().__init__(
+ error_code="AUTHENTICATION_REQUIRED",
+ message=message,
+ status_code=401
+ )
+
+class AuthorizationException(BaseAPIException):
+ """Authorization exception"""
+
+ def __init__(self, message: str = "Permission denied"):
+ super().__init__(
+ error_code="INSUFFICIENT_PERMISSIONS",
+ message=message,
+ status_code=403
+ )
+```
+
+### 全局异常处理器(`src/main.py`)
+
+```python
+from fastapi import FastAPI, Request, status
+from fastapi.exceptions import RequestValidationError, HTTPException
+from fastapi.responses import JSONResponse
+from pydantic import ValidationError
+import logging
+import traceback
+
+from src.helper.exceptions import BaseAPIException
+from src.utils.responses import error_response, generate_request_id
+from src.schemas.base import ValidationErrorDetail, ValidationErrorResponse
+
+logger = logging.getLogger(__name__)
+
+app = FastAPI(
+ title="Advanced API Server",
+ description="API server with advanced response handling",
+ version="1.0.0"
+)
+
+@app.exception_handler(BaseAPIException)
+async def custom_api_exception_handler(request: Request, exc: BaseAPIException):
+ """Custom API exception handler"""
+ request_id = generate_request_id()
+
+ logger.error(
+ f"API Exception: {exc.error_code} - {exc.message}",
+ extra={
+ "request_id": request_id,
+ "path": request.url.path,
+ "method": request.method,
+ "details": exc.details
+ }
+ )
+
+ return error_response(
+ error_code=exc.error_code,
+ error_message=exc.message,
+ details=exc.details,
+ status_code=exc.status_code,
+ request_id=request_id
+ )
+
+@app.exception_handler(RequestValidationError)
+async def validation_exception_handler(request: Request, exc: RequestValidationError):
+ """Pydantic 校验异常处理器"""
+ request_id = generate_request_id()
+
+ validation_errors = []
+ for error in exc.errors():
+ field = ".".join(str(loc) for loc in error["loc"])
+ validation_errors.append(
+ ValidationErrorDetail(
+ field=field,
+ message=error["msg"],
+ invalid_value=error.get("input", "")
+ )
+ )
+
+ error_response_data = ValidationErrorResponse(
+ error={
+ "code": "VALIDATION_ERROR",
+ "message": "Input data validation failed",
+ "details": {"error_count": len(validation_errors)}
+ },
+ validation_errors=validation_errors,
+ request_id=request_id
+ )
+
+ logger.warning(
+ f"Validation Error: {len(validation_errors)} validation errors",
+ extra={
+ "request_id": request_id,
+ "path": request.url.path,
+ "method": request.method,
+ "errors": [err.dict() for err in validation_errors]
+ }
+ )
+
+ return JSONResponse(
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+ content=error_response_data.dict(exclude_none=True)
+ )
+
+@app.exception_handler(HTTPException)
+async def http_exception_handler(request: Request, exc: HTTPException):
+ """HTTP exception handler"""
+ request_id = generate_request_id()
+
+ error_code_map = {
+ 400: "BAD_REQUEST",
+ 401: "UNAUTHORIZED",
+ 403: "FORBIDDEN",
+ 404: "NOT_FOUND",
+ 405: "METHOD_NOT_ALLOWED",
+ 500: "INTERNAL_SERVER_ERROR"
+ }
+
+ error_code = error_code_map.get(exc.status_code, "HTTP_ERROR")
+
+ return error_response(
+ error_code=error_code,
+ error_message=exc.detail,
+ status_code=exc.status_code,
+ request_id=request_id
+ )
+
+@app.exception_handler(Exception)
+async def general_exception_handler(request: Request, exc: Exception):
+ """General exception handler"""
+ request_id = generate_request_id()
+
+ logger.error(
+ f"Unhandled Exception: {type(exc).__name__} - {str(exc)}",
+ extra={
+ "request_id": request_id,
+ "path": request.url.path,
+ "method": request.method,
+ "traceback": traceback.format_exc()
+ }
+ )
+
+ return error_response(
+ error_code="INTERNAL_SERVER_ERROR",
+ error_message="Unexpected error occurred",
+ status_code=500,
+ request_id=request_id
+ )
+```
+
+## 第 5 步:进阶分页系统
+
+### 分页助手(`src/helper/pagination.py`)
+
+```python
+from typing import List, Optional, Any, Dict, Callable
+from pydantic import BaseModel, Field
+from fastapi import Query
+from enum import Enum
+
+class SortOrder(str, Enum):
+ """Sort order"""
+ ASC = "asc"
+ DESC = "desc"
+
+class PaginationParams(BaseModel):
+ """Pagination parameters"""
+ page: int = Field(1, ge=1, description="Page number")
+ size: int = Field(20, ge=1, le=100, description="Page size")
+ sort_by: Optional[str] = Field(None, description="Sort field")
+ sort_order: SortOrder = Field(SortOrder.ASC, description="Sort order")
+
+class FilterParams(BaseModel):
+ """Filtering parameters"""
+ search: Optional[str] = Field(None, description="Search term")
+ category: Optional[str] = Field(None, description="Category")
+ status: Optional[str] = Field(None, description="Status")
+ date_from: Optional[str] = Field(None, description="Start date (YYYY-MM-DD)")
+ date_to: Optional[str] = Field(None, description="End date (YYYY-MM-DD)")
+
+def pagination_params(
+ page: int = Query(1, ge=1, description="Page number"),
+ size: int = Query(20, ge=1, le=100, description="Page size"),
+ sort_by: Optional[str] = Query(None, description="Sort field"),
+ sort_order: SortOrder = Query(SortOrder.ASC, description="Sort order")
+) -> PaginationParams:
+ """Pagination parameters dependency"""
+ return PaginationParams(
+ page=page,
+ size=size,
+ sort_by=sort_by,
+ sort_order=sort_order
+ )
+
+def filter_params(
+ search: Optional[str] = Query(None, description="Search term"),
+ category: Optional[str] = Query(None, description="Category"),
+ status: Optional[str] = Query(None, description="Status"),
+ date_from: Optional[str] = Query(None, description="Start date (YYYY-MM-DD)"),
+ date_to: Optional[str] = Query(None, description="End date (YYYY-MM-DD)")
+) -> FilterParams:
+ """Filtering parameters dependency"""
+ return FilterParams(
+ search=search,
+ category=category,
+ status=status,
+ date_from=date_from,
+ date_to=date_to
+ )
+
+class AdvancedPaginator:
+ """Advanced pagination class"""
+
+ def __init__(self, data: List[Any], pagination: PaginationParams, filters: FilterParams):
+ self.data = data
+ self.pagination = pagination
+ self.filters = filters
+ self.filtered_data = self._apply_filters()
+ self.sorted_data = self._apply_sorting()
+
+ def _apply_filters(self) -> List[Any]:
+ """Apply filters"""
+ filtered = self.data
+
+ if self.filters.search:
+ # Filter by search term (example: search in name or description fields)
+ search_term = self.filters.search.lower()
+ filtered = [
+ item for item in filtered
+ if (hasattr(item, 'name') and search_term in item.name.lower()) or
+ (hasattr(item, 'description') and item.description and search_term in item.description.lower())
+ ]
+
+ if self.filters.category:
+ filtered = [item for item in filtered if hasattr(item, 'category') and item.category == self.filters.category]
+
+ if self.filters.status:
+ filtered = [item for item in filtered if hasattr(item, 'status') and item.status == self.filters.status]
+
+ # Implement date filtering (if date field exists)
+ if self.filters.date_from or self.filters.date_to:
+ from datetime import datetime
+ filtered = self._apply_date_filter(filtered)
+
+ return filtered
+
+ def _apply_date_filter(self, data: List[Any]) -> List[Any]:
+ """Apply date filter"""
+ from datetime import datetime
+
+ if not self.filters.date_from and not self.filters.date_to:
+ return data
+
+ filtered = []
+ for item in data:
+ if not hasattr(item, 'created_at'):
+ continue
+
+ item_date = item.created_at.date() if hasattr(item.created_at, 'date') else item.created_at
+
+ if self.filters.date_from:
+ start_date = datetime.strptime(self.filters.date_from, "%Y-%m-%d").date()
+ if item_date < start_date:
+ continue
+
+ if self.filters.date_to:
+ end_date = datetime.strptime(self.filters.date_to, "%Y-%m-%d").date()
+ if item_date > end_date:
+ continue
+
+ filtered.append(item)
+
+ return filtered
+
+ def _apply_sorting(self) -> List[Any]:
+ """Apply sorting"""
+ if not self.pagination.sort_by:
+ return self.filtered_data
+
+ reverse = self.pagination.sort_order == SortOrder.DESC
+
+ try:
+ return sorted(
+ self.filtered_data,
+ key=lambda x: getattr(x, self.pagination.sort_by, 0),
+ reverse=reverse
+ )
+ except (AttributeError, TypeError):
+ # Return original data if sort field is not found or cannot be sorted
+ return self.filtered_data
+
+ def get_page(self) -> tuple[List[Any], int]:
+ """Return current page data and total count"""
+ total = len(self.sorted_data)
+ start = (self.pagination.page - 1) * self.pagination.size
+ end = start + self.pagination.size
+
+ page_data = self.sorted_data[start:end]
+ return page_data, total
+
+ def get_metadata(self) -> Dict[str, Any]:
+ """Return pagination metadata"""
+ total = len(self.sorted_data)
+ pages = (total + self.pagination.size - 1) // self.pagination.size
+
+ return {
+ "page": self.pagination.page,
+ "size": self.pagination.size,
+ "total": total,
+ "pages": pages,
+ "has_next": self.pagination.page < pages,
+ "has_prev": self.pagination.page > 1,
+ "filters_applied": {
+ "search": self.filters.search,
+ "category": self.filters.category,
+ "status": self.filters.status,
+ "date_range": f"{self.filters.date_from} ~ {self.filters.date_to}" if self.filters.date_from or self.filters.date_to else None
+ },
+ "sorting": {
+ "field": self.pagination.sort_by,
+ "order": self.pagination.sort_order
+ } if self.pagination.sort_by else None
+ }
+```
+
+## 第 6 步:实现进阶 API 端点
+
+### Item API 路由(`src/api/routes/items.py`)
+
+```python
+from typing import List, Optional
+from fastapi import APIRouter, Depends, HTTPException, Query, Path, BackgroundTasks
+from fastapi.responses import JSONResponse
+
+from src.schemas.items import Item, ItemCreate, ItemUpdate, ItemResponse
+from src.helper.pagination import pagination_params, filter_params, PaginationParams, FilterParams, AdvancedPaginator
+from src.helper.exceptions import ResourceNotFoundException, DuplicateResourceException, ValidationException
+from src.utils.responses import success_response, paginated_response, ResponseHelper
+from src.crud.items import ItemCRUD
+
+router = APIRouter(prefix="/items", tags=["items"])
+crud = ItemCRUD()
+
+@router.post("/", response_model=dict, status_code=201)
+async def create_item(
+ item_create: ItemCreate,
+ background_tasks: BackgroundTasks
+) -> JSONResponse:
+ """
+ 创建新条目
+
+ - **name**:条目名称(必填)
+ - **description**:条目描述(可选)
+ - **price**:价格(必填,且不小于 0)
+ - **category**:分类(可选)
+ """
+ # 检查是否存在重复条目
+ existing_item = await crud.get_by_name(item_create.name)
+ if existing_item:
+ raise DuplicateResourceException("Item", "name", item_create.name)
+
+ # 业务逻辑校验
+ if item_create.price < 0:
+ raise ValidationException("Price must be 0 or greater", "price")
+
+ # 创建条目
+ created_item = await crud.create(item_create)
+
+ # 后台任务(如发送通知、记录日志等)
+ background_tasks.add_task(send_creation_notification, created_item.id)
+
+ return ResponseHelper.created(
+ data=created_item.dict(),
+ message=f"Item '{created_item.name}' created successfully"
+ )
+
+@router.get("/", response_model=dict)
+async def list_items(
+ pagination: PaginationParams = Depends(pagination_params),
+ filters: FilterParams = Depends(filter_params)
+) -> JSONResponse:
+ """
+ 获取条目列表(支持分页、筛选与排序)
+
+ **分页:**
+ - page:页码(默认:1)
+ - size:每页数量(默认:20,最大:100)
+
+ **排序:**
+ - sort_by:排序字段(name、price、created_at 等)
+ - sort_order:排序顺序(asc、desc)
+
+ **筛选:**
+ - search:搜索关键词(在名称或描述字段中搜索)
+ - category:分类筛选
+ - status:状态筛选
+ - date_from:开始日期(YYYY-MM-DD)
+ - date_to:结束日期(YYYY-MM-DD)
+ """
+ # 获取全部条目
+ all_items = await crud.get_all()
+
+ # 应用高级分页
+ paginator = AdvancedPaginator(all_items, pagination, filters)
+ page_data, total = paginator.get_page()
+
+ # 在响应中加入额外元数据
+ metadata = paginator.get_metadata()
+
+ # 生成自定义提示信息
+ message = f"Total {total} items, {len(page_data)} items retrieved"
+ if filters.search:
+ message += f" (Search term: '{filters.search}')"
+
+ return paginated_response(
+ data=[item.dict() for item in page_data],
+ page=pagination.page,
+ size=pagination.size,
+ total=total,
+ message=message
+ )
+
+@router.get("/search/advanced", response_model=dict)
+async def advanced_search(
+ q: str = Query(..., min_length=1, description="搜索关键词"),
+ fields: List[str] = Query(["name", "description"], description="搜索字段"),
+ exact_match: bool = Query(False, description="是否精确匹配"),
+ case_sensitive: bool = Query(False, description="是否区分大小写"),
+ pagination: PaginationParams = Depends(pagination_params)
+) -> JSONResponse:
+ """
+ 高级搜索功能
+
+ - **q**:搜索关键词(必填)
+ - **fields**:搜索字段列表
+ - **exact_match**:是否精确匹配
+ - **case_sensitive**:是否区分大小写
+ """
+ results = await crud.advanced_search(
+ query=q,
+ fields=fields,
+ exact_match=exact_match,
+ case_sensitive=case_sensitive
+ )
+
+ # 应用分页
+ total = len(results)
+ start = (pagination.page - 1) * pagination.size
+ end = start + pagination.size
+ page_data = results[start:end]
+
+ return paginated_response(
+ data=[item.dict() for item in page_data],
+ page=pagination.page,
+ size=pagination.size,
+ total=total,
+ message=f"'{q}' search results: {total} items"
+ )
+
+@router.get("/{item_id}", response_model=dict)
+async def get_item(
+ item_id: int = Path(..., gt=0, description="条目 ID")
+) -> JSONResponse:
+ """获取指定条目"""
+ item = await crud.get_by_id(item_id)
+ if not item:
+ raise ResourceNotFoundException("Item", item_id)
+
+ return success_response(
+ data=item.dict(),
+ message=f"Item '{item.name}' retrieved successfully"
+ )
+
+@router.put("/{item_id}", response_model=dict)
+async def update_item(
+ item_id: int = Path(..., gt=0, description="条目 ID"),
+ item_update: ItemUpdate
+) -> JSONResponse:
+ """更新条目"""
+ existing_item = await crud.get_by_id(item_id)
+ if not existing_item:
+ raise ResourceNotFoundException("Item", item_id)
+
+ # 检查名称是否与其他条目重复
+ if item_update.name and item_update.name != existing_item.name:
+ duplicate = await crud.get_by_name(item_update.name)
+ if duplicate:
+ raise DuplicateResourceException("Item", "name", item_update.name)
+
+ updated_item = await crud.update(item_id, item_update)
+
+ return ResponseHelper.updated(
+ data=updated_item.dict(),
+ message=f"Item '{updated_item.name}' updated successfully"
+ )
+
+@router.delete("/{item_id}", response_model=dict, status_code=204)
+async def delete_item(
+ item_id: int = Path(..., gt=0, description="条目 ID"),
+ force: bool = Query(False, description="是否强制删除")
+) -> JSONResponse:
+ """删除条目"""
+ item = await crud.get_by_id(item_id)
+ if not item:
+ raise ResourceNotFoundException("Item", item_id)
+
+ # 删除前校验(例如是否存在关联订单)
+ if not force and await crud.has_related_orders(item_id):
+ raise ValidationException(
+ "Related orders exist, cannot be deleted. Use force=true to force delete"
+ )
+
+ await crud.delete(item_id)
+
+ return ResponseHelper.deleted(
+ message=f"Item '{item.name}' deleted successfully"
+ )
+
+@router.post("/bulk", response_model=dict)
+async def bulk_create_items(
+ items: List[ItemCreate],
+ skip_duplicates: bool = Query(False, description="跳过重复项")
+) -> JSONResponse:
+ """批量创建条目"""
+ if len(items) > 100:
+ raise ValidationException("Maximum 100 items can be created at once")
+
+ created_items = []
+ skipped_items = []
+ errors = []
+
+ for i, item_create in enumerate(items):
+ try:
+ # 检查是否存在重复项
+ existing = await crud.get_by_name(item_create.name)
+ if existing:
+ if skip_duplicates:
+ skipped_items.append({"index": i, "name": item_create.name, "reason": "Duplicate name"})
+ continue
+ else:
+ errors.append({"index": i, "name": item_create.name, "error": "Duplicate name"})
+ continue
+
+ created_item = await crud.create(item_create)
+ created_items.append(created_item)
+
+ except Exception as e:
+ errors.append({"index": i, "name": item_create.name, "error": str(e)})
+
+ result = {
+ "created_count": len(created_items),
+ "skipped_count": len(skipped_items),
+ "error_count": len(errors),
+ "created_items": [item.dict() for item in created_items],
+ "skipped_items": skipped_items,
+ "errors": errors
+ }
+
+ message = f"{len(created_items)} items created"
+ if skipped_items:
+ message += f", {len(skipped_items)} skipped"
+ if errors:
+ message += f", {len(errors)} errors"
+
+ return success_response(data=result, message=message)
+
+async def send_creation_notification(item_id: int):
+ """条目创建通知(后台任务)"""
+ # 在实际实现中,可以通过邮件、Slack 等方式发送通知
+ import asyncio
+ await asyncio.sleep(1) # 模拟耗时处理
+ print(f"Item {item_id} creation notification sent")
+```
+
+## 第 7 步:自定义 OpenAPI 文档
+
+### 自定义 OpenAPI 文档(`src/utils/documents.py`)
+
+```python
+from fastapi import FastAPI
+from fastapi.openapi.utils import get_openapi
+from typing import Dict, Any
+
+def custom_openapi(app: FastAPI) -> Dict[str, Any]:
+ """创建自定义 OpenAPI Schema"""
+ if app.openapi_schema:
+ return app.openapi_schema
+
+ openapi_schema = get_openapi(
+ title=app.title,
+ version=app.version,
+ description=app.description,
+ routes=app.routes,
+ )
+
+ # 添加自定义信息
+ openapi_schema["info"].update({
+ "contact": {
+ "name": "API Support",
+ "url": "https://example.com/support",
+ "email": "support@example.com"
+ },
+ "license": {
+ "name": "MIT",
+ "url": "https://opensource.org/licenses/MIT"
+ },
+ "termsOfService": "https://example.com/terms"
+ })
+
+ # Add server information
+ openapi_schema["servers"] = [
+ {
+ "url": "https://api.example.com",
+ "description": "Production server"
+ },
+ {
+ "url": "https://staging-api.example.com",
+ "description": "Staging server"
+ },
+ {
+ "url": "http://localhost:8000",
+ "description": "Development server"
+ }
+ ]
+
+ # Add common response schema
+ openapi_schema["components"]["schemas"].update({
+ "SuccessResponse": {
+ "type": "object",
+ "properties": {
+ "success": {"type": "boolean", "example": True},
+ "status": {"type": "string", "example": "success"},
+ "data": {"type": "object"},
+ "message": {"type": "string", "example": "Request processed successfully"},
+ "timestamp": {"type": "string", "format": "date-time"},
+ "request_id": {"type": "string", "example": "123e4567-e89b-12d3-a456-426614174000"}
+ }
+ },
+ "ErrorResponse": {
+ "type": "object",
+ "properties": {
+ "success": {"type": "boolean", "example": False},
+ "status": {"type": "string", "example": "error"},
+ "error": {
+ "type": "object",
+ "properties": {
+ "code": {"type": "string", "example": "RESOURCE_NOT_FOUND"},
+ "message": {"type": "string", "example": "Resource not found"},
+ "details": {"type": "object"}
+ }
+ },
+ "timestamp": {"type": "string", "format": "date-time"},
+ "request_id": {"type": "string", "example": "123e4567-e89b-12d3-a456-426614174000"}
+ }
+ }
+ })
+
+ # Add tag grouping and description
+ openapi_schema["tags"] = [
+ {
+ "name": "items",
+ "description": "Item management API",
+ "externalDocs": {
+ "description": "More information",
+ "url": "https://example.com/docs/items"
+ }
+ },
+ {
+ "name": "health",
+ "description": "System status check API"
+ }
+ ]
+
+ # Add security schema
+ openapi_schema["components"]["securitySchemes"] = {
+ "BearerAuth": {
+ "type": "http",
+ "scheme": "bearer",
+ "bearerFormat": "JWT"
+ },
+ "ApiKeyAuth": {
+ "type": "apiKey",
+ "in": "header",
+ "name": "X-API-Key"
+ }
+ }
+
+ app.openapi_schema = openapi_schema
+ return app.openapi_schema
+
+def setup_docs(app: FastAPI):
+ """Setup documentation"""
+ app.openapi = lambda: custom_openapi(app)
+
+ # Swagger UI setup
+ app.docs_url = "/docs"
+ app.redoc_url = "/redoc"
+
+ # Additional document endpoint
+ @app.get("/openapi.json", include_in_schema=False)
+ async def get_openapi_endpoint():
+ return custom_openapi(app)
+```
+
+### 应用到主程序(`src/main.py` 中追加)
+
+```python
+from src.utils.documents import setup_docs
+from src.api.routes import items
+
+# Include router
+app.include_router(items.router, prefix="/api/v1")
+
+# Apply documentation setup
+setup_docs(app)
+
+# Add request ID middleware
+@app.middleware("http")
+async def add_request_id(request: Request, call_next):
+ request_id = generate_request_id()
+ request.state.request_id = request_id
+
+ response = await call_next(request)
+ response.headers["X-Request-ID"] = request_id
+
+ return response
+```
+
+## 第 8 步:实现缓存系统
+
+### 响应缓存(`src/utils/cache.py`)
+
+```python
+from typing import Optional, Any, Dict
+from functools import wraps
+import asyncio
+import json
+import hashlib
+from datetime import datetime, timedelta
+
+class MemoryCache:
+ """Memory-based cache"""
+
+ def __init__(self):
+ self._cache: Dict[str, Dict[str, Any]] = {}
+
+ async def get(self, key: str) -> Optional[Any]:
+ """Get value from cache"""
+ if key not in self._cache:
+ return None
+
+ item = self._cache[key]
+ if datetime.utcnow() > item["expires_at"]:
+ del self._cache[key]
+ return None
+
+ return item["value"]
+
+ async def set(self, key: str, value: Any, ttl_seconds: int = 300):
+ """Save value to cache"""
+ self._cache[key] = {
+ "value": value,
+ "expires_at": datetime.utcnow() + timedelta(seconds=ttl_seconds),
+ "created_at": datetime.utcnow()
+ }
+
+ async def delete(self, key: str):
+ """Delete value from cache"""
+ self._cache.pop(key, None)
+
+ async def clear(self):
+ """Delete all cache"""
+ self._cache.clear()
+
+ def get_stats(self) -> Dict[str, Any]:
+ """Cache statistics"""
+ now = datetime.utcnow()
+ valid_items = [
+ item for item in self._cache.values()
+ if now <= item["expires_at"]
+ ]
+
+ return {
+ "total_items": len(self._cache),
+ "valid_items": len(valid_items),
+ "expired_items": len(self._cache) - len(valid_items),
+ "memory_usage_mb": len(str(self._cache)) / 1024 / 1024
+ }
+
+# 全局缓存实例
+cache = MemoryCache()
+
+def cache_response(ttl_seconds: int = 300, key_prefix: str = ""):
+ """响应缓存装饰器"""
+ def decorator(func):
+ @wraps(func)
+ async def wrapper(*args, **kwargs):
+ # 生成缓存键
+ cache_key = generate_cache_key(func.__name__, args, kwargs, key_prefix)
+
+ # 从缓存中读取
+ cached_response = await cache.get(cache_key)
+ if cached_response:
+ return cached_response
+
+ # 执行原始函数
+ response = await func(*args, **kwargs)
+
+ # 写入缓存
+ await cache.set(cache_key, response, ttl_seconds)
+
+ return response
+ return wrapper
+ return decorator
+
+def generate_cache_key(func_name: str, args: tuple, kwargs: dict, prefix: str = "") -> str:
+ """Generate cache key"""
+ # Generate unique key based on function name and arguments
+ key_data = {
+ "function": func_name,
+ "args": str(args),
+ "kwargs": sorted(kwargs.items())
+ }
+
+ key_string = json.dumps(key_data, sort_keys=True)
+ key_hash = hashlib.md5(key_string.encode()).hexdigest()
+
+ return f"{prefix}:{func_name}:{key_hash}" if prefix else f"{func_name}:{key_hash}"
+
+# Cache management endpoint
+@app.get("/admin/cache/stats")
+async def get_cache_stats():
+ """Get cache statistics"""
+ stats = cache.get_stats()
+ return success_response(data=stats, message="Cache statistics retrieved")
+
+@app.delete("/admin/cache/clear")
+async def clear_cache():
+ """Delete all cache"""
+ await cache.clear()
+ return success_response(message="Cache deleted successfully")
+```
+
+### 缓存使用示例
+
+```python
+# Apply caching to src/api/routes/items.py
+
+from src.utils.cache import cache_response
+
+@router.get("/", response_model=dict)
+@cache_response(ttl_seconds=60, key_prefix="items_list") # 1 minute caching
+async def list_items(
+ pagination: PaginationParams = Depends(pagination_params),
+ filters: FilterParams = Depends(filter_params)
+) -> JSONResponse:
+ # ... existing code ...
+
+@router.get("/{item_id}", response_model=dict)
+@cache_response(ttl_seconds=300, key_prefix="item_detail") # 5 minute caching
+async def get_item(item_id: int = Path(..., gt=0)) -> JSONResponse:
+ # ... existing code ...
+```
+
+## 第 9 步:API 测试
+
+### 启动服务器并做基础测试
+
+
+
+```console
+$ cd advanced-api-server
+$ fastkit runserver
+Starting FastAPI server at 127.0.0.1:8000...
+
+# Custom response format test
+$ curl -X POST "http://localhost:8000/api/v1/items/" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "Advanced notebook",
+ "description": "Notebook with latest technology",
+ "price": 2500000,
+ "category": "electronics"
+ }'
+
+{
+ "success": true,
+ "status": "success",
+ "data": {
+ "id": 1,
+ "name": "Advanced notebook",
+ "description": "Notebook with latest technology",
+ "price": 2500000,
+ "category": "electronics",
+ "created_at": "2024-01-01T12:00:00Z"
+ },
+ "message": "Item 'Advanced notebook' created successfully",
+ "timestamp": "2024-01-01T12:00:00.123456Z",
+ "request_id": "123e4567-e89b-12d3-a456-426614174000"
+}
+
+# Pagination and filtering test
+$ curl "http://localhost:8000/api/v1/items/?page=1&size=10&search=notebook&sort_by=price&sort_order=desc"
+
+# Advanced search test
+$ curl "http://localhost:8000/api/v1/items/search/advanced?q=notebook&fields=name&fields=description&exact_match=false"
+
+# Error response test
+$ curl "http://localhost:8000/api/v1/items/999"
+
+{
+ "success": false,
+ "status": "error",
+ "error": {
+ "code": "RESOURCE_NOT_FOUND",
+ "message": "Item (ID: 999) not found",
+ "details": {
+ "resource": "Item",
+ "id": 999
+ }
+ },
+ "timestamp": "2024-01-01T12:00:00.123456Z",
+ "request_id": "123e4567-e89b-12d3-a456-426614174000"
+}
+```
+
+
+
+### 查看 OpenAPI 文档
+
+在浏览器中访问 http://localhost:8000/docs,查看已自定义过的 API 文档。
+
+## 下一步
+
+恭喜您完成了自定义响应处理系统!接下来可以尝试:
+
+1. **[MCP 集成](mcp-integration.md)** —— 实现 Model Context Protocol
+
+
+
+
+## 小结
+
+在本教程中,我们实现了一套进阶的响应处理系统:
+
+- ✅ 设计标准化的 API 响应格式
+- ✅ 全局异常处理与自定义错误响应
+- ✅ 进阶的分页与过滤系统
+- ✅ 自定义 OpenAPI 文档
+- ✅ 响应缓存与性能优化
+- ✅ 请求追踪系统
+- ✅ 后台任务处理
+- ✅ 批量操作 API
+
+现在您已经能实现企业级 API 服务器的全部核心功能!
diff --git a/docs/zh/tutorial/database-integration.md b/docs/zh/tutorial/database-integration.md
new file mode 100644
index 0000000..1f10f09
--- /dev/null
+++ b/docs/zh/tutorial/database-integration.md
@@ -0,0 +1,1027 @@
+# 数据库集成(PostgreSQL + SQLAlchemy)
+
+使用 PostgreSQL 数据库与 SQLAlchemy ORM,构建一个可用于真实生产环境的 FastAPI 应用。本教程中我们将通过 `fastapi-psql-orm` 模板,实现完整的数据库集成。
+
+## 您将学到的内容
+
+- PostgreSQL 数据库的搭建与集成
+- 用 SQLAlchemy ORM 做数据建模
+- 使用 Alembic 做数据库迁移
+- 通过 Docker Compose 搭建开发环境
+- 数据库连接池管理
+- 事务处理与数据一致性
+
+## 前置条件
+
+- 已完成 [异步 CRUD API 教程](async-crud-api.md)
+- 已安装 Docker 与 Docker Compose
+- 具备 PostgreSQL 基础知识
+- 理解 SQLAlchemy ORM 的基本概念
+
+## 为什么选择 PostgreSQL 与 SQLAlchemy?
+
+### JSON 文件 vs PostgreSQL 对比
+
+| 类别 | JSON 文件 | PostgreSQL |
+|----------|------------|------------|
+| **性能** | 受限 | 高性能索引 |
+| **并发** | 文件锁问题 | 事务支持 |
+| **可扩展性** | 受内存限制 | 大规模数据处理 |
+| **一致性** | 无保证 | 保证 ACID 特性 |
+| **查询** | 需加载全部数据 | 支持复杂查询 |
+| **备份** | 复制文件 | 完整的备份 / 恢复 |
+
+## 第 1 步:创建 PostgreSQL + ORM 项目
+
+使用 `fastapi-psql-orm` 模板创建项目:
+
+
+
+```console
+$ fastkit startdemo fastapi-psql-orm
+Enter the project name: todo-postgres-api
+Enter the author name: Developer Kim
+Enter the author email: developer@example.com
+Enter the project description: Todo management API using PostgreSQL
+Deploying FastAPI project using 'fastapi-psql-orm' template
+
+ Project Information
+┌──────────────┬─────────────────────────────────────────┐
+│ Project Name │ todo-postgres-api │
+│ Author │ Developer Kim │
+│ Author Email │ developer@example.com │
+│ Description │ Todo management API using PostgreSQL │
+└──────────────┴─────────────────────────────────────────┘
+
+ Template Dependencies
+┌──────────────┬────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ sqlalchemy │
+│ Dependency 4 │ alembic │
+│ Dependency 5 │ psycopg2 │
+│ Dependency 6 │ asyncpg │
+│ Dependency 7 │ sqlmodel │
+└──────────────┴────────────────┘
+
+Select package manager (pip, uv, pdm, poetry) [uv]: uv
+Do you want to proceed with project creation? [y/N]: y
+
+✨ FastAPI project 'todo-postgres-api' from 'fastapi-psql-orm' has been created successfully!
+```
+
+
+
+## 第 2 步:分析项目结构
+
+生成的项目提供了完整的数据库集成环境:
+
+```
+todo-postgres-api/
+├── docker-compose.yml # PostgreSQL container configuration
+├── Dockerfile # Application container
+├── alembic.ini # Alembic configuration
+├── template-config.yml # Template configuration
+├── scripts/
+│ ├── pre-start.sh # Pre-start initialization
+│ └── test.sh # Test execution script
+├── src/
+│ ├── main.py # FastAPI application
+│ ├── core/
+│ │ ├── config.py # Environment configuration
+│ │ └── db.py # 数据库连接配置
+│ ├── api/
+│ │ ├── deps.py # 依赖注入
+│ │ └── routes/
+│ │ └── items.py # API 端点
+│ ├── crud/
+│ │ └── items.py # 数据库操作
+│ ├── schemas/
+│ │ └── items.py # Pydantic 模型
+│ ├── utils/
+│ │ ├── backend_pre_start.py # 后端初始化
+│ │ ├── init_data.py # 初始数据加载
+│ │ └── tests_pre_start.py # 测试准备
+│ └── alembic/
+│ ├── env.py # Alembic 环境配置
+│ └── versions/ # 迁移文件
+└── tests/
+ ├── conftest.py # 测试配置
+ └── test_items.py # API 测试
+```
+
+### 核心组件
+
+1. **SQLModel**:SQLAlchemy 与 Pydantic 的融合
+2. **Alembic**:数据库模式迁移
+3. **asyncpg**:异步 PostgreSQL 驱动
+4. **Docker Compose**:开发环境容器化
+
+## 第 3 步:理解数据库配置
+
+### 数据库连接设置(`src/core/db.py`)
+
+```python
+from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
+from sqlalchemy.orm import sessionmaker
+from sqlmodel import SQLModel
+
+from src.core.config import settings
+
+# 创建异步 PostgreSQL 引擎
+engine = create_async_engine(
+ settings.DATABASE_URL,
+ echo=settings.DEBUG, # 输出 SQL 日志
+ pool_size=20, # 连接池大小
+ max_overflow=0, # 允许额外创建的连接数
+ pool_pre_ping=True, # 预先检查连接状态
+)
+
+# 异步会话工厂
+AsyncSessionLocal = sessionmaker(
+ autocommit=False,
+ autoflush=False,
+ bind=engine,
+ class_=AsyncSession,
+ expire_on_commit=False,
+)
+
+async def create_tables():
+ """创建数据库表"""
+ async with engine.begin() as conn:
+ await conn.run_sync(SQLModel.metadata.create_all)
+
+async def get_session() -> AsyncSession:
+ """提供数据库会话(用于依赖注入)"""
+ async with AsyncSessionLocal() as session:
+ try:
+ yield session
+ finally:
+ await session.close()
+```
+
+### 环境配置(`src/core/config.py`)
+
+```python
+from pydantic_settings import BaseSettings
+from typing import Optional
+
+class Settings(BaseSettings):
+ PROJECT_NAME: str = "Todo PostgreSQL API"
+ VERSION: str = "1.0.0"
+ DESCRIPTION: str = "Todo management API using PostgreSQL"
+
+ # Database configuration
+ POSTGRES_SERVER: str = "localhost"
+ POSTGRES_USER: str = "postgres"
+ POSTGRES_PASSWORD: str = "password"
+ POSTGRES_DB: str = "todoapp"
+ POSTGRES_PORT: int = 5432
+
+ # Test database
+ TEST_DATABASE_URL: Optional[str] = None
+
+ # Debug mode
+ DEBUG: bool = False
+
+ @property
+ def DATABASE_URL(self) -> str:
+ """Generate PostgreSQL connection URL"""
+ return (
+ f"postgresql+asyncpg://{self.POSTGRES_USER}:"
+ f"{self.POSTGRES_PASSWORD}@{self.POSTGRES_SERVER}:"
+ f"{self.POSTGRES_PORT}/{self.POSTGRES_DB}"
+ )
+
+ class Config:
+ env_file = ".env"
+
+settings = Settings()
+```
+
+## 第 4 步:定义数据模型
+
+### 使用 SQLModel 的数据模型(`src/schemas/items.py`)
+
+```python
+from sqlmodel import SQLModel, Field
+from typing import Optional
+from datetime import datetime
+
+# Define common fields
+class ItemBase(SQLModel):
+ name: str = Field(index=True, max_length=100)
+ description: Optional[str] = Field(default=None, max_length=500)
+ price: float = Field(gt=0, description="Price must be greater than 0")
+ tax: Optional[float] = Field(default=None, ge=0)
+ is_active: bool = Field(default=True)
+
+# Database table model
+class Item(ItemBase, table=True):
+ __tablename__ = "items"
+
+ id: Optional[int] = Field(default=None, primary_key=True)
+ created_at: datetime = Field(default_factory=datetime.utcnow)
+ updated_at: Optional[datetime] = Field(default=None)
+
+ # Set index
+ class Config:
+ schema_extra = {
+ "example": {
+ "name": "notebook",
+ "description": "High-performance gaming notebook",
+ "price": 1500000.0,
+ "tax": 150000.0,
+ "is_active": True
+ }
+ }
+
+# API request/response model
+class ItemCreate(ItemBase):
+ pass
+
+class ItemUpdate(SQLModel):
+ name: Optional[str] = Field(default=None, max_length=100)
+ description: Optional[str] = Field(default=None, max_length=500)
+ price: Optional[float] = Field(default=None, gt=0)
+ tax: Optional[float] = Field(default=None, ge=0)
+ is_active: Optional[bool] = Field(default=None)
+
+class ItemResponse(ItemBase):
+ id: int
+ created_at: datetime
+ updated_at: Optional[datetime]
+```
+
+## 第 5 步:实现 CRUD 操作
+
+### 数据库 CRUD 逻辑(`src/crud/items.py`)
+
+```python
+from typing import List, Optional
+from sqlalchemy.ext.asyncio import AsyncSession
+from sqlalchemy import select, update, delete
+from sqlalchemy.orm import selectinload
+from datetime import datetime
+
+from src.schemas.items import Item, ItemCreate, ItemUpdate
+
+class ItemCRUD:
+ def __init__(self, db: AsyncSession):
+ self.db = db
+
+ async def create(self, item_create: ItemCreate) -> Item:
+ """Create new item"""
+ db_item = Item(**item_create.dict())
+
+ self.db.add(db_item)
+ await self.db.commit()
+ await self.db.refresh(db_item)
+
+ return db_item
+
+ async def get_by_id(self, item_id: int) -> Optional[Item]:
+ """Get item by ID"""
+ statement = select(Item).where(Item.id == item_id)
+ result = await self.db.execute(statement)
+ return result.scalar_one_or_none()
+
+ async def get_many(
+ self,
+ skip: int = 0,
+ limit: int = 100,
+ active_only: bool = True
+ ) -> List[Item]:
+ """Get multiple items (pagination supported)"""
+ statement = select(Item)
+
+ if active_only:
+ statement = statement.where(Item.is_active == True)
+
+ statement = statement.offset(skip).limit(limit)
+ result = await self.db.execute(statement)
+ return result.scalars().all()
+
+ async def update(self, item_id: int, item_update: ItemUpdate) -> Optional[Item]:
+ """Update item"""
+ # Prepare update data
+ update_data = item_update.dict(exclude_unset=True)
+ if update_data:
+ update_data["updated_at"] = datetime.utcnow()
+
+ # Execute update
+ statement = (
+ update(Item)
+ .where(Item.id == item_id)
+ .values(**update_data)
+ .returning(Item)
+ )
+
+ result = await self.db.execute(statement)
+ await self.db.commit()
+
+ return result.scalar_one_or_none()
+
+ async def delete(self, item_id: int) -> bool:
+ """Delete item (soft delete)"""
+ statement = (
+ update(Item)
+ .where(Item.id == item_id)
+ .values(is_active=False, updated_at=datetime.utcnow())
+ )
+
+ result = await self.db.execute(statement)
+ await self.db.commit()
+
+ return result.rowcount > 0
+
+ async def hard_delete(self, item_id: int) -> bool:
+ """Delete item completely"""
+ statement = delete(Item).where(Item.id == item_id)
+ result = await self.db.execute(statement)
+ await self.db.commit()
+
+ return result.rowcount > 0
+
+ async def search(self, query: str) -> List[Item]:
+ """Search item (name, description)"""
+ statement = select(Item).where(
+ (Item.name.ilike(f"%{query}%")) |
+ (Item.description.ilike(f"%{query}%"))
+ ).where(Item.is_active == True)
+
+ result = await self.db.execute(statement)
+ return result.scalars().all()
+
+ async def get_total_count(self, active_only: bool = True) -> int:
+ """Get total item count"""
+ from sqlalchemy import func
+
+ statement = select(func.count(Item.id))
+ if active_only:
+ statement = statement.where(Item.is_active == True)
+
+ result = await self.db.execute(statement)
+ return result.scalar()
+```
+
+## 第 6 步:实现 API 端点
+
+### 依赖注入设置(`src/api/deps.py`)
+
+```python
+from typing import AsyncGenerator
+from fastapi import Depends
+from sqlalchemy.ext.asyncio import AsyncSession
+
+from src.core.db import get_session
+from src.crud.items import ItemCRUD
+
+async def get_db() -> AsyncGenerator[AsyncSession, None]:
+ """Database session dependency"""
+ async for session in get_session():
+ yield session
+
+def get_item_crud(db: AsyncSession = Depends(get_db)) -> ItemCRUD:
+ """Item CRUD dependency"""
+ return ItemCRUD(db)
+```
+
+### API 路由实现(`src/api/routes/items.py`)
+
+```python
+from typing import List
+from fastapi import APIRouter, Depends, HTTPException, Query, status
+
+from src.api.deps import get_item_crud
+from src.crud.items import ItemCRUD
+from src.schemas.items import Item, ItemCreate, ItemUpdate, ItemResponse
+
+router = APIRouter()
+
+@router.post("/", response_model=ItemResponse, status_code=status.HTTP_201_CREATED)
+async def create_item(
+ item_create: ItemCreate,
+ crud: ItemCRUD = Depends(get_item_crud)
+):
+ """Create new item"""
+ return await crud.create(item_create)
+
+@router.get("/", response_model=List[ItemResponse])
+async def read_items(
+ skip: int = Query(0, ge=0, description="Skip items"),
+ limit: int = Query(100, ge=1, le=1000, description="Maximum items to retrieve"),
+ active_only: bool = Query(True, description="Only active items"),
+ crud: ItemCRUD = Depends(get_item_crud)
+):
+ """Get item list (pagination supported)"""
+ return await crud.get_many(skip=skip, limit=limit, active_only=active_only)
+
+@router.get("/search", response_model=List[ItemResponse])
+async def search_items(
+ q: str = Query(..., min_length=1, description="Search term"),
+ crud: ItemCRUD = Depends(get_item_crud)
+):
+ """Search item"""
+ return await crud.search(q)
+
+@router.get("/count")
+async def get_items_count(
+ active_only: bool = Query(True, description="Only active items"),
+ crud: ItemCRUD = Depends(get_item_crud)
+):
+ """Get total item count"""
+ count = await crud.get_total_count(active_only)
+ return {"total": count}
+
+@router.get("/{item_id}", response_model=ItemResponse)
+async def read_item(
+ item_id: int,
+ crud: ItemCRUD = Depends(get_item_crud)
+):
+ """Get specific item"""
+ item = await crud.get_by_id(item_id)
+ if not item:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail=f"Item ID {item_id} not found"
+ )
+ return item
+
+@router.put("/{item_id}", response_model=ItemResponse)
+async def update_item(
+ item_id: int,
+ item_update: ItemUpdate,
+ crud: ItemCRUD = Depends(get_item_crud)
+):
+ """Update item"""
+ updated_item = await crud.update(item_id, item_update)
+ if not updated_item:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail=f"Item ID {item_id} not found"
+ )
+ return updated_item
+
+@router.delete("/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
+async def delete_item(
+ item_id: int,
+ hard_delete: bool = Query(False, description="Complete delete"),
+ crud: ItemCRUD = Depends(get_item_crud)
+):
+ """Delete item"""
+ if hard_delete:
+ deleted = await crud.hard_delete(item_id)
+ else:
+ deleted = await crud.delete(item_id)
+
+ if not deleted:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail=f"Item ID {item_id} not found"
+ )
+```
+
+## 第 7 步:运行 Docker 容器
+
+### 检查 Docker Compose 配置(`docker-compose.yml`)
+
+```yaml
+version: '3.8'
+
+services:
+ db:
+ image: postgres:15
+ restart: always
+ environment:
+ POSTGRES_DB: todoapp
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: password
+ ports:
+ - "5432:5432"
+ volumes:
+ - postgres_data:/var/lib/postgresql/data
+
+ app:
+ build: .
+ restart: always
+ ports:
+ - "8000:8000"
+ environment:
+ POSTGRES_SERVER: db
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: password
+ POSTGRES_DB: todoapp
+ depends_on:
+ - db
+ volumes:
+ - ./src:/app/src
+
+volumes:
+ postgres_data:
+```
+
+### 运行容器
+
+
+
+```console
+$ cd todo-postgres-api
+
+# Start service in background
+$ docker-compose up -d
+Creating network "todo-postgres-api_default" with the default driver
+Creating volume "todo-postgres-api_postgres_data" with default driver
+Pulling db (postgres:15)...
+Creating todo-postgres-api_db_1 ... done
+Building app
+Creating todo-postgres-api_app_1 ... done
+
+# Check service status
+$ docker-compose ps
+ Name Command State Ports
+-------------------------------------------------------------------------------------
+todo-postgres-api_app_1 uvicorn src.main:app --host=0.0.0.0 --port=8000 Up 0.0.0.0:8000->8000/tcp
+todo-postgres-api_db_1 docker-entrypoint.sh postgres Up 0.0.0.0:5432->5432/tcp
+
+# Check log
+$ docker-compose logs app
+```
+
+
+
+## 第 8 步:数据库迁移
+
+### 使用 Alembic 创建初始迁移
+
+
+
+```console
+# Run migration inside container
+$ docker-compose exec app alembic revision --autogenerate -m "Create items table"
+INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
+INFO [alembic.runtime.migration] Will assume transactional DDL.
+INFO [alembic.autogenerate.compare] Detected added table 'items'
+Generating migration script /app/src/alembic/versions/001_create_items_table.py ... done
+
+# Apply migration
+$ docker-compose exec app alembic upgrade head
+INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
+INFO [alembic.runtime.migration] Will assume transactional DDL.
+INFO [alembic.runtime.migration] Running upgrade -> 001, Create items table
+```
+
+
+
+### 查看迁移文件
+
+查看生成的迁移文件:
+
+```python
+# src/alembic/versions/001_create_items_table.py
+"""Create items table
+
+Revision ID: 001
+Revises:
+Create Date: 2024-01-01 12:00:00.000000
+
+"""
+from alembic import op
+import sqlalchemy as sa
+import sqlmodel
+
+# revision identifiers
+revision = '001'
+down_revision = None
+branch_labels = None
+depends_on = None
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.create_table('items',
+ sa.Column('name', sqlmodel.sql.sqltypes.AutoString(length=100), nullable=False),
+ sa.Column('description', sqlmodel.sql.sqltypes.AutoString(length=500), nullable=True),
+ sa.Column('price', sa.Float(), nullable=False),
+ sa.Column('tax', sa.Float(), nullable=True),
+ sa.Column('is_active', sa.Boolean(), nullable=False),
+ sa.Column('id', sa.Integer(), nullable=False),
+ sa.Column('created_at', sa.DateTime(), nullable=False),
+ sa.Column('updated_at', sa.DateTime(), nullable=True),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_items_name'), 'items', ['name'], unique=False)
+ # ### end Alembic commands ###
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_index(op.f('ix_items_name'), table_name='items')
+ op.drop_table('items')
+ # ### end Alembic commands ###
+```
+
+## 第 9 步:API 测试
+
+### 基础 CRUD 测试
+
+
+
+```console
+# Create new item
+$ curl -X POST "http://localhost:8000/items/" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "MacBook Pro",
+ "description": "M2 chipset-equipped high-performance notebook",
+ "price": 2500000,
+ "tax": 250000
+ }'
+
+{
+ "id": 1,
+ "name": "MacBook Pro",
+ "description": "M2 chipset-equipped high-performance notebook",
+ "price": 2500000.0,
+ "tax": 250000.0,
+ "is_active": true,
+ "created_at": "2024-01-01T12:00:00.123456",
+ "updated_at": null
+}
+
+# Get item list
+$ curl "http://localhost:8000/items/"
+
+# Get item list with pagination
+$ curl "http://localhost:8000/items/?skip=0&limit=10"
+
+# Search item
+$ curl "http://localhost:8000/items/search?q=MacBook"
+
+# Get item count
+$ curl "http://localhost:8000/items/count"
+{"total": 1}
+```
+
+
+
+### 进阶查询能力测试
+
+
+
+```console
+# Get item list with inactive items
+$ curl "http://localhost:8000/items/?active_only=false"
+
+# Update item
+$ curl -X PUT "http://localhost:8000/items/1" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "price": 2300000,
+ "tax": 230000
+ }'
+
+# Soft delete item
+$ curl -X DELETE "http://localhost:8000/items/1"
+
+# Hard delete item
+$ curl -X DELETE "http://localhost:8000/items/1?hard_delete=true"
+```
+
+
+
+## 第 10 步:进阶数据库特性
+
+### 事务处理
+
+```python
+# Add to src/crud/items.py
+
+from sqlalchemy.exc import SQLAlchemyError
+
+async def create_items_batch(self, items_create: List[ItemCreate]) -> List[Item]:
+ """Create multiple items in a transaction"""
+ created_items = []
+
+ try:
+ for item_create in items_create:
+ db_item = Item(**item_create.dict())
+ self.db.add(db_item)
+ created_items.append(db_item)
+
+ await self.db.commit()
+
+ # Refresh all items
+ for item in created_items:
+ await self.db.refresh(item)
+
+ return created_items
+
+ except SQLAlchemyError:
+ await self.db.rollback()
+ raise
+```
+
+### 关系型数据建模
+
+```python
+# Add to src/schemas/items.py
+
+from sqlmodel import Relationship
+
+class Category(SQLModel, table=True):
+ __tablename__ = "categories"
+
+ id: Optional[int] = Field(default=None, primary_key=True)
+ name: str = Field(max_length=50, unique=True)
+ description: Optional[str] = None
+
+ # Set relationship
+ items: List["Item"] = Relationship(back_populates="category")
+
+class Item(ItemBase, table=True):
+ __tablename__ = "items"
+
+ id: Optional[int] = Field(default=None, primary_key=True)
+ created_at: datetime = Field(default_factory=datetime.utcnow)
+ updated_at: Optional[datetime] = Field(default=None)
+
+ # Add foreign key
+ category_id: Optional[int] = Field(foreign_key="categories.id")
+
+ # Set relationship
+ category: Optional[Category] = Relationship(back_populates="items")
+```
+
+### 索引优化
+
+```python
+# Add to src/schemas/items.py
+
+from sqlalchemy import Index
+
+class Item(ItemBase, table=True):
+ __tablename__ = "items"
+
+ # ... existing fields ...
+
+ # Set composite index
+ __table_args__ = (
+ Index('ix_items_price_active', 'price', 'is_active'),
+ Index('ix_items_created_at', 'created_at'),
+ Index('ix_items_name_description', 'name', 'description'), # For full text search
+ )
+```
+
+## 第 11 步:编写测试
+
+### 数据库测试配置(`tests/conftest.py`)
+
+```python
+import pytest
+import asyncio
+from httpx import AsyncClient
+from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
+from sqlalchemy.orm import sessionmaker
+from sqlmodel import SQLModel
+
+from src.main import app
+from src.core.db import get_session
+from src.core.config import settings
+
+# Test database engine
+test_engine = create_async_engine(
+ settings.TEST_DATABASE_URL or "sqlite+aiosqlite:///./test.db",
+ echo=False,
+)
+
+TestSessionLocal = sessionmaker(
+ autocommit=False,
+ autoflush=False,
+ bind=test_engine,
+ class_=AsyncSession,
+ expire_on_commit=False,
+)
+
+@pytest.fixture(scope="session")
+def event_loop():
+ loop = asyncio.get_event_loop_policy().new_event_loop()
+ yield loop
+ loop.close()
+
+@pytest.fixture(scope="function")
+async def db_session():
+ # Create test table
+ async with test_engine.begin() as conn:
+ await conn.run_sync(SQLModel.metadata.create_all)
+
+ # Provide session
+ async with TestSessionLocal() as session:
+ yield session
+
+ # Delete table after test
+ async with test_engine.begin() as conn:
+ await conn.run_sync(SQLModel.metadata.drop_all)
+
+@pytest.fixture
+async def client(db_session: AsyncSession):
+ # Override dependency
+ async def override_get_session():
+ yield db_session
+
+ app.dependency_overrides[get_session] = override_get_session
+
+ async with AsyncClient(app=app, base_url="http://test") as client:
+ yield client
+
+ app.dependency_overrides.clear()
+```
+
+### 集成测试(`tests/test_items.py`)
+
+```python
+import pytest
+from httpx import AsyncClient
+
+@pytest.mark.asyncio
+async def test_create_and_read_item(client: AsyncClient):
+ """Integration test for creating and reading item"""
+ # Create item
+ item_data = {
+ "name": "Test Item",
+ "description": "Database test",
+ "price": 50000,
+ "tax": 5000
+ }
+
+ response = await client.post("/items/", json=item_data)
+ assert response.status_code == 201
+
+ created_item = response.json()
+ assert created_item["name"] == item_data["name"]
+ assert "id" in created_item
+ assert "created_at" in created_item
+
+ # Get created item
+ item_id = created_item["id"]
+ response = await client.get(f"/items/{item_id}")
+ assert response.status_code == 200
+
+ retrieved_item = response.json()
+ assert retrieved_item["id"] == item_id
+ assert retrieved_item["name"] == item_data["name"]
+
+@pytest.mark.asyncio
+async def test_item_pagination(client: AsyncClient):
+ """Test pagination feature"""
+ # Create multiple items
+ for i in range(15):
+ item_data = {
+ "name": f"Item {i}",
+ "description": f"Description {i}",
+ "price": i * 1000,
+ "tax": i * 100
+ }
+ await client.post("/items/", json=item_data)
+
+ # Get first page
+ response = await client.get("/items/?skip=0&limit=10")
+ assert response.status_code == 200
+
+ items = response.json()
+ assert len(items) == 10
+
+ # Get second page
+ response = await client.get("/items/?skip=10&limit=10")
+ assert response.status_code == 200
+
+ items = response.json()
+ assert len(items) == 5
+
+@pytest.mark.asyncio
+async def test_item_search(client: AsyncClient):
+ """Test search feature"""
+ # Create test items
+ items = [
+ {"name": "iPhone 15", "description": "Latest smartphone", "price": 1200000, "tax": 120000},
+ {"name": "Galaxy S24", "description": "Samsung flagship", "price": 1100000, "tax": 110000},
+ {"name": "MacBook Air", "description": "Apple notebook", "price": 1500000, "tax": 150000},
+ ]
+
+ for item in items:
+ await client.post("/items/", json=item)
+
+ # Search "iPhone"
+ response = await client.get("/items/search?q=iPhone")
+ assert response.status_code == 200
+
+ results = response.json()
+ assert len(results) == 1
+ assert results[0]["name"] == "iPhone 15"
+
+ # Search "smartphone" (description)
+ response = await client.get("/items/search?q=smartphone")
+ assert response.status_code == 200
+
+ results = response.json()
+ assert len(results) == 1
+ assert results[0]["description"] == "Latest smartphone"
+```
+
+### 运行测试
+
+
+
+```console
+# Run tests inside container
+$ docker-compose exec app python -m pytest tests/ -v
+======================== test session starts ========================
+collected 12 items
+
+tests/test_items.py::test_create_and_read_item PASSED [ 8%]
+tests/test_items.py::test_item_pagination PASSED [16%]
+tests/test_items.py::test_item_search PASSED [25%]
+tests/test_items.py::test_update_item PASSED [33%]
+tests/test_items.py::test_delete_item PASSED [41%]
+tests/test_items.py::test_soft_delete PASSED [50%]
+tests/test_items.py::test_item_not_found PASSED [58%]
+tests/test_items.py::test_invalid_item_data PASSED [66%]
+tests/test_items.py::test_database_transaction PASSED [75%]
+tests/test_items.py::test_concurrent_operations PASSED [83%]
+tests/test_items.py::test_item_count PASSED [91%]
+tests/test_items.py::test_batch_operations PASSED [100%]
+
+======================== 12 passed in 2.34s ========================
+```
+
+
+
+## 第 12 步:生产部署的考量
+
+### 优化连接池
+
+```python
+# Add to src/core/config.py
+
+class Settings(BaseSettings):
+ # ... existing settings ...
+
+ # Database connection pool settings
+ DB_POOL_SIZE: int = 20
+ DB_MAX_OVERFLOW: int = 0
+ DB_POOL_PRE_PING: bool = True
+ DB_POOL_RECYCLE: int = 300 # 5 minutes
+
+ # Query timeout
+ DB_QUERY_TIMEOUT: int = 30
+
+ # Connection retry settings
+ DB_RETRY_ATTEMPTS: int = 3
+ DB_RETRY_DELAY: int = 1
+```
+
+### 数据库监控
+
+```python
+# Add to src/core/db.py
+
+import logging
+from sqlalchemy import event
+from sqlalchemy.engine import Engine
+
+logger = logging.getLogger(__name__)
+
+@event.listens_for(Engine, "before_cursor_execute")
+def receive_before_cursor_execute(conn, cursor, statement, parameters, context, executemany):
+ """Log before query execution"""
+ context._query_start_time = time.time()
+
+@event.listens_for(Engine, "after_cursor_execute")
+def receive_after_cursor_execute(conn, cursor, statement, parameters, context, executemany):
+ """Log after query execution"""
+ total = time.time() - context._query_start_time
+ if total > 1.0: # Log slow queries (1 second or more)
+ logger.warning(f"Slow query: {total:.2f}s - {statement[:100]}...")
+```
+
+## 下一步
+
+恭喜您完成了 PostgreSQL 数据库集成!接下来可以尝试:
+
+1. **[Docker 容器化](docker-deployment.md)** —— 构建生产部署环境
+2. **[自定义响应处理](custom-response-handling.md)** —— 进阶的 API 响应格式
+
+
+
+## 小结
+
+在本教程中,我们用 PostgreSQL 与 SQLAlchemy 完成了:
+
+- ✅ 集成 PostgreSQL 数据库
+- ✅ 使用 SQLModel 实现 ORM
+- ✅ 配置 Alembic 迁移系统
+- ✅ 进阶的 CRUD 操作与查询优化
+- ✅ 事务处理与数据一致性
+- ✅ 分页、搜索与排序功能
+- ✅ 集成测试与数据库测试
+- ✅ 生产部署的考量
+
+现在您可以构建出能在真实生产环境中使用的、稳健的、数据库驱动型 API!
diff --git a/docs/zh/tutorial/docker-deployment.md b/docs/zh/tutorial/docker-deployment.md
new file mode 100644
index 0000000..7ea5d0a
--- /dev/null
+++ b/docs/zh/tutorial/docker-deployment.md
@@ -0,0 +1,1177 @@
+# Docker 容器化与部署
+
+学习如何用 Docker 把 FastAPI 应用容器化,构建一致的开发环境并为生产部署做准备。本节我们将通过 `fastapi-dockerized` 模板搭建一套完整的 Docker 部署环境。
+
+## 您将学到的内容
+
+- 用 Docker 把 FastAPI 应用容器化
+- 通过多阶段构建生成优化的 Docker 镜像
+- 用 Docker Compose 搭建开发环境
+- 面向生产部署的 Docker 配置
+- 容器监控与日志管理
+- 构建 CI/CD 流水线
+
+## 前置条件
+
+- 完成 [数据库集成教程](database-integration.md)
+- 已安装 Docker 与 Docker Compose
+- 熟悉常见的 Docker 命令
+- 对容器概念有基础认知
+
+## Docker 容器化的优势
+
+### 传统方式 vs Docker 方式
+
+| 类别 | 传统方式 | Docker 方式 |
+|----------|---------------------|-----------------|
+| **环境一致性** | 各环境间存在差异 | 各处环境一致 |
+| **依赖管理** | 需要手动安装 | 所有依赖打入镜像 |
+| **部署速度** | 慢 | 可快速部署 |
+| **可扩展性** | 受限 | 易于扩展 |
+| **回滚** | 复杂 | 可立即回滚到上一版本 |
+| **资源占用** | 较重 | 轻量级容器 |
+
+## 第 1 步:创建基于 Docker 的项目
+
+使用 `fastapi-dockerized` 模板创建项目:
+
+
+
+```console
+$ fastkit startdemo fastapi-dockerized
+Enter the project name: dockerized-todo-api
+Enter the author name: Developer Kim
+Enter the author email: developer@example.com
+Enter the project description: Dockerized todo management API
+Deploying FastAPI project using 'fastapi-dockerized' template
+
+ Project Information
+┌──────────────┬─────────────────────────────────────────────┐
+│ Project Name │ dockerized-todo-api │
+│ Author │ Developer Kim │
+│ Author Email │ developer@example.com │
+│ Description │ Dockerized todo management API │
+└──────────────┴─────────────────────────────────────────────┘
+
+ Template Dependencies
+┌──────────────┬───────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ pydantic │
+│ Dependency 4 │ pydantic-settings │
+│ Dependency 5 │ python-dotenv │
+└──────────────┴───────────────────┘
+
+Select package manager (pip, uv, pdm, poetry) [uv]: uv
+Do you want to proceed with project creation? [y/N]: y
+
+✨ FastAPI project 'dockerized-todo-api' from 'fastapi-dockerized' has been created successfully!
+```
+
+
+
+## 第 2 步:分析 Docker 配置文件
+
+让我们看看生成项目中的 Docker 相关文件:
+
+```
+dockerized-todo-api/
+├── Dockerfile # Docker image build configuration
+├── docker-compose.yml # Development environment container setup
+├── docker-compose.prod.yml # Production environment configuration
+├── .dockerignore # Files to exclude during Docker build
+├── scripts/
+│ ├── start.sh # Container startup script
+│ ├── prestart.sh # Pre-start initialization script
+│ └── gunicorn.conf.py # Gunicorn configuration
+├── src/
+│ ├── main.py # FastAPI application
+│ └── ... # Other source code
+└── requirements.txt # Python 依赖
+```
+
+### Dockerfile 解析
+
+```dockerfile
+# 使用多阶段构建优化 Dockerfile
+
+# ============================================
+# 阶段 1:构建阶段
+# ============================================
+FROM python:3.12-slim as builder
+
+# 安装构建工具
+RUN apt-get update && apt-get install -y \
+ build-essential \
+ curl \
+ && rm -rf /var/lib/apt/lists/*
+
+# 复制依赖文件并安装
+COPY requirements.txt .
+RUN pip install --user --no-cache-dir -r requirements.txt
+
+# ============================================
+# 阶段 2:运行阶段
+# ============================================
+FROM python:3.12-slim
+
+# 更新系统并安装必要软件包
+RUN apt-get update && apt-get install -y \
+ curl \
+ && rm -rf /var/lib/apt/lists/* \
+ && apt-get clean
+
+# 创建非 root 用户(增强安全性)
+RUN groupadd -r appuser && useradd -r -g appuser appuser
+
+# 创建应用目录
+WORKDIR /app
+
+# 从构建阶段复制 Python 包
+COPY --from=builder /root/.local /home/appuser/.local
+
+# 复制应用代码
+COPY . .
+
+# 设置文件权限
+RUN chown -R appuser:appuser /app
+RUN chmod +x scripts/start.sh scripts/prestart.sh
+
+# 将 Python 包路径加入 PATH
+ENV PATH=/home/appuser/.local/bin:$PATH
+
+# 切换到非 root 用户
+USER appuser
+
+# 配置健康检查
+HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
+ CMD curl -f http://localhost:8000/health || exit 1
+
+# 暴露端口
+EXPOSE 8000
+
+# 执行启动脚本
+CMD ["./scripts/start.sh"]
+```
+
+### Docker Compose 开发环境(`docker-compose.yml`)
+
+```yaml
+version: '3.8'
+
+services:
+ app:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ container_name: dockerized-todo-api
+ restart: unless-stopped
+ ports:
+ - "8000:8000"
+ environment:
+ - ENVIRONMENT=development
+ - DEBUG=true
+ - RELOAD=true
+ volumes:
+ # 挂载开发用卷(代码变化时自动重载)
+ - ./src:/app/src:ro
+ - ./scripts:/app/scripts:ro
+ networks:
+ - app-network
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 40s
+
+ # Redis (for caching and session store)
+ redis:
+ image: redis:7-alpine
+ container_name: dockerized-todo-redis
+ restart: unless-stopped
+ ports:
+ - "6379:6379"
+ volumes:
+ - redis_data:/data
+ networks:
+ - app-network
+ healthcheck:
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+
+ # Nginx (reverse proxy)
+ nginx:
+ image: nginx:alpine
+ container_name: dockerized-todo-nginx
+ restart: unless-stopped
+ ports:
+ - "80:80"
+ - "443:443"
+ volumes:
+ - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
+ - ./nginx/ssl:/etc/nginx/ssl:ro
+ depends_on:
+ - app
+ networks:
+ - app-network
+ healthcheck:
+ test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+
+volumes:
+ redis_data:
+
+networks:
+ app-network:
+ driver: bridge
+```
+
+### Docker Compose 生产环境(`docker-compose.prod.yml`)
+
+```yaml
+version: '3.8'
+
+services:
+ app:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ restart: always
+ environment:
+ - ENVIRONMENT=production
+ - DEBUG=false
+ - WORKERS=4
+ - MAX_WORKERS=8
+ volumes:
+ - app_logs:/app/logs
+ networks:
+ - app-network
+ deploy:
+ replicas: 2
+ resources:
+ limits:
+ cpus: '1.0'
+ memory: 1G
+ reservations:
+ cpus: '0.5'
+ memory: 512M
+ restart_policy:
+ condition: on-failure
+ delay: 5s
+ max_attempts: 3
+
+ redis:
+ image: redis:7-alpine
+ restart: always
+ command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
+ volumes:
+ - redis_data:/data
+ networks:
+ - app-network
+ deploy:
+ resources:
+ limits:
+ cpus: '0.5'
+ memory: 512M
+
+ nginx:
+ image: nginx:alpine
+ restart: always
+ ports:
+ - "80:80"
+ - "443:443"
+ volumes:
+ - ./nginx/nginx.prod.conf:/etc/nginx/nginx.conf:ro
+ - ./nginx/ssl:/etc/nginx/ssl:ro
+ - nginx_logs:/var/log/nginx
+ depends_on:
+ - app
+ networks:
+ - app-network
+ deploy:
+ resources:
+ limits:
+ cpus: '0.5'
+ memory: 256M
+
+volumes:
+ redis_data:
+ app_logs:
+ nginx_logs:
+
+networks:
+ app-network:
+ driver: overlay
+ attachable: true
+```
+
+## 第 3 步:配置启动脚本
+
+### 主启动脚本(`scripts/start.sh`)
+
+```bash
+#!/bin/bash
+
+set -e
+
+# 设置环境变量
+export PYTHONPATH=/app:$PYTHONPATH
+
+# 运行预启动脚本
+echo "Running pre-start script..."
+./scripts/prestart.sh
+
+# 根据环境决定运行模式
+if [[ "$ENVIRONMENT" == "production" ]]; then
+ echo "Starting production server with Gunicorn..."
+ exec gunicorn src.main:app \
+ --config scripts/gunicorn.conf.py \
+ --bind 0.0.0.0:8000 \
+ --workers ${WORKERS:-4} \
+ --worker-class uvicorn.workers.UvicornWorker \
+ --max-requests 1000 \
+ --max-requests-jitter 100 \
+ --preload \
+ --access-logfile - \
+ --error-logfile -
+else
+ echo "Starting development server with Uvicorn..."
+ if [[ "$RELOAD" == "true" ]]; then
+ exec uvicorn src.main:app \
+ --host 0.0.0.0 \
+ --port 8000 \
+ --reload \
+ --reload-dir src \
+ --log-level debug
+ else
+ exec uvicorn src.main:app \
+ --host 0.0.0.0 \
+ --port 8000 \
+ --log-level info
+ fi
+fi
+```
+
+### 预启动脚本(`scripts/prestart.sh`)
+
+```bash
+#!/bin/bash
+
+set -e
+
+echo "Running pre-start checks..."
+
+# 检查 Python 模块和依赖
+echo "Checking Python dependencies..."
+python -c "import fastapi, uvicorn, pydantic; print('✓ Core dependencies OK')"
+
+# 检查环境变量
+if [[ -z "$ENVIRONMENT" ]]; then
+ export ENVIRONMENT="development"
+ echo "ℹ ENVIRONMENT not set, defaulting to development"
+fi
+
+# 创建日志目录
+mkdir -p /app/logs
+touch /app/logs/app.log
+
+# 检查是否存在 health 端点
+echo "Checking health endpoint..."
+python -c "
+from src.main import app
+routes = [route.path for route in app.routes]
+if '/health' not in routes:
+ print('⚠ Warning: /health endpoint not found')
+else:
+ print('✓ Health endpoint OK')
+"
+
+echo "Pre-start checks completed successfully!"
+```
+
+### Gunicorn 配置(`scripts/gunicorn.conf.py`)
+
+```python
+import multiprocessing
+import os
+
+# 服务端监听配置
+bind = "0.0.0.0:8000"
+backlog = 2048
+
+# Worker 进程配置
+workers = int(os.getenv("WORKERS", multiprocessing.cpu_count() * 2 + 1))
+worker_class = "uvicorn.workers.UvicornWorker"
+worker_connections = 1000
+max_requests = 1000
+max_requests_jitter = 100
+
+# Worker 重启设置
+preload_app = True
+timeout = 120
+keepalive = 2
+
+# 日志配置
+accesslog = "-"
+errorlog = "-"
+loglevel = "info"
+access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
+
+# 进程名称
+proc_name = "dockerized-todo-api"
+
+# 安全限制
+limit_request_line = 4094
+limit_request_fields = 100
+limit_request_field_size = 8190
+
+# 性能调优
+def when_ready(server):
+ server.log.info("Server is ready. Spawning workers")
+
+def worker_int(worker):
+ worker.log.info("worker received INT or QUIT signal")
+
+def pre_fork(server, worker):
+ server.log.info("Worker spawned (pid: %s)", worker.pid)
+
+def post_fork(server, worker):
+ server.log.info("Worker spawned (pid: %s)", worker.pid)
+
+def worker_abort(worker):
+ worker.log.info("worker received SIGABRT signal")
+```
+
+## 第 4 步:实现健康检查与监控
+
+### 添加健康检查端点(`src/main.py`)
+
+```python
+from fastapi import FastAPI, status, Depends
+from fastapi.responses import JSONResponse
+import psutil
+import time
+from datetime import datetime
+
+app = FastAPI(
+ title="Dockerized Todo API",
+ description="Dockerized todo management API",
+ version="1.0.0"
+)
+
+# 应用启动时间
+start_time = time.time()
+
+@app.get("/health", status_code=status.HTTP_200_OK)
+async def health_check():
+ """
+ 容器健康检查端点
+ """
+ current_time = time.time()
+ uptime = current_time - start_time
+
+ # 系统资源信息
+ memory_info = psutil.virtual_memory()
+ cpu_percent = psutil.cpu_percent(interval=1)
+
+ health_data = {
+ "status": "healthy",
+ "timestamp": datetime.utcnow().isoformat(),
+ "uptime_seconds": round(uptime, 2),
+ "version": app.version,
+ "system": {
+ "memory_usage_percent": memory_info.percent,
+ "memory_available_mb": round(memory_info.available / 1024 / 1024, 2),
+ "cpu_usage_percent": cpu_percent,
+ },
+ "checks": {
+ "database": await check_database_connection(),
+ "redis": await check_redis_connection(),
+ "disk_space": check_disk_space(),
+ }
+ }
+
+ # 检查所有健康项是否通过
+ all_checks_passed = all(health_data["checks"].values())
+
+ if not all_checks_passed:
+ return JSONResponse(
+ status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
+ content=health_data
+ )
+
+ return health_data
+
+async def check_database_connection() -> bool:
+ """检查数据库连接状态"""
+ try:
+ # 在实际实现中,这里应执行数据库连通性检测
+ return True
+ except Exception:
+ return False
+
+async def check_redis_connection() -> bool:
+ """检查 Redis 连接状态"""
+ try:
+ # 在实际实现中,这里应执行 Redis 连通性检测
+ return True
+ except Exception:
+ return False
+
+def check_disk_space() -> bool:
+ """检查磁盘空间"""
+ disk_usage = psutil.disk_usage('/')
+ free_percentage = (disk_usage.free / disk_usage.total) * 100
+ return free_percentage > 10 # 至少保留 10% 可用空间
+
+@app.get("/health/ready", status_code=status.HTTP_200_OK)
+async def readiness_check():
+ """
+ Kubernetes 就绪探针端点
+ """
+ # 检查应用是否已准备好接收流量
+ return {"status": "ready", "timestamp": datetime.utcnow().isoformat()}
+
+@app.get("/health/live", status_code=status.HTTP_200_OK)
+async def liveness_check():
+ """
+ Kubernetes 存活探针端点
+ """
+ return {"status": "alive", "timestamp": datetime.utcnow().isoformat()}
+```
+
+## 第 5 步:配置 Nginx 反向代理
+
+### 开发环境 Nginx 配置(`nginx/nginx.conf`)
+
+```nginx
+events {
+ worker_connections 1024;
+}
+
+http {
+ upstream fastapi_backend {
+ # 通过容器名指定后端服务
+ server app:8000;
+ }
+
+ # 定义日志格式
+ log_format main '$remote_addr - $remote_user [$time_local] "$request" '
+ '$status $body_bytes_sent "$http_referer" '
+ '"$http_user_agent" "$http_x_forwarded_for" '
+ 'rt=$request_time uct="$upstream_connect_time" '
+ 'uht="$upstream_header_time" urt="$upstream_response_time"';
+
+ access_log /var/log/nginx/access.log main;
+ error_log /var/log/nginx/error.log warn;
+
+ # 默认设置
+ sendfile on;
+ tcp_nopush on;
+ tcp_nodelay on;
+ keepalive_timeout 65;
+ types_hash_max_size 2048;
+ client_max_body_size 100M;
+
+ # Gzip 压缩
+ gzip on;
+ gzip_vary on;
+ gzip_min_length 1024;
+ gzip_types text/plain text/css text/xml text/javascript
+ application/json application/javascript application/xml+rss
+ application/atom+xml image/svg+xml;
+
+ server {
+ listen 80;
+ server_name localhost;
+
+ # 安全响应头
+ add_header X-Content-Type-Options nosniff;
+ add_header X-Frame-Options DENY;
+ add_header X-XSS-Protection "1; mode=block";
+
+ # 健康检查端点
+ location /health {
+ proxy_pass http://fastapi_backend;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+
+ # 健康检查应快速返回
+ proxy_connect_timeout 5s;
+ proxy_send_timeout 5s;
+ proxy_read_timeout 5s;
+ }
+
+ # API 入口
+ location / {
+ proxy_pass http://fastapi_backend;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+
+ # 超时设置
+ proxy_connect_timeout 30s;
+ proxy_send_timeout 30s;
+ proxy_read_timeout 30s;
+
+ # 缓冲设置
+ proxy_buffering on;
+ proxy_buffer_size 4k;
+ proxy_buffers 8 4k;
+ }
+
+ # 静态文件缓存(后续可扩展)
+ location /static {
+ expires 1y;
+ add_header Cache-Control public;
+ add_header ETag "";
+ }
+ }
+}
+```
+
+### 生产环境 Nginx 配置(`nginx/nginx.prod.conf`)
+
+```nginx
+events {
+ worker_connections 2048;
+}
+
+http {
+ upstream fastapi_backend {
+ # Load balancing for multiple app instances
+ server app:8000 max_fails=3 fail_timeout=30s;
+ # server app2:8000 max_fails=3 fail_timeout=30s; # For scaling
+
+ # Keep-alive
+ keepalive 32;
+ }
+
+ # Security settings
+ server_tokens off;
+
+ # Rate limiting
+ limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
+ limit_req_zone $binary_remote_addr zone=health:10m rate=100r/s;
+
+ # SSL settings
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
+ ssl_prefer_server_ciphers off;
+ ssl_session_cache shared:SSL:10m;
+ ssl_session_timeout 10m;
+
+ server {
+ listen 80;
+ server_name your-domain.com;
+ return 301 https://$server_name$request_uri;
+ }
+
+ server {
+ listen 443 ssl http2;
+ server_name your-domain.com;
+
+ ssl_certificate /etc/nginx/ssl/cert.pem;
+ ssl_certificate_key /etc/nginx/ssl/key.pem;
+
+ # Security headers
+ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
+ add_header X-Content-Type-Options nosniff always;
+ add_header X-Frame-Options DENY always;
+ add_header X-XSS-Protection "1; mode=block" always;
+ add_header Referrer-Policy "strict-origin-when-cross-origin" always;
+
+ # Health check (rate limit applied)
+ location /health {
+ limit_req zone=health burst=20 nodelay;
+ proxy_pass http://fastapi_backend;
+ include /etc/nginx/proxy_params;
+ }
+
+ # API endpoint (rate limit applied)
+ location / {
+ limit_req zone=api burst=20 nodelay;
+ proxy_pass http://fastapi_backend;
+ include /etc/nginx/proxy_params;
+ }
+ }
+}
+```
+
+## 第 6 步:构建并运行容器
+
+### 在开发环境运行
+
+
+
+```console
+$ cd dockerized-todo-api
+
+# Build Docker image
+$ docker-compose build
+Building app
+Step 1/15 : FROM python:3.12-slim as builder
+ ---> abc123def456
+Step 2/15 : RUN apt-get update && apt-get install -y build-essential curl
+ ---> Running in xyz789abc123
+...
+Successfully built def456ghi789
+Successfully tagged dockerized-todo-api_app:latest
+
+# Run container (background)
+$ docker-compose up -d
+Creating network "dockerized-todo-api_app-network" with driver "bridge"
+Creating volume "dockerized-todo-api_redis_data" with default driver
+Creating dockerized-todo-redis ... done
+Creating dockerized-todo-api ... done
+Creating dockerized-todo-nginx ... done
+
+# Check container status
+$ docker-compose ps
+ Name Command State Ports
+------------------------------------------------------------------------------------------------
+dockerized-todo-api ./scripts/start.sh Up (healthy) 8000/tcp
+dockerized-todo-nginx /docker-entrypoint.sh ngin ... Up 0.0.0.0:80->80/tcp, :::80->80/tcp
+dockerized-todo-redis docker-entrypoint.sh redis ... Up (healthy) 0.0.0.0:6379->6379/tcp, :::6379->6379/tcp
+```
+
+
+
+### 查看日志
+
+
+
+```console
+# Check all service logs
+$ docker-compose logs
+
+# Check specific service logs
+$ docker-compose logs app
+$ docker-compose logs nginx
+$ docker-compose logs redis
+
+# Check real-time logs
+$ docker-compose logs -f app
+```
+
+
+
+### 健康检查测试
+
+
+
+```console
+# Basic health check
+$ curl http://localhost/health
+{
+ "status": "healthy",
+ "timestamp": "2024-01-01T12:00:00.123456",
+ "uptime_seconds": 45.67,
+ "version": "1.0.0",
+ "system": {
+ "memory_usage_percent": 25.3,
+ "memory_available_mb": 3072.45,
+ "cpu_usage_percent": 5.2
+ },
+ "checks": {
+ "database": true,
+ "redis": true,
+ "disk_space": true
+ }
+}
+
+# Kubernetes probe test
+$ curl http://localhost/health/ready
+$ curl http://localhost/health/live
+```
+
+
+
+## 第 7 步:生产部署
+
+### 设置环境变量(`.env.prod`)
+
+```bash
+# Application settings
+ENVIRONMENT=production
+DEBUG=false
+SECRET_KEY=your-super-secret-key-here
+WORKERS=4
+
+# Database settings
+DATABASE_URL=postgresql://user:password@db:5432/todoapp
+REDIS_URL=redis://:password@redis:6379/0
+REDIS_PASSWORD=your-redis-password
+
+# Logging settings
+LOG_LEVEL=info
+LOG_FILE=/app/logs/app.log
+
+# Security settings
+ALLOWED_HOSTS=["your-domain.com"]
+CORS_ORIGINS=["https://your-frontend.com"]
+
+# Monitoring
+SENTRY_DSN=https://your-sentry-dsn@sentry.io/project-id
+```
+
+### 生产部署命令
+
+
+
+```console
+# Deploy in production environment
+$ docker-compose -f docker-compose.prod.yml --env-file .env.prod up -d
+
+# Scaling (app instance scaling)
+$ docker-compose -f docker-compose.prod.yml up -d --scale app=3
+
+# Rolling update
+$ docker-compose -f docker-compose.prod.yml build app
+$ docker-compose -f docker-compose.prod.yml up -d --no-deps app
+
+# Safe shutdown before backup
+$ docker-compose -f docker-compose.prod.yml down --timeout 30
+```
+
+
+
+## 第 8 步:监控与日志
+
+### Docker 容器资源监控
+
+
+
+```console
+# Check real-time resource usage
+$ docker stats
+
+CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
+abc123def456 dockerized-todo-api 2.34% 128.5MiB / 1GiB 12.55% 1.23MB / 456kB 12.3MB / 4.56MB 15
+def456ghi789 dockerized-todo-nginx 0.12% 12.5MiB / 256MiB 4.88% 456kB / 1.23MB 1.23MB / 456kB 3
+ghi789jkl012 dockerized-todo-redis 1.45% 32.1MiB / 512MiB 6.27% 789kB / 2.34MB 4.56MB / 1.23MB 4
+
+# Check specific container details
+$ docker inspect dockerized-todo-api
+
+# Check container internal processes
+$ docker-compose exec app ps aux
+```
+
+
+
+### 日志聚合与分析
+
+```yaml
+# docker-compose.logging.yml
+version: '3.8'
+
+services:
+ # ELK Stack for log aggregation
+ elasticsearch:
+ image: docker.elastic.co/elasticsearch/elasticsearch:8.6.0
+ environment:
+ - discovery.type=single-node
+ - xpack.security.enabled=false
+ volumes:
+ - elasticsearch_data:/usr/share/elasticsearch/data
+ networks:
+ - logging
+
+ logstash:
+ image: docker.elastic.co/logstash/logstash:8.6.0
+ volumes:
+ - ./logstash/pipeline:/usr/share/logstash/pipeline:ro
+ - ./logstash/config:/usr/share/logstash/config:ro
+ networks:
+ - logging
+ depends_on:
+ - elasticsearch
+
+ kibana:
+ image: docker.elastic.co/kibana/kibana:8.6.0
+ ports:
+ - "5601:5601"
+ environment:
+ - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
+ networks:
+ - logging
+ depends_on:
+ - elasticsearch
+
+ # Fluentd for log collection
+ fluentd:
+ image: fluent/fluentd:v1.16-debian-1
+ volumes:
+ - ./fluentd/conf:/fluentd/etc:ro
+ - /var/log:/var/log:ro
+ networks:
+ - logging
+ depends_on:
+ - elasticsearch
+
+volumes:
+ elasticsearch_data:
+
+networks:
+ logging:
+ driver: bridge
+```
+
+### Prometheus 指标收集
+
+```python
+# src/monitoring.py
+from prometheus_client import Counter, Histogram, Gauge, generate_latest
+from fastapi import Request, Response
+import time
+
+# Define metrics
+REQUEST_COUNT = Counter(
+ 'http_requests_total',
+ 'Total HTTP requests',
+ ['method', 'endpoint', 'status_code']
+)
+
+REQUEST_DURATION = Histogram(
+ 'http_request_duration_seconds',
+ 'HTTP request duration in seconds',
+ ['method', 'endpoint']
+)
+
+ACTIVE_CONNECTIONS = Gauge(
+ 'active_connections',
+ 'Number of active connections'
+)
+
+async def metrics_middleware(request: Request, call_next):
+ """Prometheus metric collection middleware"""
+ start_time = time.time()
+ method = request.method
+ endpoint = request.url.path
+
+ ACTIVE_CONNECTIONS.inc()
+
+ try:
+ response = await call_next(request)
+ status_code = response.status_code
+ except Exception as e:
+ status_code = 500
+ raise
+ finally:
+ duration = time.time() - start_time
+ REQUEST_DURATION.labels(method=method, endpoint=endpoint).observe(duration)
+ REQUEST_COUNT.labels(method=method, endpoint=endpoint, status_code=status_code).inc()
+ ACTIVE_CONNECTIONS.dec()
+
+ return response
+
+@app.get("/metrics")
+async def get_metrics():
+ """Prometheus metric endpoint"""
+ return Response(generate_latest(), media_type="text/plain")
+```
+
+## 第 9 步:构建 CI/CD 流水线
+
+### GitHub Actions 工作流(`.github/workflows/deploy.yml`)
+
+```yaml
+name: Deploy to Production
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+ branches: [main]
+
+env:
+ REGISTRY: ghcr.io
+ IMAGE_NAME: ${{ github.repository }}
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.12'
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install -r requirements.txt
+ pip install pytest pytest-asyncio httpx
+
+ - name: Run tests
+ run: |
+ pytest tests/ -v --cov=src --cov-report=xml
+
+ - name: Upload coverage reports
+ uses: codecov/codecov-action@v3
+ with:
+ file: ./coverage.xml
+
+ build:
+ needs: test
+ runs-on: ubuntu-latest
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Log in to Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ${{ env.REGISTRY }}
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Extract metadata
+ id: meta
+ uses: docker/metadata-action@v5
+ with:
+ images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
+ tags: |
+ type=ref,event=branch
+ type=ref,event=pr
+ type=sha
+ type=raw,value=latest
+
+ - name: Build and push Docker image
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ file: ./Dockerfile
+ push: true
+ tags: ${{ steps.meta.outputs.tags }}
+ labels: ${{ steps.meta.outputs.labels }}
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
+
+ deploy:
+ needs: build
+ runs-on: ubuntu-latest
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Deploy to production
+ uses: appleboy/ssh-action@v1.0.0
+ with:
+ host: ${{ secrets.PROD_HOST }}
+ username: ${{ secrets.PROD_USERNAME }}
+ key: ${{ secrets.PROD_SSH_KEY }}
+ script: |
+ cd /opt/dockerized-todo-api
+
+ # Pull new image
+ docker-compose -f docker-compose.prod.yml pull
+
+ # Rolling update
+ docker-compose -f docker-compose.prod.yml up -d --no-deps app
+
+ # Health check
+ sleep 30
+ curl -f http://localhost/health || exit 1
+
+ # Clean up previous image
+ docker image prune -f
+```
+
+## 第 10 步:加强安全
+
+### 容器安全设置
+
+```dockerfile
+# Add security enhancement to Dockerfile
+
+# Run as non-root user
+USER appuser
+
+# Read-only root filesystem
+# docker run --read-only --tmpfs /tmp dockerized-todo-api
+
+# Limit permissions
+# docker run --cap-drop=ALL dockerized-todo-api
+
+# Network isolation
+# docker run --network=none dockerized-todo-api
+```
+
+### Docker Compose 安全设置
+
+```yaml
+# Add security settings to docker-compose.yml
+services:
+ app:
+ # ... existing settings ...
+ security_opt:
+ - no-new-privileges:true
+ cap_drop:
+ - ALL
+ cap_add:
+ - NET_BIND_SERVICE
+ read_only: true
+ tmpfs:
+ - /tmp
+ - /app/logs
+ user: "1000:1000"
+```
+
+### 机密管理
+
+```yaml
+# Add secrets settings to docker-compose.yml
+version: '3.8'
+
+services:
+ app:
+ secrets:
+ - db_password
+ - api_key
+ environment:
+ - DB_PASSWORD_FILE=/run/secrets/db_password
+ - API_KEY_FILE=/run/secrets/api_key
+
+secrets:
+ db_password:
+ file: ./secrets/db_password.txt
+ api_key:
+ external: true
+```
+
+## 下一步
+
+恭喜您完成了 Docker 容器化!接下来可以尝试:
+
+1. **[自定义响应处理](custom-response-handling.md)** —— 实现进阶的 API 响应格式
+
+
+
+
+## 小结
+
+在本教程中,我们用 Docker 完成了:
+
+- ✅ 通过多阶段构建生成优化的容器镜像
+- ✅ 用 Docker Compose 搭建开发 / 生产环境
+- ✅ 配置 Nginx 反向代理与负载均衡
+- ✅ 构建健康检查与监控体系
+- ✅ 通过 CI/CD 流水线实现自动化部署
+- ✅ 配置生产级别的安全设置
+- ✅ 实现日志与指标收集系统
+
+现在您可以安全、高效地把 FastAPI 应用部署到生产环境!
diff --git a/docs/zh/tutorial/domain-starter.md b/docs/zh/tutorial/domain-starter.md
new file mode 100644
index 0000000..8610fb6
--- /dev/null
+++ b/docs/zh/tutorial/domain-starter.md
@@ -0,0 +1,392 @@
+# 使用 `fastapi-domain-starter` 构建面向领域的 FastAPI
+
+按推荐的现代布局构建一个中型 FastAPI 服务 —— **每个业务概念在 `src/app/domains/` 下对应一个文件夹**。本教程会端到端走完 `fastapi-domain-starter` 模板:如何生成、每个顶层包的职责、自带的 `items` 示例如何接入,以及如何添加下一个领域。
+
+## 您将学到的内容
+
+- 使用 `fastkit startdemo fastapi-domain-starter` 生成项目
+- 布局中 `core`、`db`、`domains`、`tests` 各自的角色
+- 一个领域如何拆分为 router → service → repository → schemas → models
+- 添加新领域的契约(复制 items 文件夹,注册路由)
+- 自带的 `/health` 端点与 `/api/v1/items` CRUD 如何接入应用
+
+## 前置条件
+
+- Python 3.12+
+- 已安装 FastAPI-fastkit(`pip install fastapi-fastkit`)
+- 熟悉 FastAPI 的基础概念(路径操作、pydantic 模式、依赖)
+
+如果这是您的第一个 FastAPI 项目,请先从 [构建基础 API 服务器](basic-api-server.md) 开始 —— 那篇教程使用更简单的 `fastapi-default` 模板。
+
+## 第 1 步:生成项目
+
+```console
+$ fastkit startdemo fastapi-domain-starter
+Enter the project name: orders-api
+Enter the author name: Developer Kim
+Enter the author email: developer@example.com
+Enter the project description: Domain-oriented orders service
+Select package manager (pip, uv, pdm, poetry) [uv]: uv
+Do you want to proceed with project creation? [y/N]: y
+```
+
+`fastkit` 会部署模板、填入占位符、创建虚拟环境并安装依赖。完成后即可进入项目:
+
+```console
+$ cd orders-api
+$ bash scripts/run-server.sh # or: uvicorn src.app.main:app --reload
+```
+
+随后可在 查看 API 文档。
+
+## 第 2 步:生成的目录树
+
+```
+orders-api/
+├── README.md
+├── pyproject.toml # PEP 621 metadata + [tool.fastapi-fastkit]
+├── requirements.txt # pinned deps (template ships both files; you maintain them as you add packages)
+├── .env # SECRET_KEY, ENVIRONMENT
+├── .gitignore
+├── scripts/
+│ ├── format.sh # black + isort
+│ ├── lint.sh # black --check + isort --check + mypy
+│ ├── run-server.sh # uvicorn src.app.main:app --reload
+│ └── test.sh # pytest
+├── src/
+│ ├── __init__.py
+│ └── app/ # the application package
+│ ├── __init__.py
+│ ├── main.py # FastAPI() + middleware + api_router include
+│ ├── core/ # cross-cutting configuration
+│ │ ├── __init__.py
+│ │ └── config.py # pydantic-settings (PROJECT_NAME, CORS, ...)
+│ ├── db/ # persistence abstractions
+│ │ ├── __init__.py
+│ │ └── memory.py # InMemoryStore[T] generic key-value store
+│ ├── api/ # transport-level routing
+│ │ ├── __init__.py
+│ │ ├── health.py # GET /health
+│ │ └── router.py # aggregates health + every domain router
+│ └── domains/ # business concepts (one folder each)
+│ ├── __init__.py
+│ └── items/ # the example domain
+│ ├── __init__.py
+│ ├── models.py # @dataclass Item (entity)
+│ ├── schemas.py # ItemCreate, ItemRead (pydantic)
+│ ├── repository.py # ItemRepository over InMemoryStore
+│ ├── service.py # ItemService + ItemNotFoundError
+│ └── router.py # APIRouter(prefix="/items")
+└── tests/
+ ├── __init__.py
+ ├── conftest.py # TestClient fixture, store reset
+ ├── test_health.py
+ └── test_items.py
+```
+
+需要内化的两个概念:
+
+1. **`src/app/`** 是 **应用包** —— 运行时导入的所有内容都在这里。测试也从这里导入(`from src.app.main import app`)。外层 `src/` 是为了让项目能 `pip install`。
+2. **`src/app/domains//`** 是 **每个概念的切片** —— 每个业务概念(items、orders、users……)拥有各自的 router / service / repository / schemas / models,且仅有这些。
+
+## 第 3 步:每个顶层包的职责
+
+### `src/app/core/` —— 配置
+
+存放跨切面的应用配置。自带的 `config.py` 暴露一个 pydantic-settings 的 `Settings` 类,从 `.env` / 环境变量读取:
+
+```python
+class Settings(BaseSettings):
+ PROJECT_NAME: str = ""
+ ENVIRONMENT: Literal["development", "staging", "production"] = "development"
+ SECRET_KEY: str = secrets.token_urlsafe(32)
+ API_V1_PREFIX: str = "/api/v1"
+ BACKEND_CORS_ORIGINS: ... = []
+ ...
+
+settings = Settings()
+```
+
+`main.py` 读取 `settings.PROJECT_NAME`、`settings.API_V1_PREFIX` 与 `settings.all_cors_origins` 来接入 FastAPI 应用。
+
+**什么时候应往 `core/` 添加内容:** 任何与单个领域无关的内容 —— 全局设置、结构化日志、自定义中间件、安全工具等。
+
+### `src/app/db/` —— 持久化边界
+
+存放对数据存储的抽象。starter 自带 `memory.py` —— 一个进程内的 `InMemoryStore[T]`,对实体类型进行了泛化。每个领域的 repository 都封装一个 `InMemoryStore`,后续切换到 SQLAlchemy / 异步驱动也只是一次受控的变更:只需要重写 repository。
+
+```python
+class InMemoryStore(Generic[T]):
+ def list(self) -> Iterable[T]: ...
+ def get(self, id_: int) -> Optional[T]: ...
+ def add(self, item: T) -> int: ...
+ def replace(self, id_: int, item: T) -> bool: ...
+ def delete(self, id_: int) -> bool: ...
+ def clear(self) -> None: ...
+```
+
+**什么时候应扩展 `db/`:** 当您从 `InMemoryStore` 迁移走时,加上一个 `session.py`,放真实数据库的 session 工厂。保留同样的公共方法形状(`list` / `get` / `add` / ……),这样领域的 repository 不必修改其内部契约。
+
+### `src/app/api/` —— 传输层路由
+
+由两部分组成:
+
+- `health.py` —— 一个小的 `APIRouter`,暴露 `GET /health` 并返回 `{"status": "ok"}`。无副作用,适合做存活探针。
+- `router.py` —— **顶层聚合器**。它纳入健康检查路由器以及每个领域的路由器,再把这个合并后的 `api_router` 挂载在 FastAPI 应用的 `/api/v1` 下:
+
+```python
+# src/app/api/router.py
+api_router = APIRouter()
+api_router.include_router(health.router)
+api_router.include_router(items_router.router)
+```
+
+```python
+# src/app/main.py
+app.include_router(api_router, prefix=settings.API_V1_PREFIX)
+```
+
+**为何要在这里聚合:** 添加新领域时,只需要编辑 `src/app/api/router.py` 来注册它的路由器,`main.py` 从不需要改动。
+
+### `src/app/domains//` —— 业务切片
+
+随着项目成长,大多数代码会落在这里。每个领域拥有五个文件:
+
+| 文件 | 角色 |
+|---|---|
+| `models.py` | 领域实体(starter 中是 `@dataclass`;以后可以换成 SQLAlchemy / SQLModel)。表示内部形状 —— 并非线上格式。 |
+| `schemas.py` | API 输入输出模式(pydantic)。与实体分离,这样线上格式可以独立演进而不影响领域逻辑。 |
+| `repository.py` | 数据访问层。用领域实体类型的方法封装存储,是切换持久化方案的接缝。 |
+| `service.py` | 业务逻辑。Router 调用 `service`,绝不直接调用 `repository`。领域专属异常(如 `ItemNotFoundError`)放在这里。 |
+| `router.py` | HTTP 传输。负责在 pydantic 模式 ↔ service 调用之间翻译,把领域异常转换为 `HTTPException`。 |
+
+**依赖方向**是 `router → service → repository → store`。每层只依赖其下一层。Schema 由 router 与 service 引用;model 由 repository 与 service 引用。
+
+### `tests/`
+
+镜像运行时布局 —— 对每个值得固定行为的对外面都对应一个测试模块。starter 自带:
+
+- `conftest.py` —— autouse fixture,在测试之间重置 items 存储;另外一个 `client` fixture 封装了 `TestClient(app)`。
+- `test_health.py` —— 验证 `GET /api/v1/health` 返回 200 + `{"status": "ok"}`。
+- `test_items.py` —— 对 items 端点做完整 CRUD 覆盖,包括对未知 id 返回 404、对无效负载返回 422。
+
+运行测试:
+
+```console
+$ bash scripts/test.sh # or: pytest
+```
+
+## 第 4 步:走读自带的 `items` 领域
+
+这个示例领域是一个针对极小实体的 CRUD:
+
+```python
+# src/app/domains/items/models.py
+@dataclass
+class Item:
+ id: int
+ name: str
+ price: float
+ in_stock: bool = True
+```
+
+API 模式把输入形状与输出形状分开,这样可以加入服务端控制的字段(`id`)与校验(price ≥ 0):
+
+```python
+# src/app/domains/items/schemas.py
+class ItemCreate(BaseModel):
+ name: str = Field(min_length=1, max_length=120)
+ price: float = Field(ge=0)
+ in_stock: bool = True
+
+class ItemRead(BaseModel):
+ id: int
+ name: str
+ price: float
+ in_stock: bool
+ model_config = ConfigDict(from_attributes=True)
+```
+
+Repository 封装内存存储,并在插入时分配 id:
+
+```python
+# src/app/domains/items/repository.py
+class ItemRepository:
+ def __init__(self, store: Optional[InMemoryStore[Item]] = None) -> None:
+ self._store = store if store is not None else _store
+
+ def add(self, name: str, price: float, in_stock: bool = True) -> Item:
+ item = Item(id=0, name=name, price=price, in_stock=in_stock)
+ new_id = self._store.add(item)
+ item.id = new_id
+ return item
+ # list_all / get / replace / delete / reset elided
+```
+
+Service 层用于沉淀业务规则。现在它只是带一个自定义异常的薄包装,但未来的业务策略会落在这里(比如「不能删除已存在于未关闭订单中的商品」):
+
+```python
+# src/app/domains/items/service.py
+class ItemNotFoundError(Exception): ...
+
+class ItemService:
+ def __init__(self, repository: Optional[ItemRepository] = None) -> None:
+ self._repository = repository if repository is not None else ItemRepository()
+
+ def get_item(self, item_id: int) -> Item:
+ item = self._repository.get(item_id)
+ if item is None:
+ raise ItemNotFoundError(f"Item {item_id} does not exist")
+ return item
+ # list_items / create_item / replace_item / delete_item elided
+```
+
+Router 是唯一了解 HTTP 的那一层。注意它通过 FastAPI 的 `Depends(...)` 接收 service,以便测试中覆盖;并把 `ItemNotFoundError` 映射成 `HTTPException(404)`:
+
+```python
+# src/app/domains/items/router.py
+router = APIRouter(prefix="/items", tags=["items"])
+
+def get_item_service() -> ItemService:
+ return ItemService()
+
+@router.get("/{item_id}", response_model=ItemRead)
+def get_item(item_id: int, service: ItemService = Depends(get_item_service)) -> ItemRead:
+ try:
+ return ItemRead.model_validate(service.get_item(item_id))
+ except ItemNotFoundError as exc:
+ raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc))
+```
+
+完整的 router 暴露:
+
+| 方法 | 路径 | 作用 |
+|---|---|---|
+| `GET` | `/api/v1/items` | 列出 item |
+| `GET` | `/api/v1/items/{item_id}` | 读取单个 |
+| `POST` | `/api/v1/items` | 创建(返回 201) |
+| `PUT` | `/api/v1/items/{item_id}` | 替换 |
+| `DELETE` | `/api/v1/items/{item_id}` | 删除(返回 204) |
+| `GET` | `/api/v1/health` | 存活探针 |
+
+试一下:
+
+```console
+$ curl -X POST http://127.0.0.1:8000/api/v1/items \
+ -H 'Content-Type: application/json' \
+ -d '{"name":"Mug","price":9.5,"in_stock":true}'
+{"id":1,"name":"Mug","price":9.5,"in_stock":true}
+
+$ curl http://127.0.0.1:8000/api/v1/items
+[{"id":1,"name":"Mug","price":9.5,"in_stock":true}]
+
+$ curl http://127.0.0.1:8000/api/v1/items/999
+{"detail":"Item 999 does not exist"}
+```
+
+## 第 5 步:添加下一个领域
+
+starter 的设计目标是**让添加领域变成一次复制 + 改名操作**。假设您想在 `items` 之外加一个 `users` 领域:
+
+### 1. 复制 `items/` 文件夹
+
+```console
+$ cp -r src/app/domains/items src/app/domains/users
+```
+
+### 2. 重写实体、模式以及各文件中的类名
+
+```python
+# src/app/domains/users/models.py
+from dataclasses import dataclass
+
+@dataclass
+class User:
+ id: int
+ email: str
+ is_active: bool = True
+```
+
+```python
+# src/app/domains/users/schemas.py
+from pydantic import BaseModel, ConfigDict, Field
+
+class UserCreate(BaseModel):
+ # Plain ``str`` keeps the snippet drop-in safe. To use pydantic's
+ # built-in email validation instead, install the optional dependency
+ # (``pip install 'pydantic[email]'`` — pulls in ``email-validator``)
+ # and switch ``str`` to ``EmailStr``.
+ email: str = Field(min_length=3, max_length=320)
+ is_active: bool = True
+
+class UserRead(BaseModel):
+ id: int
+ email: str
+ is_active: bool
+ model_config = ConfigDict(from_attributes=True)
+```
+
+在 `models.py`、`schemas.py`、`repository.py`、`service.py` 与 `router.py` 中把 `Item → User`、`ItemNotFoundError → UserNotFoundError`、`ItemRepository → UserRepository`、`ItemService → UserService` 全部改名。别忘了 router 中的 `prefix="/items"` → `prefix="/users"`,以及 `tags=["items"]` → `tags=["users"]`。
+
+Repository 仍可保留同样的 `InMemoryStore` 模式 —— 它本身就是基于实体类型的泛型:
+
+```python
+# src/app/domains/users/repository.py
+_store: InMemoryStore[User] = InMemoryStore()
+
+class UserRepository:
+ def __init__(self, store: Optional[InMemoryStore[User]] = None) -> None:
+ self._store = store if store is not None else _store
+ # ... same shape as ItemRepository ...
+```
+
+### 3. 更新领域的 `__init__.py`
+
+items 领域会重新导出其模块,以便调用方可以写 `from src.app.domains.items import service`。对 users 也照样做:
+
+```python
+# src/app/domains/users/__init__.py
+from src.app.domains.users import ( # noqa: F401
+ models,
+ repository,
+ router,
+ schemas,
+ service,
+)
+```
+
+### 4. 在聚合器中注册路由
+
+这是 **`domains/users/` 之外您唯一需要修改的文件**:
+
+```python
+# src/app/api/router.py
+from src.app.api import health
+from src.app.domains.items import router as items_router
+from src.app.domains.users import router as users_router # ← add
+
+api_router = APIRouter()
+api_router.include_router(health.router)
+api_router.include_router(items_router.router)
+api_router.include_router(users_router.router) # ← add
+```
+
+重启服务器后,您会在 `/docs` 中看到挂载好的 `/api/v1/users`。
+
+### 5. 添加测试
+
+把 `tests/test_items.py` 镜像成 `tests/test_users.py` —— 同样基于 client 的结构,只是请求新端点。`conftest.py` 中 autouse 的存储重置 fixture 已经能保证每个测试的隔离。
+
+如果第二个领域也使用 `InMemoryStore`,可以扩展该 fixture 让它也重置该存储,或者每个领域各保留一个 fixture。
+
+## 第 6 步:接下来去哪里
+
+- [架构预设矩阵](../reference/preset-feature-matrix.md) 展示了 `fastkit init --interactive` 对每种预设会生成什么,包括 `domain-starter` 下哪些功能选择需要手动接入。
+- [`fastapi-default` 教程](basic-api-server.md) 介绍了分层备选方案,如果您想在选定之前比较一下布局,这里很有帮助。
+- 对于数据库集成,[数据库集成教程](database-integration.md) 展示了 PostgreSQL + SQLAlchemy + Alembic 的模式。同样的思路可以套用到 `src/app/db/` 与各领域的 `repository.py`。
+
+## 回顾
+
+- **生成**:`fastkit startdemo fastapi-domain-starter` → `bash scripts/run-server.sh` → 在 `/docs` 查看文档。
+- **布局**:`core/` 放配置,`db/` 放持久化抽象,`domains//` 放业务切片,`api/router.py` 作为唯一聚合点,`tests/` 镜像运行时模块。
+- **添加领域**:复制 `items/`,改实体 / 模式 / 类名,更新 `__init__.py` 的重新导出,在 `src/app/api/router.py` 注册路由,新增测试模块。`main.py` 完全不需要改动。
diff --git a/docs/zh/tutorial/first-project.md b/docs/zh/tutorial/first-project.md
new file mode 100644
index 0000000..e075bb0
--- /dev/null
+++ b/docs/zh/tutorial/first-project.md
@@ -0,0 +1,1252 @@
+# 您的第一个项目
+
+使用 FastAPI-fastkit 构建一个完整的博客 API,包含用户管理、文章创建与评论系统。
+
+## 项目概览
+
+在本教程中,我们将创建一个具备以下特性的 **博客 API**:
+
+- **用户管理**:注册、认证与用户资料
+- **文章管理**:创建、读取、更新与删除博客文章
+- **评论系统**:为博客文章添加评论
+- **数据校验**:稳健的输入校验与错误处理
+- **API 文档**:自动生成的 OpenAPI 文档
+- **测试**:完整的测试套件
+
+### 您将学到的内容
+
+本教程结束时,您将理解:
+
+- 进阶的 FastAPI-fastkit 项目结构
+- 与 SQLAlchemy 的数据库集成
+- 用户认证与授权
+- 复杂的数据关系
+- 错误处理与校验
+- 测试的最佳实践
+
+## 前置条件
+
+开始前请确认:
+
+- 已完成 [入门指南](getting-started.md) 教程
+- 对 REST API 有基础理解
+- 已安装 Python 3.12+
+- 已准备好文本编辑器或 IDE
+
+## 第 1 步:创建项目
+
+让我们用 **STANDARD** 栈来创建一个新项目,以获得数据库支持:
+
+
+
+```console
+$ fastkit init
+Enter the project name: blog-api
+Enter the author name: Your Name
+Enter the author email: your.email@example.com
+Enter the project description: A complete blog API with users, posts, and comments
+
+ Project Information
+┌──────────────┬─────────────────────────────────────────┐
+│ Project Name │ blog-api │
+│ Author │ Your Name │
+│ Author Email │ your.email@example.com │
+│ Description │ A complete blog API with users, posts, │
+│ │ and comments │
+└──────────────┴─────────────────────────────────────────┘
+
+Available Stacks and Dependencies:
+ MINIMAL Stack
+┌──────────────┬───────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ pydantic │
+│ Dependency 4 │ pydantic-settings │
+└──────────────┴───────────────────┘
+
+ STANDARD Stack
+┌──────────────┬───────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ sqlalchemy │
+│ Dependency 4 │ alembic │
+│ Dependency 5 │ pytest │
+│ Dependency 6 │ pydantic │
+│ Dependency 7 │ pydantic-settings │
+└──────────────┴───────────────────┘
+
+Select stack (minimal, standard, full): standard
+
+Available Package Managers:
+ Package Managers
+┌────────┬────────────────────────────────────────────┐
+│ PIP │ Standard Python package manager │
+│ UV │ Fast Python package manager │
+│ PDM │ Modern Python dependency management │
+│ POETRY │ Python dependency management and packaging │
+└────────┴────────────────────────────────────────────┘
+
+Select package manager (pip, uv, pdm, poetry) [uv]: uv
+Do you want to proceed with project creation? [y/N]: y
+
+✨ FastAPI project 'blog-api' has been created successfully!
+```
+
+
+
+## 第 2 步:配置项目
+
+进入项目目录并激活虚拟环境:
+
+
+
+```console
+$ cd blog-api
+$ source .venv/bin/activate
+```
+
+
+
+## 第 3 步:添加所需路由
+
+为博客 API 添加主要资源:
+
+
+
+```console
+$ fastkit addroute users blog-api
+✨ Successfully added new route 'users' to project 'blog-api'
+
+$ fastkit addroute posts blog-api
+✨ Successfully added new route 'posts' to project 'blog-api'
+
+$ fastkit addroute comments blog-api
+✨ Successfully added new route 'comments' to project 'blog-api'
+```
+
+
+
+## 第 4 步:设计数据模型
+
+让我们设计数据模式,先更新用户模式,使其更贴近真实场景。
+
+### 更新用户模式
+
+编辑 `src/schemas/users.py`:
+
+```python
+from typing import Optional, List
+from datetime import datetime
+from pydantic import BaseModel, EmailStr, Field
+
+class UserBase(BaseModel):
+ email: EmailStr
+ username: str = Field(..., min_length=3, max_length=50)
+ full_name: Optional[str] = None
+ bio: Optional[str] = Field(None, max_length=500)
+ is_active: bool = True
+
+class UserCreate(UserBase):
+ password: str = Field(..., min_length=8)
+
+class UserUpdate(BaseModel):
+ email: Optional[EmailStr] = None
+ username: Optional[str] = Field(None, min_length=3, max_length=50)
+ full_name: Optional[str] = None
+ bio: Optional[str] = Field(None, max_length=500)
+ is_active: Optional[bool] = None
+
+class User(UserBase):
+ id: int
+ created_at: datetime
+ posts_count: int = 0
+
+ class Config:
+ from_attributes = True
+
+class UserInDB(User):
+ hashed_password: str
+```
+
+### 创建文章模式
+
+编辑 `src/schemas/posts.py`:
+
+```python
+from typing import Optional, List
+from datetime import datetime
+from pydantic import BaseModel, Field
+
+class PostBase(BaseModel):
+ title: str = Field(..., min_length=1, max_length=200)
+ content: str = Field(..., min_length=1)
+ published: bool = True
+
+class PostCreate(PostBase):
+ pass
+
+class PostUpdate(BaseModel):
+ title: Optional[str] = Field(None, min_length=1, max_length=200)
+ content: Optional[str] = Field(None, min_length=1)
+ published: Optional[bool] = None
+
+class Post(PostBase):
+ id: int
+ author_id: int
+ created_at: datetime
+ updated_at: datetime
+ comments_count: int = 0
+
+ class Config:
+ from_attributes = True
+
+class PostWithAuthor(Post):
+ author: "User"
+
+class PostWithComments(Post):
+ comments: List["Comment"] = []
+
+# Import to avoid circular imports
+from src.schemas.users import User
+from src.schemas.comments import Comment
+PostWithAuthor.model_rebuild()
+PostWithComments.model_rebuild()
+```
+
+### 创建评论模式
+
+编辑 `src/schemas/comments.py`:
+
+```python
+from typing import Optional
+from datetime import datetime
+from pydantic import BaseModel, Field
+
+class CommentBase(BaseModel):
+ content: str = Field(..., min_length=1, max_length=1000)
+
+class CommentCreate(CommentBase):
+ post_id: int
+
+class CommentUpdate(BaseModel):
+ content: Optional[str] = Field(None, min_length=1, max_length=1000)
+
+class Comment(CommentBase):
+ id: int
+ post_id: int
+ author_id: int
+ created_at: datetime
+ updated_at: datetime
+
+ class Config:
+ from_attributes = True
+
+class CommentWithAuthor(Comment):
+ author: "User"
+
+# Import to avoid circular imports
+from src.schemas.users import User
+CommentWithAuthor.model_rebuild()
+```
+
+## 第 5 步:实现进阶的 CRUD 操作
+
+### 增强的用户 CRUD
+
+更新 `src/crud/users.py`:
+
+```python
+from typing import List, Optional
+from datetime import datetime
+import hashlib
+from src.schemas.users import UserCreate, UserUpdate, UserInDB
+
+class UsersCRUD:
+ def __init__(self):
+ self._users: List[UserInDB] = []
+ self._next_id = 1
+
+ def _hash_password(self, password: str) -> str:
+ """Simple password hashing (use bcrypt in production)"""
+ return hashlib.sha256(password.encode()).hexdigest()
+
+ def _verify_password(self, plain_password: str, hashed_password: str) -> bool:
+ """Verify password against hash"""
+ return self._hash_password(plain_password) == hashed_password
+
+ def get_all(self) -> List[UserInDB]:
+ """Get all users"""
+ return [user for user in self._users if user.is_active]
+
+ def get_by_id(self, user_id: int) -> Optional[UserInDB]:
+ """Get user by ID"""
+ return next((user for user in self._users if user.id == user_id), None)
+
+ def get_by_email(self, email: str) -> Optional[UserInDB]:
+ """Get user by email"""
+ return next((user for user in self._users if user.email == email), None)
+
+ def get_by_username(self, username: str) -> Optional[UserInDB]:
+ """Get user by username"""
+ return next((user for user in self._users if user.username == username), None)
+
+ def create(self, user: UserCreate) -> UserInDB:
+ """Create a new user with validation"""
+ # Check for duplicates
+ if self.get_by_email(user.email):
+ raise ValueError("Email already registered")
+ if self.get_by_username(user.username):
+ raise ValueError("Username already taken")
+
+ new_user = UserInDB(
+ id=self._next_id,
+ email=user.email,
+ username=user.username,
+ full_name=user.full_name,
+ bio=user.bio,
+ is_active=user.is_active,
+ created_at=datetime.now(),
+ posts_count=0,
+ hashed_password=self._hash_password(user.password)
+ )
+ self._next_id += 1
+ self._users.append(new_user)
+ return new_user
+
+ def update(self, user_id: int, user_update: UserUpdate) -> Optional[UserInDB]:
+ """Update an existing user"""
+ user = self.get_by_id(user_id)
+ if not user:
+ return None
+
+ # Check for duplicates on email/username changes
+ update_data = user_update.dict(exclude_unset=True)
+ if "email" in update_data and update_data["email"] != user.email:
+ if self.get_by_email(update_data["email"]):
+ raise ValueError("Email already registered")
+
+ if "username" in update_data and update_data["username"] != user.username:
+ if self.get_by_username(update_data["username"]):
+ raise ValueError("Username already taken")
+
+ for field, value in update_data.items():
+ setattr(user, field, value)
+
+ return user
+
+ def delete(self, user_id: int) -> bool:
+ """Soft delete user (deactivate)"""
+ user = self.get_by_id(user_id)
+ if user:
+ user.is_active = False
+ return True
+ return False
+
+ def authenticate(self, email: str, password: str) -> Optional[UserInDB]:
+ """Authenticate user by email and password"""
+ user = self.get_by_email(email)
+ if user and self._verify_password(password, user.hashed_password):
+ return user
+ return None
+
+users_crud = UsersCRUD()
+```
+
+### 文章 CRUD
+
+更新 `src/crud/posts.py`:
+
+```python
+from typing import List, Optional
+from datetime import datetime
+from src.schemas.posts import PostCreate, PostUpdate, Post
+
+class PostsCRUD:
+ def __init__(self):
+ self._posts: List[Post] = []
+ self._next_id = 1
+
+ def get_all(self, skip: int = 0, limit: int = 100, published_only: bool = True) -> List[Post]:
+ """Get all posts with pagination"""
+ posts = self._posts
+ if published_only:
+ posts = [post for post in posts if post.published]
+ return posts[skip:skip + limit]
+
+ def get_by_id(self, post_id: int) -> Optional[Post]:
+ """Get post by ID"""
+ return next((post for post in self._posts if post.id == post_id), None)
+
+ def get_by_author(self, author_id: int, skip: int = 0, limit: int = 100) -> List[Post]:
+ """Get posts by author"""
+ author_posts = [post for post in self._posts if post.author_id == author_id]
+ return author_posts[skip:skip + limit]
+
+ def create(self, post: PostCreate, author_id: int) -> Post:
+ """Create a new post"""
+ now = datetime.now()
+ new_post = Post(
+ id=self._next_id,
+ title=post.title,
+ content=post.content,
+ published=post.published,
+ author_id=author_id,
+ created_at=now,
+ updated_at=now,
+ comments_count=0
+ )
+ self._next_id += 1
+ self._posts.append(new_post)
+
+ # Update author's post count
+ from src.crud.users import users_crud
+ author = users_crud.get_by_id(author_id)
+ if author:
+ author.posts_count += 1
+
+ return new_post
+
+ def update(self, post_id: int, post_update: PostUpdate, author_id: int) -> Optional[Post]:
+ """Update an existing post"""
+ post = self.get_by_id(post_id)
+ if not post or post.author_id != author_id:
+ return None
+
+ update_data = post_update.dict(exclude_unset=True)
+ for field, value in update_data.items():
+ setattr(post, field, value)
+
+ post.updated_at = datetime.now()
+ return post
+
+ def delete(self, post_id: int, author_id: int) -> bool:
+ """Delete a post"""
+ post = self.get_by_id(post_id)
+ if post and post.author_id == author_id:
+ self._posts.remove(post)
+
+ # Update author's post count
+ from src.crud.users import users_crud
+ author = users_crud.get_by_id(author_id)
+ if author:
+ author.posts_count = max(0, author.posts_count - 1)
+
+ return True
+ return False
+
+ def search(self, query: str, skip: int = 0, limit: int = 100) -> List[Post]:
+ """Search posts by title or content"""
+ query_lower = query.lower()
+ matching_posts = [
+ post for post in self._posts
+ if post.published and (
+ query_lower in post.title.lower() or
+ query_lower in post.content.lower()
+ )
+ ]
+ return matching_posts[skip:skip + limit]
+
+posts_crud = PostsCRUD()
+```
+
+### 评论 CRUD
+
+更新 `src/crud/comments.py`:
+
+```python
+from typing import List, Optional
+from datetime import datetime
+from src.schemas.comments import CommentCreate, CommentUpdate, Comment
+
+class CommentsCRUD:
+ def __init__(self):
+ self._comments: List[Comment] = []
+ self._next_id = 1
+
+ def get_all(self) -> List[Comment]:
+ """Get all comments"""
+ return self._comments
+
+ def get_by_id(self, comment_id: int) -> Optional[Comment]:
+ """Get comment by ID"""
+ return next((comment for comment in self._comments if comment.id == comment_id), None)
+
+ def get_by_post(self, post_id: int, skip: int = 0, limit: int = 100) -> List[Comment]:
+ """Get comments for a specific post"""
+ post_comments = [comment for comment in self._comments if comment.post_id == post_id]
+ return post_comments[skip:skip + limit]
+
+ def get_by_author(self, author_id: int, skip: int = 0, limit: int = 100) -> List[Comment]:
+ """Get comments by author"""
+ author_comments = [comment for comment in self._comments if comment.author_id == author_id]
+ return author_comments[skip:skip + limit]
+
+ def create(self, comment: CommentCreate, author_id: int) -> Comment:
+ """Create a new comment"""
+ # Verify post exists
+ from src.crud.posts import posts_crud
+ post = posts_crud.get_by_id(comment.post_id)
+ if not post:
+ raise ValueError("Post not found")
+
+ now = datetime.now()
+ new_comment = Comment(
+ id=self._next_id,
+ content=comment.content,
+ post_id=comment.post_id,
+ author_id=author_id,
+ created_at=now,
+ updated_at=now
+ )
+ self._next_id += 1
+ self._comments.append(new_comment)
+
+ # Update post's comment count
+ post.comments_count += 1
+
+ return new_comment
+
+ def update(self, comment_id: int, comment_update: CommentUpdate, author_id: int) -> Optional[Comment]:
+ """Update an existing comment"""
+ comment = self.get_by_id(comment_id)
+ if not comment or comment.author_id != author_id:
+ return None
+
+ update_data = comment_update.dict(exclude_unset=True)
+ for field, value in update_data.items():
+ setattr(comment, field, value)
+
+ comment.updated_at = datetime.now()
+ return comment
+
+ def delete(self, comment_id: int, author_id: int) -> bool:
+ """Delete a comment"""
+ comment = self.get_by_id(comment_id)
+ if comment and comment.author_id == author_id:
+ self._comments.remove(comment)
+
+ # Update post's comment count
+ from src.crud.posts import posts_crud
+ post = posts_crud.get_by_id(comment.post_id)
+ if post:
+ post.comments_count = max(0, post.comments_count - 1)
+
+ return True
+ return False
+
+comments_crud = CommentsCRUD()
+```
+
+## 第 6 步:实现进阶的 API 路由
+
+### 增强的用户路由
+
+更新 `src/api/routes/users.py`:
+
+```python
+from typing import List
+from fastapi import APIRouter, HTTPException, status, Depends, Query
+from src.schemas.users import User, UserCreate, UserUpdate
+from src.crud.users import users_crud
+
+router = APIRouter()
+
+# 获取当前用户的辅助函数(教程里做了简化)
+def get_current_user_id() -> int:
+ # 在真实项目中,这里应当校验 JWT 并返回用户 ID
+ return 1 # 教程中仅用于演示
+
+@router.get("/", response_model=List[User])
+def read_users(
+ skip: int = Query(0, ge=0),
+ limit: int = Query(100, ge=1, le=100)
+):
+ """分页获取所有用户"""
+ users = users_crud.get_all()[skip:skip + limit]
+ return [User(**user.dict()) for user in users]
+
+@router.post("/", response_model=User, status_code=status.HTTP_201_CREATED)
+def create_user(user: UserCreate):
+ """Register a new user"""
+ try:
+ new_user = users_crud.create(user)
+ return User(**new_user.dict())
+ except ValueError as e:
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
+ detail=str(e)
+ )
+
+@router.get("/{user_id}", response_model=User)
+def read_user(user_id: int):
+ """Get a specific user"""
+ user = users_crud.get_by_id(user_id)
+ if not user:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail=f"User with id {user_id} not found"
+ )
+ return User(**user.dict())
+
+@router.put("/{user_id}", response_model=User)
+def update_user(
+ user_id: int,
+ user_update: UserUpdate,
+ current_user_id: int = Depends(get_current_user_id)
+):
+ """Update user profile"""
+ if user_id != current_user_id:
+ raise HTTPException(
+ status_code=status.HTTP_403_FORBIDDEN,
+ detail="You can only update your own profile"
+ )
+
+ try:
+ updated_user = users_crud.update(user_id, user_update)
+ if not updated_user:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="User not found"
+ )
+ return User(**updated_user.dict())
+ except ValueError as e:
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
+ detail=str(e)
+ )
+
+@router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
+def delete_user(
+ user_id: int,
+ current_user_id: int = Depends(get_current_user_id)
+):
+ """Deactivate user account"""
+ if user_id != current_user_id:
+ raise HTTPException(
+ status_code=status.HTTP_403_FORBIDDEN,
+ detail="You can only delete your own account"
+ )
+
+ success = users_crud.delete(user_id)
+ if not success:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="User not found"
+ )
+
+@router.post("/login")
+def login(email: str, password: str):
+ """Authenticate user"""
+ user = users_crud.authenticate(email, password)
+ if not user:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Invalid email or password"
+ )
+
+ # In a real app, return JWT token
+ return {
+ "message": "Login successful",
+ "user_id": user.id,
+ "username": user.username
+ }
+```
+
+### 增强的文章路由
+
+更新 `src/api/routes/posts.py`:
+
+```python
+from typing import List, Optional
+from fastapi import APIRouter, HTTPException, status, Depends, Query
+from src.schemas.posts import Post, PostCreate, PostUpdate
+from src.crud.posts import posts_crud
+
+router = APIRouter()
+
+def get_current_user_id() -> int:
+ return 1 # 教程中做了简化
+
+@router.get("/", response_model=List[Post])
+def read_posts(
+ skip: int = Query(0, ge=0),
+ limit: int = Query(100, ge=1, le=100),
+ search: Optional[str] = Query(None)
+):
+ """获取文章列表,并支持可选搜索"""
+ if search:
+ posts = posts_crud.search(search, skip, limit)
+ else:
+ posts = posts_crud.get_all(skip, limit)
+ return posts
+
+@router.post("/", response_model=Post, status_code=status.HTTP_201_CREATED)
+def create_post(
+ post: PostCreate,
+ current_user_id: int = Depends(get_current_user_id)
+):
+ """Create a new blog post"""
+ new_post = posts_crud.create(post, current_user_id)
+ return new_post
+
+@router.get("/{post_id}", response_model=Post)
+def read_post(post_id: int):
+ """Get a specific post"""
+ post = posts_crud.get_by_id(post_id)
+ if not post:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Post not found"
+ )
+ return post
+
+@router.put("/{post_id}", response_model=Post)
+def update_post(
+ post_id: int,
+ post_update: PostUpdate,
+ current_user_id: int = Depends(get_current_user_id)
+):
+ """Update a blog post"""
+ updated_post = posts_crud.update(post_id, post_update, current_user_id)
+ if not updated_post:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Post not found or you don't have permission to edit it"
+ )
+ return updated_post
+
+@router.delete("/{post_id}", status_code=status.HTTP_204_NO_CONTENT)
+def delete_post(
+ post_id: int,
+ current_user_id: int = Depends(get_current_user_id)
+):
+ """Delete a blog post"""
+ success = posts_crud.delete(post_id, current_user_id)
+ if not success:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Post not found or you don't have permission to delete it"
+ )
+
+@router.get("/author/{author_id}", response_model=List[Post])
+def read_posts_by_author(
+ author_id: int,
+ skip: int = Query(0, ge=0),
+ limit: int = Query(100, ge=1, le=100)
+):
+ """Get posts by a specific author"""
+ posts = posts_crud.get_by_author(author_id, skip, limit)
+ return posts
+```
+
+### 增强的评论路由
+
+更新 `src/api/routes/comments.py`:
+
+```python
+from typing import List
+from fastapi import APIRouter, HTTPException, status, Depends, Query
+from src.schemas.comments import Comment, CommentCreate, CommentUpdate
+from src.crud.comments import comments_crud
+
+router = APIRouter()
+
+def get_current_user_id() -> int:
+ return 1 # 教程中做了简化
+
+@router.get("/", response_model=List[Comment])
+def read_comments(
+ skip: int = Query(0, ge=0),
+ limit: int = Query(100, ge=1, le=100)
+):
+ """Get all comments"""
+ comments = comments_crud.get_all()[skip:skip + limit]
+ return comments
+
+@router.post("/", response_model=Comment, status_code=status.HTTP_201_CREATED)
+def create_comment(
+ comment: CommentCreate,
+ current_user_id: int = Depends(get_current_user_id)
+):
+ """Create a new comment"""
+ try:
+ new_comment = comments_crud.create(comment, current_user_id)
+ return new_comment
+ except ValueError as e:
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
+ detail=str(e)
+ )
+
+@router.get("/{comment_id}", response_model=Comment)
+def read_comment(comment_id: int):
+ """Get a specific comment"""
+ comment = comments_crud.get_by_id(comment_id)
+ if not comment:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Comment not found"
+ )
+ return comment
+
+@router.put("/{comment_id}", response_model=Comment)
+def update_comment(
+ comment_id: int,
+ comment_update: CommentUpdate,
+ current_user_id: int = Depends(get_current_user_id)
+):
+ """Update a comment"""
+ updated_comment = comments_crud.update(comment_id, comment_update, current_user_id)
+ if not updated_comment:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Comment not found or you don't have permission to edit it"
+ )
+ return updated_comment
+
+@router.delete("/{comment_id}", status_code=status.HTTP_204_NO_CONTENT)
+def delete_comment(
+ comment_id: int,
+ current_user_id: int = Depends(get_current_user_id)
+):
+ """Delete a comment"""
+ success = comments_crud.delete(comment_id, current_user_id)
+ if not success:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Comment not found or you don't have permission to delete it"
+ )
+
+@router.get("/post/{post_id}", response_model=List[Comment])
+def read_comments_by_post(
+ post_id: int,
+ skip: int = Query(0, ge=0),
+ limit: int = Query(100, ge=1, le=100)
+):
+ """Get comments for a specific post"""
+ comments = comments_crud.get_by_post(post_id, skip, limit)
+ return comments
+
+@router.get("/author/{author_id}", response_model=List[Comment])
+def read_comments_by_author(
+ author_id: int,
+ skip: int = Query(0, ge=0),
+ limit: int = Query(100, ge=1, le=100)
+):
+ """Get comments by a specific author"""
+ comments = comments_crud.get_by_author(author_id, skip, limit)
+ return comments
+```
+
+## 第 7 步:测试您的博客 API
+
+启动服务器,测试完整的博客 API:
+
+
+
+```console
+$ fastkit runserver
+INFO: Uvicorn running on http://127.0.0.1:8000
+```
+
+
+
+### 测试用户注册
+
+
+
+```console
+$ curl -X POST "http://127.0.0.1:8000/api/v1/users/" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "email": "john@example.com",
+ "username": "john_doe",
+ "full_name": "John Doe",
+ "bio": "Software developer and blogger",
+ "password": "securepassword123"
+ }'
+
+{
+ "id": 1,
+ "email": "john@example.com",
+ "username": "john_doe",
+ "full_name": "John Doe",
+ "bio": "Software developer and blogger",
+ "is_active": true,
+ "created_at": "2023-12-07T10:30:00",
+ "posts_count": 0
+}
+```
+
+
+
+### 测试用户登录
+
+
+
+```console
+$ curl -X POST "http://127.0.0.1:8000/api/v1/users/login" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "email": "john@example.com",
+ "password": "securepassword123"
+ }'
+
+{
+ "message": "Login successful",
+ "user_id": 1,
+ "username": "john_doe"
+}
+```
+
+
+
+### 测试文章创建
+
+
+
+```console
+$ curl -X POST "http://127.0.0.1:8000/api/v1/posts/" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "title": "My First Blog Post",
+ "content": "This is the content of my first blog post. It is about learning FastAPI with FastAPI-fastkit!",
+ "published": true
+ }'
+
+{
+ "id": 1,
+ "title": "My First Blog Post",
+ "content": "This is the content of my first blog post. It is about learning FastAPI with FastAPI-fastkit!",
+ "published": true,
+ "author_id": 1,
+ "created_at": "2023-12-07T10:35:00",
+ "updated_at": "2023-12-07T10:35:00",
+ "comments_count": 0
+}
+```
+
+
+
+### 测试评论创建
+
+
+
+```console
+$ curl -X POST "http://127.0.0.1:8000/api/v1/comments/" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "content": "Great post! I learned a lot from this.",
+ "post_id": 1
+ }'
+
+{
+ "id": 1,
+ "content": "Great post! I learned a lot from this.",
+ "post_id": 1,
+ "author_id": 1,
+ "created_at": "2023-12-07T10:40:00",
+ "updated_at": "2023-12-07T10:40:00"
+}
+```
+
+
+
+### 测试搜索功能
+
+
+
+```console
+$ curl "http://127.0.0.1:8000/api/v1/posts/?search=FastAPI"
+
+[
+ {
+ "id": 1,
+ "title": "My First Blog Post",
+ "content": "This is the content of my first blog post. It is about learning FastAPI with FastAPI-fastkit!",
+ "published": true,
+ "author_id": 1,
+ "created_at": "2023-12-07T10:35:00",
+ "updated_at": "2023-12-07T10:35:00",
+ "comments_count": 1
+ }
+]
+```
+
+
+
+## 第 8 步:API 文档
+
+访问 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) 查看完整的 API 文档。您现在应该能看到:
+
+- **Users**:注册、登录、资料管理
+- **Posts**:CRUD 操作、搜索、按作者筛选
+- **Comments**:CRUD 操作、按文章 / 作者筛选
+- **Items**:原始示例端点
+
+文档会展示:
+
+- 所有可用端点
+- 请求 / 响应模式
+- 数据校验规则
+- 错误响应
+
+## 第 9 步:编写测试
+
+为博客 API 编写完善的测试。创建 `tests/test_blog_api.py`:
+
+```python
+from fastapi.testclient import TestClient
+from src.main import app
+
+client = TestClient(app)
+
+class TestUserAPI:
+ def test_create_user(self):
+ user_data = {
+ "email": "test@example.com",
+ "username": "testuser",
+ "full_name": "Test User",
+ "bio": "Test bio",
+ "password": "testpassword123"
+ }
+ response = client.post("/api/v1/users/", json=user_data)
+ assert response.status_code == 201
+ data = response.json()
+ assert data["email"] == user_data["email"]
+ assert data["username"] == user_data["username"]
+ assert "id" in data
+ assert "hashed_password" not in data # Should not expose password
+
+ def test_duplicate_email(self):
+ # First user
+ user_data1 = {
+ "email": "duplicate@example.com",
+ "username": "user1",
+ "password": "password123"
+ }
+ response1 = client.post("/api/v1/users/", json=user_data1)
+ assert response1.status_code == 201
+
+ # Second user with same email
+ user_data2 = {
+ "email": "duplicate@example.com",
+ "username": "user2",
+ "password": "password123"
+ }
+ response2 = client.post("/api/v1/users/", json=user_data2)
+ assert response2.status_code == 400
+ assert "Email already registered" in response2.json()["detail"]
+
+ def test_login(self):
+ # Create user first
+ user_data = {
+ "email": "login@example.com",
+ "username": "loginuser",
+ "password": "loginpassword123"
+ }
+ client.post("/api/v1/users/", json=user_data)
+
+ # Test login
+ login_data = {
+ "email": "login@example.com",
+ "password": "loginpassword123"
+ }
+ response = client.post("/api/v1/users/login", json=login_data)
+ assert response.status_code == 200
+ data = response.json()
+ assert "user_id" in data
+ assert data["username"] == "loginuser"
+
+class TestPostAPI:
+ def test_create_post(self):
+ post_data = {
+ "title": "Test Post",
+ "content": "This is a test post content",
+ "published": True
+ }
+ response = client.post("/api/v1/posts/", json=post_data)
+ assert response.status_code == 201
+ data = response.json()
+ assert data["title"] == post_data["title"]
+ assert data["content"] == post_data["content"]
+ assert "id" in data
+ assert "author_id" in data
+
+ def test_read_posts(self):
+ response = client.get("/api/v1/posts/")
+ assert response.status_code == 200
+ data = response.json()
+ assert isinstance(data, list)
+
+ def test_search_posts(self):
+ # Create a post with specific content
+ post_data = {
+ "title": "FastAPI Tutorial",
+ "content": "Learn how to build APIs with FastAPI",
+ "published": True
+ }
+ client.post("/api/v1/posts/", json=post_data)
+
+ # Search for the post
+ response = client.get("/api/v1/posts/?search=FastAPI")
+ assert response.status_code == 200
+ data = response.json()
+ assert len(data) > 0
+ assert any("FastAPI" in post["title"] or "FastAPI" in post["content"] for post in data)
+
+class TestCommentAPI:
+ def test_create_comment(self):
+ # Create a post first
+ post_data = {
+ "title": "Post for Comments",
+ "content": "This post will receive comments",
+ "published": True
+ }
+ post_response = client.post("/api/v1/posts/", json=post_data)
+ post_id = post_response.json()["id"]
+
+ # Create comment
+ comment_data = {
+ "content": "This is a test comment",
+ "post_id": post_id
+ }
+ response = client.post("/api/v1/comments/", json=comment_data)
+ assert response.status_code == 201
+ data = response.json()
+ assert data["content"] == comment_data["content"]
+ assert data["post_id"] == post_id
+
+ def test_get_comments_by_post(self):
+ # Create post and comment first
+ post_data = {
+ "title": "Post with Comments",
+ "content": "This post has comments",
+ "published": True
+ }
+ post_response = client.post("/api/v1/posts/", json=post_data)
+ post_id = post_response.json()["id"]
+
+ comment_data = {
+ "content": "Comment on post",
+ "post_id": post_id
+ }
+ client.post("/api/v1/comments/", json=comment_data)
+
+ # Get comments for the post
+ response = client.get(f"/api/v1/comments/post/{post_id}")
+ assert response.status_code == 200
+ data = response.json()
+ assert len(data) > 0
+ assert all(comment["post_id"] == post_id for comment in data)
+
+# Run the tests
+if __name__ == "__main__":
+ import pytest
+ pytest.main([__file__])
+```
+
+### 运行测试
+
+
+
+```console
+$ python -m pytest tests/test_blog_api.py -v
+======================== test session starts ========================
+tests/test_blog_api.py::TestUserAPI::test_create_user PASSED
+tests/test_blog_api.py::TestUserAPI::test_duplicate_email PASSED
+tests/test_blog_api.py::TestUserAPI::test_login PASSED
+tests/test_blog_api.py::TestPostAPI::test_create_post PASSED
+tests/test_blog_api.py::TestPostAPI::test_read_posts PASSED
+tests/test_blog_api.py::TestPostAPI::test_search_posts PASSED
+tests/test_blog_api.py::TestCommentAPI::test_create_comment PASSED
+tests/test_blog_api.py::TestCommentAPI::test_get_comments_by_post PASSED
+======================== 8 passed in 1.23s ========================
+```
+
+
+
+## 您已构建的成果
+
+恭喜!您已经成功构建了一个完整的博客 API,包含:
+
+### ✅ 已实现的功能
+
+- **用户管理**
+ - 带校验的用户注册
+ - 用户认证(登录)
+ - 资料管理
+ - 重复防护
+
+- **博客文章**
+ - 创建、读取、更新、删除文章
+ - 按作者筛选
+ - 搜索功能
+ - 发布 / 草稿状态
+
+- **评论系统**
+ - 为文章添加评论
+ - 按文章或作者查看评论
+ - 评论管理
+
+- **数据校验**
+ - 邮箱校验
+ - 密码长度要求
+ - 内容长度上限
+ - 必填字段校验
+
+- **错误处理**
+ - 合适的 HTTP 状态码
+ - 描述清晰的错误信息
+ - 输入校验错误
+
+- **API 文档**
+ - 自动生成 OpenAPI
+ - 交互式测试界面
+ - 请求 / 响应模式
+
+- **测试**
+ - 完整的测试覆盖
+ - 针对所有端点的单元测试
+ - 边界情况测试
+
+## 下一步
+
+### 可能的增强方向
+
+1. **真正的认证**
+ - 实现 JWT token
+ - 使用 bcrypt 做密码哈希
+ - 基于角色的权限
+
+2. **数据库集成**
+ - 使用 PostgreSQL 或 MySQL
+ - 实现完整的数据库模型
+ - 添加数据库迁移
+
+3. **进阶特性**
+ - 图片上传
+ - 邮件通知
+ - 文章分类 / 标签
+ - 点赞 / 反对系统
+
+4. **生产可用**
+ - 加入日志
+ - 实现缓存
+ - 加入限流
+ - 环境配置
+
+### 继续学习
+
+1. **[使用模板](../user-guide/using-templates.md)**:探索 `fastapi-psql-orm` 模板,获得数据库集成
+2. **[添加路由](../user-guide/adding-routes.md)**:学习更进阶的路由模式
+3. **[参与贡献](../contributing/development-setup.md)**:为 FastAPI-fastkit 贡献代码
+
+!!! tip "您已掌握的最佳实践"
+ - **模块化架构**:通过 schemas、CRUD、routes 做关注点分离
+ - **数据校验**:使用 Pydantic 实现稳健的输入校验
+ - **错误处理**:合适的 HTTP 状态码与错误信息
+ - **测试**:对所有功能做完善的测试覆盖
+ - **文档**:善用自动生成的 API 文档能力
+
+您现在已经具备使用 FastAPI-fastkit 构建生产级 API 的能力!🚀
diff --git a/docs/zh/tutorial/getting-started.md b/docs/zh/tutorial/getting-started.md
new file mode 100644
index 0000000..fac4085
--- /dev/null
+++ b/docs/zh/tutorial/getting-started.md
@@ -0,0 +1,564 @@
+# 入门指南
+
+这是一份完整的 FastAPI-fastkit 上手教程,会带您一步步从安装走到运行第一个 API,大约 15 分钟即可完成。
+
+## 前置条件
+
+开始之前,请确认您已具备:
+
+- 已在系统上安装 **Python 3.12 及以上**
+- 具备 **Python 基础知识**(变量、函数、类)
+- 可以访问 **终端 / 命令行**
+- 一个 **文本编辑器或 IDE**(VS Code、PyCharm 等)
+
+## 第 1 步:安装
+
+首先安装 FastAPI-fastkit。建议使用虚拟环境以保持项目隔离。
+
+### 方案 A:使用 pip(传统)
+
+
+
+```console
+$ pip install fastapi-fastkit
+---> 100%
+Successfully installed fastapi-fastkit
+```
+
+
+
+### 方案 B:使用 UV(推荐 —— 更快)
+
+UV 是一款高速的 Python 包管理器。若您尚未安装 UV:
+
+
+
+```console
+# Install UV first
+$ curl -LsSf https://astral.sh/uv/install.sh | sh
+
+# Then install FastAPI-fastkit
+$ uv pip install fastapi-fastkit
+---> 100%
+Successfully installed fastapi-fastkit
+```
+
+
+
+### 方案 C:使用虚拟环境
+
+
+
+```console
+$ python -m venv fastapi-env
+$ source fastapi-env/bin/activate # On Windows: fastapi-env\Scripts\activate
+$ pip install fastapi-fastkit
+```
+
+
+
+### 验证安装
+
+确认 FastAPI-fastkit 已正确安装:
+
+
+
+```console
+$ fastkit --version
+FastAPI-fastkit version 1.0.0
+```
+
+
+
+## 第 2 步:创建您的第一个项目
+
+接下来用交互式的 `init` 命令创建第一个 FastAPI 项目:
+
+
+
+```console
+$ fastkit init
+Enter the project name: my-first-api
+Enter the author name: Your Name
+Enter the author email: your.email@example.com
+Enter the project description: My first FastAPI project
+
+ Project Information
+┌──────────────┬─────────────────────────┐
+│ Project Name │ my-first-api │
+│ Author │ Your Name │
+│ Author Email │ your.email@example.com │
+│ Description │ My first FastAPI project│
+└──────────────┴─────────────────────────┘
+
+Available Stacks and Dependencies:
+ MINIMAL Stack
+┌──────────────┬───────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ pydantic │
+│ Dependency 4 │ pydantic-settings │
+└──────────────┴───────────────────┘
+
+ STANDARD Stack
+┌──────────────┬───────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ sqlalchemy │
+│ Dependency 4 │ alembic │
+│ Dependency 5 │ pytest │
+│ Dependency 6 │ pydantic │
+│ Dependency 7 │ pydantic-settings │
+└──────────────┴───────────────────┘
+
+Select stack (minimal, standard, full): minimal
+
+Available Package Managers:
+ Package Managers
+┌────────┬────────────────────────────────────────────┐
+│ PIP │ Standard Python package manager │
+│ UV │ Fast Python package manager │
+│ PDM │ Modern Python dependency management │
+│ POETRY │ Python dependency management and packaging │
+└────────┴────────────────────────────────────────────┘
+
+Select package manager (pip, uv, pdm, poetry) [uv]: uv
+Do you want to proceed with project creation? [y/N]: y
+
+Creating virtual environment...
+Installing dependencies...
+✨ FastAPI project 'my-first-api' has been created successfully!
+```
+
+
+
+!!! note "技术栈选择"
+ 本教程为简化起见选择了 **MINIMAL**。在真实项目中,可以考虑 **STANDARD**(包含数据库支持)或 **FULL**(包含后台任务)。
+
+## 第 3 步:进入项目目录
+
+进入刚创建好的项目目录:
+
+
+
+```console
+$ cd my-first-api
+$ ls -la
+total 32
+drwxr-xr-x 8 user user 256 Dec 7 10:30 .
+drwxr-xr-x 3 user user 96 Dec 7 10:30 ..
+drwxr-xr-x 5 user user 160 Dec 7 10:30 .venv
+-rw-r--r-- 1 user user 156 Dec 7 10:30 README.md
+-rw-r--r-- 1 user user 243 Dec 7 10:30 requirements.txt
+drwxr-xr-x 3 user user 96 Dec 7 10:30 scripts
+-rw-r--r-- 1 user user 1245 Dec 7 10:30 setup.py
+drwxr-xr-x 8 user user 256 Dec 7 10:30 src
+drwxr-xr-x 3 user user 96 Dec 7 10:30 tests
+```
+
+
+
+## 第 4 步:激活虚拟环境
+
+您的项目已预先配置好虚拟环境,激活它:
+
+
+
+```console
+$ source .venv/bin/activate # On Windows: .venv\Scripts\activate
+(my-first-api) $
+```
+
+
+
+注意您的终端提示符现在会显示 `(my-first-api)`,表示虚拟环境已激活。
+
+## 第 5 步:启动开发服务器
+
+接下来是激动人心的部分 —— 启动 FastAPI 服务器:
+
+
+
+```console
+$ fastkit runserver
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+INFO: Started reloader process [28720] using StatReload
+INFO: Started server process [28722]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+```
+
+
+
+🎉 **恭喜!** 您的 FastAPI 服务器已经运行起来了。
+
+## 第 6 步:测试 API
+
+下面用几种方式测试您的 API:
+
+### 方式 1:浏览器
+
+打开浏览器,访问:
+
+- **API 主端点**:[http://127.0.0.1:8000](http://127.0.0.1:8000)
+
+您会看到:
+```json
+{"message": "Hello World"}
+```
+
+### 方式 2:交互式 API 文档
+
+访问 FastAPI 自动生成的 API 文档:
+
+- **Swagger UI**:[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)
+- **ReDoc**:[http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc)
+
+Swagger UI 尤为实用,您可以:
+
+- 查看所有可用端点
+- 直接在浏览器中测试端点
+- 查看请求 / 响应的模式
+- 下载 OpenAPI 规范
+
+### 方式 3:命令行
+
+另开一个终端(保持服务器运行),用 curl 测试:
+
+
+
+```console
+$ curl http://127.0.0.1:8000
+{"message":"Hello World"}
+
+$ curl http://127.0.0.1:8000/api/v1/items/
+[]
+
+$ curl -X POST "http://127.0.0.1:8000/api/v1/items/" \
+ -H "Content-Type: application/json" \
+ -d '{"title": "My First Item", "description": "This is a test item"}'
+{
+ "id": 1,
+ "title": "My First Item",
+ "description": "This is a test item"
+}
+```
+
+
+
+## 第 7 步:了解您的项目结构
+
+来看看 FastAPI-fastkit 为您生成了哪些内容:
+
+
+
+```console
+$ tree src
+src/
+├── __init__.py
+├── main.py # FastAPI 应用入口
+├── core/
+│ ├── __init__.py
+│ └── config.py # 应用配置
+├── api/
+│ ├── __init__.py
+│ ├── api.py # 主 API 路由
+│ └── routes/
+│ ├── __init__.py
+│ └── items.py # items API 端点
+├── crud/
+│ ├── __init__.py
+│ └── items.py # items 相关业务逻辑
+├── schemas/
+│ ├── __init__.py
+│ └── items.py # 数据校验模式
+└── mocks/
+ ├── __init__.py
+ └── mock_items.json # 示例数据
+```
+
+
+
+### 关键文件说明
+
+**`src/main.py`** —— 应用的核心:
+```python
+from fastapi import FastAPI
+from src.api.api import api_router
+from src.core.config import settings
+
+app = FastAPI(
+ title=settings.PROJECT_NAME,
+ version=settings.VERSION,
+ openapi_url=f"{settings.API_V1_STR}/openapi.json"
+)
+
+app.include_router(api_router, prefix=settings.API_V1_STR)
+
+@app.get("/")
+def read_root():
+ return {"message": "Hello World"}
+```
+
+**`src/core/config.py`** —— 应用设置:
+```python
+from pydantic_settings import BaseSettings
+
+class Settings(BaseSettings):
+ PROJECT_NAME: str = "my-first-api"
+ VERSION: str = "1.0.0"
+ API_V1_STR: str = "/api/v1"
+
+ class Config:
+ env_file = ".env"
+
+settings = Settings()
+```
+
+**`src/api/routes/items.py`** —— API 端点:
+```python
+from typing import List
+from fastapi import APIRouter, HTTPException
+from src.schemas.items import Item, ItemCreate, ItemUpdate
+from src.crud.items import items_crud
+
+router = APIRouter()
+
+@router.get("/", response_model=List[Item])
+def read_items():
+ """Get all items"""
+ return items_crud.get_all()
+
+@router.post("/", response_model=Item)
+def create_item(item: ItemCreate):
+ """Create a new item"""
+ return items_crud.create(item)
+```
+
+## 第 8 步:添加您的第一个自定义路由
+
+接下来添加一个新的 API 路由,练习刚学到的内容:
+
+
+
+```console
+$ fastkit addroute users my-first-api
+ Adding New Route
+┌──────────────────┬──────────────────────────────────────────┐
+│ Project │ my-first-api │
+│ Route Name │ users │
+│ Target Directory │ ~/my-first-api │
+└──────────────────┴──────────────────────────────────────────┘
+
+Do you want to add route 'users' to project 'my-first-api'? [Y/n]: y
+
+✨ Successfully added new route 'users' to project 'my-first-api'
+```
+
+
+
+服务器会自动重启,您将拥有以下新端点:
+
+- `GET /api/v1/users/` —— 获取所有用户
+- `POST /api/v1/users/` —— 创建新用户
+- `GET /api/v1/users/{user_id}` —— 获取指定用户
+- 等等……
+
+### 测试新路由
+
+
+
+```console
+$ curl -X POST "http://127.0.0.1:8000/api/v1/users/" \
+ -H "Content-Type: application/json" \
+ -d '{"title": "John Doe", "description": "Software Developer"}'
+{
+ "id": 1,
+ "title": "John Doe",
+ "description": "Software Developer"
+}
+
+$ curl http://127.0.0.1:8000/api/v1/users/
+[
+ {
+ "id": 1,
+ "title": "John Doe",
+ "description": "Software Developer"
+ }
+]
+```
+
+
+
+## 第 9 步:探索并修改代码
+
+我们做一个小修改,看看代码是如何运作的。
+
+### 修改欢迎信息
+
+在编辑器中打开 `src/main.py`,修改根端点:
+
+```python
+@app.get("/")
+def read_root():
+ return {"message": "Welcome to my first FastAPI application!"}
+```
+
+保存文件。由于启用了自动重载,服务器会自动重启。
+
+### 测试改动
+
+
+
+```console
+$ curl http://127.0.0.1:8000
+{"message":"Welcome to my first FastAPI application!"}
+```
+
+
+
+### 添加一个新端点
+
+在 `src/main.py` 中加入一个简单的端点:
+
+```python
+@app.get("/hello/{name}")
+def say_hello(name: str):
+ return {"message": f"Hello, {name}!"}
+```
+
+### 测试新端点
+
+
+
+```console
+$ curl http://127.0.0.1:8000/hello/World
+{"message":"Hello, World!"}
+
+$ curl http://127.0.0.1:8000/hello/FastAPI
+{"message":"Hello, FastAPI!"}
+```
+
+
+
+## 第 10 步:运行测试
+
+您的项目已预置好测试,运行它们:
+
+
+
+```console
+$ python -m pytest
+======================== test session starts ========================
+collected 5 items
+
+tests/test_items.py::test_create_item PASSED
+tests/test_items.py::test_read_items PASSED
+tests/test_items.py::test_read_item PASSED
+tests/test_items.py::test_update_item PASSED
+tests/test_items.py::test_delete_item PASSED
+
+======================== 5 passed in 0.45s ========================
+```
+
+
+
+## 理解核心概念
+
+### 1. FastAPI 应用结构
+
+FastAPI-fastkit 采用 **模块化架构**:
+
+- **`main.py`**:应用入口与全局端点
+- **`api/`**:API 路由组织
+- **`core/`**:应用配置与设置
+- **`crud/`**:业务逻辑与数据操作
+- **`schemas/`**:数据校验与序列化
+- **`tests/`**:自动化测试
+
+### 2. 依赖管理
+
+您的项目采用现代 Python 依赖管理:
+
+- **虚拟环境**:隔离的 Python 环境
+- **requirements.txt**:列出所有依赖
+- **自动安装**:在创建项目时自动安装依赖
+
+### 3. 开发服务器
+
+FastAPI-fastkit 使用 **Uvicorn** 作为 ASGI 服务器:
+
+- **自动重载**:代码变更时自动重启
+- **快速启动**:开发迭代迅速
+- **可用于生产**:开发与生产使用同一款服务器
+
+### 4. API 文档
+
+FastAPI 会自动生成:
+
+- **OpenAPI 规范**:业界标准的 API 文档
+- **Swagger UI**:交互式测试界面
+- **ReDoc**:另一种文档视图
+
+## 下一步
+
+恭喜!您已成功完成:
+
+✅ 安装 FastAPI-fastkit
+✅ 创建第一个项目
+✅ 启动开发服务器
+✅ 测试 API 端点
+✅ 添加新路由
+✅ 修改现有代码
+✅ 运行测试
+
+### 继续学习
+
+1. **[您的第一个项目](first-project.md)**:构建一个带有进阶特性的完整博客 API
+2. **[添加路由](../user-guide/adding-routes.md)**:学习创建复杂的 API 端点
+3. **[使用模板](../user-guide/using-templates.md)**:探索预构建的项目模板
+
+### 多多动手
+
+尝试以下挑战:
+
+1. **添加校验**:修改 schema,加入数据校验规则
+2. **自定义响应**:更改路由的响应格式
+3. **环境变量**:使用 `.env` 文件做配置
+4. **添加中间件**:实现 CORS 或认证
+5. **数据库集成**:升级到 STANDARD 栈以获得数据库支持
+
+### 常见问题与解决方案
+
+**服务器无法启动:**
+
+- 检查是否处于项目目录中
+- 确认虚拟环境已激活
+- 确认代码没有语法错误
+
+**导入错误:**
+
+- 确认所有 `__init__.py` 文件存在
+- 检查导入路径是否正确
+- 确认正在使用虚拟环境
+
+**端口已被占用:**
+```console
+$ fastkit runserver --port 8080
+```
+
+## 您已掌握的最佳实践
+
+1. **虚拟环境**:始终使用隔离的环境
+2. **项目结构**:遵循组织良好的模块化架构
+3. **自动重载**:利用开发服务器实现快速迭代
+4. **API 文档**:善用自动文档生成能力
+5. **测试**:在开发过程中定期运行测试
+
+!!! tip "开发小贴士"
+ - 编码时让开发服务器一直运行
+ - 使用交互式文档(`/docs`)测试您的 API
+ - 关注终端中的报错信息
+ - 经常把代码提交到版本控制
+
+您已经准备好用 FastAPI-fastkit 构建出色的 API 了!🚀
diff --git a/docs/zh/tutorial/mcp-integration.md b/docs/zh/tutorial/mcp-integration.md
new file mode 100644
index 0000000..e26df37
--- /dev/null
+++ b/docs/zh/tutorial/mcp-integration.md
@@ -0,0 +1,1730 @@
+# MCP(Model Context Protocol)集成
+
+学习如何把 Model Context Protocol(MCP)与 FastAPI 集成,构建一个让 AI 模型能把 API 端点作为工具使用的系统。本节我们将通过 `fastapi-mcp` 模板实现一套完整的 AI 集成 API,涵盖认证、权限管理与 MCP 服务器实现。
+
+## 您将学到的内容
+
+- Model Context Protocol(MCP)的概念与实现
+- 构建基于 JWT 的认证体系
+- 实现基于角色的访问控制(RBAC)
+- 暴露并管理 MCP 工具
+- 与 AI 模型间的安全 API 通信
+- 用户会话与上下文管理
+
+## 前置条件
+
+- 完成 [自定义响应处理教程](custom-response-handling.md)
+- 理解 JWT 与 OAuth2 的基本概念
+- 熟悉与 AI / LLM 模型的 API 通信
+- 对 MCP 协议有基础认识
+
+## 什么是 Model Context Protocol(MCP)?
+
+MCP 是一种标准化协议,让 AI 模型可以与外部系统进行交互。
+
+### 传统方式 vs MCP 方式
+
+**传统方式(直接 API 调用):**
+```
+AI Model → HTTP Request → API Server → Response
+```
+
+**MCP 方式:**
+```
+AI Model → MCP Client → MCP Server (FastAPI) → Safe Tool Execution → Response
+```
+
+### MCP 的优势
+
+- **安全性**:统一的认证与权限管理
+- **标准化**:提供一致的接口
+- **上下文管理**:基于会话的状态维护
+- **工具抽象**:把复杂 API 暴露为简单工具
+
+## 第 1 步:创建 MCP 集成项目
+
+使用 `fastapi-mcp` 模板创建项目:
+
+
+
+```console
+$ fastkit startdemo fastapi-mcp
+Enter the project name: ai-integrated-api
+Enter the author name: Developer Kim
+Enter the author email: developer@example.com
+Enter the project description: MCP-based API server integrated with AI models
+Deploying FastAPI project using 'fastapi-mcp' template
+
+ Project Information
+┌──────────────┬─────────────────────────────────────────────┐
+│ Project Name │ ai-integrated-api │
+│ Author │ Developer Kim │
+│ Author Email │ developer@example.com │
+│ Description │ MCP-based API server integrated with AI models │
+└──────────────┴─────────────────────────────────────────────┘
+
+ Template Dependencies
+┌──────────────┬────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ pydantic │
+│ Dependency 4 │ python-jose │
+│ Dependency 5 │ passlib │
+│ Dependency 6 │ python-multipart│
+│ Dependency 7 │ mcp │
+└──────────────┴────────────────┘
+
+Select package manager (pip, uv, pdm, poetry) [uv]: uv
+Do you want to proceed with project creation? [y/N]: y
+
+✨ FastAPI project 'ai-integrated-api' from 'fastapi-mcp' has been created successfully!
+```
+
+
+
+## 第 2 步:项目结构分析
+
+让我们看看生成项目的结构:
+
+```
+ai-integrated-api/
+├── src/
+│ ├── main.py # FastAPI application
+│ ├── auth/
+│ │ ├── __init__.py
+│ │ ├── models.py # Authentication-related data models
+│ │ ├── jwt_handler.py # JWT token processing
+│ │ ├── dependencies.py # Authentication dependencies
+│ │ └── routes.py # Authentication router
+│ ├── mcp/
+│ │ ├── __init__.py
+│ │ ├── server.py # MCP server implementation
+│ │ ├── tools.py # MCP tool definitions
+│ │ └── client.py # MCP client (for testing)
+│ ├── api/
+│ │ ├── __init__.py
+│ │ ├── api.py # API router collection
+│ │ └── routes/
+│ │ ├── items.py # Item management API
+│ │ ├── users.py # User management API
+│ │ └── admin.py # Admin API
+│ ├── schemas/
+│ │ ├── __init__.py
+│ │ ├── auth.py # Authentication schemas
+│ │ ├── users.py # User schemas
+│ │ └── items.py # Item schemas
+│ └── core/
+│ ├── __init__.py
+│ ├── config.py # Configuration
+│ ├── database.py # Database (in-memory)
+│ └── security.py # Security configuration
+└── tests/
+ ├── test_auth.py # Authentication tests
+ ├── test_mcp.py # MCP tests
+ └── test_integration.py # Integration tests
+```
+
+## 第 3 步:实现认证系统
+
+### JWT 令牌处理(`src/auth/jwt_handler.py`)
+
+```python
+from datetime import datetime, timedelta
+from typing import Optional, Dict, Any
+from jose import JWTError, jwt
+from passlib.context import CryptContext
+
+from src.core.config import settings
+
+# 密码哈希处理
+pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
+
+def verify_password(plain_password: str, hashed_password: str) -> bool:
+ """校验密码"""
+ return pwd_context.verify(plain_password, hashed_password)
+
+def get_password_hash(password: str) -> str:
+ """生成密码哈希"""
+ return pwd_context.hash(password)
+
+def create_access_token(data: Dict[str, Any], expires_delta: Optional[timedelta] = None) -> str:
+ """生成访问令牌"""
+ to_encode = data.copy()
+
+ if expires_delta:
+ expire = datetime.utcnow() + expires_delta
+ else:
+ expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
+
+ to_encode.update({"exp": expire, "iat": datetime.utcnow()})
+
+ encoded_jwt = jwt.encode(
+ to_encode,
+ settings.SECRET_KEY,
+ algorithm=settings.ALGORITHM
+ )
+
+ return encoded_jwt
+
+def create_refresh_token(user_id: str) -> str:
+ """生成刷新令牌"""
+ data = {"sub": user_id, "type": "refresh"}
+ expire = datetime.utcnow() + timedelta(days=settings.REFRESH_TOKEN_EXPIRE_DAYS)
+
+ to_encode = data.copy()
+ to_encode.update({"exp": expire, "iat": datetime.utcnow()})
+
+ return jwt.encode(
+ to_encode,
+ settings.SECRET_KEY,
+ algorithm=settings.ALGORITHM
+ )
+
+def decode_token(token: str) -> Optional[Dict[str, Any]]:
+ """解析令牌"""
+ try:
+ payload = jwt.decode(
+ token,
+ settings.SECRET_KEY,
+ algorithms=[settings.ALGORITHM]
+ )
+ return payload
+ except JWTError:
+ return None
+
+def verify_token(token: str, token_type: str = "access") -> Optional[str]:
+ """校验令牌并返回用户 ID"""
+ payload = decode_token(token)
+
+ if not payload:
+ return None
+
+ # 校验令牌类型
+ if token_type == "refresh" and payload.get("type") != "refresh":
+ return None
+
+ user_id = payload.get("sub")
+ if not user_id:
+ return None
+
+ return user_id
+
+class TokenManager:
+ """令牌管理类"""
+
+ def __init__(self):
+ self.blacklisted_tokens = set()
+
+ def blacklist_token(self, token: str):
+ """将令牌加入黑名单"""
+ self.blacklisted_tokens.add(token)
+
+ def is_blacklisted(self, token: str) -> bool:
+ """检查令牌是否在黑名单中"""
+ return token in self.blacklisted_tokens
+
+ def create_token_pair(self, user_id: str, user_role: str) -> Dict[str, str]:
+ """创建访问令牌与刷新令牌对"""
+ access_token_data = {
+ "sub": user_id,
+ "role": user_role,
+ "type": "access"
+ }
+
+ access_token = create_access_token(access_token_data)
+ refresh_token = create_refresh_token(user_id)
+
+ return {
+ "access_token": access_token,
+ "refresh_token": refresh_token,
+ "token_type": "bearer"
+ }
+
+# Global token manager
+token_manager = TokenManager()
+```
+
+### 用户模型与数据库(`src/auth/models.py`)
+
+```python
+from typing import List, Optional, Dict, Any
+from pydantic import BaseModel, EmailStr
+from enum import Enum
+from datetime import datetime
+
+class UserRole(str, Enum):
+ """User roles"""
+ ADMIN = "admin"
+ USER = "user"
+ AI_AGENT = "ai_agent"
+ READONLY = "readonly"
+
+class Permission(str, Enum):
+ """Permissions"""
+ READ_ITEMS = "read:items"
+ WRITE_ITEMS = "write:items"
+ DELETE_ITEMS = "delete:items"
+ MANAGE_USERS = "manage:users"
+ USE_MCP_TOOLS = "use:mcp_tools"
+ ADMIN_MCP = "admin:mcp"
+
+class User(BaseModel):
+ """User model"""
+ id: str
+ email: EmailStr
+ username: str
+ full_name: Optional[str] = None
+ role: UserRole
+ permissions: List[Permission]
+ is_active: bool = True
+ created_at: datetime
+ last_login: Optional[datetime] = None
+ api_key: Optional[str] = None # For MCP client
+
+class UserInDB(User):
+ """User model for database storage"""
+ hashed_password: str
+
+class UserCreate(BaseModel):
+ """User creation schema"""
+ email: EmailStr
+ username: str
+ password: str
+ full_name: Optional[str] = None
+ role: UserRole = UserRole.USER
+
+class UserUpdate(BaseModel):
+ """User update schema"""
+ email: Optional[EmailStr] = None
+ username: Optional[str] = None
+ full_name: Optional[str] = None
+ role: Optional[UserRole] = None
+ is_active: Optional[bool] = None
+
+class LoginRequest(BaseModel):
+ """Login request schema"""
+ username: str
+ password: str
+
+class TokenResponse(BaseModel):
+ """Token response schema"""
+ access_token: str
+ refresh_token: str
+ token_type: str = "bearer"
+ expires_in: int
+ user: User
+
+# 按角色划分的默认权限映射
+ROLE_PERMISSIONS = {
+ UserRole.ADMIN: [
+ Permission.READ_ITEMS,
+ Permission.WRITE_ITEMS,
+ Permission.DELETE_ITEMS,
+ Permission.MANAGE_USERS,
+ Permission.USE_MCP_TOOLS,
+ Permission.ADMIN_MCP
+ ],
+ UserRole.USER: [
+ Permission.READ_ITEMS,
+ Permission.WRITE_ITEMS,
+ Permission.USE_MCP_TOOLS
+ ],
+ UserRole.AI_AGENT: [
+ Permission.READ_ITEMS,
+ Permission.WRITE_ITEMS,
+ Permission.USE_MCP_TOOLS
+ ],
+ UserRole.READONLY: [
+ Permission.READ_ITEMS
+ ]
+}
+
+class UserDatabase:
+ """Memory-based user database"""
+
+ def __init__(self):
+ self.users: Dict[str, UserInDB] = {}
+ self._init_default_users()
+
+ def _init_default_users(self):
+ """Create default users"""
+ from src.auth.jwt_handler import get_password_hash
+ import uuid
+
+ # Admin account
+ admin_id = str(uuid.uuid4())
+ self.users[admin_id] = UserInDB(
+ id=admin_id,
+ email="admin@example.com",
+ username="admin",
+ full_name="System Administrator",
+ role=UserRole.ADMIN,
+ permissions=ROLE_PERMISSIONS[UserRole.ADMIN],
+ hashed_password=get_password_hash("admin123"),
+ created_at=datetime.utcnow(),
+ api_key=str(uuid.uuid4())
+ )
+
+ # AI agent account
+ ai_id = str(uuid.uuid4())
+ self.users[ai_id] = UserInDB(
+ id=ai_id,
+ email="ai@example.com",
+ username="ai_agent",
+ full_name="AI Assistant",
+ role=UserRole.AI_AGENT,
+ permissions=ROLE_PERMISSIONS[UserRole.AI_AGENT],
+ hashed_password=get_password_hash("ai123"),
+ created_at=datetime.utcnow(),
+ api_key=str(uuid.uuid4())
+ )
+
+ def get_user_by_username(self, username: str) -> Optional[UserInDB]:
+ """Get user by username"""
+ return next(
+ (user for user in self.users.values() if user.username == username),
+ None
+ )
+
+ def get_user_by_id(self, user_id: str) -> Optional[UserInDB]:
+ """Get user by ID"""
+ return self.users.get(user_id)
+
+ def get_user_by_api_key(self, api_key: str) -> Optional[UserInDB]:
+ """Get user by API key"""
+ return next(
+ (user for user in self.users.values() if user.api_key == api_key),
+ None
+ )
+
+ def create_user(self, user_create: UserCreate) -> UserInDB:
+ """Create user"""
+ import uuid
+ from src.auth.jwt_handler import get_password_hash
+
+ user_id = str(uuid.uuid4())
+ user = UserInDB(
+ id=user_id,
+ email=user_create.email,
+ username=user_create.username,
+ full_name=user_create.full_name,
+ role=user_create.role,
+ permissions=ROLE_PERMISSIONS[user_create.role],
+ hashed_password=get_password_hash(user_create.password),
+ created_at=datetime.utcnow(),
+ api_key=str(uuid.uuid4())
+ )
+
+ self.users[user_id] = user
+ return user
+
+ def update_user(self, user_id: str, user_update: UserUpdate) -> Optional[UserInDB]:
+ """Update user"""
+ if user_id not in self.users:
+ return None
+
+ user = self.users[user_id]
+ update_data = user_update.dict(exclude_unset=True)
+
+ for field, value in update_data.items():
+ setattr(user, field, value)
+
+ # Update permissions if role changed
+ if "role" in update_data:
+ user.permissions = ROLE_PERMISSIONS[user.role]
+
+ return user
+
+ def update_last_login(self, user_id: str):
+ """Update last login time"""
+ if user_id in self.users:
+ self.users[user_id].last_login = datetime.utcnow()
+
+# Global database instance
+user_db = UserDatabase()
+```
+
+## 第 4 步:实现认证依赖
+
+### 认证依赖(`src/auth/dependencies.py`)
+
+```python
+from typing import Optional, List
+from fastapi import Depends, HTTPException, status, Security
+from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials, APIKeyHeader
+from jose import JWTError
+
+from src.auth.jwt_handler import decode_token, token_manager
+from src.auth.models import User, UserInDB, Permission, user_db
+
+# Security schema
+security = HTTPBearer()
+api_key_header = APIKeyHeader(name="X-API-Key", auto_error=False)
+
+async def get_current_user(
+ credentials: HTTPAuthorizationCredentials = Security(security)
+) -> User:
+ """Get current authenticated user"""
+ credentials_exception = HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Could not validate credentials",
+ headers={"WWW-Authenticate": "Bearer"},
+ )
+
+ try:
+ token = credentials.credentials
+
+ # Check blacklist
+ if token_manager.is_blacklisted(token):
+ raise credentials_exception
+
+ payload = decode_token(token)
+ if payload is None:
+ raise credentials_exception
+
+ user_id: str = payload.get("sub")
+ if user_id is None:
+ raise credentials_exception
+
+ except JWTError:
+ raise credentials_exception
+
+ user = user_db.get_user_by_id(user_id)
+ if user is None:
+ raise credentials_exception
+
+ if not user.is_active:
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
+ detail="Inactive user"
+ )
+
+ return User(**user.dict())
+
+async def get_current_user_by_api_key(
+ api_key: Optional[str] = Security(api_key_header)
+) -> Optional[User]:
+ """Authenticate user by API key"""
+ if not api_key:
+ return None
+
+ user = user_db.get_user_by_api_key(api_key)
+ if not user or not user.is_active:
+ return None
+
+ return User(**user.dict())
+
+async def get_current_user_flexible(
+ token_user: Optional[User] = Depends(get_current_user),
+ api_key_user: Optional[User] = Depends(get_current_user_by_api_key)
+) -> User:
+ """Authenticate user by token or API key (flexible authentication)"""
+ user = token_user or api_key_user
+
+ if not user:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Authentication required"
+ )
+
+ return user
+
+def require_permissions(*required_permissions: Permission):
+ """Dependency requiring specific permissions"""
+ def permission_checker(current_user: User = Depends(get_current_user_flexible)) -> User:
+ for permission in required_permissions:
+ if permission not in current_user.permissions:
+ raise HTTPException(
+ status_code=status.HTTP_403_FORBIDDEN,
+ detail=f"Permission '{permission}' required"
+ )
+ return current_user
+
+ return permission_checker
+
+def require_roles(*required_roles):
+ """Dependency requiring specific roles"""
+ def role_checker(current_user: User = Depends(get_current_user_flexible)) -> User:
+ if current_user.role not in required_roles:
+ raise HTTPException(
+ status_code=status.HTTP_403_FORBIDDEN,
+ detail=f"Role must be one of: {', '.join(required_roles)}"
+ )
+ return current_user
+
+ return role_checker
+
+# Common permission dependencies
+RequireAdmin = require_roles("admin")
+RequireReadItems = require_permissions(Permission.READ_ITEMS)
+RequireWriteItems = require_permissions(Permission.WRITE_ITEMS)
+RequireDeleteItems = require_permissions(Permission.DELETE_ITEMS)
+RequireMCPTools = require_permissions(Permission.USE_MCP_TOOLS)
+RequireAdminMCP = require_permissions(Permission.ADMIN_MCP)
+```
+
+### 认证路由(`src/auth/routes.py`)
+
+```python
+from datetime import timedelta
+from fastapi import APIRouter, Depends, HTTPException, status
+from fastapi.security import OAuth2PasswordRequestForm
+
+from src.auth.models import (
+ User, UserCreate, UserUpdate, LoginRequest, TokenResponse,
+ user_db, UserRole
+)
+from src.auth.jwt_handler import (
+ verify_password, token_manager, verify_token, create_access_token
+)
+from src.auth.dependencies import get_current_user, RequireAdmin
+from src.core.config import settings
+
+router = APIRouter(prefix="/auth", tags=["authentication"])
+
+@router.post("/register", response_model=User)
+async def register_user(user_create: UserCreate):
+ """注册用户"""
+ # 检查用户名是否重复
+ if user_db.get_user_by_username(user_create.username):
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
+ detail="Username already registered"
+ )
+
+ # 第一个用户自动设为管理员
+ if not user_db.users:
+ user_create.role = UserRole.ADMIN
+
+ user = user_db.create_user(user_create)
+ return User(**user.dict())
+
+@router.post("/login", response_model=TokenResponse)
+async def login_user(form_data: OAuth2PasswordRequestForm = Depends()):
+ """用户登录"""
+ user = user_db.get_user_by_username(form_data.username)
+
+ if not user or not verify_password(form_data.password, user.hashed_password):
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Incorrect username or password",
+ headers={"WWW-Authenticate": "Bearer"},
+ )
+
+ if not user.is_active:
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
+ detail="Inactive user"
+ )
+
+ # 生成令牌
+ tokens = token_manager.create_token_pair(user.id, user.role)
+
+ # 更新最后登录时间
+ user_db.update_last_login(user.id)
+
+ return TokenResponse(
+ access_token=tokens["access_token"],
+ refresh_token=tokens["refresh_token"],
+ token_type=tokens["token_type"],
+ expires_in=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60,
+ user=User(**user.dict())
+ )
+
+@router.post("/refresh", response_model=dict)
+async def refresh_token(refresh_token: str):
+ """刷新令牌"""
+ user_id = verify_token(refresh_token, "refresh")
+
+ if not user_id:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Invalid refresh token"
+ )
+
+ user = user_db.get_user_by_id(user_id)
+ if not user or not user.is_active:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="User not found or inactive"
+ )
+
+ # 生成新的令牌对
+ tokens = token_manager.create_token_pair(user.id, user.role)
+
+ return {
+ "access_token": tokens["access_token"],
+ "refresh_token": tokens["refresh_token"],
+ "token_type": tokens["token_type"],
+ "expires_in": settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60
+ }
+
+@router.post("/logout")
+async def logout_user(current_user: User = Depends(get_current_user)):
+ """用户登出"""
+ # 在实际实现中,这里应将令牌加入黑名单
+ return {"message": "Successfully logged out"}
+
+@router.get("/me", response_model=User)
+async def get_current_user_info(current_user: User = Depends(get_current_user)):
+ """获取当前用户信息"""
+ return current_user
+
+@router.put("/me", response_model=User)
+async def update_current_user(
+ user_update: UserUpdate,
+ current_user: User = Depends(get_current_user)
+):
+ """更新当前用户信息"""
+ # 普通用户不能修改角色
+ if user_update.role and current_user.role != UserRole.ADMIN:
+ user_update.role = None
+
+ updated_user = user_db.update_user(current_user.id, user_update)
+ if not updated_user:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="User not found"
+ )
+
+ return User(**updated_user.dict())
+
+@router.get("/users", response_model=list[User])
+async def list_users(admin_user: User = Depends(RequireAdmin)):
+ """获取用户列表(仅管理员)"""
+ return [User(**user.dict()) for user in user_db.users.values()]
+
+@router.post("/users/{user_id}/generate-api-key")
+async def generate_api_key(
+ user_id: str,
+ admin_user: User = Depends(RequireAdmin)
+):
+ """创建用户 API Key(仅管理员)"""
+ import uuid
+
+ user = user_db.get_user_by_id(user_id)
+ if not user:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="User not found"
+ )
+
+ # 生成新的 API Key
+ new_api_key = str(uuid.uuid4())
+ user.api_key = new_api_key
+
+ return {
+ "api_key": new_api_key,
+ "message": "API key generated successfully"
+ }
+```
+
+## 第 5 步:实现 MCP 服务器
+
+### MCP 工具定义(`src/mcp/tools.py`)
+
+```python
+from typing import Dict, Any, List, Optional
+from pydantic import BaseModel, Field
+from enum import Enum
+
+class ToolCategory(str, Enum):
+ """工具分类"""
+ DATA_MANAGEMENT = "data_management"
+ SEARCH = "search"
+ ANALYSIS = "analysis"
+ ADMIN = "admin"
+
+class MCPTool(BaseModel):
+ """MCP 工具定义"""
+ name: str = Field(..., description="工具名称")
+ description: str = Field(..., description="工具说明")
+ category: ToolCategory = Field(..., description="工具分类")
+ parameters: Dict[str, Any] = Field(default_factory=dict, description="参数结构")
+ required_permissions: List[str] = Field(default_factory=list, description="所需权限")
+ examples: List[Dict[str, Any]] = Field(default_factory=list, description="使用示例")
+
+class ToolRegistry:
+ """工具注册表"""
+
+ def __init__(self):
+ self.tools: Dict[str, MCPTool] = {}
+ self._register_default_tools()
+
+ def _register_default_tools(self):
+ """注册默认工具"""
+
+ # 注册创建条目工具
+ self.register_tool(MCPTool(
+ name="create_item",
+ description="Create a new item",
+ category=ToolCategory.DATA_MANAGEMENT,
+ parameters={
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Item name"
+ },
+ "description": {
+ "type": "string",
+ "description": "Item description"
+ },
+ "price": {
+ "type": "number",
+ "description": "Item price",
+ "minimum": 0
+ },
+ "category": {
+ "type": "string",
+ "description": "Item category"
+ }
+ },
+ "required": ["name", "price"]
+ },
+ required_permissions=["write:items"],
+ examples=[
+ {
+ "name": "Notebook",
+ "description": "High-performance gaming notebook",
+ "price": 1500000,
+ "category": "electronics"
+ }
+ ]
+ ))
+
+ # Search item tool
+ self.register_tool(MCPTool(
+ name="search_items",
+ description="Search for items",
+ category=ToolCategory.SEARCH,
+ parameters={
+ "type": "object",
+ "properties": {
+ "query": {
+ "type": "string",
+ "description": "Search query"
+ },
+ "category": {
+ "type": "string",
+ "description": "Category filter"
+ },
+ "min_price": {
+ "type": "number",
+ "description": "Minimum price"
+ },
+ "max_price": {
+ "type": "number",
+ "description": "Maximum price"
+ },
+ "limit": {
+ "type": "integer",
+ "description": "Result count limit",
+ "default": 10,
+ "maximum": 100
+ }
+ },
+ "required": ["query"]
+ },
+ required_permissions=["read:items"],
+ examples=[
+ {
+ "query": "Notebook",
+ "category": "electronics",
+ "max_price": 2000000,
+ "limit": 5
+ }
+ ]
+ ))
+
+ # Analyze item tool
+ self.register_tool(MCPTool(
+ name="analyze_items",
+ description="Analyze item data",
+ category=ToolCategory.ANALYSIS,
+ parameters={
+ "type": "object",
+ "properties": {
+ "analysis_type": {
+ "type": "string",
+ "enum": ["price_distribution", "category_breakdown", "trend_analysis"],
+ "description": "Analysis type"
+ },
+ "date_range": {
+ "type": "object",
+ "properties": {
+ "start_date": {"type": "string", "format": "date"},
+ "end_date": {"type": "string", "format": "date"}
+ },
+ "description": "Analysis period"
+ }
+ },
+ "required": ["analysis_type"]
+ },
+ required_permissions=["read:items"],
+ examples=[
+ {
+ "analysis_type": "price_distribution",
+ "date_range": {
+ "start_date": "2024-01-01",
+ "end_date": "2024-12-31"
+ }
+ }
+ ]
+ ))
+
+ # Manage user tool (admin only)
+ self.register_tool(MCPTool(
+ name="manage_users",
+ description="Manage users",
+ category=ToolCategory.ADMIN,
+ parameters={
+ "type": "object",
+ "properties": {
+ "action": {
+ "type": "string",
+ "enum": ["list", "create", "update", "deactivate"],
+ "description": "Action to perform"
+ },
+ "user_data": {
+ "type": "object",
+ "description": "User data (create/update)"
+ },
+ "user_id": {
+ "type": "string",
+ "description": "User ID (update/deactivate)"
+ }
+ },
+ "required": ["action"]
+ },
+ required_permissions=["manage:users"],
+ examples=[
+ {
+ "action": "list"
+ },
+ {
+ "action": "create",
+ "user_data": {
+ "username": "newuser",
+ "email": "newuser@example.com",
+ "role": "user"
+ }
+ }
+ ]
+ ))
+
+ def register_tool(self, tool: MCPTool):
+ """Register tool"""
+ self.tools[tool.name] = tool
+
+ def get_tool(self, tool_name: str) -> Optional[MCPTool]:
+ """Get tool"""
+ return self.tools.get(tool_name)
+
+ def list_tools(self, user_permissions: List[str] = None) -> List[MCPTool]:
+ """List tools by user permissions"""
+ if user_permissions is None:
+ return list(self.tools.values())
+
+ available_tools = []
+ for tool in self.tools.values():
+ # Check permissions
+ if all(perm in user_permissions for perm in tool.required_permissions):
+ available_tools.append(tool)
+
+ return available_tools
+
+ def get_tools_by_category(self, category: ToolCategory, user_permissions: List[str] = None) -> List[MCPTool]:
+ """List tools by category"""
+ tools = self.list_tools(user_permissions)
+ return [tool for tool in tools if tool.category == category]
+
+# Global tool registry
+tool_registry = ToolRegistry()
+```
+
+### MCP 服务器实现(`src/mcp/server.py`)
+
+```python
+from typing import Dict, Any, List, Optional
+from fastapi import HTTPException, status
+import asyncio
+import json
+
+from src.mcp.tools import tool_registry, ToolCategory
+from src.auth.models import User, Permission
+from src.api.routes.items import ItemCRUD
+from src.auth.models import user_db
+
+class MCPServer:
+ """Model Context Protocol server"""
+
+ def __init__(self):
+ self.item_crud = ItemCRUD()
+ self.active_sessions: Dict[str, Dict[str, Any]] = {}
+
+ async def create_session(self, user: User) -> str:
+ """Create MCP session"""
+ import uuid
+
+ session_id = str(uuid.uuid4())
+ self.active_sessions[session_id] = {
+ "user_id": user.id,
+ "user": user,
+ "created_at": datetime.utcnow(),
+ "context": {},
+ "tool_usage_count": 0,
+ "last_activity": datetime.utcnow()
+ }
+
+ return session_id
+
+ async def get_session(self, session_id: str) -> Optional[Dict[str, Any]]:
+ """Get session"""
+ session = self.active_sessions.get(session_id)
+ if session:
+ session["last_activity"] = datetime.utcnow()
+ return session
+
+ async def close_session(self, session_id: str):
+ """Close session"""
+ if session_id in self.active_sessions:
+ del self.active_sessions[session_id]
+
+ async def list_tools(self, user: User) -> List[Dict[str, Any]]:
+ """List tools available to user"""
+ user_permissions = [perm.value for perm in user.permissions]
+ tools = tool_registry.list_tools(user_permissions)
+
+ return [
+ {
+ "name": tool.name,
+ "description": tool.description,
+ "category": tool.category,
+ "parameters": tool.parameters,
+ "examples": tool.examples
+ }
+ for tool in tools
+ ]
+
+ async def execute_tool(
+ self,
+ tool_name: str,
+ parameters: Dict[str, Any],
+ user: User,
+ session_id: Optional[str] = None
+ ) -> Dict[str, Any]:
+ """Execute tool"""
+
+ # Check if tool exists
+ tool = tool_registry.get_tool(tool_name)
+ if not tool:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail=f"Tool '{tool_name}' not found"
+ )
+
+ # Check permissions
+ user_permissions = [perm.value for perm in user.permissions]
+ for required_perm in tool.required_permissions:
+ if required_perm not in user_permissions:
+ raise HTTPException(
+ status_code=status.HTTP_403_FORBIDDEN,
+ detail=f"Permission '{required_perm}' required for tool '{tool_name}'"
+ )
+
+ # Update session
+ if session_id:
+ session = await self.get_session(session_id)
+ if session:
+ session["tool_usage_count"] += 1
+
+ # Execute tool
+ try:
+ result = await self._execute_tool_logic(tool_name, parameters, user)
+
+ return {
+ "success": True,
+ "tool": tool_name,
+ "result": result,
+ "timestamp": datetime.utcnow().isoformat()
+ }
+
+ except Exception as e:
+ return {
+ "success": False,
+ "tool": tool_name,
+ "error": str(e),
+ "timestamp": datetime.utcnow().isoformat()
+ }
+
+ async def _execute_tool_logic(
+ self,
+ tool_name: str,
+ parameters: Dict[str, Any],
+ user: User
+ ) -> Any:
+ """Execute tool logic"""
+
+ if tool_name == "create_item":
+ return await self._create_item(parameters)
+
+ elif tool_name == "search_items":
+ return await self._search_items(parameters)
+
+ elif tool_name == "analyze_items":
+ return await self._analyze_items(parameters)
+
+ elif tool_name == "manage_users":
+ return await self._manage_users(parameters, user)
+
+ else:
+ raise ValueError(f"Tool '{tool_name}' implementation not found")
+
+ async def _create_item(self, parameters: Dict[str, Any]) -> Dict[str, Any]:
+ """Create item tool implementation"""
+ from src.schemas.items import ItemCreate
+
+ try:
+ item_create = ItemCreate(**parameters)
+ created_item = await self.item_crud.create(item_create)
+
+ return {
+ "action": "create_item",
+ "item": created_item.dict(),
+ "message": f"Item '{created_item.name}' created successfully"
+ }
+ except Exception as e:
+ raise ValueError(f"Failed to create item: {str(e)}")
+
+ async def _search_items(self, parameters: Dict[str, Any]) -> Dict[str, Any]:
+ """Search item tool implementation"""
+ query = parameters.get("query", "")
+ category = parameters.get("category")
+ min_price = parameters.get("min_price")
+ max_price = parameters.get("max_price")
+ limit = parameters.get("limit", 10)
+
+ # Search logic implementation
+ all_items = await self.item_crud.get_all()
+ filtered_items = []
+
+ for item in all_items:
+ # Text search
+ if query.lower() not in item.name.lower() and query.lower() not in (item.description or "").lower():
+ continue
+
+ # Category filter
+ if category and getattr(item, 'category', None) != category:
+ continue
+
+ # Price filter
+ if min_price is not None and item.price < min_price:
+ continue
+ if max_price is not None and item.price > max_price:
+ continue
+
+ filtered_items.append(item)
+
+ # Result limit
+ result_items = filtered_items[:limit]
+
+ return {
+ "action": "search_items",
+ "query": query,
+ "total_found": len(filtered_items),
+ "returned_count": len(result_items),
+ "items": [item.dict() for item in result_items]
+ }
+
+ async def _analyze_items(self, parameters: Dict[str, Any]) -> Dict[str, Any]:
+ """Analyze item tool implementation"""
+ analysis_type = parameters.get("analysis_type")
+ date_range = parameters.get("date_range", {})
+
+ all_items = await self.item_crud.get_all()
+
+ if analysis_type == "price_distribution":
+ prices = [item.price for item in all_items]
+ if not prices:
+ return {"analysis": "price_distribution", "result": "No items found"}
+
+ return {
+ "analysis": "price_distribution",
+ "result": {
+ "total_items": len(prices),
+ "min_price": min(prices),
+ "max_price": max(prices),
+ "average_price": sum(prices) / len(prices),
+ "price_ranges": {
+ "under_100k": len([p for p in prices if p < 100000]),
+ "100k_to_500k": len([p for p in prices if 100000 <= p < 500000]),
+ "500k_to_1m": len([p for p in prices if 500000 <= p < 1000000]),
+ "over_1m": len([p for p in prices if p >= 1000000])
+ }
+ }
+ }
+
+ elif analysis_type == "category_breakdown":
+ categories = {}
+ for item in all_items:
+ category = getattr(item, 'category', 'uncategorized')
+ categories[category] = categories.get(category, 0) + 1
+
+ return {
+ "analysis": "category_breakdown",
+ "result": {
+ "total_categories": len(categories),
+ "categories": categories
+ }
+ }
+
+ else:
+ raise ValueError(f"Unknown analysis type: {analysis_type}")
+
+ async def _manage_users(self, parameters: Dict[str, Any], requesting_user: User) -> Dict[str, Any]:
+ """Manage user tool implementation"""
+ action = parameters.get("action")
+
+ # Check admin permissions
+ if Permission.MANAGE_USERS not in requesting_user.permissions:
+ raise ValueError("Insufficient permissions for user management")
+
+ if action == "list":
+ users = [User(**user.dict()) for user in user_db.users.values()]
+ return {
+ "action": "list_users",
+ "total_users": len(users),
+ "users": [user.dict() for user in users]
+ }
+
+ elif action == "create":
+ user_data = parameters.get("user_data", {})
+ from src.auth.models import UserCreate
+
+ user_create = UserCreate(**user_data)
+ created_user = user_db.create_user(user_create)
+
+ return {
+ "action": "create_user",
+ "user": User(**created_user.dict()).dict(),
+ "message": f"User '{created_user.username}' created successfully"
+ }
+
+ else:
+ raise ValueError(f"Unknown user management action: {action}")
+
+# Global MCP server instance
+mcp_server = MCPServer()
+```
+
+## 第 6 步:实现 MCP API 端点
+
+### MCP API 路由(`src/api/routes/mcp.py`)
+
+```python
+from typing import Dict, Any, Optional
+from fastapi import APIRouter, Depends, HTTPException, status, BackgroundTasks
+from pydantic import BaseModel
+
+from src.auth.dependencies import get_current_user_flexible, RequireMCPTools
+from src.auth.models import User
+from src.mcp.server import mcp_server
+from src.mcp.tools import ToolCategory
+
+router = APIRouter(prefix="/mcp", tags=["MCP"])
+
+class ToolExecuteRequest(BaseModel):
+ """Tool execution request"""
+ tool_name: str
+ parameters: Dict[str, Any]
+ session_id: Optional[str] = None
+
+class SessionCreateResponse(BaseModel):
+ """Session creation response"""
+ session_id: str
+ message: str
+
+@router.post("/session", response_model=SessionCreateResponse)
+async def create_mcp_session(
+ current_user: User = Depends(RequireMCPTools)
+):
+ """Create MCP session"""
+ session_id = await mcp_server.create_session(current_user)
+
+ return SessionCreateResponse(
+ session_id=session_id,
+ message=f"MCP session created (User: {current_user.username})"
+ )
+
+@router.delete("/session/{session_id}")
+async def close_mcp_session(
+ session_id: str,
+ current_user: User = Depends(RequireMCPTools)
+):
+ """Close MCP session"""
+ session = await mcp_server.get_session(session_id)
+
+ if not session:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Session not found"
+ )
+
+ # Check session owner
+ if session["user_id"] != current_user.id:
+ raise HTTPException(
+ status_code=status.HTTP_403_FORBIDDEN,
+ detail="Cannot close another user's session"
+ )
+
+ await mcp_server.close_session(session_id)
+
+ return {"message": "Session closed successfully"}
+
+@router.get("/tools")
+async def list_mcp_tools(
+ category: Optional[ToolCategory] = None,
+ current_user: User = Depends(RequireMCPTools)
+):
+ """List available MCP tools"""
+ tools = await mcp_server.list_tools(current_user)
+
+ if category:
+ tools = [tool for tool in tools if tool["category"] == category]
+
+ return {
+ "user": current_user.username,
+ "total_tools": len(tools),
+ "tools": tools
+ }
+
+@router.post("/execute")
+async def execute_mcp_tool(
+ request: ToolExecuteRequest,
+ background_tasks: BackgroundTasks,
+ current_user: User = Depends(RequireMCPTools)
+):
+ """Execute MCP tool"""
+
+ # Check session (optional)
+ if request.session_id:
+ session = await mcp_server.get_session(request.session_id)
+ if not session:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Session not found"
+ )
+
+ if session["user_id"] != current_user.id:
+ raise HTTPException(
+ status_code=status.HTTP_403_FORBIDDEN,
+ detail="Cannot use another user's session"
+ )
+
+ # Execute tool
+ result = await mcp_server.execute_tool(
+ tool_name=request.tool_name,
+ parameters=request.parameters,
+ user=current_user,
+ session_id=request.session_id
+ )
+
+ # Log tool usage in background
+ background_tasks.add_task(
+ log_tool_usage,
+ current_user.id,
+ request.tool_name,
+ result["success"]
+ )
+
+ return result
+
+@router.get("/sessions")
+async def list_user_sessions(
+ current_user: User = Depends(RequireMCPTools)
+):
+ """List active user sessions"""
+ user_sessions = []
+
+ for session_id, session_data in mcp_server.active_sessions.items():
+ if session_data["user_id"] == current_user.id:
+ user_sessions.append({
+ "session_id": session_id,
+ "created_at": session_data["created_at"],
+ "tool_usage_count": session_data["tool_usage_count"],
+ "last_activity": session_data["last_activity"]
+ })
+
+ return {
+ "user": current_user.username,
+ "active_sessions": len(user_sessions),
+ "sessions": user_sessions
+ }
+
+@router.get("/stats")
+async def get_mcp_stats(
+ current_user: User = Depends(RequireMCPTools)
+):
+ """MCP usage statistics"""
+ total_sessions = len(mcp_server.active_sessions)
+ user_sessions = len([
+ s for s in mcp_server.active_sessions.values()
+ if s["user_id"] == current_user.id
+ ])
+
+ return {
+ "user_stats": {
+ "username": current_user.username,
+ "active_sessions": user_sessions,
+ "permissions": [perm.value for perm in current_user.permissions]
+ },
+ "server_stats": {
+ "total_active_sessions": total_sessions,
+ "available_tools": len(await mcp_server.list_tools(current_user))
+ }
+ }
+
+async def log_tool_usage(user_id: str, tool_name: str, success: bool):
+ """Log tool usage (background job)"""
+ import logging
+
+ logger = logging.getLogger("mcp.usage")
+ logger.info(
+ f"Tool usage - User: {user_id}, Tool: {tool_name}, Success: {success}"
+ )
+```
+
+## 第 7 步:应用集成与测试
+
+### 主应用(`src/main.py`)
+
+```python
+from fastapi import FastAPI
+from fastapi.middleware.cors import CORSMiddleware
+
+from src.auth.routes import router as auth_router
+from src.api.routes.items import router as items_router
+from src.api.routes.mcp import router as mcp_router
+from src.core.config import settings
+
+app = FastAPI(
+ title="AI Integrated API",
+ description="AI model integrated MCP-based API server",
+ version="1.0.0"
+)
+
+# CORS settings
+app.add_middleware(
+ CORSMiddleware,
+ allow_origins=settings.ALLOWED_HOSTS,
+ allow_credentials=True,
+ allow_methods=["*"],
+ allow_headers=["*"],
+)
+
+# Include routers
+app.include_router(auth_router)
+app.include_router(items_router, prefix="/api/v1")
+app.include_router(mcp_router, prefix="/api/v1")
+
+@app.get("/")
+async def root():
+ return {
+ "message": "AI Integrated API with MCP Support",
+ "version": "1.0.0",
+ "endpoints": {
+ "authentication": "/auth",
+ "items": "/api/v1/items",
+ "mcp": "/api/v1/mcp",
+ "docs": "/docs"
+ }
+ }
+
+@app.get("/health")
+async def health_check():
+ """Health check endpoint"""
+ return {
+ "status": "healthy",
+ "version": "1.0.0",
+ "services": {
+ "auth": "operational",
+ "mcp": "operational",
+ "database": "operational"
+ }
+ }
+```
+
+### 启动服务器并测试
+
+
+
+```console
+$ cd ai-integrated-api
+$ fastkit runserver
+Starting FastAPI server at 127.0.0.1:8000...
+
+# User login
+$ curl -X POST "http://localhost:8000/auth/login" \
+ -H "Content-Type: application/x-www-form-urlencoded" \
+ -d "username=admin&password=admin123"
+
+{
+ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
+ "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
+ "token_type": "bearer",
+ "expires_in": 1800,
+ "user": {
+ "id": "123e4567-e89b-12d3-a456-426614174000",
+ "email": "admin@example.com",
+ "username": "admin",
+ "role": "admin",
+ "permissions": ["read:items", "write:items", ...]
+ }
+}
+
+# Create MCP session
+$ curl -X POST "http://localhost:8000/api/v1/mcp/session" \
+ -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
+
+{
+ "session_id": "abc123-def456-ghi789",
+ "message": "MCP session created (User: admin)"
+}
+
+# List available tools
+$ curl "http://localhost:8000/api/v1/mcp/tools" \
+ -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
+
+{
+ "user": "admin",
+ "total_tools": 4,
+ "tools": [
+ {
+ "name": "create_item",
+ "description": "Create a new item",
+ "category": "data_management",
+ "parameters": {...},
+ "examples": [...]
+ },
+ ...
+ ]
+}
+
+# Execute MCP tool (create item)
+$ curl -X POST "http://localhost:8000/api/v1/mcp/execute" \
+ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "tool_name": "create_item",
+ "parameters": {
+ "name": "AI generated item",
+ "description": "MCP through AI generated item",
+ "price": 500000,
+ "category": "ai_generated"
+ },
+ "session_id": "abc123-def456-ghi789"
+ }'
+
+{
+ "success": true,
+ "tool": "create_item",
+ "result": {
+ "action": "create_item",
+ "item": {
+ "id": 1,
+ "name": "AI generated item",
+ "description": "MCP through AI generated item",
+ "price": 500000,
+ "category": "ai_generated",
+ "created_at": "2024-01-01T12:00:00Z"
+ },
+ "message": "Item 'AI generated item' created successfully"
+ },
+ "timestamp": "2024-01-01T12:00:00.123456Z"
+}
+
+# Execute MCP tool (search item)
+$ curl -X POST "http://localhost:8000/api/v1/mcp/execute" \
+ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "tool_name": "search_items",
+ "parameters": {
+ "query": "AI",
+ "limit": 5
+ }
+ }'
+```
+
+
+
+## 第 8 步:AI 客户端示例
+
+### Python MCP 客户端示例
+
+```python
+# client_example.py
+import asyncio
+import aiohttp
+from typing import Dict, Any, List
+
+class MCPClient:
+ """MCP client example"""
+
+ def __init__(self, base_url: str, api_key: str):
+ self.base_url = base_url
+ self.api_key = api_key
+ self.session_id = None
+ self.session = None
+
+ async def __aenter__(self):
+ self.session = aiohttp.ClientSession(
+ headers={"X-API-Key": self.api_key}
+ )
+ return self
+
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
+ if self.session_id:
+ await self.close_session()
+ if self.session:
+ await self.session.close()
+
+ async def create_session(self) -> str:
+ """Create MCP session"""
+ async with self.session.post(f"{self.base_url}/api/v1/mcp/session") as resp:
+ data = await resp.json()
+ self.session_id = data["session_id"]
+ return self.session_id
+
+ async def close_session(self):
+ """Close MCP session"""
+ if self.session_id:
+ async with self.session.delete(f"{self.base_url}/api/v1/mcp/session/{self.session_id}"):
+ pass
+ self.session_id = None
+
+ async def list_tools(self) -> List[Dict[str, Any]]:
+ """List available tools"""
+ async with self.session.get(f"{self.base_url}/api/v1/mcp/tools") as resp:
+ data = await resp.json()
+ return data["tools"]
+
+ async def execute_tool(self, tool_name: str, parameters: Dict[str, Any]) -> Dict[str, Any]:
+ """Execute tool"""
+ payload = {
+ "tool_name": tool_name,
+ "parameters": parameters,
+ "session_id": self.session_id
+ }
+
+ async with self.session.post(
+ f"{self.base_url}/api/v1/mcp/execute",
+ json=payload
+ ) as resp:
+ return await resp.json()
+
+ async def ai_assistant_workflow(self, user_request: str) -> str:
+ """模拟 AI 助手工作流"""
+
+ # 1. 创建会话
+ await self.create_session()
+ print(f"Session created: {self.session_id}")
+
+ # 2. 分析用户请求并选择合适的工具
+ if "Create item" in user_request or "Create" in user_request:
+ # 处理创建 item 的请求
+ result = await self.execute_tool("create_item", {
+ "name": "AI recommended item",
+ "description": "AI generated item based on user request",
+ "price": 100000,
+ "category": "ai_recommended"
+ })
+
+ if result["success"]:
+ item_name = result["result"]["item"]["name"]
+ return f"✅ '{item_name}' item created successfully!"
+ else:
+ return f"❌ Item creation failed: {result.get('error', 'Unknown error')}"
+
+ elif "Search" in user_request or "Find" in user_request:
+ # Search request
+ search_query = "Item" # Actually extracted from NLP
+ result = await self.execute_tool("search_items", {
+ "query": search_query,
+ "limit": 5
+ })
+
+ if result["success"]:
+ items = result["result"]["items"]
+ item_list = "\n".join([f"- {item['name']} (₩{item['price']:,})" for item in items])
+ return f"🔍 Search results ({len(items)} items):\n{item_list}"
+ else:
+ return f"❌ Search failed: {result.get('error', 'Unknown error')}"
+
+ elif "Analyze" in user_request:
+ # Analyze request
+ result = await self.execute_tool("analyze_items", {
+ "analysis_type": "price_distribution"
+ })
+
+ if result["success"]:
+ analysis = result["result"]["result"]
+ return f"📊 Price analysis:\nAverage price: ₩{analysis['average_price']:,.0f}\nMinimum: ₩{analysis['min_price']:,} - Maximum: ₩{analysis['max_price']:,}"
+ else:
+ return f"❌ Analysis failed: {result.get('error', 'Unknown error')}"
+
+ else:
+ return "Sorry, I couldn't find a tool to handle that request."
+
+async def main():
+ """Client test"""
+ async with MCPClient("http://localhost:8000", "your-api-key-here") as client:
+
+ # List available tools
+ tools = await client.list_tools()
+ print(f"Available tools: {len(tools)}")
+ for tool in tools:
+ print(f"- {tool['name']}: {tool['description']}")
+
+ print("\n" + "="*50 + "\n")
+
+ # AI assistant simulation
+ test_requests = [
+ "Create a new item",
+ "Search for items",
+ "Analyze price distribution"
+ ]
+
+ for request in test_requests:
+ print(f"User request: {request}")
+ response = await client.ai_assistant_workflow(request)
+ print(f"AI response: {response}")
+ print("-" * 30)
+
+if __name__ == "__main__":
+ asyncio.run(main())
+```
+
+
+
+
+
+## 小结
+
+在本教程中,我们实现了 MCP(Model Context Protocol)集成,包括:
+
+- ✅ 构建基于 JWT 的认证体系
+- ✅ 实现基于角色的访问控制(RBAC)
+- ✅ 实现 MCP 服务器与工具系统
+- ✅ 基于会话的上下文管理
+- ✅ 与 AI 模型间的安全 API 通信
+- ✅ 工具权限管理与使用追踪
+- ✅ 实际可用的 AI 客户端示例
+
+现在您可以构建一个完整的基于 MCP 的系统,让 AI 模型能够安全、高效地使用 API 能力!
diff --git a/docs/zh/user-guide/adding-routes.md b/docs/zh/user-guide/adding-routes.md
new file mode 100644
index 0000000..e54880c
--- /dev/null
+++ b/docs/zh/user-guide/adding-routes.md
@@ -0,0 +1,581 @@
+# 添加路由
+
+学习如何向已有的 FastAPI 项目添加新的 API 路由。
+
+## 基本的路由添加
+
+### 使用 `addroute` 命令
+
+FastAPI-fastkit 的 `addroute` 命令让添加新路由变得很简单:
+
+
+
+```console
+$ fastkit addroute users my-awesome-api
+ Adding New Route
+┌──────────────────┬──────────────────────────────────────────┐
+│ Project │ my-awesome-api │
+│ Route Name │ users │
+│ Target Directory │ ~/my-awesome-api │
+└──────────────────┴──────────────────────────────────────────┘
+
+Do you want to add route 'users' to project 'my-awesome-api'? [Y/n]: y
+
+╭──────────────────────── Info ────────────────────────╮
+│ ℹ Updated main.py to include the API router │
+╰──────────────────────────────────────────────────────╯
+╭─────────────────────── Success ───────────────────────╮
+│ ✨ Successfully added new route 'users' to project │
+│ `my-awesome-api` │
+╰───────────────────────────────────────────────────────╯
+```
+
+
+
+## 会生成什么
+
+当您添加一个路由时,FastAPI-fastkit 会自动创建:
+
+### 1. 路由文件:`src/api/routes/users.py`
+
+```python
+from typing import List
+from fastapi import APIRouter, HTTPException, status
+from src.schemas.users import User, UserCreate, UserUpdate
+from src.crud.users import users_crud
+
+router = APIRouter()
+
+@router.get("/", response_model=List[User])
+def read_users():
+ """获取所有用户"""
+ return users_crud.get_all()
+
+@router.post("/", response_model=User, status_code=status.HTTP_201_CREATED)
+def create_user(user: UserCreate):
+ """创建新用户"""
+ return users_crud.create(user)
+
+@router.get("/{user_id}", response_model=User)
+def read_user(user_id: int):
+ """获取指定用户"""
+ user = users_crud.get_by_id(user_id)
+ if user is None:
+ raise HTTPException(status_code=404, detail="User not found")
+ return user
+
+@router.put("/{user_id}", response_model=User)
+def update_user(user_id: int, user: UserUpdate):
+ """更新用户"""
+ updated_user = users_crud.update(user_id, user)
+ if updated_user is None:
+ raise HTTPException(status_code=404, detail="User not found")
+ return updated_user
+
+@router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
+def delete_user(user_id: int):
+ """删除用户"""
+ success = users_crud.delete(user_id)
+ if not success:
+ raise HTTPException(status_code=404, detail="User not found")
+```
+
+### 2. CRUD 操作:`src/crud/users.py`
+
+```python
+from typing import List, Optional
+from src.schemas.users import User, UserCreate, UserUpdate
+
+class UsersCRUD:
+ def __init__(self):
+ self._users: List[User] = []
+ self._next_id = 1
+
+ def get_all(self) -> List[User]:
+ """获取所有用户"""
+ return self._users
+
+ def get_by_id(self, user_id: int) -> Optional[User]:
+ """根据 ID 获取用户"""
+ return next((user for user in self._users if user.id == user_id), None)
+
+ def create(self, user: UserCreate) -> User:
+ """创建新用户"""
+ new_user = User(
+ id=self._next_id,
+ title=user.title,
+ description=user.description
+ )
+ self._next_id += 1
+ self._users.append(new_user)
+ return new_user
+
+ def update(self, user_id: int, user: UserUpdate) -> Optional[User]:
+ """更新已有用户"""
+ existing_user = self.get_by_id(user_id)
+ if existing_user:
+ update_data = user.dict(exclude_unset=True)
+ for field, value in update_data.items():
+ setattr(existing_user, field, value)
+ return existing_user
+ return None
+
+ def delete(self, user_id: int) -> bool:
+ """删除用户"""
+ user = self.get_by_id(user_id)
+ if user:
+ self._users.remove(user)
+ return True
+ return False
+
+users_crud = UsersCRUD()
+```
+
+### 3. Pydantic 模式:`src/schemas/users.py`
+
+```python
+from typing import Optional
+from pydantic import BaseModel
+
+class UserBase(BaseModel):
+ title: str
+ description: Optional[str] = None
+
+class UserCreate(UserBase):
+ pass
+
+class UserUpdate(BaseModel):
+ title: Optional[str] = None
+ description: Optional[str] = None
+
+class User(UserBase):
+ id: int
+
+ class Config:
+ from_attributes = True
+```
+
+### 4. 注册路由
+
+该命令会自动更新 `src/api/api.py`,把新路由器纳入其中:
+
+```python
+from fastapi import APIRouter
+from src.api.routes import items, users
+
+api_router = APIRouter()
+
+api_router.include_router(items.router, prefix="/items", tags=["items"])
+api_router.include_router(users.router, prefix="/users", tags=["users"])
+```
+
+## 生成的 API 端点
+
+添加 `users` 路由后,您将拥有以下端点:
+
+| 方法 | 端点 | 描述 |
+|--------|----------|-------------|
+| `GET` | `/api/v1/users/` | 获取所有用户 |
+| `POST` | `/api/v1/users/` | 创建新用户 |
+| `GET` | `/api/v1/users/{user_id}` | 获取指定用户 |
+| `PUT` | `/api/v1/users/{user_id}` | 更新用户 |
+| `DELETE` | `/api/v1/users/{user_id}` | 删除用户 |
+
+## 测试新路由
+
+### 1. 启动服务器
+
+
+
+```console
+$ fastkit runserver
+INFO: Uvicorn running on http://127.0.0.1:8000
+```
+
+
+
+### 2. 查看 API 文档
+
+访问 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs),在交互式文档中查看新端点。
+
+### 3. 使用 curl 测试
+
+**创建用户:**
+
+
+```console
+$ curl -X POST "http://127.0.0.1:8000/api/v1/users/" \
+ -H "Content-Type: application/json" \
+ -d '{"title": "John Doe", "description": "Software Developer"}'
+
+{
+ "id": 1,
+ "title": "John Doe",
+ "description": "Software Developer"
+}
+```
+
+
+
+**获取所有用户:**
+
+
+```console
+$ curl http://127.0.0.1:8000/api/v1/users/
+
+[
+ {
+ "id": 1,
+ "title": "John Doe",
+ "description": "Software Developer"
+ }
+]
+```
+
+
+
+**获取指定用户:**
+
+
+```console
+$ curl http://127.0.0.1:8000/api/v1/users/1
+
+{
+ "id": 1,
+ "title": "John Doe",
+ "description": "Software Developer"
+}
+```
+
+
+
+## 定制生成的代码
+
+生成出来的代码可以完全按需定制。下面是一些常见的扩展方式:
+
+### 1. 扩展的用户模式
+
+修改 `src/schemas/users.py`,加入更贴近真实场景的字段:
+
+```python
+from typing import Optional
+from datetime import datetime
+from pydantic import BaseModel, EmailStr, Field
+
+class UserBase(BaseModel):
+ email: EmailStr
+ username: str = Field(..., min_length=3, max_length=50)
+ full_name: Optional[str] = None
+ is_active: bool = True
+
+class UserCreate(UserBase):
+ password: str = Field(..., min_length=8)
+
+class UserUpdate(BaseModel):
+ email: Optional[EmailStr] = None
+ username: Optional[str] = Field(None, min_length=3, max_length=50)
+ full_name: Optional[str] = None
+ is_active: Optional[bool] = None
+
+class User(UserBase):
+ id: int
+ created_at: datetime
+
+ class Config:
+ from_attributes = True
+
+class UserInDB(User):
+ hashed_password: str
+```
+
+### 2. 增强 CRUD,加入校验
+
+更新 `src/crud/users.py`,加入更完善的校验:
+
+```python
+from typing import List, Optional
+from datetime import datetime
+import hashlib
+from src.schemas.users import UserCreate, UserUpdate, UserInDB
+
+class UsersCRUD:
+ def __init__(self):
+ self._users: List[UserInDB] = []
+ self._next_id = 1
+
+ def _hash_password(self, password: str) -> str:
+ """简单的密码哈希示例(生产环境请使用 bcrypt)"""
+ return hashlib.sha256(password.encode()).hexdigest()
+
+ def get_by_email(self, email: str) -> Optional[UserInDB]:
+ """根据邮箱获取用户"""
+ return next((user for user in self._users if user.email == email), None)
+
+ def get_by_username(self, username: str) -> Optional[UserInDB]:
+ """根据用户名获取用户"""
+ return next((user for user in self._users if user.username == username), None)
+
+ def create(self, user: UserCreate) -> UserInDB:
+ """带校验地创建新用户"""
+ # 检查是否存在重复用户
+ if self.get_by_email(user.email):
+ raise ValueError("Email already registered")
+ if self.get_by_username(user.username):
+ raise ValueError("Username already taken")
+
+ new_user = UserInDB(
+ id=self._next_id,
+ email=user.email,
+ username=user.username,
+ full_name=user.full_name,
+ is_active=user.is_active,
+ created_at=datetime.now(),
+ hashed_password=self._hash_password(user.password)
+ )
+ self._next_id += 1
+ self._users.append(new_user)
+ return new_user
+
+users_crud = UsersCRUD()
+```
+
+### 3. 加入错误处理的路由
+
+更新 `src/api/routes/users.py`,加入更完善的错误处理:
+
+```python
+from typing import List
+from fastapi import APIRouter, HTTPException, status
+from src.schemas.users import User, UserCreate, UserUpdate
+from src.crud.users import users_crud
+
+router = APIRouter()
+
+@router.post("/", response_model=User, status_code=status.HTTP_201_CREATED)
+def create_user(user: UserCreate):
+ """创建新用户"""
+ try:
+ new_user = users_crud.create(user)
+ # 返回时去掉密码哈希
+ return User(**new_user.dict())
+ except ValueError as e:
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
+ detail=str(e)
+ )
+
+@router.get("/{user_id}", response_model=User)
+def read_user(user_id: int):
+ """获取指定用户"""
+ user = users_crud.get_by_id(user_id)
+ if not user:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail=f"User with id {user_id} not found"
+ )
+ return User(**user.dict())
+```
+
+## 同时添加多个路由
+
+您可以连续添加多个路由,构建一个完整的 API:
+
+
+
+```console
+# 添加更多资源路由(先写路由名,再写项目目录)
+$ fastkit addroute products my-awesome-api
+$ fastkit addroute orders my-awesome-api
+$ fastkit addroute categories my-awesome-api
+
+# 每条命令都会生成一整套 CRUD 结构
+```
+
+
+
+由此可获得一个更完整的 API:
+
+- `/api/v1/users/` —— 用户管理
+- `/api/v1/products/` —— 商品目录
+- `/api/v1/orders/` —— 订单处理
+- `/api/v1/categories/` —— 类目管理
+
+## 路由组织
+
+### 按相关性分组端点
+
+可按领域组织路由:
+
+```python
+# src/api/api.py
+from fastapi import APIRouter
+from src.api.routes import users, products, orders, categories
+
+api_router = APIRouter()
+
+# 用户管理
+api_router.include_router(
+ users.router,
+ prefix="/users",
+ tags=["User Management"]
+)
+
+# 电商相关
+api_router.include_router(
+ products.router,
+ prefix="/products",
+ tags=["E-commerce"]
+)
+api_router.include_router(
+ orders.router,
+ prefix="/orders",
+ tags=["E-commerce"]
+)
+api_router.include_router(
+ categories.router,
+ prefix="/categories",
+ tags=["E-commerce"]
+)
+```
+
+### 为路由添加依赖
+
+为路由添加认证或其他依赖:
+
+```python
+from fastapi import APIRouter, Depends
+from src.core.auth import get_current_user
+
+router = APIRouter()
+
+@router.get("/profile", response_model=User)
+def get_user_profile(current_user: User = Depends(get_current_user)):
+ """获取当前用户的个人资料"""
+ return current_user
+
+@router.post("/", response_model=User)
+def create_user(
+ user: UserCreate,
+ current_user: User = Depends(get_current_user)
+):
+ """创建新用户(仅限管理员)"""
+ if not current_user.is_admin:
+ raise HTTPException(status_code=403, detail="Admin access required")
+ return users_crud.create(user)
+```
+
+## 最佳实践
+
+### 1. 命名一致
+
+遵循一致的命名约定:
+
+- **路由名称**:使用复数名词(`users`、`products`、`orders`)
+- **模式名称**:使用单数(`User`、`Product`、`Order`)
+- **CRUD 类**:以 `CRUD` 结尾(`UsersCRUD`、`ProductsCRUD`)
+
+### 2. 错误处理
+
+始终优雅地处理错误:
+
+```python
+@router.post("/", response_model=User)
+def create_user(user: UserCreate):
+ try:
+ return users_crud.create(user)
+ except ValueError as e:
+ raise HTTPException(status_code=400, detail=str(e))
+ except Exception as e:
+ raise HTTPException(status_code=500, detail="Internal server error")
+```
+
+### 3. 文档
+
+建议为接口补充清晰的 docstring:
+
+```python
+@router.get("/{user_id}", response_model=User)
+def read_user(user_id: int):
+ """
+ 根据 ID 获取指定用户。
+
+ Args:
+ user_id:用户的唯一标识
+
+ Returns:
+ User:包含完整信息的用户对象
+
+ Raises:
+ HTTPException:当用户不存在时返回 404
+ """
+ user = users_crud.get_by_id(user_id)
+ if not user:
+ raise HTTPException(status_code=404, detail="User not found")
+ return user
+```
+
+### 4. 测试
+
+始终为新路由编写测试:
+
+```python
+# tests/test_users.py
+from fastapi.testclient import TestClient
+from src.main import app
+
+client = TestClient(app)
+
+def test_create_user():
+ user_data = {
+ "email": "test@example.com",
+ "username": "testuser",
+ "password": "securepassword123"
+ }
+ response = client.post("/api/v1/users/", json=user_data)
+ assert response.status_code == 201
+ assert response.json()["email"] == user_data["email"]
+
+def test_get_user():
+ response = client.get("/api/v1/users/1")
+ assert response.status_code == 200
+```
+
+## 故障排查
+
+### 路由未出现
+
+如果您的路由没有出现在 API 文档中:
+
+1. **检查路由器是否在 `src/api/api.py` 中注册**
+2. **添加路由后重启服务器**
+3. **检查路由文件中的导入错误**
+
+### 导入错误
+
+如果出现导入错误:
+
+1. **核对文件结构是否符合预期布局**
+2. **检查路由文件与 CRUD 文件中的模式导入**
+3. **确保所有 `__init__.py` 文件都存在**
+
+### 服务器无法启动
+
+如果添加路由后服务器无法启动:
+
+1. **检查生成文件是否存在语法错误**
+2. **检查文件之间的模式是否兼容**
+3. **查看日志获取具体的错误信息**
+
+## 下一步
+
+学会添加路由后:
+
+1. **[您的第一个项目](../tutorial/first-project.md)**:构建完整的博客 API
+2. **[CLI 参考](cli-reference.md)**:学习所有可用命令
+3. **[使用模板](using-templates.md)**:探索预构建的项目模板
+
+!!! tip "路由开发小贴士"
+ - 始终在交互式文档(`/docs`)中测试新路由
+ - 使用合适的 HTTP 状态码
+ - 为所有端点实现完善的错误处理
+ - 让路由处理器保持简单,把业务逻辑委托给 CRUD 类
diff --git a/docs/zh/user-guide/choosing-a-starter.md b/docs/zh/user-guide/choosing-a-starter.md
new file mode 100644
index 0000000..29b3a46
--- /dev/null
+++ b/docs/zh/user-guide/choosing-a-starter.md
@@ -0,0 +1,145 @@
+# 应该选择哪个 starter?
+
+FastAPI-fastkit 提供了多种项目起步方式。本页是一份**面向新手的选型指南**:先在这里决定路线,再跳转到 [快速上手](quick-start.md) 实际创建项目。
+
+如果您拿不定主意,最简短的建议是:
+
+> **从 `fastkit init --interactive` 开始,并选择 `domain-starter` 预设。** 它是现代 API 项目的推荐默认选项。
+
+下面会进一步解释为什么这样推荐,以及在哪些情况下更适合选择其他方案。
+
+## TL;DR —— 按用户类型选择
+
+| 您的情况 | 起点 |
+|---|---|
+| 刚接触 FastAPI,想要引导式上手 | `fastkit init --interactive`(预设:**`domain-starter`**) |
+| 想要一个可运行的 CRUD 示例来阅读与修改 | `fastkit startdemo fastapi-default` |
+| 想要尽可能小的骨架 | `fastkit init --interactive`(预设:**`minimal`**) |
+| 编写快速原型 / 单文件脚本 | `fastkit init --interactive`(预设:**`single-module`**) |
+| 需要真实的数据库(PostgreSQL + SQLAlchemy + Alembic) | `fastkit startdemo fastapi-psql-orm` |
+| 想要面向中型 API 的生产风格领域布局 | `fastkit init --interactive`(预设:**`domain-starter`**) |
+
+## `startdemo` 与 `init --interactive` —— 有什么区别?
+
+这是两个主要入口,分别面向不同的使用需求。
+
+### `fastkit startdemo `
+
+它会基于内置模板(`fastapi-default`、`fastapi-async-crud`、`fastapi-psql-orm`、`fastapi-domain-starter` 等)直接生成一个**完整、可运行的示例项目**。模板源码会原样复制,并自动填充 `` 等元数据占位符。
+
+- ✅ 这是拿到可运行 demo 的最快方式。
+- ✅ 代码完整可读,非常适合通过示例学习。
+- ❌ 模板的技术栈与结构是固定的;您无法在生成过程中只保留 CORS、去掉认证等组件。
+
+```console
+$ fastkit list-templates # 查看可用模板
+$ fastkit startdemo fastapi-default # 基于某个模板生成项目
+```
+
+### `fastkit init --interactive`
+
+它会通过一个 **引导式向导** 带您依次完成:项目元数据 → 架构预设 → 功能选择(数据库、认证、测试、部署等)→ 包管理器 → 最终确认。生成器会根据预设挑选合适的基础模板,再叠加您选中的功能。
+
+- ✅ 您可以组合出更贴近自身需求的技术栈。
+- ✅ 架构预设会直接决定项目布局(单文件、分层、领域驱动等)。
+- ❌ 对于保留自带 `main.py` 的较完整预设(`classic-layered`、`domain-starter`),工具会生成配置模块,但仍需要您手动接入到已有路由中。具体契约请参阅 [架构预设矩阵](../reference/preset-feature-matrix.md)。
+
+```console
+$ fastkit init --interactive
+```
+
+## 四种架构预设
+
+它们会在 `fastkit init --interactive` 收集完项目信息后出现。请根据本节决定选哪一个。
+
+### `minimal` —— 从最简单开始,后续再扩展
+
+最小可行的 FastAPI 应用。空骨架 + 一个根据您的功能开关重新生成的 `src/main.py`。若您选择了 CORS、限流、Prometheus 监控,会自动接入到 `main.py`。
+
+- 👤 **适合谁**:希望自己在项目成长过程中逐步加入结构的人,或者想在不预设布局观念的情况下探索 FastAPI 的人。
+- 📦 **基础模板**:`fastapi-empty`。
+- 🧠 **心智模型**:“先给我一个能跑起来的 FastAPI 文件,其余部分我自己来决定。”
+
+### `single-module` —— 脚本风格的原型
+
+一切都放在一个模块里。`main.py` 的重新生成方式与 `minimal` 相同。
+
+- 👤 **适合谁**:编写一个粘合脚本、一个小型 webhook 或一天就能写完的原型,不需要包级别的划分。
+- 📦 **基础模板**:`fastapi-single-module`。
+- 🧠 **心智模型**:“我想要一个坐下来就能跑、也能一次读完的 Python 文件。”
+
+### `classic-layered` —— 分层布局(api / crud / schemas / core)
+
+这是一种带有 “Django 风味” 的布局 —— 按关注点横向拆分:所有路由放在 `api/`,所有 CRUD 逻辑放在 `crud/`,所有 Pydantic 模式放在 `schemas/`,所有配置放在 `core/`。自带的 `main.py` 会**保留**(其中已经接入了 CORS);生成的数据库 / 认证配置会写入 `src/core/`。
+
+- 👤 **适合谁**:熟悉 Django/Rails 风格布局的团队,或者拥有大量小型端点、共享 CRUD 底座的项目。
+- 📦 **基础模板**:`fastapi-default`。
+- 🧠 **心智模型**:“按代码 _是什么_ 来拆分。”
+
+### `domain-starter` —— 领域驱动(推荐默认)
+
+代码按 **业务概念** 纵向切分:每个领域在 `src/app/domains//` 下拥有自己的路由、service、repository 与 schemas。自带一个 `/health` 端点,以及一个 `items` 示例领域,您可以复制并重命名以创建新的概念。自带的 `main.py`(位于 `src/app/`)会保留;生成的配置落在 `src/app/core/`。
+
+- 👤 **适合谁**:适用于包含多个独立业务概念(users、orders、billing 等)的中型 API。也是当前推荐的现代默认选项。
+- 📦 **基础模板**:`fastapi-domain-starter`。
+- 🧠 **心智模型**:“按代码 _为业务做什么_ 来拆分。”
+
+## 对比矩阵
+
+下面是一眼就能看明白的并列对比。
+
+| | `minimal` | `single-module` | `classic-layered` | `domain-starter` |
+|---|---|---|---|---|
+| 基础模板 | `fastapi-empty` | `fastapi-single-module` | `fastapi-default` | `fastapi-domain-starter` |
+| 项目入口 | `src/main.py` | `src/main.py` | `src/main.py` | `src/app/main.py` |
+| 路由位置 | (您自行添加) | (在 `main.py` 内) | `src/api/routes/` | `src/app/domains//router.py` |
+| 每领域文件夹 | ❌ | ❌ | ❌ | ✅ |
+| 内置 `/health` 端点 | ✅ | ✅ | ❌ | ✅ |
+| 根据功能重新生成 `main.py` | ✅ | ✅ | ❌ | ❌ |
+| `main.py` 中已接入 CORS | 选中后自动加入 | 选中后自动加入 | 是(由环境变量驱动) | 是(由环境变量驱动) |
+| pyproject-first | 可选 | 可选 | 可选 | ✅ |
+| 最适合 | “结构由我后续添加” | “单文件原型” | “按关注点切分” | “按业务概念切分” |
+
+要查看每个功能的完整契约(数据库 / 认证配置会生成到哪里、哪些选择需要手动接入、哪些会触发警告),请参阅 [架构预设矩阵](../reference/preset-feature-matrix.md)。
+
+## 选择 `startdemo` 模板
+
+如果您更想要一个**完整、可运行的示例项目**,而不是一步步引导式拼装,那 `fastkit startdemo ` 会更适合。大多数模板都大致对应上面的四种预设之一,但还额外附带了示例代码(如基于 mock 存储的 CRUD 端点、自定义响应处理、Docker 配置等)。
+
+| 模板 | 最接近的预设 | 何时选择 |
+|---|---|---|
+| `fastapi-default` | `classic-layered` | 带分层布局的可运行 CRUD 示例。一个不错的起点。 |
+| `fastapi-empty` | `minimal` | 裸骨架;与 `minimal` 落地后的形态相同。 |
+| `fastapi-single-module` | `single-module` | 单文件示例。 |
+| `fastapi-domain-starter` | `domain-starter` | 推荐的现代默认选项;自带 items 示例领域。 |
+| `fastapi-async-crud` | `classic-layered` | `fastapi-default` 的异步版本。 |
+| `fastapi-custom-response` | `classic-layered` | 演示自定义响应包装 / 格式化。 |
+| `fastapi-dockerized` | `classic-layered` | 在默认布局之上加入生产级 Dockerfile。 |
+| `fastapi-psql-orm` | (无直接对应预设) | PostgreSQL + SQLAlchemy + Alembic。需要真实数据库时选它。 |
+| `fastapi-mcp` | (无直接对应预设) | Model Context Protocol 集成。 |
+
+`fastkit list-templates` 会显示当前可用模板及其一行说明。
+
+## 常见问题
+
+**Q. 是否需要在一开始就选定预设 / 模板?**
+不用 —— 之后您仍然可以手动重组生成的代码。预设只是起点,并不是硬性约束,不必过度纠结。
+
+**Q. 哪个是“现代”选项?**
+`domain-starter`。它采用 pyproject-first 结构,自带 `/health` 端点,布局也更贴近许多成熟的中型 FastAPI 项目。
+
+**Q. 之后能从 `classic-layered` 切换到 `domain-starter` 吗?**
+可以,但这属于手动重构 —— 目前没有自动迁移命令。如果您预计项目后续会发展到需要按领域分目录,建议一开始就选它。
+
+**Q. 我只是想学习 FastAPI 怎么办?**
+可以从 `fastkit startdemo fastapi-default` 开始 —— 先阅读代码、运行测试、改几个端点。熟悉之后,再过渡到 `fastkit init --interactive` + `domain-starter` 会很自然。
+
+**Q. 在哪里能看到每个预设生成的精确文件?**
+[架构预设矩阵](../reference/preset-feature-matrix.md) 是这方面的参考页面。
+
+## 下一步
+
+- [快速上手](quick-start.md) —— 真正动手创建您的第一个项目。
+- [创建项目](creating-projects.md) —— 更深入地了解 CLI 参数。
+- [领域驱动项目教程](../tutorial/domain-starter.md) —— 如果您选择了 `domain-starter`,这是从生成的目录树、内置 `items` 示例,到如何添加下一个领域的完整演练。
+- [架构预设矩阵](../reference/preset-feature-matrix.md) —— 每个预设 / 功能的完整契约。
diff --git a/docs/zh/user-guide/cli-reference.md b/docs/zh/user-guide/cli-reference.md
new file mode 100644
index 0000000..dc6e8f4
--- /dev/null
+++ b/docs/zh/user-guide/cli-reference.md
@@ -0,0 +1,832 @@
+# CLI 参考
+
+FastAPI-fastkit 命令行接口的完整命令参考。
+
+## 全局选项
+
+所有命令都支持以下全局选项:
+
+```console
+$ fastkit [GLOBAL_OPTIONS] COMMAND [COMMAND_OPTIONS]
+```
+
+### 全局选项
+
+| 选项 | 描述 |
+|--------|-------------|
+| `--version` | 显示 FastAPI-fastkit 版本 |
+| `--help` | 显示帮助信息 |
+
+### 示例
+
+
+
+```console
+$ fastkit --version
+FastAPI-fastkit version 1.0.0
+
+$ fastkit --help
+Usage: fastkit [OPTIONS] COMMAND [ARGS]...
+
+ FastAPI-fastkit CLI
+
+Options:
+ --version Show the version and exit.
+ --help Show this message and exit.
+
+Commands:
+ addroute Add a new route to FastAPI project
+ init Create a new FastAPI project
+ list-templates List available FastAPI templates
+ runserver Start FastAPI development server
+ startdemo Create FastAPI project from template
+```
+
+
+
+## 命令
+
+### `init`
+
+通过交互式流程创建一个新的 FastAPI 项目。
+
+#### 语法
+
+```console
+$ fastkit init [OPTIONS]
+```
+
+#### 选项
+
+| 选项 | 描述 | 默认值 |
+|--------|-------------|---------|
+| `--package-manager` | 要使用的包管理器(pip、uv、pdm、poetry) | uv |
+| `--help` | 显示命令帮助 | - |
+
+#### 交互式提示
+
+`init` 命令会依次提示您输入:
+
+1. **项目名称**:目录与包的名称
+2. **作者名称**:包的作者信息
+3. **作者邮箱**:包的联系邮箱
+4. **项目描述**:项目的简短描述
+5. **栈选择**:在 minimal、standard、full 中选择
+6. **包管理器选择**:在 pip、uv、pdm、poetry 中选择(除非用 `--package-manager` 指定)
+
+#### 栈选项
+
+**MINIMAL 栈:**
+
+- `fastapi` —— FastAPI 框架
+- `uvicorn` —— ASGI 服务器
+- `pydantic` —— 数据校验
+- `pydantic-settings` —— 配置管理
+
+**STANDARD 栈:**
+
+- 所有 MINIMAL 栈的依赖
+- `sqlalchemy` —— SQL 工具包与 ORM
+- `alembic` —— 数据库迁移工具
+- `pytest` —— 测试框架
+
+**FULL 栈:**
+
+- 所有 STANDARD 栈的依赖
+- `redis` —— 内存数据存储
+- `celery` —— 分布式任务队列
+
+#### 示例
+
+
+
+```console
+$ fastkit init
+Enter the project name: my-api
+Enter the author name: John Doe
+Enter the author email: john@example.com
+Enter the project description: My awesome API
+
+Select stack (minimal, standard, full): standard
+Select package manager (pip, uv, pdm, poetry) [uv]: uv
+Do you want to proceed with project creation? [y/N]: y
+
+✨ FastAPI project 'my-api' has been created successfully!
+```
+
+
+
+#### 生成的结构
+
+创建出的项目结构如下:
+
+```
+my-api/
+├── .venv/ # 虚拟环境
+├── src/
+│ ├── __init__.py
+│ ├── main.py # FastAPI 应用入口
+│ ├── core/
+│ │ ├── __init__.py
+│ │ └── config.py # 配置文件
+│ ├── api/
+│ │ ├── __init__.py
+│ │ ├── api.py # API 路由汇总
+│ │ └── routes/
+│ │ ├── __init__.py
+│ │ └── items.py # 示例路由
+│ ├── crud/
+│ │ ├── __init__.py
+│ │ └── items.py # CRUD 操作
+│ ├── schemas/
+│ │ ├── __init__.py
+│ │ └── items.py # Pydantic 模式
+│ └── mocks/
+│ ├── __init__.py
+│ └── mock_items.json # 测试数据
+├── tests/
+├── scripts/
+├── requirements.txt
+├── setup.py
+└── README.md
+```
+
+### `addroute`
+
+向已有的 FastAPI 项目添加新的 API 路由。
+
+#### 语法
+
+```console
+$ fastkit addroute ROUTE_NAME [PROJECT_DIR] [OPTIONS]
+```
+
+#### 参数
+
+| 参数 | 描述 | 必填 |
+|----------|-------------|----------|
+| `ROUTE_NAME` | 新路由的名称(推荐使用复数) | 是 |
+| `PROJECT_DIR` | 工作区下的项目目录(默认 `.`,即当前目录) | 否 |
+
+#### 选项
+
+| 选项 | 描述 | 默认值 |
+|--------|-------------|---------|
+| `--help` | 显示命令帮助 | - |
+
+#### 示例
+
+
+
+```console
+$ cd my-api
+$ fastkit addroute users
+ Adding New Route
+┌──────────────────┬──────────────────────────────────────────┐
+│ Project │ my-api │
+│ Route Name │ users │
+│ Target Directory │ ~/my-api │
+└──────────────────┴──────────────────────────────────────────┘
+
+Do you want to add route 'users' to project 'my-api'? [Y/n]: y
+
+✨ Successfully added new route 'users' to project 'my-api'
+```
+
+
+
+您也可以通过名称定位工作区下的项目,无需先 `cd`:
+
+
+
+```console
+$ fastkit addroute users my-api
+```
+
+
+
+#### 生成的文件
+
+会在项目中生成以下文件:
+
+- `src/api/routes/users.py` —— 路由处理器
+- `src/crud/users.py` —— CRUD 操作
+- `src/schemas/users.py` —— Pydantic 模式
+
+同时会更新 `src/api/api.py`,把新路由器纳入其中。
+
+#### 生成的端点
+
+会创建完整的一组 CRUD 端点:
+
+| 方法 | 端点 | 描述 |
+|--------|----------|-------------|
+| `GET` | `/api/v1/users/` | 获取所有用户 |
+| `POST` | `/api/v1/users/` | 创建新用户 |
+| `GET` | `/api/v1/users/{user_id}` | 获取指定用户 |
+| `PUT` | `/api/v1/users/{user_id}` | 更新用户 |
+| `DELETE` | `/api/v1/users/{user_id}` | 删除用户 |
+
+### `startdemo`
+
+基于预构建的模板创建 FastAPI 项目。
+
+#### 语法
+
+```console
+$ fastkit startdemo [OPTIONS]
+```
+
+#### 选项
+
+| 选项 | 描述 | 默认值 |
+|--------|-------------|---------|
+| `--package-manager` | 要使用的包管理器(pip、uv、pdm、poetry) | uv |
+| `--help` | 显示命令帮助 | - |
+
+#### 交互式提示
+
+`startdemo` 命令会依次提示您输入:
+
+1. **项目名称**:新项目的目录名称
+2. **作者名称**:包的作者信息
+3. **作者邮箱**:联系邮箱
+4. **项目描述**:简短描述
+5. **包管理器选择**:在 pip、uv、pdm、poetry 中选择(除非用 `--package-manager` 指定)
+
+#### 可用的模板
+
+| 模板 | 描述 | 特性 |
+|----------|-------------|----------|
+| `fastapi-default` | 简单的 FastAPI 项目 | 基础 CRUD、mock 数据 |
+| `fastapi-async-crud` | 异步 item 管理 API | async/await、性能优化 |
+| `fastapi-custom-response` | 自定义响应系统 | 自定义响应、分页 |
+| `fastapi-dockerized` | 已 Docker 化的 FastAPI | Docker、适合生产部署 |
+| `fastapi-psql-orm` | 基于 PostgreSQL 的 FastAPI | PostgreSQL、SQLAlchemy、Alembic |
+| `fastapi-empty` | 最小化的 FastAPI 项目 | 极简骨架 |
+
+#### 示例
+
+
+
+```console
+$ fastkit startdemo fastapi-psql-orm
+Enter the project name: my-blog
+Enter the author name: Jane Smith
+Enter the author email: jane@example.com
+Enter the project description: Blog API with PostgreSQL
+
+Select package manager (pip, uv, pdm, poetry) [uv]: poetry
+Do you want to proceed with project creation? [y/N]: y
+
+✨ FastAPI project 'my-blog' from 'fastapi-psql-orm' has been created!
+```
+
+
+
+### `runserver`
+
+启动 FastAPI 开发服务器。
+
+#### 语法
+
+```console
+$ fastkit runserver [OPTIONS]
+```
+
+#### 选项
+
+| 选项 | 短选项 | 描述 | 默认值 |
+|--------|-------|-------------|---------|
+| `--host` | `-h` | 绑定的主机 | `127.0.0.1` |
+| `--port` | `-p` | 绑定的端口 | `8000` |
+| `--reload` | `-r` | 启用自动重载 | `True` |
+| `--workers` | `-w` | worker 数量 | `1` |
+| `--help` | | 显示命令帮助 | - |
+
+#### 示例
+
+
+
+```console
+# 基本用法(默认设置)
+$ fastkit runserver
+INFO: Uvicorn running on http://127.0.0.1:8000
+
+# 自定义主机与端口
+$ fastkit runserver --host 0.0.0.0 --port 8080
+INFO: Uvicorn running on http://0.0.0.0:8080
+
+# 关闭自动重载
+$ fastkit runserver --no-reload
+INFO: Uvicorn running on http://127.0.0.1:8000
+
+# 多 worker 运行(偏生产场景)
+$ fastkit runserver --workers 4
+INFO: Uvicorn running on http://127.0.0.1:8000
+```
+
+
+
+#### 前置条件
+
+- 必须在 FastAPI 项目目录中运行
+- 项目必须含有 `src/main.py`,并定义了 FastAPI 应用
+- 建议提前激活虚拟环境
+
+### `list-templates`
+
+列出所有可用的 FastAPI 项目模板。
+
+#### 语法
+
+```console
+$ fastkit list-templates [OPTIONS]
+```
+
+#### 选项
+
+| 选项 | 描述 | 默认值 |
+|--------|-------------|---------|
+| `--help` | 显示命令帮助 | - |
+
+#### 示例
+
+
+
+```console
+$ fastkit list-templates
+ Available Templates
+┌─────────────────────────┬───────────────────────────────────┐
+│ fastapi-custom-response │ Async Item Management API with │
+│ │ Custom Response System │
+│ fastapi-dockerized │ Dockerized FastAPI Item │
+│ │ Management API │
+│ fastapi-empty │ No description │
+│ fastapi-async-crud │ Async Item Management API Server │
+│ fastapi-psql-orm │ Dockerized FastAPI Item │
+│ │ Management API with PostgreSQL │
+│ fastapi-default │ Simple FastAPI Project │
+└─────────────────────────┴───────────────────────────────────┘
+```
+
+
+
+## 环境变量
+
+FastAPI-fastkit 会读取以下环境变量:
+
+| 变量 | 描述 | 默认值 |
+|----------|-------------|---------|
+| `FASTKIT_CONFIG_DIR` | 配置目录 | `~/.fastkit` |
+| `FASTKIT_TEMPLATES_DIR` | 自定义模板目录 | 内置模板 |
+| `FASTKIT_LOG_LEVEL` | 日志级别 | `INFO` |
+
+### 示例
+
+
+
+```console
+# 自定义配置目录
+$ export FASTKIT_CONFIG_DIR=~/my-fastkit-config
+$ fastkit init
+
+# 自定义模板目录
+$ export FASTKIT_TEMPLATES_DIR=~/my-templates
+$ fastkit list-templates
+
+# 调试日志
+$ export FASTKIT_LOG_LEVEL=DEBUG
+$ fastkit init
+```
+
+
+
+## 配置文件
+
+FastAPI-fastkit 可以使用配置文件存放默认设置。
+
+### 配置文件位置
+
+1. `$FASTKIT_CONFIG_DIR/config.yaml`(若设置了 `FASTKIT_CONFIG_DIR`)
+2. `~/.fastkit/config.yaml`(默认)
+3. `./fastkit.yaml`(项目级)
+
+### 配置格式
+
+```yaml
+# ~/.fastkit/config.yaml
+default:
+ author:
+ name: "Your Name"
+ email: "your.email@example.com"
+
+ project:
+ stack: "standard"
+ create_venv: true
+ install_deps: true
+
+ server:
+ host: "127.0.0.1"
+ port: 8000
+ reload: true
+
+templates:
+ custom_dir: "~/my-templates"
+
+logging:
+ level: "INFO"
+ file: "~/.fastkit/logs/fastkit.log"
+```
+
+## 常见工作流
+
+### 1. 创建新项目
+
+
+
+```console
+# 创建新项目
+$ fastkit init
+# 按提示完成选择……
+
+# 进入项目目录
+$ cd my-awesome-api
+
+# 激活虚拟环境
+$ source .venv/bin/activate
+
+# 启动开发服务器
+$ fastkit runserver
+```
+
+
+
+### 2. 为已有项目添加功能
+
+
+
+```console
+# 添加多个路由(第二个位置参数为工作区中的项目名)
+$ fastkit addroute users my-api
+$ fastkit addroute products my-api
+$ fastkit addroute orders my-api
+
+# 测试 API
+$ fastkit runserver
+# 打开 http://127.0.0.1:8000/docs
+```
+
+
+
+### 3. 借助模板搭建复杂项目
+
+
+
+```console
+# 列出可用模板
+$ fastkit list-templates
+
+# 基于模板创建项目
+$ fastkit startdemo
+# 如果是数据库项目,可选择 fastapi-psql-orm
+
+# 初始化数据库(适用于 PostgreSQL 模板)
+$ cd my-project
+$ docker-compose up -d postgres
+$ source .venv/bin/activate
+$ alembic upgrade head
+$ fastkit runserver
+```
+
+
+
+## 故障排查
+
+### 找不到命令
+
+如果找不到 `fastkit` 命令:
+
+1. **确认是否已安装:**
+
+ ```console
+ $ pip show fastapi-fastkit
+ ```
+
+
+2. **必要时重新安装:**
+
+ ```console
+ $ pip uninstall fastapi-fastkit
+ $ pip install fastapi-fastkit
+ ```
+
+
+3. **检查 PATH:**
+
+ ```console
+ $ which fastkit
+ ```
+
+
+### 虚拟环境问题
+
+如果虚拟环境创建失败:
+
+1. **检查 Python 版本:**
+
+ ```console
+ $ python --version # Should be 3.12+
+ ```
+
+
+2. **检查 venv 模块:**
+
+ ```console
+ $ python -m venv --help
+ ```
+
+
+3. **手动创建虚拟环境:**
+
+ ```console
+ $ python -m venv .venv
+ $ source .venv/bin/activate
+ $ pip install -r requirements.txt
+ ```
+
+
+### 服务器无法启动
+
+如果 `fastkit runserver` 失败:
+
+1. **确认当前目录是项目根目录**
+2. **确认 `src/main.py` 存在**
+3. **激活虚拟环境:**
+
+ ```console
+ $ source .venv/bin/activate
+ ```
+
+
+4. **检查语法错误:**
+
+ ```console
+ $ python -c "from src.main import app"
+ ```
+
+
+### 端口已被占用
+
+如果 8000 端口被占用:
+
+
+
+```console
+# 换一个端口运行
+$ fastkit runserver --port 8080
+
+# 或结束当前占用端口的进程
+$ lsof -ti:8000 | xargs kill -9
+```
+
+
+
+## 进阶用法
+
+### 自定义模板
+
+您可以这样创建自定义模板:
+
+1. **创建模板目录:**
+ ```
+ my-template/
+ ├── src/
+ │ └── main.py-tpl
+ ├── requirements.txt-tpl
+ └── setup.py-tpl
+ ```
+
+2. **设置环境变量:**
+
+ ```console
+ $ export FASTKIT_TEMPLATES_DIR=~/my-templates
+ ```
+
+
+3. **使用自定义模板:**
+
+ ```console
+ $ fastkit startdemo
+ # 您的自定义模板会出现在列表中
+ ```
+
+
+### 在脚本中使用 FastAPI-fastkit
+
+可以将 FastAPI-fastkit 嵌入到脚本中:
+
+```bash
+#!/bin/bash
+# create-microservices.sh
+
+for service in users products orders; do
+ echo "正在创建 $service 服务..."
+ fastkit init <
+
+```console
+$ fastkit init --package-manager uv
+# 生成带 UV 配置的 pyproject.toml
+```
+
+
+
+#### PDM
+- **现代**:支持 PEP 582 与 PEP 621
+- **进阶**:更复杂的依赖解析
+- **灵活**:支持多种项目布局
+
+
+
+```console
+$ fastkit init --package-manager pdm
+# 生成带 PDM 配置的 pyproject.toml
+```
+
+
+
+#### Poetry
+- **成熟**:广为使用
+- **一体化**:支持构建与发布
+- **锁文件**:poetry.lock 保证可复现构建
+
+
+
+```console
+$ fastkit init --package-manager poetry
+# 生成带 Poetry 配置的 pyproject.toml
+```
+
+
+
+#### PIP
+- **标准**:Python 内置
+- **兼容**:到哪都能用
+- **简单**:工作流朴素直接
+
+
+
+```console
+$ fastkit init --package-manager pip
+# 生成 requirements.txt
+```
+
+
+
+### 创建后的使用方式
+
+使用对应包管理器创建项目后:
+
+#### UV 项目
+```console
+cd my-project
+uv sync # 安装依赖
+uv add requests # 添加新依赖
+uv run pytest # 在项目环境中运行命令
+```
+
+#### PDM 项目
+```console
+cd my-project
+pdm install # 安装依赖
+pdm add requests # 添加新依赖
+pdm run pytest # 在项目环境中运行命令
+```
+
+#### Poetry 项目
+```console
+cd my-project
+poetry install # 安装依赖
+poetry add requests # 添加新依赖
+poetry run pytest # 在项目环境中运行命令
+```
+
+#### PIP 项目
+```console
+cd my-project
+source .venv/bin/activate # Linux/macOS
+.venv\Scripts\activate # Windows
+pip install -r requirements.txt
+pip install requests
+pytest
+```
+
+## 下一步
+
+现在您已经了解 CLI:
+
+1. **[快速上手](quick-start.md)**:动手体验各命令
+2. **[您的第一个项目](../tutorial/first-project.md)**:构建一个完整的应用
+3. **[参与贡献](../contributing/development-setup.md)**:为 FastAPI-fastkit 贡献代码
+
+!!! tip "CLI 小贴士"
+ - 任何命令搭配 `--help` 都可以查看详细帮助
+ - 配置默认设置可以加快项目创建
+ - 借助模板搭建复杂项目
+ - 把命令组合起来,可以构建强大的工作流
diff --git a/docs/zh/user-guide/creating-projects.md b/docs/zh/user-guide/creating-projects.md
new file mode 100644
index 0000000..f0a4b18
--- /dev/null
+++ b/docs/zh/user-guide/creating-projects.md
@@ -0,0 +1,540 @@
+# 创建项目
+
+详细介绍如何使用 FastAPI-fastkit 创建各种类型的 FastAPI 项目。
+
+## 基本的项目创建
+
+### 1. 交互模式下的项目创建
+
+最基础的创建方式如下:
+
+
+
+```console
+$ fastkit init
+Enter the project name: my-awesome-api
+Enter the author name: John Doe
+Enter the author email: john@example.com
+Enter the project description: Awesome FastAPI project
+
+ Project Information
+┌──────────────┬─────────────────────────┐
+│ Project Name │ my-awesome-api │
+│ Author │ John Doe │
+│ Author Email │ john@example.com │
+│ Description │ Awesome FastAPI project │
+└──────────────┴─────────────────────────┘
+```
+
+
+
+### 2. 选择技术栈
+
+选择您希望项目包含的依赖栈:
+
+#### MINIMAL 栈(默认)
+
+最基础的 FastAPI 项目:
+
+- `fastapi` —— FastAPI 框架
+- `uvicorn` —— ASGI 服务器
+- `pydantic` —— 数据校验
+- `pydantic-settings` —— 设置管理
+
+**适合:**
+
+- 学习 FastAPI
+- 简单的 API
+- 原型
+- 微服务
+
+#### STANDARD 栈
+
+包含数据库支持与测试:
+
+- 所有 MINIMAL 依赖
+- `sqlalchemy` —— 数据库操作的 ORM
+- `alembic` —— 数据库迁移
+- `pytest` —— 测试框架
+
+**适合:**
+
+- 大多数 Web 应用
+- 带数据库存储的 API
+- 准备走向生产的应用
+- 团队项目
+
+#### FULL 栈
+
+完整的开发环境:
+
+- 所有 STANDARD 依赖
+- `redis` —— 缓存与会话存储
+- `celery` —— 后台任务处理
+
+**适合:**
+
+- 大型应用
+- 对性能有较高要求
+- 复杂的业务逻辑
+- 企业应用
+
+## 高级项目选项
+
+### 自定义项目配置
+
+您可以在创建项目时进行定制:
+
+
+
+```console
+$ fastkit init
+Enter the project name: advanced-api
+Enter the author name: Development Team
+Enter the author email: dev@company.com
+Enter the project description: Advanced FastAPI application with custom features
+
+# 选择 STANDARD 栈以获得数据库支持
+Select stack (minimal, standard, full): standard
+Do you want to proceed with project creation? [y/N]: y
+```
+
+
+
+### 项目结构说明
+
+创建项目时,FastAPI-fastkit 会生成如下结构:
+
+```
+my-awesome-api/
+├── .venv/ # 虚拟环境
+├── src/ # 源代码
+│ ├── __init__.py
+│ ├── main.py # 应用入口
+│ ├── core/ # 核心配置
+│ │ ├── __init__.py
+│ │ └── config.py # 设置与配置
+│ ├── api/ # API 层
+│ │ ├── __init__.py
+│ │ ├── api.py # 主 API 路由
+│ │ └── routes/ # 各个路由模块
+│ │ ├── __init__.py
+│ │ └── items.py # items 示例端点
+│ ├── crud/ # 数据库操作
+│ │ ├── __init__.py
+│ │ └── items.py # items 相关的 CRUD 操作
+│ ├── schemas/ # Pydantic 模型
+│ │ ├── __init__.py
+│ │ └── items.py # 数据校验模式
+│ └── mocks/ # 测试数据
+│ ├── __init__.py
+│ └── mock_items.json # 开发用示例数据
+├── tests/ # 测试套件
+│ ├── __init__.py
+│ ├── conftest.py # 测试配置
+│ └── test_items.py # 示例测试
+├── scripts/ # 辅助脚本
+│ ├── test.sh # 运行测试
+│ ├── coverage.sh # 测试覆盖率
+│ └── lint.sh # 代码检查
+├── requirements.txt # Python 依赖
+├── setup.py # 包配置
+└── README.md # 项目文档
+```
+
+### 3. 选择包管理器
+
+FastAPI-fastkit 支持多种 Python 包管理器,请选择最适合您工作流程的那一种:
+
+#### 可用的包管理器
+
+
+
+```console
+Available Package Managers:
+ Package Managers
+┌────────┬────────────────────────────────────────────┐
+│ PIP │ Standard Python package manager │
+│ UV │ Fast Python package manager │
+│ PDM │ Modern Python dependency management │
+│ POETRY │ Python dependency management and packaging │
+└────────┴────────────────────────────────────────────┘
+
+Select package manager (pip, uv, pdm, poetry) [uv]: uv
+```
+
+
+
+每种包管理器都有各自的优势:
+
+#### UV(默认 —— 推荐)
+
+**基于 Rust 的高速包管理器**
+
+- ⚡ **超快**:比 pip 快 10–100 倍
+- 🔧 **上手直接**:兼容 pip 工作流
+- 📦 **现代**:完整支持 PEP 621
+- 🛠️ **可靠**:确定性的依赖解析
+
+**生成的文件:**
+
+- `pyproject.toml`(PEP 621 格式)
+- `uv.lock`(锁文件)
+
+**创建项目后常用的命令:**
+```console
+cd my-project
+uv sync # 安装依赖
+uv add requests # 添加新依赖
+uv run pytest # 运行测试
+```
+
+#### PDM
+
+**现代化的 Python 依赖管理**
+
+- 🚀 **现代**:支持 PEP 582 与 PEP 621
+- 🧠 **智能**:更强的依赖解析
+- 💼 **专业**:支持工作区与多项目
+- 📊 **分析能力**:依赖分析工具
+
+**生成的文件:**
+
+- `pyproject.toml`(PEP 621 格式)
+- `pdm.lock`(锁文件)
+
+**创建项目后常用的命令:**
+```console
+cd my-project
+pdm install # 安装依赖
+pdm add requests # 添加新依赖
+pdm run pytest # 运行测试
+```
+
+#### Poetry
+
+**成熟的依赖管理与打包工具**
+
+- ✅ **成熟**:广泛使用
+- 📦 **一体化**:支持构建与发布
+- 🔒 **可复现**:poetry.lock 锁定精确版本
+- 🏗️ **完整**:覆盖项目完整生命周期
+
+**生成的文件:**
+
+- `pyproject.toml`(Poetry 格式)
+- `poetry.lock`(锁文件)
+
+**创建项目后常用的命令:**
+```console
+cd my-project
+poetry install # 安装依赖
+poetry add requests # 添加新依赖
+poetry run pytest # 运行测试
+```
+
+#### PIP
+
+**标准的 Python 包管理器**
+
+- 🏠 **内置**:Python 自带
+- 🌍 **通用**:到哪都能用
+- 📚 **熟悉**:大多数开发者都很熟悉
+- 🔧 **简单**:工作流朴素直接
+
+**生成的文件:**
+
+- `requirements.txt`
+
+**创建项目后常用的命令:**
+```console
+cd my-project
+source .venv/bin/activate # Linux/macOS
+.venv\Scripts\activate # Windows
+pip install -r requirements.txt
+pip install requests
+pytest
+```
+
+#### 指定包管理器
+
+您也可以直接指定偏好的包管理器:
+
+**交互式选择(默认):**
+```console
+$ fastkit init
+# ... 接下来会提示选择包管理器
+```
+
+**命令行参数:**
+```console
+$ fastkit init --package-manager poetry
+$ fastkit init --package-manager pdm
+$ fastkit init --package-manager uv
+$ fastkit init --package-manager pip
+```
+
+### 各目录用途解析
+
+#### `src/` 目录
+
+这里包含项目的全部应用源代码,采用 **src 布局** —— 这是 Python 打包中的常见最佳实践。
+
+#### `core/` 模块
+
+- **config.py**:应用设置、环境变量与配置
+- 集中管理所有配置
+- 支持 `.env` 文件以满足按环境配置的需求
+
+#### `api/` 模块
+
+- **api.py**:主 API 路由,统一汇总所有子路由
+- **routes/**:针对不同资源拆分出的独立路由模块
+- 不同 API 端点之间职责清晰
+
+#### `crud/` 模块
+
+- 数据库操作与业务逻辑
+- **C**reate / **R**ead / **U**pdate / **D**elete 操作
+- API 路由与数据存储之间的抽象层
+
+#### `schemas/` 模块
+
+- 用于数据校验的 Pydantic 模型
+- 请求 / 响应模式
+- 类型定义与数据模型
+
+#### `tests/` 目录
+
+- 应用完整的测试套件
+- 包含单元测试与集成测试
+- 已预配置 pytest
+
+## 各栈对比
+
+| 功能 | MINIMAL | STANDARD | FULL |
+|---------|---------|----------|------|
+| FastAPI 与 Uvicorn | ✅ | ✅ | ✅ |
+| 数据校验 | ✅ | ✅ | ✅ |
+| 数据库支持 | ❌ | ✅ | ✅ |
+| 数据迁移 | ❌ | ✅ | ✅ |
+| 测试框架 | ❌ | ✅ | ✅ |
+| 缓存(Redis) | ❌ | ❌ | ✅ |
+| 后台任务 | ❌ | ❌ | ✅ |
+| **适合** | 学习、简单 API | 大多数应用 | 企业、复杂应用 |
+
+## 项目创建示例
+
+### 示例 1:学习项目
+
+
+
+```console
+$ fastkit init
+Enter the project name: fastapi-learning
+Enter the author name: Student
+Enter the author email: student@example.com
+Enter the project description: Learning FastAPI basics
+
+Select stack (minimal, standard, full): minimal
+Do you want to proceed with project creation? [y/N]: y
+```
+
+
+
+### 示例 2:电商 API
+
+
+
+```console
+$ fastkit init
+Enter the project name: ecommerce-api
+Enter the author name: E-commerce Team
+Enter the author email: team@ecommerce.com
+Enter the project description: E-commerce platform API
+
+Select stack (minimal, standard, full): standard
+Do you want to proceed with project creation? [y/N]: y
+```
+
+
+
+### 示例 3:高性能应用
+
+
+
+```console
+$ fastkit init
+Enter the project name: enterprise-api
+Enter the author name: Enterprise Team
+Enter the author email: enterprise@company.com
+Enter the project description: High-performance enterprise API
+
+Select stack (minimal, standard, full): full
+Do you want to proceed with project creation? [y/N]: y
+```
+
+
+
+## 创建项目之后
+
+### 1. 激活虚拟环境
+
+
+
+```console
+$ cd my-awesome-api
+$ source .venv/bin/activate # Linux/macOS
+$ .venv\Scripts\activate # Windows
+```
+
+
+
+### 2. 校验安装
+
+
+
+```console
+$ pip list
+Package Version
+fastapi 0.104.1
+uvicorn 0.24.0
+pydantic 2.5.0
+...
+```
+
+
+
+### 3. 开始开发
+
+
+
+```console
+$ fastkit runserver
+INFO: Uvicorn running on http://127.0.0.1:8000
+```
+
+
+
+## 配置管理
+
+### 环境变量
+
+项目支持通过 `.env` 文件按环境进行配置:
+
+在项目根目录创建 `.env` 文件:
+
+```env
+# .env
+APP_NAME=My Awesome API
+APP_VERSION=1.0.0
+DEBUG=True
+DATABASE_URL=sqlite:///./app.db
+SECRET_KEY=your-secret-key-here
+```
+
+### 在代码中的配置
+
+生成的 `src/core/config.py` 会自动加载这些变量:
+
+```python
+from pydantic_settings import BaseSettings
+
+class Settings(BaseSettings):
+ APP_NAME: str = "FastAPI Application"
+ APP_VERSION: str = "1.0.0"
+ DEBUG: bool = False
+ DATABASE_URL: str = "sqlite:///./app.db"
+ SECRET_KEY: str = "dev-secret-key"
+
+ class Config:
+ env_file = ".env"
+
+settings = Settings()
+```
+
+## 定制选项
+
+### 添加自定义依赖
+
+项目创建后,还可以继续添加更多依赖:
+
+
+
+```console
+$ pip install requests httpx python-jose
+$ pip freeze > requirements.txt
+```
+
+
+
+### 修改项目结构
+
+生成的结构遵循最佳实践,但您完全可以按需调整:
+
+- 在 `src/` 下添加新模块
+- 在 `api/routes/` 下新增路由文件
+- 在 `crud/` 中扩展 CRUD 操作
+- 在 `schemas/` 中添加更多模式
+
+## 最佳实践
+
+### 1. 虚拟环境
+
+请始终使用虚拟环境隔离项目依赖:
+
+```bash
+# 创建项目(会自动生成 .venv)
+$ fastkit init # Automatically creates .venv/
+
+# 开始开发前激活环境
+$ source .venv/bin/activate
+```
+
+### 2. 版本控制
+
+项目创建后建议初始化 git 仓库:
+
+
+
+```console
+$ cd my-awesome-api
+$ git init
+$ git add .
+$ git commit -m "Initial commit - FastAPI project setup"
+```
+
+
+
+### 3. 环境配置
+
+- 使用 `.env` 文件做本地开发配置
+- 在生产环境使用环境变量
+- 切勿将敏感信息提交到版本控制
+
+### 4. 测试
+
+充分使用内置的测试框架:
+
+
+
+```console
+$ python -m pytest
+$ bash scripts/test.sh
+```
+
+
+
+## 下一步
+
+创建项目之后:
+
+1. **[添加路由](adding-routes.md)**:学习如何添加新的 API 端点
+2. **[CLI 参考](cli-reference.md)**:掌握所有可用命令
+3. **[您的第一个项目教程](../tutorial/first-project.md)**:构建一个完整的应用
+
+!!! tip "项目创建小贴士"
+ - 选择与项目需求相匹配的技术栈
+ - 学习时从 MINIMAL 开始,大多数项目用 STANDARD 即可
+ - 项目结构兼顾扩展性与可维护性
+ - 所有生成的代码都遵循 FastAPI 的最佳实践
diff --git a/docs/zh/user-guide/installation.md b/docs/zh/user-guide/installation.md
new file mode 100644
index 0000000..153c03c
--- /dev/null
+++ b/docs/zh/user-guide/installation.md
@@ -0,0 +1,209 @@
+# 安装
+
+本指南介绍如何安装 FastAPI-fastkit。
+
+## 系统要求
+
+要使用 FastAPI-fastkit,您需要满足以下条件:
+
+- **Python**:3.12 或更高版本
+- **操作系统**:支持 Windows、macOS、Linux
+
+## 安装方式
+
+### 使用 pip 安装(推荐)
+
+最简单的方式是:
+
+
+
+```console
+$ pip install FastAPI-fastkit
+---> 100%
+Successfully installed FastAPI-fastkit
+```
+
+
+
+### 安装指定版本
+
+如果要安装指定版本:
+
+
+
+```console
+$ pip install FastAPI-fastkit==1.0.0
+---> 100%
+Successfully installed FastAPI-fastkit-1.0.0
+```
+
+
+
+### 安装开发版
+
+直接从 GitHub 安装最新的开发版本:
+
+
+
+```console
+$ pip install git+https://github.com/bnbong/FastAPI-fastkit.git
+---> 100%
+Successfully installed FastAPI-fastkit
+```
+
+
+
+!!! warning "开发版警告"
+ 开发版可能不稳定,不建议用于生产环境。
+
+## 配置虚拟环境(推荐)
+
+强烈建议使用虚拟环境,以避免依赖冲突:
+
+### 使用 venv
+
+
+
+```console
+$ python -m venv fastapi-env
+$ source fastapi-env/bin/activate # Linux/macOS
+$ fastapi-env\Scripts\activate # Windows
+$ pip install FastAPI-fastkit
+```
+
+
+
+### 使用 conda
+
+
+
+```console
+$ conda create -n fastapi-env python=3.12
+$ conda activate fastapi-env
+$ pip install FastAPI-fastkit
+```
+
+
+
+## 校验安装
+
+安装完成后,请确认 FastAPI-fastkit 已正确安装:
+
+
+
+```console
+$ fastkit --version
+FastAPI-fastkit version 1.0.0
+```
+
+
+
+
+
+```console
+$ fastkit --help
+Usage: fastkit [OPTIONS] COMMAND [ARGS]...
+
+ FastAPI-fastkit CLI
+
+Options:
+ --version Show the version and exit.
+ --help Show this message and exit.
+
+Commands:
+ addroute Add a new route to FastAPI project
+ init Create a new FastAPI project
+ list-templates List available FastAPI templates
+ runserver Start FastAPI development server
+ startdemo Create FastAPI project from template
+```
+
+
+
+## 故障排查
+
+### 找不到命令
+
+若出现 “command not found” 错误:
+
+1. **确认 FastAPI-fastkit 已安装**:
+
+
+ ```console
+ $ pip show FastAPI-fastkit
+ ```
+
+
+2. **检查虚拟环境**:
+
+
+ ```console
+ $ which python
+ $ which pip
+ ```
+
+
+3. **重新安装 FastAPI-fastkit**:
+
+
+ ```console
+ $ pip uninstall FastAPI-fastkit
+ $ pip install FastAPI-fastkit
+ ```
+
+
+### 权限错误
+
+若在安装过程中遇到权限错误:
+
+**在 Linux/macOS 上:**
+
+
+
+```console
+$ pip install --user FastAPI-fastkit
+```
+
+
+
+**在 Windows 上(以管理员身份运行):**
+
+
+
+```console
+$ pip install FastAPI-fastkit
+```
+
+
+
+### Python 版本兼容性
+
+FastAPI-fastkit 需要 Python 3.12 及以上版本。请先检查当前 Python 版本:
+
+
+
+```console
+$ python --version
+Python 3.12.0
+```
+
+
+
+如果版本较旧,请升级 Python:
+
+- **官方 Python**:[python.org/downloads](https://www.python.org/downloads/)
+- **使用 pyenv**:`pyenv install 3.12.0`
+- **使用 conda**:`conda install python=3.12`
+
+## 下一步
+
+安装完成后:
+
+1. **[快速上手](quick-start.md)**:5 分钟内创建您的第一个项目
+2. **[入门教程](../tutorial/getting-started.md)**:分步详细教程
+3. **[CLI 参考](cli-reference.md)**:完整的命令参考
+
+!!! tip "安装小贴士"
+ - 始终使用虚拟环境隔离不同项目
+ - 让 FastAPI-fastkit 保持最新
+ - 查看 [GitHub 仓库](https://github.com/bnbong/FastAPI-fastkit) 获取更新与问题反馈
diff --git a/docs/zh/user-guide/quick-start.md b/docs/zh/user-guide/quick-start.md
new file mode 100644
index 0000000..b1d6787
--- /dev/null
+++ b/docs/zh/user-guide/quick-start.md
@@ -0,0 +1,368 @@
+# 快速上手
+
+5 分钟内使用 FastAPI-fastkit 创建您的第一个 FastAPI 项目!
+
+!!! tip "不确定该选哪个 starter?"
+ 请参阅 [**应该选择哪个 starter?**](choosing-a-starter.md)。其中对 `startdemo` 模板与交互式架构预设(`minimal` / `single-module` / `classic-layered` / `domain-starter`)做了面向新手的对比。简短结论是:**推荐使用 `fastkit init --interactive`,并选择 `domain-starter` 预设。**
+
+## 1. 创建项目
+
+使用 FastAPI-fastkit 的 `init` 命令创建一个新项目:
+
+
+
+```console
+$ fastkit init
+Enter the project name: my-first-app
+Enter the author name: Your Name
+Enter the author email: your.email@example.com
+Enter the project description: My first FastAPI application
+
+ Project Information
+┌──────────────┬─────────────────────────────┐
+│ Project Name │ my-first-app │
+│ Author │ Your Name │
+│ Author Email │ your.email@example.com │
+│ Description │ My first FastAPI application│
+└──────────────┴─────────────────────────────┘
+
+Available Stacks and Dependencies:
+ MINIMAL Stack
+┌──────────────┬───────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ pydantic │
+│ Dependency 4 │ pydantic-settings │
+└──────────────┴───────────────────┘
+
+ STANDARD Stack
+┌──────────────┬───────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ sqlalchemy │
+│ Dependency 4 │ alembic │
+│ Dependency 5 │ pytest │
+│ Dependency 6 │ pydantic │
+│ Dependency 7 │ pydantic-settings │
+└──────────────┴───────────────────┘
+
+ FULL Stack
+┌──────────────┬───────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ sqlalchemy │
+│ Dependency 4 │ alembic │
+│ Dependency 5 │ pytest │
+│ Dependency 6 │ redis │
+│ Dependency 7 │ celery │
+│ Dependency 8 │ pydantic │
+│ Dependency 9 │ pydantic-settings │
+└──────────────┴───────────────────┘
+
+Select stack (minimal, standard, full): minimal
+
+Available Package Managers:
+ Package Managers
+┌────────┬────────────────────────────────────────────┐
+│ PIP │ Standard Python package manager │
+│ UV │ Fast Python package manager │
+│ PDM │ Modern Python dependency management │
+│ POETRY │ Python dependency management and packaging │
+└────────┴────────────────────────────────────────────┘
+
+Select package manager (pip, uv, pdm, poetry) [uv]: uv
+Do you want to proceed with project creation? [y/N]: y
+
+✨ FastAPI project 'my-first-app' has been created successfully!
+```
+
+
+
+## 2. 激活虚拟环境
+
+进入项目目录并激活虚拟环境:
+
+
+
+```console
+$ cd my-first-app
+$ source .venv/bin/activate # Linux/macOS
+$ .venv\Scripts\activate # Windows
+```
+
+
+
+## 3. 启动开发服务器
+
+启动 FastAPI 开发服务器:
+
+
+
+```console
+$ fastkit runserver
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+INFO: Started reloader process [28720]
+INFO: Started server process [28722]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+```
+
+
+
+!!! success "恭喜!"
+ 您的 FastAPI 服务器已经运行起来了!现在就可以打开浏览器查看。
+
+## 4. 测试您的 API
+
+打开浏览器,访问以下 URL:
+
+### 主要端点
+
+访问 [http://127.0.0.1:8000](http://127.0.0.1:8000)
+
+您将看到:
+
+```json
+{"message": "Hello World"}
+```
+
+### 交互式 API 文档
+
+访问 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)
+
+这是自动生成的 **Swagger UI** 文档,您可以在其中:
+
+- 查看所有 API 端点
+- 直接在浏览器中测试端点
+- 查看请求/响应模式
+
+### 备选文档
+
+访问 [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc)
+
+这是 **ReDoc** 文档界面,展示方式更偏文档化,阅读起来也更清晰。
+
+## 5. 添加您的第一个路由
+
+让我们为项目添加一个新的 API 路由:
+
+
+
+```console
+$ fastkit addroute users my-first-app
+ Adding New Route
+┌──────────────────┬──────────────────────────────────────────┐
+│ Project │ my-first-app │
+│ Route Name │ users │
+│ Target Directory │ ~/my-first-app │
+└──────────────────┴──────────────────────────────────────────┘
+
+Do you want to add route 'users' to project 'my-first-app'? [Y/n]: y
+
+╭──────────────────────── Info ────────────────────────╮
+│ ℹ Updated main.py to include the API router │
+╰──────────────────────────────────────────────────────╯
+╭─────────────────────── Success ───────────────────────╮
+│ ✨ Successfully added new route 'users' to project │
+│ `my-first-app` │
+╰───────────────────────────────────────────────────────╯
+```
+
+
+
+服务器会自动重载,现在您拥有了新的端点:
+
+- `GET /api/v1/users/` —— 获取所有用户
+- `POST /api/v1/users/` —— 创建新用户
+- `GET /api/v1/users/{user_id}` —— 获取指定用户
+- `PUT /api/v1/users/{user_id}` —— 更新用户
+- `DELETE /api/v1/users/{user_id}` —— 删除用户
+
+## 6. 测试新增 API
+
+### 使用 curl
+
+**获取所有用户:**
+
+
+
+```console
+$ curl http://127.0.0.1:8000/api/v1/users/
+[]
+```
+
+
+
+**创建新用户:**
+
+
+
+```console
+$ curl -X POST "http://127.0.0.1:8000/api/v1/users/" \
+ -H "Content-Type: application/json" \
+ -d '{"title": "John Doe", "description": "Software Developer"}'
+{
+ "id": 1,
+ "title": "John Doe",
+ "description": "Software Developer"
+}
+```
+
+
+
+### 通过交互式文档
+
+1. 访问 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)
+2. 展开 **“users”** 部分
+3. 点击 **“POST /api/v1/users/”**
+4. 点击 **“Try it out”**
+5. 填写请求体:
+ ```json
+ {
+ "title": "Jane Smith",
+ "description": "Product Manager"
+ }
+ ```
+6. 点击 **“Execute”**
+
+## 7. 了解项目结构
+
+生成的项目结构清晰、易于扩展:
+
+```
+my-first-app/
+├── .venv/ # 虚拟环境
+├── src/
+│ ├── __init__.py
+│ ├── main.py # FastAPI 应用入口
+│ ├── core/
+│ │ ├── __init__.py
+│ │ └── config.py # 应用配置
+│ ├── api/
+│ │ ├── __init__.py
+│ │ ├── api.py # API 路由汇总
+│ │ └── routes/
+│ │ ├── __init__.py
+│ │ ├── items.py # 默认的 items 路由
+│ │ └── users.py # 新增的 users 路由
+│ ├── crud/
+│ │ ├── __init__.py
+│ │ ├── items.py # items 相关的 CRUD 操作
+│ │ └── users.py # users 相关的 CRUD 操作
+│ ├── schemas/
+│ │ ├── __init__.py
+│ │ ├── items.py # items 的 Pydantic 模式
+│ │ └── users.py # users 的 Pydantic 模式
+│ └── mocks/
+│ ├── __init__.py
+│ └── mock_items.json # 测试数据
+├── tests/ # 测试文件
+├── scripts/ # 辅助脚本
+├── requirements.txt # Python 依赖
+├── setup.py # 包配置
+└── README.md # 项目文档
+```
+
+## 8. 包管理器选项
+
+FastAPI-fastkit 支持多种 Python 包管理器以适应不同偏好:
+
+### 可用的包管理器
+
+| 管理器 | 描述 | 适用场景 |
+|---------|-------------|----------|
+| **UV** | 快速的 Python 包管理器(默认) | 追求速度与性能 |
+| **PDM** | 现代化的 Python 依赖管理 | 需要更强的依赖解析 |
+| **Poetry** | Python 依赖管理与打包 | 基于 Poetry 的工作流 |
+| **PIP** | 标准 Python 包管理器 | 传统 Python 开发 |
+
+### 指定包管理器
+
+您可以通过多种方式指定偏好的包管理器:
+
+#### 1. 交互式选择(默认)
+
+运行 `fastkit init` 或 `fastkit startdemo` 时,系统会提示您选择:
+
+
+
+```console
+$ fastkit init
+# ... after project details and stack selection ...
+
+Available Package Managers:
+ Package Managers
+┌────────┬────────────────────────────────────────────┐
+│ PIP │ Standard Python package manager │
+│ UV │ Fast Python package manager │
+│ PDM │ Modern Python dependency management │
+│ POETRY │ Python dependency management and packaging │
+└────────┴────────────────────────────────────────────┘
+
+Select package manager (pip, uv, pdm, poetry) [uv]: uv
+```
+
+
+
+#### 2. 命令行参数
+
+直接通过参数指定包管理器,跳过交互选择:
+
+
+
+```console
+$ fastkit init --package-manager poetry
+$ fastkit startdemo --package-manager pdm
+```
+
+
+
+### 生成的依赖文件
+
+每种包管理器会生成相应的依赖文件:
+
+- **UV/PDM**:`pyproject.toml`(PEP 621 格式)
+- **Poetry**:`pyproject.toml`(Poetry 格式)
+- **PIP**:`requirements.txt`
+
+## 9. 接下来呢?
+
+恭喜!您已经成功完成了以下任务:
+
+✅ 创建了您的第一个 FastAPI 项目
+✅ 启动了开发服务器
+✅ 添加了新的 API 路由
+✅ 测试了您的 API
+
+### 继续学习
+
+1. **[您的第一个项目](../tutorial/first-project.md)**:构建一个更完整的博客 API
+2. **[创建项目](creating-projects.md)**:了解不同的技术栈与选项
+3. **[添加路由](adding-routes.md)**:精通 API 开发
+4. **[使用模板](using-templates.md)**:探索预构建的项目模板
+
+### 多动手实践
+
+您还可以试试下面这些命令,继续探索更多功能:
+
+
+
+```console
+# 列出可用模板
+$ fastkit list-templates
+
+# 基于模板创建项目
+$ fastkit startdemo
+
+# 继续添加更多路由(先写路由名,再写项目目录)
+$ fastkit addroute products my-first-app
+$ fastkit addroute orders my-first-app
+```
+
+
+
+!!! tip "开发小贴士"
+ - 修改代码后,服务器会自动重载
+ - 添加新功能时,记得查看交互式文档 `/docs`
+ - 使用虚拟环境隔离项目依赖
+ - 多阅读生成出来的代码,熟悉项目结构
diff --git a/docs/zh/user-guide/using-templates.md b/docs/zh/user-guide/using-templates.md
new file mode 100644
index 0000000..dd68815
--- /dev/null
+++ b/docs/zh/user-guide/using-templates.md
@@ -0,0 +1,608 @@
+# 使用模板
+
+FastAPI-fastkit 提供了一组预构建项目模板,帮助您按不同技术栈快速起步。
+
+## 可用的模板
+
+使用 `list-templates` 命令查看可用模板:
+
+
+
+```console
+$ fastkit list-templates
+ Available Templates
+┌─────────────────────────┬───────────────────────────────────┐
+│ fastapi-custom-response │ Async Item Management API with │
+│ │ Custom Response System │
+│ fastapi-dockerized │ Dockerized FastAPI Item │
+│ │ Management API │
+│ fastapi-empty │ No description │
+│ fastapi-async-crud │ Async Item Management API Server │
+│ fastapi-psql-orm │ Dockerized FastAPI Item │
+│ │ Management API with PostgreSQL │
+│ fastapi-default │ Simple FastAPI Project │
+└─────────────────────────┴───────────────────────────────────┘
+```
+
+
+
+## 模板说明
+
+### 1. `fastapi-default`
+
+**简单的 FastAPI 项目**
+
+- 包含必要功能的基础 FastAPI 配置
+- 基于 mock 数据的 item 管理
+- 适合学习与简单 API
+- 内置基本的 CRUD 操作
+
+**适合:**
+
+- FastAPI 新手
+- 简单的 Web API
+- 学习与原型开发
+
+### 2. `fastapi-async-crud`
+
+**异步 Item 管理 API 服务**
+
+- 完全异步的 FastAPI 应用
+- 基于 async/await 的进阶 CRUD 操作
+- I/O 操作性能更好
+- 基于 mock 数据的异步模式
+
+**适合:**
+
+- 高性能应用
+- I/O 密集型操作
+- 现代异步 Python 开发
+
+### 3. `fastapi-custom-response`
+
+**带自定义响应系统的异步 Item 管理 API**
+
+- 自定义响应模型与格式化
+- 进阶的错误处理
+- 支持分页
+- 自定义 HTTP 状态码与响应
+
+**适合:**
+
+- 需要特定响应格式的 API
+- 复杂的错误处理需求
+- 在响应中加入自定义业务逻辑
+
+### 4. `fastapi-dockerized`
+
+**已容器化的 FastAPI Item 管理 API**
+
+- 完整的 Docker 容器化
+- 面向生产的部署配置
+- 多阶段 Docker 构建
+- 基于环境变量的配置
+
+**适合:**
+
+- 生产部署
+- 容器化环境
+- DevOps 与 CI/CD 管道
+
+### 5. `fastapi-psql-orm`
+
+**集成 PostgreSQL 的已容器化 FastAPI Item 管理 API**
+
+- 集成 PostgreSQL 数据库
+- 使用 SQLAlchemy ORM 与 Alembic 迁移
+- 通过 Docker Compose 支持本地开发
+- 完整的基于数据库的 CRUD 操作
+
+**适合:**
+
+- 数据驱动的应用
+- 生产级数据存储
+- 复杂的数据关系
+
+### 6. `fastapi-empty`
+
+**极简 FastAPI 项目**
+
+- 极简的 FastAPI 配置
+- 不预置任何功能
+- 适合从零开始定制开发
+
+**适合:**
+
+- 从零开始
+- 依赖最少
+- 自定义架构需求
+
+## 基于模板创建项目
+
+使用 `startdemo` 命令基于模板创建项目:
+
+
+
+```console
+$ fastkit startdemo
+Enter the project name: my-blog-api
+Enter the author name: John Doe
+Enter the author email: john@example.com
+Enter the project description: Blog API with PostgreSQL
+
+Available Templates:
+ fastapi-default
+┌─────────────┬──────────────────────┐
+│ Description │ Simple FastAPI │
+│ │ Project │
+│ Stack │ FastAPI, Uvicorn │
+│ Database │ Mock Data │
+│ Features │ Basic CRUD │
+└─────────────┴──────────────────────┘
+
+ fastapi-psql-orm
+┌─────────────┬──────────────────────┐
+│ Description │ Dockerized FastAPI │
+│ │ Item Management API │
+│ │ with PostgreSQL │
+│ Stack │ FastAPI, PostgreSQL, │
+│ │ SQLAlchemy, Docker │
+│ Database │ PostgreSQL │
+│ Features │ Full ORM, Migrations │
+└─────────────┴──────────────────────┘
+
+Select template (fastapi-default, fastapi-async-crud, fastapi-custom-response, fastapi-dockerized, fastapi-psql-orm, fastapi-empty): fastapi-psql-orm
+
+ Project Information
+┌──────────────┬─────────────────────┐
+│ Project Name │ my-blog-api │
+│ Author │ John Doe │
+│ Author Email │ john@example.com │
+│ Description │ Blog API with │
+│ │ PostgreSQL │
+└──────────────┴─────────────────────┘
+
+ Template Dependencies
+┌──────────────┬───────────────────┐
+│ Dependency 1 │ fastapi │
+│ Dependency 2 │ uvicorn │
+│ Dependency 3 │ sqlalchemy │
+│ Dependency 4 │ alembic │
+│ Dependency 5 │ psycopg2-binary │
+│ Dependency 6 │ python-dotenv │
+│ Dependency 7 │ pytest │
+└──────────────┴───────────────────┘
+
+Available Package Managers:
+ Package Managers
+┌────────┬────────────────────────────────────────────┐
+│ PIP │ Standard Python package manager │
+│ UV │ Fast Python package manager │
+│ PDM │ Modern Python dependency management │
+│ POETRY │ Python dependency management and packaging │
+└────────┴────────────────────────────────────────────┘
+
+Select package manager (pip, uv, pdm, poetry) [uv]: uv
+Do you want to proceed with project creation? [y/N]: y
+
+✨ FastAPI project 'my-blog-api' from 'fastapi-psql-orm' has been created successfully!
+```
+
+
+
+## 模板功能对比
+
+| 功能 | 默认模板 | 异步 CRUD | 自定义响应 | Docker 化 | PostgreSQL ORM | 空模板 |
+|---------|---------|------------|-----------------|------------|----------------|-------|
+| **基础 FastAPI** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
+| **Mock 数据** | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
+| **异步支持** | 基础 | ✅ | ✅ | ✅ | ✅ | ❌ |
+| **自定义响应** | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
+| **Docker** | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ |
+| **数据库** | Mock | Mock | Mock | Mock | PostgreSQL | 无 |
+| **ORM** | ❌ | ❌ | ❌ | ❌ | SQLAlchemy | ❌ |
+| **数据迁移** | ❌ | ❌ | ❌ | ❌ | Alembic | ❌ |
+| **测试** | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
+| **适合** | 学习 | 性能 | 自定义 API | 生产 | 数据应用 | 自定义 |
+
+## 各模板的专属设置
+
+### 使用 `fastapi-psql-orm`
+
+该模板包含完整的 PostgreSQL 配置。创建完成后:
+
+1. **使用 Docker 启动 PostgreSQL:**
+
+
+
+```console
+$ cd my-blog-api
+$ docker-compose up -d postgres
+Starting my-blog-api_postgres_1 ... done
+```
+
+
+
+2. **运行数据库迁移:**
+
+
+
+```console
+$ source .venv/bin/activate
+$ alembic upgrade head
+INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
+INFO [alembic.runtime.migration] Will assume transactional DDL.
+INFO [alembic.runtime.migration] Running upgrade -> bedcdc35b64a, first alembic
+```
+
+
+
+3. **启动 API 服务器:**
+
+
+
+```console
+$ fastkit runserver
+INFO: Uvicorn running on http://127.0.0.1:8000
+```
+
+
+
+### 使用 `fastapi-dockerized`
+
+该模板提供完整的 Docker 支持:
+
+1. **构建 Docker 镜像:**
+
+
+
+```console
+$ cd my-dockerized-api
+$ docker build -t my-dockerized-api .
+Successfully built abc123def456
+Successfully tagged my-dockerized-api:latest
+```
+
+
+
+2. **运行容器:**
+
+
+
+```console
+$ docker run -p 8000:8000 my-dockerized-api
+INFO: Uvicorn running on http://0.0.0.0:8000
+```
+
+
+
+### 使用 `fastapi-custom-response`
+
+该模板包含进阶的响应处理:
+
+1. **自定义响应模型:**
+
+```python
+from src.helper.pagination import PaginatedResponse
+from src.schemas.base import StandardResponse
+
+@router.get("/", response_model=PaginatedResponse[Item])
+def read_items(skip: int = 0, limit: int = 10):
+ items = items_crud.get_multi(skip=skip, limit=limit)
+ total = items_crud.count()
+
+ return PaginatedResponse(
+ data=items,
+ total=total,
+ page=skip // limit + 1,
+ pages=(total + limit - 1) // limit
+ )
+
+@router.post("/", response_model=StandardResponse[Item])
+def create_item(item: ItemCreate):
+ new_item = items_crud.create(item)
+ return StandardResponse(
+ data=new_item,
+ message="Item created successfully",
+ status_code=201
+ )
+```
+
+2. **增强的错误处理:**
+
+```python
+from src.helper.exceptions import ItemNotFoundError, ValidationError
+
+@router.get("/{item_id}", response_model=StandardResponse[Item])
+def read_item(item_id: int):
+ try:
+ item = items_crud.get(item_id)
+ return StandardResponse(data=item)
+ except ItemNotFoundError:
+ raise HTTPException(
+ status_code=404,
+ detail=f"Item with id {item_id} not found"
+ )
+```
+
+## 各模板的项目结构
+
+每个模板都遵循统一但又针对自身做了定制的结构:
+
+### `fastapi-default` 结构
+```
+my-project/
+├── src/
+│ ├── main.py
+│ ├── core/config.py
+│ ├── api/
+│ │ ├── api.py
+│ │ └── routes/items.py
+│ ├── crud/items.py
+│ ├── schemas/items.py
+│ └── mocks/mock_items.json
+├── tests/
+├── scripts/
+└── requirements.txt
+```
+
+### `fastapi-psql-orm` 结构
+```
+my-project/
+├── src/
+│ ├── main.py
+│ ├── core/
+│ │ ├── config.py
+│ │ └── db.py
+│ ├── api/
+│ │ ├── api.py
+│ │ ├── deps.py
+│ │ └── routes/items.py
+│ ├── crud/items.py
+│ ├── schemas/items.py
+│ ├── alembic/
+│ │ ├── env.py
+│ │ └── versions/
+│ └── utils/
+├── tests/
+├── scripts/
+├── docker-compose.yml
+├── Dockerfile
+├── alembic.ini
+└── requirements.txt
+```
+
+## 定制模板
+
+基于模板创建项目后,您可以进行定制:
+
+### 1. 添加新路由
+
+
+
+```console
+$ fastkit addroute posts my-blog-api
+$ fastkit addroute users my-blog-api
+$ fastkit addroute comments my-blog-api
+```
+
+
+
+### 2. 修改配置
+
+按需修改 `src/core/config.py`:
+
+```python
+from pydantic_settings import BaseSettings
+
+class Settings(BaseSettings):
+ PROJECT_NAME: str = "My Blog API"
+ VERSION: str = "1.0.0"
+ API_V1_STR: str = "/api/v1"
+
+ # 数据库设置(适用于 PostgreSQL 模板)
+ DATABASE_URL: str = "postgresql://user:password@localhost/dbname"
+
+ # 安全设置
+ SECRET_KEY: str = "your-secret-key-here"
+ ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
+
+ class Config:
+ env_file = ".env"
+
+settings = Settings()
+```
+
+### 3. 添加环境变量
+
+在项目根目录创建 `.env`:
+
+```env
+# .env
+PROJECT_NAME=My Blog API
+VERSION=1.0.0
+DEBUG=True
+
+# 数据库设置(适用于 PostgreSQL 模板)
+DATABASE_URL=postgresql://user:password@localhost:5432/myblogdb
+POSTGRES_USER=user
+POSTGRES_PASSWORD=password
+POSTGRES_DB=myblogdb
+
+# 安全设置
+SECRET_KEY=your-super-secret-key-here
+ACCESS_TOKEN_EXPIRE_MINUTES=30
+```
+
+## 测试模板
+
+每个模板都附带预配置的测试:
+
+
+
+```console
+$ cd my-blog-api
+$ source .venv/bin/activate
+$ python -m pytest
+
+======================== test session starts ========================
+tests/test_items.py::test_create_item PASSED
+tests/test_items.py::test_read_items PASSED
+tests/test_items.py::test_read_item PASSED
+tests/test_items.py::test_update_item PASSED
+tests/test_items.py::test_delete_item PASSED
+======================== 5 passed in 0.23s ========================
+```
+
+
+
+## 基于模板的开发流程
+
+### 1. 选择合适的模板
+
+- **学习 / 简单 API**:`fastapi-default`
+- **高性能**:`fastapi-async-crud`
+- **自定义响应格式**:`fastapi-custom-response`
+- **生产部署**:`fastapi-dockerized`
+- **数据库应用**:`fastapi-psql-orm`
+- **自定义架构**:`fastapi-empty`
+
+### 2. 创建并配置
+
+
+
+```console
+$ fastkit startdemo
+# 按提示完成选择
+$ cd your-project
+$ source .venv/bin/activate
+```
+
+
+
+### 3. 开发
+
+
+
+```console
+# 启动开发服务器
+$ fastkit runserver
+
+# 运行测试
+$ python -m pytest
+
+# 添加新功能
+$ fastkit addroute new-resource your-project
+```
+
+
+
+### 4. 部署
+
+对于面向生产的模板(`fastapi-dockerized`、`fastapi-psql-orm`):
+
+
+
+```console
+# 构建生产镜像
+$ docker build -t your-app .
+
+# 使用 Docker Compose 部署
+$ docker-compose up -d
+```
+
+
+
+## 最佳实践
+
+### 1. 谨慎选择模板
+
+- 学习时从更简单的模板开始
+- 数据驱动应用使用数据库模板
+- 生产部署使用 Docker 模板
+
+### 2. 环境管理
+
+- 始终使用 `.env` 文件管理配置
+- 切勿将敏感信息提交到版本控制
+- 开发与生产使用不同的环境
+
+### 3. 定制策略
+
+- 使用 `fastkit addroute` 添加新路由
+- 根据您的业务逻辑改造现有代码
+- 保持项目结构清晰
+
+### 4. 测试
+
+- 开发过程中持续运行测试
+- 为新实现的功能补充测试
+- 把内置的测试结构当作参考模板
+
+## 故障排查
+
+### 数据库连接问题(PostgreSQL 模板)
+
+若无法连接 PostgreSQL:
+
+1. **检查 Docker 是否在运行:**
+
+
+ ```console
+ $ docker ps
+ ```
+
+
+2. **检查 PostgreSQL 容器:**
+
+
+ ```console
+ $ docker-compose logs postgres
+ ```
+
+
+3. **检查环境变量:**
+
+ ```env
+ DATABASE_URL=postgresql://user:password@localhost:5432/dbname
+ ```
+
+### Docker 构建失败
+
+若 Docker 构建失败:
+
+1. **检查 Dockerfile 语法**
+2. **确认所有文件都存在**
+3. **确认 Docker 守护进程已启动**
+
+### 依赖缺失
+
+若出现 import 错误:
+
+1. **激活虚拟环境:**
+
+ ```console
+ $ source .venv/bin/activate
+ ```
+
+
+2. **安装依赖:**
+
+ ```console
+ $ pip install -r requirements.txt
+ ```
+
+
+## 下一步
+
+现在您已了解模板:
+
+1. **[您的第一个项目](../tutorial/first-project.md)**:构建一个完整的应用
+2. **[添加路由](adding-routes.md)**:扩展基于模板创建的项目
+3. **[CLI 参考](cli-reference.md)**:掌握所有可用命令
+
+!!! tip "模板小贴士"
+ - 模板是优秀的起点,而非最终方案
+ - 根据具体需求自定义模板
+ - 阅读模板代码,学习 FastAPI 最佳实践
+ - 使用版本控制记录您的修改