diff --git a/.vitepress/config.mts b/.vitepress/config.mts
index c0a8203..0728899 100644
--- a/.vitepress/config.mts
+++ b/.vitepress/config.mts
@@ -1,11 +1,11 @@
import { defineConfig } from 'vitepress'
-function nav() {
+function navEn() {
return [
- { text: 'Tutorial', link: '/tutorials/getting-started', activeMatch: 'tutorials/' },
- { text: 'How-to', link: '/how-to/add-new-domain', activeMatch: 'how-to/' },
- { text: 'Explanation', link: '/explanation/architecture', activeMatch: 'explanation/' },
- { text: 'Reference', link: '/reference/configuration', activeMatch: 'reference/' },
+ { text: 'Tutorial', link: '/tutorials/getting-started', activeMatch: '/tutorials/' },
+ { text: 'How-to', link: '/how-to/add-new-domain', activeMatch: '/how-to/' },
+ { text: 'Explanation', link: '/explanation/architecture', activeMatch: '/explanation/' },
+ { text: 'Reference', link: '/reference/configuration', activeMatch: '/reference/' },
{
text: 'v1.0.0',
items: [
@@ -17,29 +17,46 @@ function nav() {
]
}
-function sidebar() {
+function navJa() {
+ return [
+ { text: 'チュートリアル', link: '/ja/tutorials/getting-started', activeMatch: '/ja/tutorials/' },
+ { text: 'ハウツー', link: '/ja/how-to/add-new-domain', activeMatch: '/ja/how-to/' },
+ { text: '解説', link: '/ja/explanation/architecture', activeMatch: '/ja/explanation/' },
+ { text: 'リファレンス', link: '/ja/reference/configuration', activeMatch: '/ja/reference/' },
+ {
+ text: 'v1.0.0',
+ items: [
+ { text: '変更履歴', link: 'https://github.com/hideyukiMORI/nene2-python/blob/main/CHANGELOG.md' },
+ { text: 'リリース', link: 'https://github.com/hideyukiMORI/nene2-python/releases' },
+ { text: 'PHP NENE2', link: 'https://hideyukimori.github.io/NENE2/' },
+ ],
+ },
+ ]
+}
+
+function sidebarEn() {
return {
'/tutorials/': [{
text: 'Tutorials',
items: [
- { text: 'Getting started', link: '/tutorials/getting-started' },
+ { text: 'Getting started', link: '/tutorials/getting-started' },
{ text: 'Implement a new domain', link: '/tutorials/first-domain' },
],
}],
'/how-to/': [{
text: 'How-to guides',
items: [
- { text: 'Add a new domain', link: '/how-to/add-new-domain' },
- { text: 'Configure auth', link: '/how-to/configure-auth' },
- { text: 'Set up MCP', link: '/howto/mcp-setup' },
- { text: 'Run tests', link: '/how-to/run-tests' },
+ { text: 'Add a new domain', link: '/how-to/add-new-domain' },
+ { text: 'Configure auth', link: '/how-to/configure-auth' },
+ { text: 'Set up MCP', link: '/howto/mcp-setup' },
+ { text: 'Run tests', link: '/how-to/run-tests' },
],
}],
'/explanation/': [{
text: 'Explanation',
items: [
- { text: 'Architecture', link: '/explanation/architecture' },
- { text: 'Design philosophy', link: '/explanation/design-philosophy' },
+ { text: 'Architecture', link: '/explanation/architecture' },
+ { text: 'Design philosophy', link: '/explanation/design-philosophy' },
],
}, {
text: 'ADR',
@@ -58,9 +75,9 @@ function sidebar() {
'/reference/': [{
text: 'Reference',
items: [
- { text: 'Configuration', link: '/reference/configuration' },
- { text: 'Framework modules', link: '/reference/framework-modules' },
- { text: 'REST API', link: '/reference/api' },
+ { text: 'Configuration', link: '/reference/configuration' },
+ { text: 'Framework modules', link: '/reference/framework-modules' },
+ { text: 'REST API', link: '/reference/api' },
],
}],
'/adr/': [{
@@ -79,6 +96,42 @@ function sidebar() {
}
}
+function sidebarJa() {
+ return {
+ '/ja/tutorials/': [{
+ text: 'チュートリアル',
+ items: [
+ { text: 'はじめての nene2-python', link: '/ja/tutorials/getting-started' },
+ { text: '新しいドメインを実装する', link: '/ja/tutorials/first-domain' },
+ ],
+ }],
+ '/ja/how-to/': [{
+ text: 'ハウツーガイド',
+ items: [
+ { text: '新しいドメインを追加する', link: '/ja/how-to/add-new-domain' },
+ { text: '認証を設定する', link: '/ja/how-to/configure-auth' },
+ { text: 'MCP セットアップ', link: '/ja/howto/mcp-setup' },
+ { text: 'テストを実行する', link: '/ja/how-to/run-tests' },
+ ],
+ }],
+ '/ja/explanation/': [{
+ text: '解説',
+ items: [
+ { text: 'アーキテクチャ概要', link: '/ja/explanation/architecture' },
+ { text: '設計思想と PHP との対応', link: '/ja/explanation/design-philosophy' },
+ ],
+ }],
+ '/ja/reference/': [{
+ text: 'リファレンス',
+ items: [
+ { text: '設定リファレンス', link: '/ja/reference/configuration' },
+ { text: 'フレームワークモジュール', link: '/ja/reference/framework-modules' },
+ { text: 'REST API', link: '/ja/reference/api' },
+ ],
+ }],
+ }
+}
+
export default defineConfig({
title: 'NENE2 Python',
description: 'FastAPI + Clean Architecture + MCP. Python 3.12+. AI-ready from day one.',
@@ -93,27 +146,132 @@ export default defineConfig({
['link', { rel: 'icon', href: 'data:image/svg+xml,' }],
],
+ locales: {
+ root: {
+ label: 'English',
+ lang: 'en',
+ themeConfig: {
+ nav: navEn(),
+ sidebar: sidebarEn(),
+ editLink: {
+ pattern: 'https://github.com/hideyukiMORI/nene2-python/edit/main/docs/:path',
+ text: 'Edit this page on GitHub',
+ },
+ footer: {
+ message: 'Released under the MIT License.',
+ copyright: 'Copyright © 2026 hideyukiMORI',
+ },
+ },
+ },
+ ja: {
+ label: '日本語',
+ lang: 'ja',
+ themeConfig: {
+ nav: navJa(),
+ sidebar: sidebarJa(),
+ editLink: {
+ pattern: 'https://github.com/hideyukiMORI/nene2-python/edit/main/docs/:path',
+ text: 'GitHub でこのページを編集',
+ },
+ footer: {
+ message: 'MIT ライセンスの下でリリースされています。',
+ copyright: 'Copyright © 2026 hideyukiMORI',
+ },
+ },
+ },
+ fr: {
+ label: 'Français',
+ lang: 'fr',
+ themeConfig: {
+ nav: [
+ { text: 'Tutoriel', link: '/fr/tutorials/getting-started' },
+ { text: 'v1.0.0', items: [{ text: 'Releases', link: 'https://github.com/hideyukiMORI/nene2-python/releases' }] },
+ ],
+ sidebar: {
+ '/fr/': [{ text: 'Tutoriels', items: [{ text: 'Premiers pas', link: '/fr/tutorials/getting-started' }] }],
+ },
+ editLink: {
+ pattern: 'https://github.com/hideyukiMORI/nene2-python/edit/main/docs/:path',
+ text: 'Éditer cette page sur GitHub',
+ },
+ footer: {
+ message: 'Publié sous la licence MIT.',
+ copyright: 'Copyright © 2026 hideyukiMORI',
+ },
+ },
+ },
+ zh: {
+ label: '简体中文',
+ lang: 'zh-CN',
+ themeConfig: {
+ nav: [
+ { text: '教程', link: '/zh/tutorials/getting-started' },
+ { text: 'v1.0.0', items: [{ text: 'Releases', link: 'https://github.com/hideyukiMORI/nene2-python/releases' }] },
+ ],
+ sidebar: {
+ '/zh/': [{ text: '教程', items: [{ text: '快速开始', link: '/zh/tutorials/getting-started' }] }],
+ },
+ editLink: {
+ pattern: 'https://github.com/hideyukiMORI/nene2-python/edit/main/docs/:path',
+ text: '在 GitHub 上编辑此页面',
+ },
+ footer: {
+ message: '根据 MIT 许可证发布。',
+ copyright: 'Copyright © 2026 hideyukiMORI',
+ },
+ },
+ },
+ 'pt-br': {
+ label: 'Português (Brasil)',
+ lang: 'pt-BR',
+ themeConfig: {
+ nav: [
+ { text: 'Tutorial', link: '/pt-br/tutorials/getting-started' },
+ { text: 'v1.0.0', items: [{ text: 'Releases', link: 'https://github.com/hideyukiMORI/nene2-python/releases' }] },
+ ],
+ sidebar: {
+ '/pt-br/': [{ text: 'Tutoriais', items: [{ text: 'Primeiros passos', link: '/pt-br/tutorials/getting-started' }] }],
+ },
+ editLink: {
+ pattern: 'https://github.com/hideyukiMORI/nene2-python/edit/main/docs/:path',
+ text: 'Editar esta página no GitHub',
+ },
+ footer: {
+ message: 'Lançado sob a Licença MIT.',
+ copyright: 'Copyright © 2026 hideyukiMORI',
+ },
+ },
+ },
+ de: {
+ label: 'Deutsch',
+ lang: 'de',
+ themeConfig: {
+ nav: [
+ { text: 'Tutorial', link: '/de/tutorials/getting-started' },
+ { text: 'v1.0.0', items: [{ text: 'Releases', link: 'https://github.com/hideyukiMORI/nene2-python/releases' }] },
+ ],
+ sidebar: {
+ '/de/': [{ text: 'Tutorials', items: [{ text: 'Erste Schritte', link: '/de/tutorials/getting-started' }] }],
+ },
+ editLink: {
+ pattern: 'https://github.com/hideyukiMORI/nene2-python/edit/main/docs/:path',
+ text: 'Diese Seite auf GitHub bearbeiten',
+ },
+ footer: {
+ message: 'Veröffentlicht unter der MIT-Lizenz.',
+ copyright: 'Copyright © 2026 hideyukiMORI',
+ },
+ },
+ },
+ },
+
themeConfig: {
siteTitle: '🐍 NENE2',
- nav: nav(),
- sidebar: sidebar(),
-
socialLinks: [
{ icon: 'github', link: 'https://github.com/hideyukiMORI/nene2-python' },
],
-
search: { provider: 'local' },
outline: { level: [2, 3] },
-
- editLink: {
- pattern: 'https://github.com/hideyukiMORI/nene2-python/edit/main/docs/:path',
- text: 'Edit this page on GitHub',
- },
-
- footer: {
- message: 'Released under the MIT License.',
- copyright: 'Copyright © 2026 hideyukiMORI',
- },
},
markdown: {
diff --git a/docs/de/index.md b/docs/de/index.md
new file mode 100644
index 0000000..a0c41a9
--- /dev/null
+++ b/docs/de/index.md
@@ -0,0 +1,43 @@
+---
+layout: home
+
+hero:
+ name: "NENE2"
+ text: "Python API Framework"
+ tagline: FastAPI · Clean Architecture · MCP · mypy --strict · Von Anfang an KI-bereit.
+ actions:
+ - theme: brand
+ text: Loslegen →
+ link: /de/tutorials/getting-started
+ - theme: alt
+ text: Auf GitHub ansehen
+ link: https://github.com/hideyukiMORI/nene2-python
+ - theme: alt
+ text: PHP-Version
+ link: https://hideyukimori.github.io/NENE2/
+
+features:
+ - icon: 🐍
+ title: Python 3.12+ nativ
+ details: Python 3.12 generische Syntax, eingefrorene Dataclasses und Pydantic v2. mypy --strict bei jedem Commit erzwungen.
+
+ - icon: ⚡
+ title: FastAPI + async
+ details: ASGI-nativ mit AsyncUseCaseProtocol für nicht blockierendes I/O. asyncio.gather für parallele Repository-Aufrufe.
+
+ - icon: 🤖
+ title: MCP integriert
+ details: UseCases werden über LocalMcpServer als MCP-Werkzeuge bereitgestellt — ohne zusätzliche Konfiguration.
+
+ - icon: 🏛️
+ title: Clean Architecture
+ details: HTTP Handler → UseCase → RepositoryInterface → SQLAlchemy. Jede Schicht mit InMemory-Repositories testbar.
+
+ - icon: 🛡️
+ title: Sicherheit zuerst
+ details: RFC 9457 Problem Details, Bearer + API Key Authentifizierung, Rate Limiting, Sicherheits-Header — sofort einsatzbereit.
+
+ - icon: 📄
+ title: OpenAPI automatisch generiert
+ details: Swagger UI und ReDoc unter /docs — keine Konfiguration. Statisches openapi.yaml mit einem Befehl exportieren.
+---
diff --git a/docs/de/tutorials/getting-started.md b/docs/de/tutorials/getting-started.md
new file mode 100644
index 0000000..1e12dbd
--- /dev/null
+++ b/docs/de/tutorials/getting-started.md
@@ -0,0 +1,54 @@
+# Erste Schritte mit nene2-python
+
+Dieses Tutorial ermöglicht es Ihnen, in 5 Minuten eine Notes-CRUD-API mit nene2-python zu starten.
+
+## Voraussetzungen
+
+- Python 3.12 oder höher
+- [uv](https://docs.astral.sh/uv/) installiert
+- Git
+
+## 1. Repository klonen
+
+```bash
+git clone https://github.com/hideyukiMORI/nene2-python.git
+cd nene2-python
+```
+
+## 2. Abhängigkeiten installieren
+
+```bash
+uv sync
+```
+
+## 3. Entwicklungsserver starten
+
+```bash
+uv run uvicorn src.example.app:app --reload --port 8080
+```
+
+Öffnen Sie `http://localhost:8080/docs` im Browser für die Swagger UI.
+
+## 4. API testen
+
+```bash
+# Notiz erstellen
+curl -X POST http://localhost:8080/notes \
+ -H "Content-Type: application/json" \
+ -d '{"title": "Meine erste Notiz", "body": "Erstellt mit nene2-python"}'
+
+# Notizen auflisten
+curl http://localhost:8080/notes
+```
+
+## 5. Tests ausführen
+
+```bash
+uv run pytest
+```
+
+Mehr als 135 Tests sollten erfolgreich sein.
+
+## Nächste Schritte
+
+- [Konfigurationsreferenz](../reference/configuration.md) — Datenbank und Authentifizierung über Umgebungsvariablen konfigurieren
diff --git a/docs/explanation/architecture.md b/docs/explanation/architecture.md
index b75e099..ab79868 100644
--- a/docs/explanation/architecture.md
+++ b/docs/explanation/architecture.md
@@ -1,8 +1,8 @@
-# アーキテクチャ概要
+# Architecture overview
-## レイヤー構造
+## Layer structure
-nene2-python はクリーンアーキテクチャに基づいており、依存関係は外から内へ向かいます。
+nene2-python follows Clean Architecture. Dependencies flow from the outside in.
```
┌─────────────────────────────────────────────┐
@@ -10,24 +10,25 @@ nene2-python はクリーンアーキテクチャに基づいており、依存
│ parse request → call use-case → response │
├─────────────────────────────────────────────┤
│ UseCase │
-│ ビジネスロジック。HTTP・DB を知らない │
+│ Business logic — no HTTP or DB knowledge │
├─────────────────────────────────────────────┤
│ RepositoryInterface (ABC) │
-│ ドメインが必要とする操作の契約 │
+│ Contract for the operations the domain │
+│ needs │
├─────────────────────────────────────────────┤
│ ConcreteRepository │
-│ SQLAlchemy / InMemory 実装 │
+│ SQLAlchemy / InMemory implementations │
└─────────────────────────────────────────────┘
```
-## 各レイヤーの責務
+## Layer responsibilities
### HTTP Handler
-- **唯一の責務**: リクエストを解析し UseCase を呼び、レスポンスを返す
-- Pydantic `BaseModel` でリクエストボディを検証(HTTP 境界のみ)
-- ドメインロジックを持たない
-- `make_xxx_router()` ファクトリ関数がルーターを返す
+- **Single responsibility**: parse the request, call a UseCase, return a response
+- Uses Pydantic `BaseModel` for request body validation (HTTP boundary only)
+- Contains zero domain logic
+- Exposed via a `make_xxx_router()` factory function
```python
@router.post("", status_code=201)
@@ -38,46 +39,46 @@ async def create_note(body: CreateNoteBody) -> JSONResponse:
### UseCase
-- **唯一の責務**: ビジネスルールを実装する
-- `execute(input_: XxxInput) -> XxxOutput` の単一メソッド
-- `import fastapi`, `import sqlalchemy` を持たない
-- 他の UseCase を呼ばない(オーケストレーションは上位層)
-- `InMemoryRepository` でテスト可能
+- **Single responsibility**: implement one business rule
+- One method: `execute(input_: XxxInput) -> XxxOutput`
+- No `import fastapi`, no `import sqlalchemy`
+- Does not call other UseCases
+- Testable with `InMemoryRepository` alone
### RepositoryInterface
-- ABC で契約を定義
-- UseCase は Interface のみに依存する(具象クラスを知らない)
-- InMemory 実装と SQLAlchemy 実装が同じ Interface を実装する
+- Defined as an ABC — the UseCase depends only on the interface
+- Same interface is implemented by InMemory and SQLAlchemy versions
+- `find_all`, `find_by_id`, `save`, `update`, `delete`, `count`
### ConcreteRepository
-- SQLAlchemy Core(ORM なし)でパラメータ化クエリを実行
-- `SqlAlchemyQueryExecutor` でクエリを抽象化
-- テーブルスキーマは `src/example/schema.py` で一元管理
+- SQLAlchemy Core (no ORM) with parameterised queries
+- Queries are executed via `SqlAlchemyQueryExecutor`
+- Table schema is managed centrally in `src/example/schema.py`
-## ミドルウェアスタック
+## Middleware stack
-リクエストは外側から内側に向かって処理されます:
+Requests pass through each middleware from outermost to innermost:
```
-BearerTokenMiddleware 認証 (Bearer Token)
-ApiKeyAuthMiddleware 認証 (API Key)
+BearerTokenMiddleware Authentication (Bearer Token)
+ApiKeyAuthMiddleware Authentication (API Key)
CORSMiddleware CORS
-ThrottleMiddleware レートリミット
-RequestSizeLimitMiddleware ペイロードサイズ制限
-RequestLoggingMiddleware リクエストロギング
-RequestIdMiddleware リクエスト ID 付与
-SecurityHeadersMiddleware セキュリティヘッダー付与
-ErrorHandlerMiddleware 例外 → RFC 9457 Problem Details 変換
+ThrottleMiddleware Rate limiting (fixed window)
+RequestSizeLimitMiddleware Payload size enforcement
+RequestLoggingMiddleware Structured request logging (structlog)
+RequestIdMiddleware X-Request-ID generation / propagation
+SecurityHeadersMiddleware Security response headers
+ErrorHandlerMiddleware Exceptions → RFC 9457 Problem Details
```
-## DI パターン
+## Dependency injection
-FastAPI の `Depends` は HTTP 境界のみで使用します。UseCase とリポジトリはコンストラクタインジェクションで接続します。
+FastAPI's `Depends` is used at the HTTP boundary only. UseCases and repositories are wired via constructor injection in `app.py`.
```python
-# app.py — ワイヤリング
+# app.py — wiring
note_repo = SqlAlchemyNoteRepository(executor)
app.include_router(make_note_router(
list_use_case=ListNotesUseCase(note_repo),
@@ -86,15 +87,15 @@ app.include_router(make_note_router(
))
```
-## ドメインパッケージ構造
+## Domain package layout
```
src/example//
__init__.py
entity.py — @dataclass(frozen=True, slots=True)
- repository.py — ABC + InMemory 実装
+ repository.py — ABC + InMemory implementation
exceptions.py — XxxNotFoundException + ExceptionHandler
- use_case.py — 5 UseCase + Input/Output DTO
- handler.py — FastAPI router
- sqlalchemy_repository.py — SQL バックエンド
+ use_case.py — 5 UseCases + Input/Output DTOs
+ handler.py — FastAPI router factory
+ sqlalchemy_repository.py — SQL backend
```
diff --git a/docs/explanation/design-philosophy.md b/docs/explanation/design-philosophy.md
index 4bcb0f1..38780c7 100644
--- a/docs/explanation/design-philosophy.md
+++ b/docs/explanation/design-philosophy.md
@@ -1,68 +1,68 @@
-# 設計思想と PHP NENE2 との対応
+# Design philosophy
-## NENE2 の設計原則
+## NENE2 core principles
-nene2-python は PHP 版 NENE2 と同一の設計思想を持ちます。
+nene2-python shares the same design philosophy as PHP NENE2.
### API First
-JSON API と OpenAPI 契約を中心に据えます。DB 設計より先に API の形を定義し、スキーマを `uv run export-openapi` で生成します。
+The JSON API contract and OpenAPI schema are defined before the database schema. Use `uv run export-openapi` to export a static `openapi.yaml` at any time.
-### 薄い HTTP 層
+### Thin HTTP layer
-HTTP Handler はビジネスロジックを持ちません。**parse → use-case → response** の 3 ステップのみ。ドメインルールは UseCase に集約されます。
+HTTP Handlers own no business logic. The rule is: **parse → use-case → response** — three steps, nothing more. Domain rules live in UseCases.
### AI-readable
-明示的なディレクトリ構造、小さなクラス(150 行以下)、型付き境界により、LLM がコードベースを正確に理解・操作できます。
+Explicit directory structure, small classes (≤ 150 lines), typed boundaries — these let an LLM navigate and modify the codebase with confidence.
-### Security First
+### Security first
-セキュリティは後付けではなく設計の出発点です。
-- Pydantic による HTTP 境界の全入力検証
-- パラメータ化クエリのみ(SQLインジェクション防止)
-- `secrets.compare_digest` によるタイミング安全な比較
-- セキュリティヘッダーをミドルウェアで付与
+Security is a design constraint, not an afterthought:
+- All HTTP inputs validated by Pydantic at the boundary
+- Parameterised queries only (SQL injection prevention)
+- `secrets.compare_digest` for timing-safe token comparison
+- Security headers applied by middleware on every response
### LLM Delivery Ready
-UseCase は HTTP・DB から独立しているため、MCP ツールとして直接再利用できます。`src/example/mcp.py` はその実証です。
+Because UseCases are independent of HTTP and database, they can be registered directly as MCP tools. `src/example/mcp.py` proves this — 15 tools, zero extra plumbing.
-## PHP NENE2 との対応表
+---
-| PHP 版 | Python 版 | 備考 |
-|---|---|---|
-| `readonly class` | `@dataclass(frozen=True, slots=True)` | 不変 Value Object |
-| `ValidationException` + `ValidationError` | 同名クラス (`nene2.validation`) | 422 + Problem Details |
-| `PaginationQueryParser` | `nene2.http.PaginationQueryParser` | クエリパラメータ解析 |
-| `PaginationResponse` | `nene2.http.PaginationResponse` | ページネーションレスポンス |
-| `ProblemDetailsResponseFactory` | `nene2.http.problem_details_response()` | RFC 9457 |
-| `ErrorHandlerMiddleware` | `nene2.middleware.ErrorHandlerMiddleware` | 全例外をキャッチ |
-| `PHPStan level 8` | `mypy --strict` | 最高レベルの型チェック |
-| `PHP-CS-Fixer` | `ruff format` | コードフォーマット |
-| `UseCaseInterface` | `nene2.use_case.UseCaseProtocol[I, O]` | 構造的サブタイピング |
+## Python vs PHP NENE2
-## Python 3.12+ 固有の選択
-
-| 用途 | 選択 | 理由 |
+| PHP | Python | Notes |
|---|---|---|
-| 型エイリアス | `type X = list[str]` | PEP 695 — 新構文 |
-| ジェネリクス | `class Foo[T]` | PEP 695 — TypeVar 不要 |
-| 不変 VO | `dataclass(frozen=True, slots=True)` | メモリ効率 + 不変性 |
-| HTTP 検証 | Pydantic v2 BaseModel | 高速 + 型安全 |
-| SQL | SQLAlchemy Core | ORM なしで SQL を直接制御 |
-| ロギング | structlog | JSON / Console の両対応 |
-| MCP | mcp (Anthropic SDK) | FastMCP ラッパー |
-
-## ADR 一覧
-
-設計の個別決定は ADR に記録されています:
-
-- [ADR-0001: ツールチェーン](../adr/0001-toolchain.md)
-- [ADR-0002: クリーンアーキテクチャ](../adr/0002-clean-architecture.md)
-- [ADR-0003: セキュリティファースト](../adr/0003-security-first.md)
-- [ADR-0004: AI ファースト設計](../adr/0004-ai-first-design.md)
-- [ADR-0005: ロギング](../adr/0005-logging.md)
-- [ADR-0006: レートリミット](../adr/0006-rate-limiting.md)
-- [ADR-0009: MCP 設計](../adr/0009-mcp-design.md)
-- [ADR-0010: AsyncUseCase パターン](../adr/0010-async-use-case.md)
+| `readonly class` | `@dataclass(frozen=True, slots=True)` | Immutable value object |
+| `ValidationException` + `ValidationError` | Same names (`nene2.validation`) | 422 + Problem Details |
+| `PaginationQueryParser` | `nene2.http.PaginationQueryParser` | Query param parsing |
+| `PaginationResponse` | `nene2.http.PaginationResponse` | Paginated response |
+| `ProblemDetailsResponseFactory` | `nene2.http.problem_details_response()` | RFC 9457 |
+| `ErrorHandlerMiddleware` | `nene2.middleware.ErrorHandlerMiddleware` | Catches all exceptions |
+| `PHPStan level 8` | `mypy --strict` | Maximum type safety |
+| `PHP-CS-Fixer` | `ruff format` | Code formatting |
+| `UseCaseInterface` | `nene2.use_case.UseCaseProtocol[I, O]` | Structural typing |
+
+## Python-only features
+
+| Feature | Why Python wins |
+|---|---|
+| `AsyncUseCaseProtocol[I, O]` | No PHP equivalent — native coroutine protocol |
+| OpenAPI auto-generation | FastAPI generates Swagger UI / ReDoc with zero config |
+| Native async/await | FastAPI + uvicorn — non-blocking I/O throughout |
+| MCP SDK | Anthropic's Python SDK is the reference implementation |
+| `mypy --strict` | Tighter than PHPStan level 8 in practice |
+
+## ADR index
+
+Individual design decisions are recorded in Architecture Decision Records:
+
+- [ADR-0001: Toolchain](../adr/0001-toolchain)
+- [ADR-0002: Clean Architecture](../adr/0002-clean-architecture)
+- [ADR-0003: Security First](../adr/0003-security-first)
+- [ADR-0004: AI-First Design](../adr/0004-ai-first-design)
+- [ADR-0005: Logging](../adr/0005-logging)
+- [ADR-0006: Rate Limiting](../adr/0006-rate-limiting)
+- [ADR-0009: MCP Design](../adr/0009-mcp-design)
+- [ADR-0010: AsyncUseCase Pattern](../adr/0010-async-use-case)
diff --git a/docs/fr/index.md b/docs/fr/index.md
new file mode 100644
index 0000000..ac2f44c
--- /dev/null
+++ b/docs/fr/index.md
@@ -0,0 +1,43 @@
+---
+layout: home
+
+hero:
+ name: "NENE2"
+ text: "Framework API Python"
+ tagline: FastAPI · Architecture propre · MCP · mypy --strict · Conçu pour l'IA dès le premier jour.
+ actions:
+ - theme: brand
+ text: Commencer →
+ link: /fr/tutorials/getting-started
+ - theme: alt
+ text: Voir sur GitHub
+ link: https://github.com/hideyukiMORI/nene2-python
+ - theme: alt
+ text: Version PHP
+ link: https://hideyukimori.github.io/NENE2/
+
+features:
+ - icon: 🐍
+ title: Python 3.12+ natif
+ details: Syntaxe générique Python 3.12, dataclasses gelées et Pydantic v2. mypy --strict appliqué à chaque commit.
+
+ - icon: ⚡
+ title: FastAPI + async
+ details: ASGI natif avec AsyncUseCaseProtocol pour les I/O non bloquants. asyncio.gather pour les appels parallèles.
+
+ - icon: 🤖
+ title: MCP intégré
+ details: Les UseCases sont exposés comme outils MCP via LocalMcpServer — sans configuration supplémentaire.
+
+ - icon: 🏛️
+ title: Architecture propre
+ details: HTTP Handler → UseCase → RepositoryInterface → SQLAlchemy. Chaque couche est testable en isolation.
+
+ - icon: 🛡️
+ title: Sécurité d'abord
+ details: RFC 9457 Problem Details, authentification Bearer + API Key, limitation de débit, en-têtes de sécurité.
+
+ - icon: 📄
+ title: OpenAPI auto-généré
+ details: Swagger UI et ReDoc à /docs — sans configuration. Export d'un openapi.yaml statique en une commande.
+---
diff --git a/docs/fr/tutorials/getting-started.md b/docs/fr/tutorials/getting-started.md
new file mode 100644
index 0000000..e44010c
--- /dev/null
+++ b/docs/fr/tutorials/getting-started.md
@@ -0,0 +1,54 @@
+# Premiers pas avec nene2-python
+
+Ce tutoriel vous permet de démarrer une API CRUD Notes avec nene2-python en 5 minutes.
+
+## Prérequis
+
+- Python 3.12 ou supérieur
+- [uv](https://docs.astral.sh/uv/) installé
+- Git
+
+## 1. Cloner le dépôt
+
+```bash
+git clone https://github.com/hideyukiMORI/nene2-python.git
+cd nene2-python
+```
+
+## 2. Installer les dépendances
+
+```bash
+uv sync
+```
+
+## 3. Démarrer le serveur de développement
+
+```bash
+uv run uvicorn src.example.app:app --reload --port 8080
+```
+
+Ouvrez `http://localhost:8080/docs` dans votre navigateur pour accéder à Swagger UI.
+
+## 4. Tester l'API
+
+```bash
+# Créer une note
+curl -X POST http://localhost:8080/notes \
+ -H "Content-Type: application/json" \
+ -d '{"title": "Ma première note", "body": "Créée avec nene2-python"}'
+
+# Lister les notes
+curl http://localhost:8080/notes
+```
+
+## 5. Exécuter les tests
+
+```bash
+uv run pytest
+```
+
+Plus de 135 tests doivent tous réussir.
+
+## Étapes suivantes
+
+- [Référence de configuration](../reference/configuration.md) — Configurer la base de données et l'authentification via les variables d'environnement
diff --git a/docs/how-to/add-new-domain.md b/docs/how-to/add-new-domain.md
index d866cd5..e297bab 100644
--- a/docs/how-to/add-new-domain.md
+++ b/docs/how-to/add-new-domain.md
@@ -1,30 +1,30 @@
-# 新しいドメインを追加する
+# Add a new domain
-既存の Note・Tag・Comment ドメインと同じパターンで新しいドメインを追加するチェックリストです。
+A checklist for adding a new domain following the same pattern as Note, Tag, and Comment.
-## チェックリスト
+## Checklist
-### 1. ドメインパッケージを作成する
+### 1. Create the domain package
```bash
mkdir -p src/example/
touch src/example//__init__.py
```
-### 2. 各ファイルを作成する
+### 2. Create each file
-| ファイル | 内容 |
+| File | Content |
|---|---|
-| `entity.py` | `@dataclass(frozen=True, slots=True)` でエンティティを定義 |
+| `entity.py` | Entity as `@dataclass(frozen=True, slots=True)` |
| `repository.py` | `XxxRepositoryInterface(ABC)` + `InMemoryXxxRepository` |
| `exceptions.py` | `XxxNotFoundException` + `XxxNotFoundExceptionHandler` |
-| `use_case.py` | 5 UseCase (List / Get / Create / Update / Delete) + Input/Output DTO |
+| `use_case.py` | 5 UseCases (List / Get / Create / Update / Delete) + Input/Output DTOs |
| `handler.py` | `make_xxx_router()` — parse → use-case → response |
-| `sqlalchemy_repository.py` | SQL バックエンド実装 |
+| `sqlalchemy_repository.py` | SQL backend implementation |
-### 3. schema.py にテーブルを追加する
+### 3. Add the table to schema.py
-`src/example/schema.py` の `ensure_schema()` にテーブル定義を追加します。
+Add a `CREATE TABLE` call to `ensure_schema()` in `src/example/schema.py`.
```python
executor.write(
@@ -36,36 +36,36 @@ executor.write(
)
```
-### 4. app.py に組み込む
+### 4. Wire into app.py
-`src/example/app.py` の `_build_repositories()` と `create_app()` を更新します。
+Update `_build_repositories()` and `create_app()` in `src/example/app.py`.
```python
-# _build_repositories() の戻り値に追加
+# Add to _build_repositories() return tuple
your_repo = SqlAlchemyYourRepository(executor)
-# create_app() でルーターを登録
+# Register the router in create_app()
app.include_router(make_your_router(
list_use_case=ListYourUseCase(your_repo),
...
))
```
-### 5. テストを書く
+### 5. Write tests
```
tests/example//
__init__.py
- test__use_case.py # UseCase 単体テスト(DB なし)
- test__repository.py # Repository 契約テスト(InMemory + SQLAlchemy)
- test__http.py # HTTP 統合テスト(TestClient)
+ test__use_case.py # UseCase unit tests (no DB)
+ test__repository.py # Repository contract tests (InMemory + SQLAlchemy)
+ test__http.py # HTTP integration tests (TestClient)
```
-### 6. MCP ツールに追加する(任意)
+### 6. Register MCP tools (optional)
-`src/example/mcp.py` の `create_mcp_server()` に UseCase を登録します。
+Add UseCase registrations to `create_mcp_server()` in `src/example/mcp.py`.
-### 7. 全チェックを通過させる
+### 7. Pass all checks
```bash
uv run pytest && \
@@ -74,14 +74,16 @@ uv run ruff check src/ tests/ && \
uv run ruff format --check src/ tests/
```
-## 命名規則
+## Naming conventions
-- エンティティクラス: `PascalCase` (`Note`, `Tag`, `Comment`)
-- UseCase 入力 DTO: `XxxInput` (`CreateNoteInput`)
-- 例外: `XxxNotFoundException`
-- ハンドラーファクトリ: `make_xxx_router()`
+| Target | Convention | Example |
+|---|---|---|
+| Entity class | PascalCase | `Note`, `Tag`, `Comment` |
+| UseCase input DTO | `XxxInput` | `CreateNoteInput` |
+| Exception | `XxxNotFoundException` | `NoteNotFoundException` |
+| Handler factory | `make_xxx_router()` | `make_note_router()` |
-## 参考実装
+## Reference implementations
-- `src/example/note/` — 基本的な CRUD ドメイン
-- `src/example/comment/` — 外部キー (note_id) を持つネストドメイン
+- `src/example/note/` — basic CRUD domain
+- `src/example/comment/` — nested domain with foreign key (`note_id`)
diff --git a/docs/how-to/configure-auth.md b/docs/how-to/configure-auth.md
index 3f4ec6b..a97c1c9 100644
--- a/docs/how-to/configure-auth.md
+++ b/docs/how-to/configure-auth.md
@@ -1,57 +1,55 @@
-# 認証を設定する
+# Configure authentication
-nene2-python は Bearer Token 認証と API Key 認証の 2 種類をサポートしています。
-どちらもミドルウェアとして実装されており、環境変数で有効化できます。
+nene2-python supports Bearer Token and API Key authentication, both implemented as middleware and enabled via environment variables.
-## Bearer Token 認証
+## Bearer Token
-### 有効化する
+### Enable
-`.env` ファイルに以下を追加します:
+Add to your `.env` file:
```dotenv
BEARER_TOKEN_ENABLED=true
BEARER_TOKENS=token1,token2,token3
```
-### 動作
+### Behaviour
-- `Authorization: Bearer ` ヘッダーが必須になります
-- トークンは `secrets.compare_digest` でタイミング安全な比較を行います
-- 無効なトークンは `401 Unauthorized` を返します
+- Every request must include `Authorization: Bearer `
+- Tokens are compared with `secrets.compare_digest` (timing-safe)
+- Invalid tokens return `401 Unauthorized` (RFC 9457 Problem Details)
-### curl での利用
+### Example
```bash
curl -H "Authorization: Bearer token1" http://localhost:8080/notes
```
-## API Key 認証
+## API Key
-### 有効化する
+### Enable
```dotenv
API_KEY_ENABLED=true
API_KEYS=key1,key2
```
-### 動作
+### Behaviour
-- `X-Api-Key: ` ヘッダーが必須になります
-- 無効なキーは `401 Unauthorized` を返します
+- Every request must include `X-Api-Key: `
+- Invalid keys return `401 Unauthorized`
-### curl での利用
+### Example
```bash
curl -H "X-Api-Key: key1" http://localhost:8080/notes
```
-## 両方を有効化する場合
+## Using both at once
-Bearer Token と API Key を同時に有効化すると、リクエストは両方の認証を通過する必要があります。
-通常は どちらか一方を使います。
+When both `BEARER_TOKEN_ENABLED` and `API_KEY_ENABLED` are set, requests must pass both checks. In practice you would choose one or the other.
-## テスト時に認証を無効化する
+## Disabling auth in tests
```python
from nene2.config import AppSettings
@@ -61,11 +59,12 @@ from example.app import create_app
client = TestClient(create_app(AppSettings(bearer_token_enabled=False)))
```
-## カスタム TokenVerifier を実装する
+## Custom TokenVerifier (e.g. JWT)
-`TokenVerifierProtocol` を実装することで、JWT や外部サービスによる検証を追加できます。
+Implement `TokenVerifierProtocol` and raise `TokenVerificationException` on failure.
```python
+from nene2.auth import TokenVerificationException
from nene2.auth.interfaces import TokenVerifierProtocol
import jwt
@@ -77,8 +76,8 @@ class JwtTokenVerifier:
try:
jwt.decode(token, self._secret, algorithms=["HS256"])
return True
- except jwt.InvalidTokenError:
- return False
+ except jwt.InvalidTokenError as exc:
+ raise TokenVerificationException(str(exc)) from exc
```
-`create_app()` の `verifier` 引数に渡すか、`BearerTokenMiddleware` を直接使います。
+Pass your verifier directly to `BearerTokenMiddleware`.
diff --git a/docs/how-to/run-tests.md b/docs/how-to/run-tests.md
index a079759..25333e6 100644
--- a/docs/how-to/run-tests.md
+++ b/docs/how-to/run-tests.md
@@ -1,45 +1,48 @@
-# テストを実行する
+# Run tests
-## 基本コマンド
+## Basic commands
```bash
-# 全テストを実行(カバレッジ付き)
+# Run all tests with coverage
uv run pytest
-# 失敗時の詳細表示
+# Verbose output on failure
uv run pytest --tb=short -v
-# 特定のファイルだけ実行
+# Run a specific directory
uv run pytest tests/example/note/
-# カバレッジ HTML レポートを生成
+# Generate an HTML coverage report
uv run pytest --cov=src --cov-report=html
-# → htmlcov/index.html をブラウザで開く
+# → open htmlcov/index.html in your browser
```
-## テスト構造
+## Test layout
```
tests/
- nene2/ フレームワークコアの単体テスト
- use_case/ UseCaseProtocol 準拠テスト
- ...
+ nene2/ Framework core unit tests
+ use_case/ UseCaseProtocol compliance
+ auth/ Auth middleware and verifiers
+ database/ TransactionManager tests
+ mcp/ McpHttpClient tests
+ middleware/ Each middleware in isolation
example/
- note/ Note ドメインテスト
- test_list_notes.py UseCase 単体テスト
- test_note_repository.py Repository 契約テスト
- test_async_note_use_case.py 非同期 UseCase テスト
+ note/ Note domain tests
+ test_list_notes.py UseCase unit tests
+ test_note_repository.py Repository contract tests
+ test_async_note_use_case.py Async UseCase tests
comment/
- test_comment_use_case.py UseCase 単体テスト(DB なし)
- test_comment_repository.py InMemory + SQLAlchemy の契約テスト
- test_comment_http.py HTTP 統合テスト(TestClient)
+ test_comment_use_case.py UseCase unit tests (no DB)
+ test_comment_repository.py InMemory + SQLAlchemy contract tests
+ test_comment_http.py HTTP integration tests (TestClient)
```
-## テストの種類
+## Test types
-### UseCase 単体テスト
+### UseCase unit tests
-DB なし・InMemory リポジトリを使用。最も高速。
+No database, no HTTP — use InMemory repositories. Fastest.
```python
def test_create_note() -> None:
@@ -48,9 +51,9 @@ def test_create_note() -> None:
assert note.title == "t"
```
-### Repository 契約テスト
+### Repository contract tests
-`@pytest.fixture(params=["inmemory", "sqlalchemy"])` で 2 実装を同一テストで検証。
+`@pytest.fixture(params=["inmemory", "sqlalchemy"])` runs the same assertions against both implementations.
```python
@pytest.fixture(params=["inmemory", "sqlalchemy"])
@@ -61,9 +64,9 @@ def test_save_and_find(repo) -> None:
assert repo.find_by_id(note.id) == note
```
-### HTTP 統合テスト
+### HTTP integration tests
-FastAPI `TestClient` 経由。ルーター全体を検証。
+Use FastAPI's `TestClient`. Tests the full stack from HTTP to repository.
```python
def test_create_note_returns_201() -> None:
@@ -72,9 +75,9 @@ def test_create_note_returns_201() -> None:
assert response.status_code == 201
```
-### 非同期テスト
+### Async tests
-`asyncio_mode = "auto"` 設定済みのため `async def test_*` がそのまま動きます。
+`asyncio_mode = "auto"` is set in `pyproject.toml`, so `async def test_*` works directly.
```python
async def test_async_list_notes() -> None:
@@ -83,16 +86,18 @@ async def test_async_list_notes() -> None:
assert result.total == 0
```
-## カバレッジ要件
+## Coverage requirements
-- 全体: 80% 以上(CI で強制)
-- UseCase / Domain 層: 90% 以上を目標
+| Scope | Target |
+|---|---|
+| Overall | ≥ 80% (CI enforced) |
+| UseCase / Domain | ≥ 90% (goal) |
-## 静的解析
+## Static analysis
```bash
-uv run mypy src/ # 型チェック
-uv run ruff check src/ # リント
-uv run ruff format --check src/ tests/ # フォーマットチェック
-uv run pip-audit # 依存関係の脆弱性スキャン
+uv run mypy src/ # Type checking (strict)
+uv run ruff check src/ # Lint
+uv run ruff format --check src/ tests/ # Format check
+uv run pip-audit # Dependency vulnerability scan
```
diff --git a/docs/howto/mcp-setup.md b/docs/howto/mcp-setup.md
index d00c1b8..e072a53 100644
--- a/docs/howto/mcp-setup.md
+++ b/docs/howto/mcp-setup.md
@@ -1,18 +1,18 @@
-# MCP セットアップガイド — Claude Desktop 連携
+# MCP setup guide — Claude Desktop integration
-## 概要
+## Overview
-`example/mcp.py` は Note と Tag の全 UseCase (10個) を MCP ツールとして公開する。
-Claude Desktop や `claude` CLI から直接 CRUD 操作が可能になる。
+`example/mcp.py` exposes all Note, Tag, and Comment UseCases (15 tools) as MCP tools.
+Once configured, Claude Desktop and the `claude` CLI can perform CRUD operations directly.
-## 前提
+## Prerequisites
-- `uv sync` 完了済み
-- Python 3.12+ 環境
+- `uv sync` completed
+- Python 3.12+ environment
-## Claude Desktop への設定
+## Claude Desktop configuration
-`claude_desktop_config.json` に以下を追加する:
+Add the following to `claude_desktop_config.json`:
```json
{
@@ -25,7 +25,7 @@ Claude Desktop や `claude` CLI から直接 CRUD 操作が可能になる。
"run",
"python",
"-m",
- "example"
+ "example.mcp"
],
"env": {
"DB_ADAPTER": "sqlite",
@@ -36,37 +36,42 @@ Claude Desktop や `claude` CLI から直接 CRUD 操作が可能になる。
}
```
-`/path/to/nene2-python` をリポジトリの絶対パスに変更すること。
+Replace `/path/to/nene2-python` with the absolute path to this repository.
-## claude CLI での起動確認
+## Available tools
-```bash
-# ファイル永続化 SQLite で起動
-DB_ADAPTER=sqlite DB_NAME=./data/nene2.db uv run python -m example
+| Tool | Description |
+|---|---|
+| `list_notes` | List notes with pagination |
+| `get_note` | Get a note by ID |
+| `create_note` | Create a new note |
+| `update_note` | Update a note |
+| `delete_note` | Delete a note |
+| `list_tags` | List tags |
+| `get_tag` | Get a tag by ID |
+| `create_tag` | Create a new tag |
+| `update_tag` | Update a tag |
+| `delete_tag` | Delete a tag |
+| `list_comments` | List comments on a note |
+| `get_comment` | Get a comment by ID |
+| `create_comment` | Create a comment on a note |
+| `update_comment` | Update a comment |
+| `delete_comment` | Delete a comment |
+
+## Running via CLI
-# インメモリ SQLite(テスト用)
-uv run python -m example
+```bash
+uv run python -m example.mcp
```
-## 利用可能なツール
+The server listens on stdin/stdout (stdio transport) — standard for MCP.
-| ツール | 説明 |
-|---|---|
-| `list_notes(limit, offset)` | Note 一覧取得 |
-| `get_note(note_id)` | Note 1件取得 |
-| `create_note(title, body)` | Note 作成 |
-| `update_note(note_id, title, body)` | Note 更新 |
-| `delete_note(note_id)` | Note 削除 |
-| `list_tags(limit, offset)` | Tag 一覧取得 |
-| `get_tag(tag_id)` | Tag 1件取得 |
-| `create_tag(name)` | Tag 作成 |
-| `update_tag(tag_id, name)` | Tag 更新 |
-| `delete_tag(tag_id)` | Tag 削除 |
-
-## データディレクトリの準備
+## Custom transport
-```bash
-mkdir -p data
-```
+```python
+from example.mcp import create_mcp_server
-SQLite ファイルは初回起動時に自動作成される。
+server = create_mcp_server()
+server.run(transport="sse") # Server-Sent Events
+server.run(transport="streamable-http") # HTTP streaming
+```
diff --git a/docs/ja/explanation/architecture.md b/docs/ja/explanation/architecture.md
new file mode 100644
index 0000000..b75e099
--- /dev/null
+++ b/docs/ja/explanation/architecture.md
@@ -0,0 +1,100 @@
+# アーキテクチャ概要
+
+## レイヤー構造
+
+nene2-python はクリーンアーキテクチャに基づいており、依存関係は外から内へ向かいます。
+
+```
+┌─────────────────────────────────────────────┐
+│ HTTP Handler (FastAPI router) │
+│ parse request → call use-case → response │
+├─────────────────────────────────────────────┤
+│ UseCase │
+│ ビジネスロジック。HTTP・DB を知らない │
+├─────────────────────────────────────────────┤
+│ RepositoryInterface (ABC) │
+│ ドメインが必要とする操作の契約 │
+├─────────────────────────────────────────────┤
+│ ConcreteRepository │
+│ SQLAlchemy / InMemory 実装 │
+└─────────────────────────────────────────────┘
+```
+
+## 各レイヤーの責務
+
+### HTTP Handler
+
+- **唯一の責務**: リクエストを解析し UseCase を呼び、レスポンスを返す
+- Pydantic `BaseModel` でリクエストボディを検証(HTTP 境界のみ)
+- ドメインロジックを持たない
+- `make_xxx_router()` ファクトリ関数がルーターを返す
+
+```python
+@router.post("", status_code=201)
+async def create_note(body: CreateNoteBody) -> JSONResponse:
+ note = create_use_case.execute(CreateNoteInput(title=body.title, body=body.body))
+ return JSONResponse({"id": note.id, "title": note.title, "body": note.body}, status_code=201)
+```
+
+### UseCase
+
+- **唯一の責務**: ビジネスルールを実装する
+- `execute(input_: XxxInput) -> XxxOutput` の単一メソッド
+- `import fastapi`, `import sqlalchemy` を持たない
+- 他の UseCase を呼ばない(オーケストレーションは上位層)
+- `InMemoryRepository` でテスト可能
+
+### RepositoryInterface
+
+- ABC で契約を定義
+- UseCase は Interface のみに依存する(具象クラスを知らない)
+- InMemory 実装と SQLAlchemy 実装が同じ Interface を実装する
+
+### ConcreteRepository
+
+- SQLAlchemy Core(ORM なし)でパラメータ化クエリを実行
+- `SqlAlchemyQueryExecutor` でクエリを抽象化
+- テーブルスキーマは `src/example/schema.py` で一元管理
+
+## ミドルウェアスタック
+
+リクエストは外側から内側に向かって処理されます:
+
+```
+BearerTokenMiddleware 認証 (Bearer Token)
+ApiKeyAuthMiddleware 認証 (API Key)
+CORSMiddleware CORS
+ThrottleMiddleware レートリミット
+RequestSizeLimitMiddleware ペイロードサイズ制限
+RequestLoggingMiddleware リクエストロギング
+RequestIdMiddleware リクエスト ID 付与
+SecurityHeadersMiddleware セキュリティヘッダー付与
+ErrorHandlerMiddleware 例外 → RFC 9457 Problem Details 変換
+```
+
+## DI パターン
+
+FastAPI の `Depends` は HTTP 境界のみで使用します。UseCase とリポジトリはコンストラクタインジェクションで接続します。
+
+```python
+# app.py — ワイヤリング
+note_repo = SqlAlchemyNoteRepository(executor)
+app.include_router(make_note_router(
+ list_use_case=ListNotesUseCase(note_repo),
+ create_use_case=CreateNoteUseCase(note_repo),
+ ...
+))
+```
+
+## ドメインパッケージ構造
+
+```
+src/example//
+ __init__.py
+ entity.py — @dataclass(frozen=True, slots=True)
+ repository.py — ABC + InMemory 実装
+ exceptions.py — XxxNotFoundException + ExceptionHandler
+ use_case.py — 5 UseCase + Input/Output DTO
+ handler.py — FastAPI router
+ sqlalchemy_repository.py — SQL バックエンド
+```
diff --git a/docs/ja/explanation/design-philosophy.md b/docs/ja/explanation/design-philosophy.md
new file mode 100644
index 0000000..4bcb0f1
--- /dev/null
+++ b/docs/ja/explanation/design-philosophy.md
@@ -0,0 +1,68 @@
+# 設計思想と PHP NENE2 との対応
+
+## NENE2 の設計原則
+
+nene2-python は PHP 版 NENE2 と同一の設計思想を持ちます。
+
+### API First
+
+JSON API と OpenAPI 契約を中心に据えます。DB 設計より先に API の形を定義し、スキーマを `uv run export-openapi` で生成します。
+
+### 薄い HTTP 層
+
+HTTP Handler はビジネスロジックを持ちません。**parse → use-case → response** の 3 ステップのみ。ドメインルールは UseCase に集約されます。
+
+### AI-readable
+
+明示的なディレクトリ構造、小さなクラス(150 行以下)、型付き境界により、LLM がコードベースを正確に理解・操作できます。
+
+### Security First
+
+セキュリティは後付けではなく設計の出発点です。
+- Pydantic による HTTP 境界の全入力検証
+- パラメータ化クエリのみ(SQLインジェクション防止)
+- `secrets.compare_digest` によるタイミング安全な比較
+- セキュリティヘッダーをミドルウェアで付与
+
+### LLM Delivery Ready
+
+UseCase は HTTP・DB から独立しているため、MCP ツールとして直接再利用できます。`src/example/mcp.py` はその実証です。
+
+## PHP NENE2 との対応表
+
+| PHP 版 | Python 版 | 備考 |
+|---|---|---|
+| `readonly class` | `@dataclass(frozen=True, slots=True)` | 不変 Value Object |
+| `ValidationException` + `ValidationError` | 同名クラス (`nene2.validation`) | 422 + Problem Details |
+| `PaginationQueryParser` | `nene2.http.PaginationQueryParser` | クエリパラメータ解析 |
+| `PaginationResponse` | `nene2.http.PaginationResponse` | ページネーションレスポンス |
+| `ProblemDetailsResponseFactory` | `nene2.http.problem_details_response()` | RFC 9457 |
+| `ErrorHandlerMiddleware` | `nene2.middleware.ErrorHandlerMiddleware` | 全例外をキャッチ |
+| `PHPStan level 8` | `mypy --strict` | 最高レベルの型チェック |
+| `PHP-CS-Fixer` | `ruff format` | コードフォーマット |
+| `UseCaseInterface` | `nene2.use_case.UseCaseProtocol[I, O]` | 構造的サブタイピング |
+
+## Python 3.12+ 固有の選択
+
+| 用途 | 選択 | 理由 |
+|---|---|---|
+| 型エイリアス | `type X = list[str]` | PEP 695 — 新構文 |
+| ジェネリクス | `class Foo[T]` | PEP 695 — TypeVar 不要 |
+| 不変 VO | `dataclass(frozen=True, slots=True)` | メモリ効率 + 不変性 |
+| HTTP 検証 | Pydantic v2 BaseModel | 高速 + 型安全 |
+| SQL | SQLAlchemy Core | ORM なしで SQL を直接制御 |
+| ロギング | structlog | JSON / Console の両対応 |
+| MCP | mcp (Anthropic SDK) | FastMCP ラッパー |
+
+## ADR 一覧
+
+設計の個別決定は ADR に記録されています:
+
+- [ADR-0001: ツールチェーン](../adr/0001-toolchain.md)
+- [ADR-0002: クリーンアーキテクチャ](../adr/0002-clean-architecture.md)
+- [ADR-0003: セキュリティファースト](../adr/0003-security-first.md)
+- [ADR-0004: AI ファースト設計](../adr/0004-ai-first-design.md)
+- [ADR-0005: ロギング](../adr/0005-logging.md)
+- [ADR-0006: レートリミット](../adr/0006-rate-limiting.md)
+- [ADR-0009: MCP 設計](../adr/0009-mcp-design.md)
+- [ADR-0010: AsyncUseCase パターン](../adr/0010-async-use-case.md)
diff --git a/docs/ja/how-to/add-new-domain.md b/docs/ja/how-to/add-new-domain.md
new file mode 100644
index 0000000..d866cd5
--- /dev/null
+++ b/docs/ja/how-to/add-new-domain.md
@@ -0,0 +1,87 @@
+# 新しいドメインを追加する
+
+既存の Note・Tag・Comment ドメインと同じパターンで新しいドメインを追加するチェックリストです。
+
+## チェックリスト
+
+### 1. ドメインパッケージを作成する
+
+```bash
+mkdir -p src/example/
+touch src/example//__init__.py
+```
+
+### 2. 各ファイルを作成する
+
+| ファイル | 内容 |
+|---|---|
+| `entity.py` | `@dataclass(frozen=True, slots=True)` でエンティティを定義 |
+| `repository.py` | `XxxRepositoryInterface(ABC)` + `InMemoryXxxRepository` |
+| `exceptions.py` | `XxxNotFoundException` + `XxxNotFoundExceptionHandler` |
+| `use_case.py` | 5 UseCase (List / Get / Create / Update / Delete) + Input/Output DTO |
+| `handler.py` | `make_xxx_router()` — parse → use-case → response |
+| `sqlalchemy_repository.py` | SQL バックエンド実装 |
+
+### 3. schema.py にテーブルを追加する
+
+`src/example/schema.py` の `ensure_schema()` にテーブル定義を追加します。
+
+```python
+executor.write(
+ "CREATE TABLE IF NOT EXISTS your_domain ("
+ "id INTEGER PRIMARY KEY AUTOINCREMENT,"
+ "name TEXT NOT NULL,"
+ "created_at DATETIME DEFAULT CURRENT_TIMESTAMP"
+ ")"
+)
+```
+
+### 4. app.py に組み込む
+
+`src/example/app.py` の `_build_repositories()` と `create_app()` を更新します。
+
+```python
+# _build_repositories() の戻り値に追加
+your_repo = SqlAlchemyYourRepository(executor)
+
+# create_app() でルーターを登録
+app.include_router(make_your_router(
+ list_use_case=ListYourUseCase(your_repo),
+ ...
+))
+```
+
+### 5. テストを書く
+
+```
+tests/example//
+ __init__.py
+ test__use_case.py # UseCase 単体テスト(DB なし)
+ test__repository.py # Repository 契約テスト(InMemory + SQLAlchemy)
+ test__http.py # HTTP 統合テスト(TestClient)
+```
+
+### 6. MCP ツールに追加する(任意)
+
+`src/example/mcp.py` の `create_mcp_server()` に UseCase を登録します。
+
+### 7. 全チェックを通過させる
+
+```bash
+uv run pytest && \
+uv run mypy src/ && \
+uv run ruff check src/ tests/ && \
+uv run ruff format --check src/ tests/
+```
+
+## 命名規則
+
+- エンティティクラス: `PascalCase` (`Note`, `Tag`, `Comment`)
+- UseCase 入力 DTO: `XxxInput` (`CreateNoteInput`)
+- 例外: `XxxNotFoundException`
+- ハンドラーファクトリ: `make_xxx_router()`
+
+## 参考実装
+
+- `src/example/note/` — 基本的な CRUD ドメイン
+- `src/example/comment/` — 外部キー (note_id) を持つネストドメイン
diff --git a/docs/ja/how-to/configure-auth.md b/docs/ja/how-to/configure-auth.md
new file mode 100644
index 0000000..7d99b8f
--- /dev/null
+++ b/docs/ja/how-to/configure-auth.md
@@ -0,0 +1,101 @@
+# 認証を設定する
+
+nene2-python は Bearer Token 認証と API Key 認証の 2 種類をサポートしています。
+どちらもミドルウェアとして実装されており、環境変数で有効化できます。
+
+## Bearer Token 認証
+
+### 有効化する
+
+`.env` ファイルに以下を追加します:
+
+```dotenv
+BEARER_TOKEN_ENABLED=true
+BEARER_TOKENS=token1,token2,token3
+```
+
+### 動作
+
+- `Authorization: Bearer ` ヘッダーが必須になります
+- トークンは `secrets.compare_digest` でタイミング安全な比較を行います
+- 無効なトークンは `401 Unauthorized` を返します
+
+### curl での利用
+
+```bash
+curl -H "Authorization: Bearer token1" http://localhost:8080/notes
+```
+
+## API Key 認証
+
+### 有効化する
+
+```dotenv
+API_KEY_ENABLED=true
+API_KEYS=key1,key2
+```
+
+### 動作
+
+- `X-Api-Key: ` ヘッダーが必須になります
+- 無効なキーは `401 Unauthorized` を返します
+
+### curl での利用
+
+```bash
+curl -H "X-Api-Key: key1" http://localhost:8080/notes
+```
+
+## 両方を有効化する場合
+
+Bearer Token と API Key を同時に有効化すると、リクエストは両方の認証を通過する必要があります。
+通常はどちらか一方を使います。
+
+## テスト時に認証を無効化する
+
+```python
+from nene2.config import AppSettings
+from fastapi.testclient import TestClient
+from example.app import create_app
+
+client = TestClient(create_app(AppSettings(bearer_token_enabled=False)))
+```
+
+## カスタム TokenVerifier を実装する
+
+`TokenVerifierProtocol` を実装することで、JWT や外部サービスによる検証を追加できます。
+
+```python
+from nene2.auth.interfaces import TokenVerifierProtocol
+from nene2.auth.exceptions import TokenVerificationException
+import jwt
+
+class JwtTokenVerifier:
+ def __init__(self, secret: str) -> None:
+ self._secret = secret
+
+ def verify(self, token: str) -> bool:
+ try:
+ jwt.decode(token, self._secret, algorithms=["HS256"])
+ return True
+ except jwt.InvalidTokenError as exc:
+ raise TokenVerificationException(str(exc)) from exc
+```
+
+`TokenVerificationException` を raise することで、`BearerTokenMiddleware` が自動的に `401 Unauthorized` を返します。
+
+## カスタム TokenIssuer を実装する
+
+`TokenIssuerProtocol` を実装して、JWT などのトークンを発行できます。
+
+```python
+from nene2.auth.interfaces import TokenIssuerProtocol
+import jwt
+
+class JwtTokenIssuer:
+ def __init__(self, secret: str) -> None:
+ self._secret = secret
+
+ def issue(self, claims: dict[str, object]) -> str:
+ return jwt.encode(claims, self._secret, algorithm="HS256")
+```
diff --git a/docs/ja/how-to/run-tests.md b/docs/ja/how-to/run-tests.md
new file mode 100644
index 0000000..a079759
--- /dev/null
+++ b/docs/ja/how-to/run-tests.md
@@ -0,0 +1,98 @@
+# テストを実行する
+
+## 基本コマンド
+
+```bash
+# 全テストを実行(カバレッジ付き)
+uv run pytest
+
+# 失敗時の詳細表示
+uv run pytest --tb=short -v
+
+# 特定のファイルだけ実行
+uv run pytest tests/example/note/
+
+# カバレッジ HTML レポートを生成
+uv run pytest --cov=src --cov-report=html
+# → htmlcov/index.html をブラウザで開く
+```
+
+## テスト構造
+
+```
+tests/
+ nene2/ フレームワークコアの単体テスト
+ use_case/ UseCaseProtocol 準拠テスト
+ ...
+ example/
+ note/ Note ドメインテスト
+ test_list_notes.py UseCase 単体テスト
+ test_note_repository.py Repository 契約テスト
+ test_async_note_use_case.py 非同期 UseCase テスト
+ comment/
+ test_comment_use_case.py UseCase 単体テスト(DB なし)
+ test_comment_repository.py InMemory + SQLAlchemy の契約テスト
+ test_comment_http.py HTTP 統合テスト(TestClient)
+```
+
+## テストの種類
+
+### UseCase 単体テスト
+
+DB なし・InMemory リポジトリを使用。最も高速。
+
+```python
+def test_create_note() -> None:
+ repo = InMemoryNoteRepository()
+ note = CreateNoteUseCase(repo).execute(CreateNoteInput(title="t", body="b"))
+ assert note.title == "t"
+```
+
+### Repository 契約テスト
+
+`@pytest.fixture(params=["inmemory", "sqlalchemy"])` で 2 実装を同一テストで検証。
+
+```python
+@pytest.fixture(params=["inmemory", "sqlalchemy"])
+def repo(request): ...
+
+def test_save_and_find(repo) -> None:
+ note = repo.save("title", "body")
+ assert repo.find_by_id(note.id) == note
+```
+
+### HTTP 統合テスト
+
+FastAPI `TestClient` 経由。ルーター全体を検証。
+
+```python
+def test_create_note_returns_201() -> None:
+ client = TestClient(create_app(AppSettings(throttle_enabled=False)))
+ response = client.post("/notes", json={"title": "t", "body": "b"})
+ assert response.status_code == 201
+```
+
+### 非同期テスト
+
+`asyncio_mode = "auto"` 設定済みのため `async def test_*` がそのまま動きます。
+
+```python
+async def test_async_list_notes() -> None:
+ repo = InMemoryNoteRepository()
+ result = await AsyncListNotesUseCase(repo).execute(ListNotesInput(limit=10, offset=0))
+ assert result.total == 0
+```
+
+## カバレッジ要件
+
+- 全体: 80% 以上(CI で強制)
+- UseCase / Domain 層: 90% 以上を目標
+
+## 静的解析
+
+```bash
+uv run mypy src/ # 型チェック
+uv run ruff check src/ # リント
+uv run ruff format --check src/ tests/ # フォーマットチェック
+uv run pip-audit # 依存関係の脆弱性スキャン
+```
diff --git a/docs/ja/howto/mcp-setup.md b/docs/ja/howto/mcp-setup.md
new file mode 100644
index 0000000..77c2d19
--- /dev/null
+++ b/docs/ja/howto/mcp-setup.md
@@ -0,0 +1,77 @@
+# MCP セットアップガイド — Claude Desktop 連携
+
+## 概要
+
+`example/mcp.py` は Note・Tag・Comment の全 UseCase(15 ツール)を MCP ツールとして公開します。
+Claude Desktop や `claude` CLI から直接 CRUD 操作が可能になります。
+
+## 前提
+
+- `uv sync` 完了済み
+- Python 3.12+ 環境
+
+## Claude Desktop への設定
+
+`claude_desktop_config.json` に以下を追加します:
+
+```json
+{
+ "mcpServers": {
+ "nene2-example": {
+ "command": "uv",
+ "args": [
+ "--directory",
+ "/path/to/nene2-python",
+ "run",
+ "python",
+ "-m",
+ "example.mcp"
+ ],
+ "env": {
+ "DB_ADAPTER": "sqlite",
+ "DB_NAME": "/path/to/nene2-python/data/nene2.db"
+ }
+ }
+ }
+}
+```
+
+`/path/to/nene2-python` をリポジトリの絶対パスに変更してください。
+
+## 利用可能なツール
+
+| ツール | 説明 |
+|---|---|
+| `list_notes` | Note 一覧取得(ページネーション付き) |
+| `get_note` | ID 指定で Note を取得 |
+| `create_note` | Note を作成 |
+| `update_note` | Note を更新 |
+| `delete_note` | Note を削除 |
+| `list_tags` | Tag 一覧取得 |
+| `get_tag` | ID 指定で Tag を取得 |
+| `create_tag` | Tag を作成 |
+| `update_tag` | Tag を更新 |
+| `delete_tag` | Tag を削除 |
+| `list_comments` | Note に紐づくコメント一覧 |
+| `get_comment` | ID 指定でコメントを取得 |
+| `create_comment` | Note にコメントを作成 |
+| `update_comment` | コメントを更新 |
+| `delete_comment` | コメントを削除 |
+
+## CLI での起動
+
+```bash
+uv run python -m example.mcp
+```
+
+サーバーは stdin/stdout(stdio トランスポート)でリッスンします — MCP の標準形式。
+
+## カスタムトランスポート
+
+```python
+from example.mcp import create_mcp_server
+
+server = create_mcp_server()
+server.run(transport="sse") # Server-Sent Events
+server.run(transport="streamable-http") # HTTP ストリーミング
+```
diff --git a/docs/ja/index.md b/docs/ja/index.md
new file mode 100644
index 0000000..779f23f
--- /dev/null
+++ b/docs/ja/index.md
@@ -0,0 +1,43 @@
+---
+layout: home
+
+hero:
+ name: "NENE2"
+ text: "Python API フレームワーク"
+ tagline: FastAPI · クリーンアーキテクチャ · MCP · mypy --strict · AI ファースト設計
+ actions:
+ - theme: brand
+ text: はじめる →
+ link: /ja/tutorials/getting-started
+ - theme: alt
+ text: GitHub で見る
+ link: https://github.com/hideyukiMORI/nene2-python
+ - theme: alt
+ text: PHP 版
+ link: https://hideyukimori.github.io/NENE2/
+
+features:
+ - icon: 🐍
+ title: Python 3.12+ ネイティブ
+ details: Python 3.12 のジェネリクス構文、frozen dataclass、Pydantic v2 を使用。後方互換 shim なし。mypy --strict を全コミットで強制。
+
+ - icon: ⚡
+ title: FastAPI + async 対応
+ details: ASGI ネイティブ。AsyncUseCaseProtocol で非同期 I/O をサポート。asyncio.gather による並列リポジトリ呼び出し。
+
+ - icon: 🤖
+ title: MCP 内蔵
+ details: UseCase を LocalMcpServer 経由で MCP ツールとして公開 — 追加配線不要。Claude と任意の MCP クライアントが API を直接呼び出せる。
+
+ - icon: 🏛️
+ title: クリーンアーキテクチャ
+ details: HTTP Handler → UseCase → RepositoryInterface → SQLAlchemy。各レイヤーを InMemory リポジトリで独立してテスト可能。
+
+ - icon: 🛡️
+ title: セキュリティファースト
+ details: RFC 9457 Problem Details、Bearer + API Key 認証、レートリミット、セキュリティヘッダー、リクエストサイズ制限 — すべて即使用可能。
+
+ - icon: 📄
+ title: OpenAPI 自動生成
+ details: Swagger UI と ReDoc を /docs で提供 — 設定ゼロ。1コマンドで静的 openapi.yaml をエクスポート。
+---
diff --git a/docs/ja/reference/api.md b/docs/ja/reference/api.md
new file mode 100644
index 0000000..d461e89
--- /dev/null
+++ b/docs/ja/reference/api.md
@@ -0,0 +1,137 @@
+# REST API リファレンス
+
+nene2-python example アプリが提供するエンドポイントの一覧です。
+
+> OpenAPI スキーマ(機械可読)は `uv run export-openapi` で `docs/openapi.yaml` に生成できます。
+> 開発サーバー起動後は `http://localhost:8080/docs` で Swagger UI を参照できます。
+
+---
+
+## Notes
+
+### `GET /notes`
+
+ノート一覧を取得します。
+
+**クエリパラメータ**
+
+| パラメータ | 型 | デフォルト | 説明 |
+|---|---|---|---|
+| `limit` | int | 20 | 最大取得件数(上限 100) |
+| `offset` | int | 0 | スキップ件数 |
+
+**レスポンス** `200 OK`
+
+```json
+{
+ "items": [{"id": 1, "title": "ノートタイトル", "body": "本文"}],
+ "limit": 20,
+ "offset": 0,
+ "total": 1
+}
+```
+
+### `POST /notes`
+
+ノートを作成します。
+
+**リクエストボディ**
+
+```json
+{"title": "タイトル", "body": "本文"}
+```
+
+**レスポンス** `201 Created`
+
+```json
+{"id": 1, "title": "タイトル", "body": "本文"}
+```
+
+### `GET /notes/{note_id}`
+
+指定した ID のノートを取得します。存在しない場合は `404` を返します。
+
+### `PUT /notes/{note_id}`
+
+ノートを更新します。
+
+**リクエストボディ**
+
+```json
+{"title": "新タイトル", "body": "新本文"}
+```
+
+**レスポンス** `200 OK` / `404 Not Found`
+
+### `DELETE /notes/{note_id}`
+
+ノートを削除します。`204 No Content` / `404 Not Found` を返します。
+
+---
+
+## Tags
+
+`/tags` エンドポイントは Notes と同じ CRUD パターンです。
+
+| メソッド | パス | 説明 |
+|---|---|---|
+| `GET` | `/tags` | タグ一覧 |
+| `POST` | `/tags` | タグ作成(`{"name": "..."}`) |
+| `GET` | `/tags/{tag_id}` | タグ取得 |
+| `PUT` | `/tags/{tag_id}` | タグ更新(`{"name": "..."}`) |
+| `DELETE` | `/tags/{tag_id}` | タグ削除 |
+
+---
+
+## Comments
+
+コメントはノートに紐づくネストリソースです。
+
+| メソッド | パス | 説明 |
+|---|---|---|
+| `GET` | `/notes/{note_id}/comments` | コメント一覧 |
+| `POST` | `/notes/{note_id}/comments` | コメント作成(`{"body": "..."}`) |
+| `GET` | `/notes/{note_id}/comments/{comment_id}` | コメント取得 |
+| `PUT` | `/notes/{note_id}/comments/{comment_id}` | コメント更新 |
+| `DELETE` | `/notes/{note_id}/comments/{comment_id}` | コメント削除 |
+
+---
+
+## Health Check
+
+### `GET /health`
+
+アプリケーションの稼働状態を返します。
+
+**レスポンス** `200 OK`
+
+```json
+{"status": "ok", "db": "ok"}
+```
+
+DB 接続失敗時は `db` フィールドが `"error"` になります。
+
+---
+
+## エラーレスポンス
+
+すべてのエラーは RFC 9457 Problem Details 形式で返します。
+
+```json
+{
+ "type": "https://nene2.dev/problems/not-found",
+ "title": "Not Found",
+ "status": 404,
+ "detail": "Note with ID 42 was not found."
+}
+```
+
+| ステータス | type | 原因 |
+|---|---|---|
+| 400 | `bad-request` | 不正なリクエスト |
+| 401 | `unauthorized` | 認証失敗 |
+| 404 | `not-found` | リソースが存在しない |
+| 413 | `payload-too-large` | ペイロードサイズ超過 |
+| 422 | `validation-failed` | バリデーションエラー |
+| 429 | `too-many-requests` | レートリミット超過 |
+| 500 | `internal-server-error` | サーバー内部エラー |
diff --git a/docs/ja/reference/configuration.md b/docs/ja/reference/configuration.md
new file mode 100644
index 0000000..49a402e
--- /dev/null
+++ b/docs/ja/reference/configuration.md
@@ -0,0 +1,105 @@
+# 設定リファレンス(環境変数)
+
+設定は `pydantic-settings` で管理されており、環境変数または `.env` ファイルから読み込みます。
+
+## 基本設定
+
+| 変数 | デフォルト | 説明 |
+|---|---|---|
+| `APP_ENV` | `local` | 実行環境。`local` / `test` / `production` |
+| `APP_DEBUG` | `false` | `true` の場合、500 エラーに例外メッセージを含める |
+| `APP_NAME` | `nene2-python` | アプリケーション名 |
+
+## セキュリティ設定
+
+| 変数 | デフォルト | 説明 |
+|---|---|---|
+| `SECURITY_HEADERS_ENABLED` | `true` | セキュリティヘッダー付与を有効化 |
+| `MAX_BODY_SIZE` | `1048576` | リクエストボディの最大バイト数(デフォルト 1 MiB) |
+
+セキュリティヘッダーの内容:
+
+| ヘッダー | 値 |
+|---|---|
+| `X-Content-Type-Options` | `nosniff` |
+| `X-Frame-Options` | `DENY` |
+| `Referrer-Policy` | `strict-origin-when-cross-origin` |
+| `Content-Security-Policy` | `default-src 'self'` |
+| `Permissions-Policy` | `geolocation=(), microphone=()` |
+
+## レートリミット
+
+| 変数 | デフォルト | 説明 |
+|---|---|---|
+| `THROTTLE_ENABLED` | `true` | レートリミットを有効化 |
+| `THROTTLE_LIMIT` | `60` | ウィンドウ内の最大リクエスト数 |
+| `THROTTLE_WINDOW` | `60` | ウィンドウの秒数 |
+
+固定ウィンドウ方式(IP アドレスをキーとする)。制限超過時は `429 Too Many Requests` + `Retry-After` ヘッダー。
+
+## CORS 設定
+
+| 変数 | デフォルト | 説明 |
+|---|---|---|
+| `CORS_ENABLED` | `false` | CORS ミドルウェアを有効化 |
+| `CORS_ORIGINS` | `[]` | 許可オリジンのリスト(カンマ区切り) |
+| `CORS_ALLOW_CREDENTIALS` | `false` | クレデンシャルを許可するか |
+| `CORS_ALLOW_METHODS` | `GET,POST,PUT,DELETE,OPTIONS` | 許可メソッド |
+| `CORS_ALLOW_HEADERS` | `*` | 許可ヘッダー |
+
+> `CORS_ORIGINS=*` は禁止です。許可オリジンを明示してください。
+
+## 認証設定
+
+| 変数 | デフォルト | 説明 |
+|---|---|---|
+| `BEARER_TOKEN_ENABLED` | `false` | Bearer Token 認証を有効化 |
+| `BEARER_TOKENS` | `[]` | 有効なトークンのリスト(カンマ区切り) |
+| `API_KEY_ENABLED` | `false` | API Key 認証を有効化 |
+| `API_KEYS` | `[]` | 有効な API キーのリスト(カンマ区切り) |
+
+## データベース設定
+
+| 変数 | デフォルト | 説明 |
+|---|---|---|
+| `DB_ADAPTER` | `sqlite` | `sqlite` / `mysql` / `pgsql` |
+| `DB_NAME` | `:memory:` | SQLite のファイルパスまたは DB 名 |
+| `DB_HOST` | `localhost` | DB ホスト(SQLite では無視) |
+| `DB_PORT` | `3306` | DB ポート(SQLite では無視) |
+| `DB_USER` | `""` | DB ユーザー名(SQLite では無視) |
+| `DB_PASSWORD` | `""` | DB パスワード — `SecretStr` 型(ログに出力されない) |
+
+### 接続 URL の例
+
+| アダプター | 生成される URL |
+|---|---|
+| `sqlite` | `sqlite:///path/to/db.sqlite3` |
+| `mysql` | `mysql+pymysql://user:pass@host:3306/dbname` |
+| `pgsql` | `postgresql+psycopg2://user:pass@host:5432/dbname` |
+
+## .env ファイル例
+
+```dotenv
+APP_ENV=production
+APP_DEBUG=false
+APP_NAME=my-api
+
+THROTTLE_ENABLED=true
+THROTTLE_LIMIT=100
+THROTTLE_WINDOW=60
+
+CORS_ENABLED=true
+CORS_ORIGINS=https://example.com,https://app.example.com
+
+BEARER_TOKEN_ENABLED=true
+BEARER_TOKENS=secret-token-1,secret-token-2
+
+DB_ADAPTER=mysql
+DB_HOST=db.example.com
+DB_PORT=3306
+DB_NAME=myapp
+DB_USER=myuser
+DB_PASSWORD=supersecret
+```
+
+> `.env` ファイルは `.gitignore` で除外してください。`.env.example` にキー一覧をコミットしてください。
diff --git a/docs/ja/reference/framework-modules.md b/docs/ja/reference/framework-modules.md
new file mode 100644
index 0000000..195a383
--- /dev/null
+++ b/docs/ja/reference/framework-modules.md
@@ -0,0 +1,224 @@
+# フレームワークモジュールリファレンス
+
+`src/nene2/` パッケージが提供するコアモジュールの一覧です。
+
+---
+
+## nene2.http
+
+### `PaginationQueryParser`
+
+クエリパラメータ `limit` と `offset` を解析します。
+
+```python
+from nene2.http import PaginationQueryParser
+
+pagination = PaginationQueryParser.parse(request)
+# pagination.limit → int (max 100, default 20)
+# pagination.offset → int (default 0)
+```
+
+### `PaginationResponse`
+
+ページネーションレスポンスの構造。
+
+```python
+from nene2.http import PaginationResponse
+
+body = PaginationResponse(items=[...], limit=20, offset=0, total=42).to_dict()
+# → {"items": [...], "limit": 20, "offset": 0, "total": 42}
+```
+
+### `problem_details_response()`
+
+RFC 9457 準拠のエラーレスポンスを生成します。
+
+```python
+from nene2.http import problem_details_response
+
+return problem_details_response("not-found", "Not Found", 404, "Note 42 not found.")
+```
+
+---
+
+## nene2.use_case
+
+### `UseCaseProtocol[I, O]`
+
+同期 UseCase の構造的型契約。
+
+```python
+from nene2.use_case import UseCaseProtocol
+
+class MyUseCase:
+ def execute(self, input_: MyInput) -> MyOutput: ...
+
+assert isinstance(MyUseCase(), UseCaseProtocol)
+```
+
+### `AsyncUseCaseProtocol[I, O]`
+
+非同期 UseCase の構造的型契約。
+
+```python
+from nene2.use_case import AsyncUseCaseProtocol
+
+class MyAsyncUseCase:
+ async def execute(self, input_: MyInput) -> MyOutput: ...
+
+assert isinstance(MyAsyncUseCase(), AsyncUseCaseProtocol)
+```
+
+> **注意**: `isinstance` はメソッドの存在のみを確認します。同期/非同期の区別は `mypy --strict` で静的に強制されます。
+
+---
+
+## nene2.config
+
+### `AppSettings`
+
+環境変数から設定を読み込む Pydantic Settings クラス。
+
+```python
+from nene2.config import AppSettings
+
+cfg = AppSettings() # 環境変数 / .env から読み込み
+cfg_test = AppSettings(throttle_enabled=False) # テスト用オーバーライド
+```
+
+詳細は [設定リファレンス](configuration.md) を参照してください。
+
+---
+
+## nene2.middleware
+
+### `ErrorHandlerMiddleware`
+
+全例外をキャッチし RFC 9457 Problem Details に変換します。
+ドメイン例外ハンドラーは `DomainExceptionHandlerProtocol` を実装して登録します。
+
+### その他のミドルウェア
+
+| クラス | モジュール | 役割 |
+|---|---|---|
+| `SecurityHeadersMiddleware` | `nene2.middleware.security_headers` | セキュリティヘッダー付与 |
+| `RequestIdMiddleware` | `nene2.middleware.request_id` | X-Request-ID 付与 |
+| `RequestLoggingMiddleware` | `nene2.middleware.request_logging` | structlog リクエストロギング |
+| `RequestSizeLimitMiddleware` | `nene2.middleware.request_size_limit` | ペイロードサイズ制限 |
+| `ThrottleMiddleware` | `nene2.middleware.throttle` | 固定ウィンドウ レートリミット |
+
+---
+
+## nene2.auth
+
+### `LocalTokenVerifier`
+
+`secrets.compare_digest` で静的トークンリストを検証します。
+
+```python
+from nene2.auth import LocalTokenVerifier
+
+verifier = LocalTokenVerifier(["token-a", "token-b"])
+verifier.verify("token-a") # True
+verifier.verify("wrong") # False
+```
+
+### `TokenVerifierProtocol` / `TokenIssuerProtocol`
+
+カスタム検証器・発行器の実装に使うプロトコル(JWT など)。
+
+### `TokenVerificationException`
+
+トークンが無効な場合にverifier から raise します。
+`BearerTokenMiddleware` が自動的に `401 Unauthorized` に変換します。
+
+---
+
+## nene2.database
+
+### `SqlAlchemyQueryExecutor`
+
+SQLAlchemy Core のラッパー。パラメータ化クエリを実行します。
+
+```python
+from nene2.database import SqlAlchemyQueryExecutor
+
+executor = SqlAlchemyQueryExecutor(engine)
+rows = executor.fetch_all("SELECT * FROM notes WHERE id = :id", {"id": 1})
+executor.write("INSERT INTO notes (title, body) VALUES (:t, :b)", {"t": "t", "b": "b"})
+```
+
+### `SqlAlchemyTransactionManager`
+
+トランザクションを管理します。手動の `begin/commit/rollback` より `transactional()` を推奨します。
+
+```python
+from nene2.database import SqlAlchemyTransactionManager
+
+mgr = SqlAlchemyTransactionManager(engine)
+
+result = mgr.transactional(
+ lambda ex: ex.fetch_one("SELECT COUNT(*) AS cnt FROM notes")
+)
+```
+
+---
+
+## nene2.mcp
+
+### `LocalMcpServer`
+
+FastMCP をラップして UseCase を MCP ツールとして登録します。
+
+```python
+from nene2.mcp import LocalMcpServer
+
+server = LocalMcpServer("my-server", instructions="...")
+
+@server.tool("ノート一覧を取得する。")
+def list_notes(limit: int = 20, offset: int = 0) -> list[dict]: ...
+
+server.run(transport="stdio")
+```
+
+### `HttpxMcpClient`
+
+MCP ツールハンドラーから nene2 API を呼び出す HTTP クライアント。
+
+```python
+from nene2.mcp import HttpxMcpClient
+
+client = HttpxMcpClient("bearer-token")
+response = client.get("http://localhost:8080", "/notes")
+response.is_successful() # True
+```
+
+---
+
+## nene2.log
+
+### `setup_logging()`
+
+structlog を初期化します。`app_env` に応じてレンダラーを切り替えます。
+
+```python
+from nene2.log import setup_logging
+
+setup_logging(app_env="production") # JSON レンダラー
+setup_logging(app_env="local") # Console レンダラー
+```
+
+---
+
+## nene2.validation
+
+### `ValidationException` / `ValidationError`
+
+HTTP 入力検証失敗時に `422 Unprocessable Entity` を返す例外。
+
+```python
+from nene2.validation.exceptions import ValidationError, ValidationException
+
+errors = [ValidationError("body", "Body must not be empty.", "required")]
+raise ValidationException(errors)
+```
diff --git a/docs/ja/tutorials/first-domain.md b/docs/ja/tutorials/first-domain.md
new file mode 100644
index 0000000..d64275c
--- /dev/null
+++ b/docs/ja/tutorials/first-domain.md
@@ -0,0 +1,154 @@
+# 新しいドメインを実装する
+
+このチュートリアルでは、`Tag` ドメインを例に nene2-python のクリーンアーキテクチャを体験します。
+各レイヤーを順番に実装することで、フレームワークの構造全体を理解できます。
+
+> **前提**: [はじめての nene2-python](getting-started.md) を完了していること
+
+## 実装するもの
+
+```
+GET /tags — タグ一覧
+POST /tags — タグ作成
+GET /tags/{tag_id} — タグ取得
+PUT /tags/{tag_id} — タグ更新
+DELETE /tags/{tag_id} — タグ削除
+```
+
+## ステップ 1: Entity を作る
+
+`src/example/tag/entity.py` を作成します。
+
+```python
+from dataclasses import dataclass
+
+@dataclass(frozen=True, slots=True)
+class Tag:
+ id: int
+ name: str
+```
+
+`frozen=True` で不変オブジェクト、`slots=True` でメモリ効率を高めています。
+
+## ステップ 2: Repository Interface を作る
+
+`src/example/tag/repository.py` に ABC を定義します。
+
+```python
+from abc import ABC, abstractmethod
+from .entity import Tag
+
+class TagRepositoryInterface(ABC):
+ @abstractmethod
+ def find_all(self, limit: int, offset: int) -> list[Tag]: ...
+
+ @abstractmethod
+ def find_by_id(self, tag_id: int) -> Tag | None: ...
+
+ @abstractmethod
+ def save(self, name: str) -> Tag: ...
+
+ @abstractmethod
+ def update(self, tag_id: int, name: str) -> Tag | None: ...
+
+ @abstractmethod
+ def delete(self, tag_id: int) -> bool: ...
+
+ @abstractmethod
+ def count(self) -> int: ...
+```
+
+## ステップ 3: InMemory 実装を作る
+
+テスト用の InMemory リポジトリを実装します。
+
+```python
+class InMemoryTagRepository(TagRepositoryInterface):
+ def __init__(self) -> None:
+ self._store: dict[int, Tag] = {}
+ self._next_id = 1
+
+ def save(self, name: str) -> Tag:
+ tag = Tag(id=self._next_id, name=name)
+ self._store[self._next_id] = tag
+ self._next_id += 1
+ return tag
+ # ... 省略
+```
+
+## ステップ 4: UseCase を作る
+
+`src/example/tag/use_case.py` に UseCase を定義します。UseCase は HTTP・DB を知りません。
+
+```python
+from dataclasses import dataclass
+from .entity import Tag
+from .exceptions import TagNotFoundException
+from .repository import TagRepositoryInterface
+
+@dataclass(frozen=True)
+class CreateTagInput:
+ name: str
+
+class CreateTagUseCase:
+ def __init__(self, repository: TagRepositoryInterface) -> None:
+ self._repository = repository
+
+ def execute(self, input_: CreateTagInput) -> Tag:
+ return self._repository.save(input_.name)
+```
+
+## ステップ 5: Handler を作る
+
+`src/example/tag/handler.py` に HTTP ルーターを定義します。**parse → use-case → response** の 3 ステップだけ。
+
+```python
+from fastapi import APIRouter
+from fastapi.responses import JSONResponse
+from pydantic import BaseModel
+from .use_case import CreateTagInput, CreateTagUseCase
+
+class CreateTagBody(BaseModel):
+ name: str
+
+def make_tag_router(create_use_case: CreateTagUseCase, ...) -> APIRouter:
+ router = APIRouter(prefix="/tags", tags=["tags"])
+
+ @router.post("", status_code=201)
+ async def create_tag(body: CreateTagBody) -> JSONResponse:
+ tag = create_use_case.execute(CreateTagInput(name=body.name))
+ return JSONResponse({"id": tag.id, "name": tag.name}, status_code=201)
+
+ return router
+```
+
+## ステップ 6: app.py に組み込む
+
+`src/example/app.py` の `create_app()` にルーターを追加します。
+
+```python
+app.include_router(make_tag_router(
+ list_use_case=ListTagsUseCase(tag_repo),
+ ...
+))
+```
+
+## ステップ 7: テストを書く
+
+```python
+# tests/example/tag/test_tag_use_case.py
+def test_create_tag() -> None:
+ repo = InMemoryTagRepository()
+ tag = CreateTagUseCase(repo).execute(CreateTagInput(name="python"))
+ assert tag.name == "python"
+```
+
+## 完了
+
+実装した Tag ドメインは Comment ドメイン (`src/example/comment/`) と同じ構造です。
+実際の実装は `src/example/tag/` を参照してください。
+
+## 次のステップ
+
+- [新しいドメインを追加する](../how-to/add-new-domain.md) — チェックリスト形式の実践ガイド
+- [アーキテクチャ概要](../explanation/architecture.md) — 各レイヤーの役割を深く理解する
diff --git a/docs/ja/tutorials/getting-started.md b/docs/ja/tutorials/getting-started.md
new file mode 100644
index 0000000..ce903a2
--- /dev/null
+++ b/docs/ja/tutorials/getting-started.md
@@ -0,0 +1,55 @@
+# はじめての nene2-python
+
+このチュートリアルでは、nene2-python を使って Note の CRUD API を 5 分で起動します。
+
+## 前提条件
+
+- Python 3.12 以上
+- [uv](https://docs.astral.sh/uv/) がインストール済み
+- Git
+
+## 1. リポジトリを clone する
+
+```bash
+git clone https://github.com/hideyukiMORI/nene2-python.git
+cd nene2-python
+```
+
+## 2. 依存関係をインストールする
+
+```bash
+uv sync
+```
+
+## 3. 開発サーバーを起動する
+
+```bash
+uv run uvicorn src.example.app:app --reload --port 8080
+```
+
+起動後、ブラウザで `http://localhost:8080/docs` を開くと Swagger UI が表示されます。
+
+## 4. API を試す
+
+```bash
+# Note を作成する
+curl -X POST http://localhost:8080/notes \
+ -H "Content-Type: application/json" \
+ -d '{"title": "はじめてのノート", "body": "nene2-python で作成しました"}'
+
+# Note 一覧を取得する
+curl http://localhost:8080/notes
+```
+
+## 5. テストを実行する
+
+```bash
+uv run pytest
+```
+
+135 件以上のテストがすべて通ることを確認してください。
+
+## 次のステップ
+
+- [新しいドメインを実装する](first-domain.md) — Tag ドメインの実装を通じてフレームワークの構造を理解する
+- [設定リファレンス](../reference/configuration.md) — 環境変数で DB や認証を設定する
diff --git a/docs/pt-br/index.md b/docs/pt-br/index.md
new file mode 100644
index 0000000..fd4fb29
--- /dev/null
+++ b/docs/pt-br/index.md
@@ -0,0 +1,43 @@
+---
+layout: home
+
+hero:
+ name: "NENE2"
+ text: "Framework de API Python"
+ tagline: FastAPI · Arquitetura Limpa · MCP · mypy --strict · Projetado para IA desde o primeiro dia.
+ actions:
+ - theme: brand
+ text: Começar →
+ link: /pt-br/tutorials/getting-started
+ - theme: alt
+ text: Ver no GitHub
+ link: https://github.com/hideyukiMORI/nene2-python
+ - theme: alt
+ text: Versão PHP
+ link: https://hideyukimori.github.io/NENE2/
+
+features:
+ - icon: 🐍
+ title: Python 3.12+ nativo
+ details: Sintaxe genérica do Python 3.12, dataclasses imutáveis e Pydantic v2. mypy --strict aplicado em todos os commits.
+
+ - icon: ⚡
+ title: FastAPI + async
+ details: ASGI nativo com AsyncUseCaseProtocol para I/O não bloqueante. asyncio.gather para chamadas paralelas.
+
+ - icon: 🤖
+ title: MCP integrado
+ details: UseCases expostos como ferramentas MCP via LocalMcpServer — sem configuração adicional.
+
+ - icon: 🏛️
+ title: Arquitetura Limpa
+ details: HTTP Handler → UseCase → RepositoryInterface → SQLAlchemy. Cada camada testável em isolamento.
+
+ - icon: 🛡️
+ title: Segurança em primeiro lugar
+ details: RFC 9457 Problem Details, autenticação Bearer + API Key, limitação de taxa, cabeçalhos de segurança.
+
+ - icon: 📄
+ title: OpenAPI gerado automaticamente
+ details: Swagger UI e ReDoc em /docs — sem configuração. Exporte um openapi.yaml estático com um comando.
+---
diff --git a/docs/pt-br/tutorials/getting-started.md b/docs/pt-br/tutorials/getting-started.md
new file mode 100644
index 0000000..b71f052
--- /dev/null
+++ b/docs/pt-br/tutorials/getting-started.md
@@ -0,0 +1,54 @@
+# Primeiros passos com nene2-python
+
+Este tutorial permite que você inicie uma API CRUD de Notes com nene2-python em 5 minutos.
+
+## Pré-requisitos
+
+- Python 3.12 ou superior
+- [uv](https://docs.astral.sh/uv/) instalado
+- Git
+
+## 1. Clonar o repositório
+
+```bash
+git clone https://github.com/hideyukiMORI/nene2-python.git
+cd nene2-python
+```
+
+## 2. Instalar dependências
+
+```bash
+uv sync
+```
+
+## 3. Iniciar o servidor de desenvolvimento
+
+```bash
+uv run uvicorn src.example.app:app --reload --port 8080
+```
+
+Abra `http://localhost:8080/docs` no navegador para acessar o Swagger UI.
+
+## 4. Testar a API
+
+```bash
+# Criar uma nota
+curl -X POST http://localhost:8080/notes \
+ -H "Content-Type: application/json" \
+ -d '{"title": "Minha primeira nota", "body": "Criada com nene2-python"}'
+
+# Listar notas
+curl http://localhost:8080/notes
+```
+
+## 5. Executar os testes
+
+```bash
+uv run pytest
+```
+
+Mais de 135 testes devem passar com sucesso.
+
+## Próximos passos
+
+- [Referência de configuração](../reference/configuration.md) — Configurar banco de dados e autenticação via variáveis de ambiente
diff --git a/docs/reference/api.md b/docs/reference/api.md
index 3a25826..24f6555 100644
--- a/docs/reference/api.md
+++ b/docs/reference/api.md
@@ -1,9 +1,9 @@
-# REST API リファレンス
+# REST API reference
-nene2-python example アプリが提供するエンドポイントの一覧です。
+Endpoints provided by the nene2-python example application.
-> OpenAPI スキーマ(機械可読)は `uv run export-openapi` で `docs/openapi.yaml` に生成できます。
-> 開発サーバー起動後は `http://localhost:8080/docs` で Swagger UI を参照できます。
+> Machine-readable schema: run `uv run export-openapi` to generate `docs/openapi.yaml`.
+> Interactive docs: start the dev server and open `http://localhost:8080/docs`.
---
@@ -11,125 +11,111 @@ nene2-python example アプリが提供するエンドポイントの一覧で
### `GET /notes`
-ノート一覧を取得します。
+List notes with pagination.
-**クエリパラメータ**
+**Query parameters**
-| パラメータ | 型 | デフォルト | 説明 |
+| Parameter | Type | Default | Description |
|---|---|---|---|
-| `limit` | int | 20 | 最大取得件数(上限 100) |
-| `offset` | int | 0 | スキップ件数 |
+| `limit` | int | 20 | Maximum results (max 100) |
+| `offset` | int | 0 | Number of results to skip |
-**レスポンス** `200 OK`
+**Response** `200 OK`
```json
{
- "items": [
- {"id": 1, "title": "ノートタイトル", "body": "本文"}
- ],
+ "items": [{"id": 1, "title": "My note", "body": "Content"}],
"limit": 20,
"offset": 0,
"total": 1
}
```
----
-
### `POST /notes`
-ノートを作成します。
+Create a note.
-**リクエストボディ**
+**Request body**
```json
-{"title": "タイトル", "body": "本文"}
+{"title": "Title", "body": "Body text"}
```
-**レスポンス** `201 Created`
+**Response** `201 Created`
```json
-{"id": 1, "title": "タイトル", "body": "本文"}
+{"id": 1, "title": "Title", "body": "Body text"}
```
----
-
### `GET /notes/{note_id}`
-指定した ID のノートを取得します。
-
-**レスポンス** `200 OK` / `404 Not Found`
-
----
+Get a single note. Returns `404` if not found.
### `PUT /notes/{note_id}`
-ノートを更新します。
+Update a note.
-**リクエストボディ**
+**Request body**
```json
-{"title": "新タイトル", "body": "新本文"}
+{"title": "New title", "body": "New body"}
```
-**レスポンス** `200 OK` / `404 Not Found`
-
----
+**Response** `200 OK` / `404 Not Found`
### `DELETE /notes/{note_id}`
-ノートを削除します。
-
-**レスポンス** `204 No Content` / `404 Not Found`
+Delete a note. Returns `204 No Content` / `404 Not Found`.
---
## Tags
-`/tags` エンドポイントは Notes と同じ CRUD パターンです。
+`/tags` follows the same CRUD pattern as Notes.
-| メソッド | パス | 説明 |
+| Method | Path | Description |
|---|---|---|
-| `GET` | `/tags` | タグ一覧 |
-| `POST` | `/tags` | タグ作成(`{"name": "..."}`) |
-| `GET` | `/tags/{tag_id}` | タグ取得 |
-| `PUT` | `/tags/{tag_id}` | タグ更新(`{"name": "..."}`) |
-| `DELETE` | `/tags/{tag_id}` | タグ削除 |
+| `GET` | `/tags` | List tags |
+| `POST` | `/tags` | Create tag (`{"name": "..."}`) |
+| `GET` | `/tags/{tag_id}` | Get tag |
+| `PUT` | `/tags/{tag_id}` | Update tag (`{"name": "..."}`) |
+| `DELETE` | `/tags/{tag_id}` | Delete tag |
---
## Comments
-コメントはノートに紐づくネストリソースです。
+Comments are nested under a Note.
-| メソッド | パス | 説明 |
+| Method | Path | Description |
|---|---|---|
-| `GET` | `/notes/{note_id}/comments` | コメント一覧 |
-| `POST` | `/notes/{note_id}/comments` | コメント作成(`{"body": "..."}`) |
-| `GET` | `/notes/{note_id}/comments/{comment_id}` | コメント取得 |
-| `PUT` | `/notes/{note_id}/comments/{comment_id}` | コメント更新 |
-| `DELETE` | `/notes/{note_id}/comments/{comment_id}` | コメント削除 |
+| `GET` | `/notes/{note_id}/comments` | List comments |
+| `POST` | `/notes/{note_id}/comments` | Create comment (`{"body": "..."}`) |
+| `GET` | `/notes/{note_id}/comments/{comment_id}` | Get comment |
+| `PUT` | `/notes/{note_id}/comments/{comment_id}` | Update comment |
+| `DELETE` | `/notes/{note_id}/comments/{comment_id}` | Delete comment |
---
-## Health Check
+## Health
### `GET /health`
-アプリケーションの稼働状態を返します。
+Returns application health status.
-**レスポンス** `200 OK`
+**Response** `200 OK`
```json
{"status": "ok", "db": "ok"}
```
-DB 接続失敗時は `db` フィールドが `"error"` になります。
+`db` is `"error"` when the database connection fails.
---
-## エラーレスポンス
+## Error responses
-すべてのエラーは RFC 9457 Problem Details 形式で返します。
+All errors use [RFC 9457 Problem Details](https://www.rfc-editor.org/rfc/rfc9457) format.
```json
{
@@ -140,12 +126,12 @@ DB 接続失敗時は `db` フィールドが `"error"` になります。
}
```
-| ステータス | type | 原因 |
+| Status | type | Cause |
|---|---|---|
-| 400 | `bad-request` | 不正なリクエスト |
-| 401 | `unauthorized` | 認証失敗 |
-| 404 | `not-found` | リソースが存在しない |
-| 413 | `payload-too-large` | ペイロードサイズ超過 |
-| 422 | `validation-failed` | バリデーションエラー |
-| 429 | `too-many-requests` | レートリミット超過 |
-| 500 | `internal-server-error` | サーバー内部エラー |
+| 400 | `bad-request` | Malformed request |
+| 401 | `unauthorized` | Authentication failure |
+| 404 | `not-found` | Resource does not exist |
+| 413 | `payload-too-large` | Body exceeds size limit |
+| 422 | `validation-failed` | Input validation error |
+| 429 | `too-many-requests` | Rate limit exceeded |
+| 500 | `internal-server-error` | Unhandled server error |
diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md
index 49a402e..187e86c 100644
--- a/docs/reference/configuration.md
+++ b/docs/reference/configuration.md
@@ -1,25 +1,25 @@
-# 設定リファレンス(環境変数)
+# Configuration reference
-設定は `pydantic-settings` で管理されており、環境変数または `.env` ファイルから読み込みます。
+All settings are managed by `AppSettings` (Pydantic Settings) and can be provided via environment variables or a `.env` file.
-## 基本設定
+## Core
-| 変数 | デフォルト | 説明 |
+| Variable | Default | Description |
|---|---|---|
-| `APP_ENV` | `local` | 実行環境。`local` / `test` / `production` |
-| `APP_DEBUG` | `false` | `true` の場合、500 エラーに例外メッセージを含める |
-| `APP_NAME` | `nene2-python` | アプリケーション名 |
+| `APP_ENV` | `local` | Runtime environment: `local` / `test` / `production` |
+| `APP_DEBUG` | `false` | Include exception messages in 500 responses when `true` |
+| `APP_NAME` | `nene2-python` | Application name |
-## セキュリティ設定
+## Security
-| 変数 | デフォルト | 説明 |
+| Variable | Default | Description |
|---|---|---|
-| `SECURITY_HEADERS_ENABLED` | `true` | セキュリティヘッダー付与を有効化 |
-| `MAX_BODY_SIZE` | `1048576` | リクエストボディの最大バイト数(デフォルト 1 MiB) |
+| `SECURITY_HEADERS_ENABLED` | `true` | Add security headers to every response |
+| `MAX_BODY_SIZE` | `1048576` | Maximum request body size in bytes (default 1 MiB) |
-セキュリティヘッダーの内容:
+Security headers added when enabled:
-| ヘッダー | 値 |
+| Header | Value |
|---|---|
| `X-Content-Type-Options` | `nosniff` |
| `X-Frame-Options` | `DENY` |
@@ -27,62 +27,61 @@
| `Content-Security-Policy` | `default-src 'self'` |
| `Permissions-Policy` | `geolocation=(), microphone=()` |
-## レートリミット
+## Rate limiting
-| 変数 | デフォルト | 説明 |
+| Variable | Default | Description |
|---|---|---|
-| `THROTTLE_ENABLED` | `true` | レートリミットを有効化 |
-| `THROTTLE_LIMIT` | `60` | ウィンドウ内の最大リクエスト数 |
-| `THROTTLE_WINDOW` | `60` | ウィンドウの秒数 |
+| `THROTTLE_ENABLED` | `true` | Enable rate limiting |
+| `THROTTLE_LIMIT` | `60` | Maximum requests per window |
+| `THROTTLE_WINDOW` | `60` | Window size in seconds |
-固定ウィンドウ方式(IP アドレスをキーとする)。制限超過時は `429 Too Many Requests` + `Retry-After` ヘッダー。
+Uses a fixed-window algorithm keyed on client IP. Exceeding the limit returns `429 Too Many Requests` with a `Retry-After` header.
-## CORS 設定
+## CORS
-| 変数 | デフォルト | 説明 |
+| Variable | Default | Description |
|---|---|---|
-| `CORS_ENABLED` | `false` | CORS ミドルウェアを有効化 |
-| `CORS_ORIGINS` | `[]` | 許可オリジンのリスト(カンマ区切り) |
-| `CORS_ALLOW_CREDENTIALS` | `false` | クレデンシャルを許可するか |
-| `CORS_ALLOW_METHODS` | `GET,POST,PUT,DELETE,OPTIONS` | 許可メソッド |
-| `CORS_ALLOW_HEADERS` | `*` | 許可ヘッダー |
+| `CORS_ENABLED` | `false` | Enable CORS middleware |
+| `CORS_ORIGINS` | `[]` | Allowed origins (comma-separated) |
+| `CORS_ALLOW_CREDENTIALS` | `false` | Allow credentials |
+| `CORS_ALLOW_METHODS` | `GET,POST,PUT,DELETE,OPTIONS` | Allowed methods |
+| `CORS_ALLOW_HEADERS` | `*` | Allowed headers |
-> `CORS_ORIGINS=*` は禁止です。許可オリジンを明示してください。
+> `CORS_ORIGINS=*` is **prohibited**. Always specify explicit origins.
-## 認証設定
+## Authentication
-| 変数 | デフォルト | 説明 |
+| Variable | Default | Description |
|---|---|---|
-| `BEARER_TOKEN_ENABLED` | `false` | Bearer Token 認証を有効化 |
-| `BEARER_TOKENS` | `[]` | 有効なトークンのリスト(カンマ区切り) |
-| `API_KEY_ENABLED` | `false` | API Key 認証を有効化 |
-| `API_KEYS` | `[]` | 有効な API キーのリスト(カンマ区切り) |
+| `BEARER_TOKEN_ENABLED` | `false` | Enable Bearer Token auth |
+| `BEARER_TOKENS` | `[]` | Valid tokens (comma-separated) |
+| `API_KEY_ENABLED` | `false` | Enable API Key auth |
+| `API_KEYS` | `[]` | Valid API keys (comma-separated) |
-## データベース設定
+## Database
-| 変数 | デフォルト | 説明 |
+| Variable | Default | Description |
|---|---|---|
| `DB_ADAPTER` | `sqlite` | `sqlite` / `mysql` / `pgsql` |
-| `DB_NAME` | `:memory:` | SQLite のファイルパスまたは DB 名 |
-| `DB_HOST` | `localhost` | DB ホスト(SQLite では無視) |
-| `DB_PORT` | `3306` | DB ポート(SQLite では無視) |
-| `DB_USER` | `""` | DB ユーザー名(SQLite では無視) |
-| `DB_PASSWORD` | `""` | DB パスワード — `SecretStr` 型(ログに出力されない) |
+| `DB_NAME` | `:memory:` | SQLite file path or DB name |
+| `DB_HOST` | `localhost` | Database host (ignored for SQLite) |
+| `DB_PORT` | `3306` | Database port (ignored for SQLite) |
+| `DB_USER` | `""` | Database user (ignored for SQLite) |
+| `DB_PASSWORD` | `""` | Database password — stored as `SecretStr`, never logged |
-### 接続 URL の例
+### Generated connection URLs
-| アダプター | 生成される URL |
+| Adapter | URL format |
|---|---|
| `sqlite` | `sqlite:///path/to/db.sqlite3` |
| `mysql` | `mysql+pymysql://user:pass@host:3306/dbname` |
| `pgsql` | `postgresql+psycopg2://user:pass@host:5432/dbname` |
-## .env ファイル例
+## Example `.env`
```dotenv
APP_ENV=production
APP_DEBUG=false
-APP_NAME=my-api
THROTTLE_ENABLED=true
THROTTLE_LIMIT=100
@@ -102,4 +101,4 @@ DB_USER=myuser
DB_PASSWORD=supersecret
```
-> `.env` ファイルは `.gitignore` で除外してください。`.env.example` にキー一覧をコミットしてください。
+> Commit `.env.example` with empty values. Keep the real `.env` in `.gitignore`.
diff --git a/docs/reference/framework-modules.md b/docs/reference/framework-modules.md
index 9d9e065..1380b4a 100644
--- a/docs/reference/framework-modules.md
+++ b/docs/reference/framework-modules.md
@@ -1,12 +1,14 @@
-# フレームワークモジュールリファレンス
+# Framework modules reference
-`src/nene2/` パッケージが提供するコアモジュールの一覧です。
+Public API of the `nene2` package.
+
+---
## nene2.http
### `PaginationQueryParser`
-クエリパラメータ `limit` と `offset` を解析します。
+Parses `limit` and `offset` query parameters.
```python
from nene2.http import PaginationQueryParser
@@ -18,29 +20,23 @@ pagination = PaginationQueryParser.parse(request)
### `PaginationResponse`
-ページネーションレスポンスの構造。
+Wraps a paginated result set.
```python
from nene2.http import PaginationResponse
-response = PaginationResponse(items=[...], limit=20, offset=0, total=42)
-return JSONResponse(response.to_dict())
+body = PaginationResponse(items=[...], limit=20, offset=0, total=42).to_dict()
# → {"items": [...], "limit": 20, "offset": 0, "total": 42}
```
### `problem_details_response()`
-RFC 9457 準拠のエラーレスポンスを生成します。
+Generates an RFC 9457 Problem Details response.
```python
from nene2.http import problem_details_response
-return problem_details_response(
- problem_type="not-found",
- title="Not Found",
- status=404,
- detail="Note with ID 42 was not found.",
-)
+return problem_details_response("not-found", "Not Found", 404, "Note 42 not found.")
```
---
@@ -49,7 +45,7 @@ return problem_details_response(
### `UseCaseProtocol[I, O]`
-同期 UseCase の構造的型契約。
+Structural contract for synchronous UseCases.
```python
from nene2.use_case import UseCaseProtocol
@@ -62,7 +58,7 @@ assert isinstance(MyUseCase(), UseCaseProtocol)
### `AsyncUseCaseProtocol[I, O]`
-非同期 UseCase の構造的型契約。
+Structural contract for async UseCases.
```python
from nene2.use_case import AsyncUseCaseProtocol
@@ -73,51 +69,43 @@ class MyAsyncUseCase:
assert isinstance(MyAsyncUseCase(), AsyncUseCaseProtocol)
```
+> **Note**: `isinstance` checks attribute presence only. The async/sync distinction is enforced statically by `mypy --strict`.
+
---
## nene2.config
### `AppSettings`
-環境変数から設定を読み込む Pydantic Settings クラス。
-詳細は [設定リファレンス](configuration.md) を参照してください。
+Pydantic Settings class — reads from environment variables and `.env`.
```python
from nene2.config import AppSettings
-cfg = AppSettings() # 環境変数 / .env から読み込み
-cfg_test = AppSettings(throttle_enabled=False) # テスト用オーバーライド
+cfg = AppSettings() # from environment
+cfg_test = AppSettings(throttle_enabled=False) # override for tests
```
+See [Configuration reference](configuration.md) for all fields.
+
---
## nene2.middleware
### `ErrorHandlerMiddleware`
-全例外をキャッチし RFC 9457 Problem Details に変換します。
-ドメイン例外ハンドラーは `DomainExceptionHandlerProtocol` を実装して登録します。
+Catches all unhandled exceptions and converts them to Problem Details responses.
+Register domain exception handlers via `DomainExceptionHandlerProtocol`.
-```python
-from nene2.middleware import ErrorHandlerMiddleware
-from nene2.middleware.domain_exception import DomainExceptionHandlerProtocol
-
-class MyExceptionHandler:
- def handles(self, exc: Exception) -> bool:
- return isinstance(exc, MyException)
- def handle(self, exc: Exception) -> Response:
- return problem_details_response("my-error", "My Error", 400)
-```
+### Other middleware
-### その他のミドルウェア
-
-| クラス | モジュール | 役割 |
+| Class | Module | Role |
|---|---|---|
-| `SecurityHeadersMiddleware` | `nene2.middleware.security_headers` | セキュリティヘッダー付与 |
-| `RequestIdMiddleware` | `nene2.middleware.request_id` | X-Request-ID 付与 |
-| `RequestLoggingMiddleware` | `nene2.middleware.request_logging` | structlog リクエストロギング |
-| `RequestSizeLimitMiddleware` | `nene2.middleware.request_size_limit` | ペイロードサイズ制限 |
-| `ThrottleMiddleware` | `nene2.middleware.throttle` | 固定ウィンドウ レートリミット |
+| `SecurityHeadersMiddleware` | `nene2.middleware.security_headers` | Add security response headers |
+| `RequestIdMiddleware` | `nene2.middleware.request_id` | Generate / propagate `X-Request-ID` |
+| `RequestLoggingMiddleware` | `nene2.middleware.request_logging` | Structured request / response logging |
+| `RequestSizeLimitMiddleware` | `nene2.middleware.request_size_limit` | Reject oversized request bodies |
+| `ThrottleMiddleware` | `nene2.middleware.throttle` | Fixed-window rate limiting per IP |
---
@@ -125,7 +113,7 @@ class MyExceptionHandler:
### `LocalTokenVerifier`
-`secrets.compare_digest` で静的トークンリストを検証します。
+Verifies tokens against a static list using `secrets.compare_digest`.
```python
from nene2.auth import LocalTokenVerifier
@@ -135,15 +123,43 @@ verifier.verify("token-a") # True
verifier.verify("wrong") # False
```
-### `TokenVerifierProtocol`
+### `TokenVerifierProtocol` / `TokenIssuerProtocol`
+
+Structural contracts for custom verifiers and issuers (e.g. JWT).
+
+### `TokenVerificationException`
+
+Raise this from a verifier to signal an invalid token.
+`BearerTokenMiddleware` maps it to `401 Unauthorized`.
+
+---
+
+## nene2.database
+
+### `SqlAlchemyQueryExecutor`
+
+Executes parameterised SQL via SQLAlchemy Core.
+
+```python
+from nene2.database import SqlAlchemyQueryExecutor
+
+executor = SqlAlchemyQueryExecutor(engine)
+rows = executor.fetch_all("SELECT * FROM notes WHERE id = :id", {"id": 1})
+executor.write("INSERT INTO notes (title, body) VALUES (:t, :b)", {"t": "t", "b": "b"})
+```
+
+### `SqlAlchemyTransactionManager`
-カスタム検証器の実装に使うプロトコル。
+Manages transactions. Prefer `transactional()` over manual `begin/commit/rollback`.
```python
-from nene2.auth.interfaces import TokenVerifierProtocol
+from nene2.database import SqlAlchemyTransactionManager
+
+mgr = SqlAlchemyTransactionManager(engine)
-class JwtVerifier:
- def verify(self, token: str) -> bool: ...
+result = mgr.transactional(
+ lambda ex: ex.fetch_one("SELECT COUNT(*) AS cnt FROM notes")
+)
```
---
@@ -152,33 +168,29 @@ class JwtVerifier:
### `LocalMcpServer`
-MCP サーバーを構築するラッパー。
+Wraps FastMCP — registers UseCase functions as MCP tools.
```python
from nene2.mcp import LocalMcpServer
server = LocalMcpServer("my-server", instructions="...")
-@server.tool("ノート一覧を取得する。")
+@server.tool("List all notes.")
def list_notes(limit: int = 20, offset: int = 0) -> list[dict]: ...
-server.run(transport="stdio") # Claude Desktop 向け
+server.run(transport="stdio")
```
----
-
-## nene2.database
-
-### `SqlAlchemyQueryExecutor`
+### `HttpxMcpClient`
-SQLAlchemy Core のラッパー。パラメータ化クエリを実行します。
+HTTP client for calling a nene2 API from MCP tool handlers.
```python
-from nene2.database import SqlAlchemyQueryExecutor
+from nene2.mcp import HttpxMcpClient
-executor = SqlAlchemyQueryExecutor(engine)
-rows = executor.query("SELECT * FROM notes WHERE id = :id", {"id": 1})
-executor.write("INSERT INTO notes (title, body) VALUES (:title, :body)", {...})
+client = HttpxMcpClient("bearer-token")
+response = client.get("http://localhost:8080", "/notes")
+response.is_successful() # True
```
---
@@ -187,13 +199,13 @@ executor.write("INSERT INTO notes (title, body) VALUES (:title, :body)", {...})
### `setup_logging()`
-structlog を初期化します。`app_env` に応じてレンダラーを切り替えます。
+Initialises structlog. Switches between ConsoleRenderer (local) and JSON (production).
```python
from nene2.log import setup_logging
-setup_logging(app_env="production") # JSON レンダラー
-setup_logging(app_env="local") # Console レンダラー
+setup_logging(app_env="production") # JSON renderer
+setup_logging(app_env="local") # Console renderer
```
---
@@ -202,7 +214,7 @@ setup_logging(app_env="local") # Console レンダラー
### `ValidationException` / `ValidationError`
-HTTP 入力検証失敗時に `422 Unprocessable Entity` を返す例外。
+Raise `ValidationException` at the HTTP boundary to return `422 Unprocessable Entity`.
```python
from nene2.validation.exceptions import ValidationError, ValidationException
diff --git a/docs/tutorials/first-domain.md b/docs/tutorials/first-domain.md
index d64275c..bc85542 100644
--- a/docs/tutorials/first-domain.md
+++ b/docs/tutorials/first-domain.md
@@ -1,23 +1,23 @@
-# 新しいドメインを実装する
+# Implement a new domain
-このチュートリアルでは、`Tag` ドメインを例に nene2-python のクリーンアーキテクチャを体験します。
-各レイヤーを順番に実装することで、フレームワークの構造全体を理解できます。
+This tutorial walks you through adding the `Tag` domain from scratch.
+By building each layer in order you will see how nene2-python's clean architecture fits together.
-> **前提**: [はじめての nene2-python](getting-started.md) を完了していること
+> **Prerequisite**: Complete [Getting started](getting-started.md) first.
-## 実装するもの
+## What we are building
```
-GET /tags — タグ一覧
-POST /tags — タグ作成
-GET /tags/{tag_id} — タグ取得
-PUT /tags/{tag_id} — タグ更新
-DELETE /tags/{tag_id} — タグ削除
+GET /tags — list tags
+POST /tags — create a tag
+GET /tags/{tag_id} — get a tag
+PUT /tags/{tag_id} — update a tag
+DELETE /tags/{tag_id} — delete a tag
```
-## ステップ 1: Entity を作る
+## Step 1: Entity
-`src/example/tag/entity.py` を作成します。
+Create `src/example/tag/entity.py`.
```python
from dataclasses import dataclass
@@ -28,11 +28,11 @@ class Tag:
name: str
```
-`frozen=True` で不変オブジェクト、`slots=True` でメモリ効率を高めています。
+`frozen=True` makes the object immutable; `slots=True` reduces memory overhead.
-## ステップ 2: Repository Interface を作る
+## Step 2: Repository Interface
-`src/example/tag/repository.py` に ABC を定義します。
+Define the contract in `src/example/tag/repository.py`.
```python
from abc import ABC, abstractmethod
@@ -58,9 +58,9 @@ class TagRepositoryInterface(ABC):
def count(self) -> int: ...
```
-## ステップ 3: InMemory 実装を作る
+## Step 3: InMemory implementation
-テスト用の InMemory リポジトリを実装します。
+Provide an in-memory repository for tests — no database required.
```python
class InMemoryTagRepository(TagRepositoryInterface):
@@ -73,12 +73,12 @@ class InMemoryTagRepository(TagRepositoryInterface):
self._store[self._next_id] = tag
self._next_id += 1
return tag
- # ... 省略
+ # ... other methods
```
-## ステップ 4: UseCase を作る
+## Step 4: UseCase
-`src/example/tag/use_case.py` に UseCase を定義します。UseCase は HTTP・DB を知りません。
+`src/example/tag/use_case.py` contains business logic — no HTTP or database imports.
```python
from dataclasses import dataclass
@@ -98,9 +98,9 @@ class CreateTagUseCase:
return self._repository.save(input_.name)
```
-## ステップ 5: Handler を作る
+## Step 5: HTTP Handler
-`src/example/tag/handler.py` に HTTP ルーターを定義します。**parse → use-case → response** の 3 ステップだけ。
+`src/example/tag/handler.py` — only three steps: **parse → use-case → response**.
```python
from fastapi import APIRouter
@@ -122,9 +122,9 @@ def make_tag_router(create_use_case: CreateTagUseCase, ...) -> APIRouter:
return router
```
-## ステップ 6: app.py に組み込む
+## Step 6: Wire into app.py
-`src/example/app.py` の `create_app()` にルーターを追加します。
+Add the router in `src/example/app.py`.
```python
app.include_router(make_tag_router(
@@ -133,7 +133,7 @@ app.include_router(make_tag_router(
))
```
-## ステップ 7: テストを書く
+## Step 7: Write tests
```python
# tests/example/tag/test_tag_use_case.py
@@ -143,12 +143,12 @@ def test_create_tag() -> None:
assert tag.name == "python"
```
-## 完了
+## Done
-実装した Tag ドメインは Comment ドメイン (`src/example/comment/`) と同じ構造です。
-実際の実装は `src/example/tag/` を参照してください。
+The Tag domain you just built matches the Comment domain at `src/example/comment/`.
+See `src/example/tag/` for the full reference implementation.
-## 次のステップ
+## Next steps
-- [新しいドメインを追加する](../how-to/add-new-domain.md) — チェックリスト形式の実践ガイド
-- [アーキテクチャ概要](../explanation/architecture.md) — 各レイヤーの役割を深く理解する
+- [Add a new domain](../how-to/add-new-domain.md) — a checklist for production-quality domain additions
+- [Architecture overview](../explanation/architecture.md) — understand the role of each layer
diff --git a/docs/tutorials/getting-started.md b/docs/tutorials/getting-started.md
index ce903a2..9c19657 100644
--- a/docs/tutorials/getting-started.md
+++ b/docs/tutorials/getting-started.md
@@ -1,55 +1,55 @@
-# はじめての nene2-python
+# Getting started with nene2-python
-このチュートリアルでは、nene2-python を使って Note の CRUD API を 5 分で起動します。
+In this tutorial you will run a Note CRUD API in under 5 minutes.
-## 前提条件
+## Prerequisites
-- Python 3.12 以上
-- [uv](https://docs.astral.sh/uv/) がインストール済み
+- Python 3.12 or later
+- [uv](https://docs.astral.sh/uv/) installed
- Git
-## 1. リポジトリを clone する
+## 1. Clone the repository
```bash
git clone https://github.com/hideyukiMORI/nene2-python.git
cd nene2-python
```
-## 2. 依存関係をインストールする
+## 2. Install dependencies
```bash
uv sync
```
-## 3. 開発サーバーを起動する
+## 3. Start the development server
```bash
uv run uvicorn src.example.app:app --reload --port 8080
```
-起動後、ブラウザで `http://localhost:8080/docs` を開くと Swagger UI が表示されます。
+Open `http://localhost:8080/docs` in your browser — Swagger UI is ready.
-## 4. API を試す
+## 4. Try the API
```bash
-# Note を作成する
+# Create a note
curl -X POST http://localhost:8080/notes \
-H "Content-Type: application/json" \
- -d '{"title": "はじめてのノート", "body": "nene2-python で作成しました"}'
+ -d '{"title": "My first note", "body": "Created with nene2-python"}'
-# Note 一覧を取得する
+# List notes
curl http://localhost:8080/notes
```
-## 5. テストを実行する
+## 5. Run the tests
```bash
uv run pytest
```
-135 件以上のテストがすべて通ることを確認してください。
+All 165+ tests should pass.
-## 次のステップ
+## Next steps
-- [新しいドメインを実装する](first-domain.md) — Tag ドメインの実装を通じてフレームワークの構造を理解する
-- [設定リファレンス](../reference/configuration.md) — 環境変数で DB や認証を設定する
+- [Implement a new domain](first-domain.md) — walk through the full layer stack using the Tag domain
+- [Configuration reference](../reference/configuration.md) — configure a real database or enable auth
diff --git a/docs/zh/index.md b/docs/zh/index.md
new file mode 100644
index 0000000..0e884e8
--- /dev/null
+++ b/docs/zh/index.md
@@ -0,0 +1,43 @@
+---
+layout: home
+
+hero:
+ name: "NENE2"
+ text: "Python API 框架"
+ tagline: FastAPI · 整洁架构 · MCP · mypy --strict · 从第一天起就为 AI 而设计。
+ actions:
+ - theme: brand
+ text: 开始使用 →
+ link: /zh/tutorials/getting-started
+ - theme: alt
+ text: 在 GitHub 上查看
+ link: https://github.com/hideyukiMORI/nene2-python
+ - theme: alt
+ text: PHP 版本
+ link: https://hideyukimori.github.io/NENE2/
+
+features:
+ - icon: 🐍
+ title: Python 3.12+ 原生
+ details: 使用 Python 3.12 泛型语法、冻结 dataclass 和 Pydantic v2。每次提交都强制执行 mypy --strict。
+
+ - icon: ⚡
+ title: FastAPI + 异步支持
+ details: ASGI 原生,通过 AsyncUseCaseProtocol 支持非阻塞 I/O。使用 asyncio.gather 进行并发仓库调用。
+
+ - icon: 🤖
+ title: 内置 MCP
+ details: 通过 LocalMcpServer 将 UseCase 作为 MCP 工具公开 — 无需额外配置。
+
+ - icon: 🏛️
+ title: 整洁架构
+ details: HTTP Handler → UseCase → RepositoryInterface → SQLAlchemy。每层都可使用 InMemory 仓库独立测试。
+
+ - icon: 🛡️
+ title: 安全优先
+ details: RFC 9457 Problem Details、Bearer + API Key 认证、速率限制、安全标头,开箱即用。
+
+ - icon: 📄
+ title: 自动生成 OpenAPI
+ details: 在 /docs 提供 Swagger UI 和 ReDoc — 零配置。一条命令导出静态 openapi.yaml。
+---
diff --git a/docs/zh/tutorials/getting-started.md b/docs/zh/tutorials/getting-started.md
new file mode 100644
index 0000000..95ff48c
--- /dev/null
+++ b/docs/zh/tutorials/getting-started.md
@@ -0,0 +1,54 @@
+# nene2-python 入门
+
+本教程将帮助您在 5 分钟内使用 nene2-python 启动一个 Notes CRUD API。
+
+## 前提条件
+
+- Python 3.12 或更高版本
+- 已安装 [uv](https://docs.astral.sh/uv/)
+- Git
+
+## 1. 克隆仓库
+
+```bash
+git clone https://github.com/hideyukiMORI/nene2-python.git
+cd nene2-python
+```
+
+## 2. 安装依赖
+
+```bash
+uv sync
+```
+
+## 3. 启动开发服务器
+
+```bash
+uv run uvicorn src.example.app:app --reload --port 8080
+```
+
+在浏览器中打开 `http://localhost:8080/docs` 查看 Swagger UI。
+
+## 4. 测试 API
+
+```bash
+# 创建笔记
+curl -X POST http://localhost:8080/notes \
+ -H "Content-Type: application/json" \
+ -d '{"title": "我的第一条笔记", "body": "使用 nene2-python 创建"}'
+
+# 获取笔记列表
+curl http://localhost:8080/notes
+```
+
+## 5. 运行测试
+
+```bash
+uv run pytest
+```
+
+135 个以上的测试应全部通过。
+
+## 下一步
+
+- [配置参考](../reference/configuration.md) — 通过环境变量配置数据库和身份验证