docs: add missing Japanese translations to complete zh-CN parity (ja-JP)

Add remaining files to match zh-CN documentation structure:
- hooks/README.md — hooks architecture and customization guide
- examples/ — 8 project CLAUDE.md templates (general, user, django, go, harmonyos, laravel, rust, saas-nextjs)
- CHANGELOG.md — version history
- the-openclaw-guide.md — OpenClaw guide (471 lines)

Total: 11 files, 2362 insertions
ja-JP now has full parity with zh-CN directory structure.
This commit is contained in:
Claude
2026-05-16 22:45:27 +09:00
committed by Affaan Mustafa
parent ec9ace9c54
commit 5a5a47e710
11 changed files with 2361 additions and 7 deletions

View File

@@ -0,0 +1,285 @@
# Rust API サービス — プロジェクト CLAUDE.md
> Axum、PostgreSQL、Dockerを使用したRust APIサービスの実世界サンプル。
> これをプロジェクトのルートにコピーしてサービスに合わせてカスタマイズしてください。
## プロジェクト概要
**スタック:** Rust 1.78+, AxumWebフレームワーク, SQLx非同期データベース, PostgreSQL, Tokio非同期ランタイム, Docker
**アーキテクチャ:** ハンドラー → サービス → リポジトリの分離を持つレイヤードアーキテクチャ。HTTPにAxum、コンパイル時に型チェックされたSQLにSQLx、横断的関心事にTowerミドルウェアを使用。
## 重要なルール
### Rust の規約
- ライブラリエラーには `thiserror` を使用し、`anyhow` はバイナリクレートまたはテストのみ
- 本番コードで `.unwrap()``.expect()` を使用しない — `?` でエラーを伝播させる
- 関数パラメーターでは `String` より `&str` を優先し、所有権が移転するときは `String` を返す
- `#![deny(clippy::all, clippy::pedantic)]``clippy` を使用 — すべての警告を修正する
- すべての公開型に `Debug` を導出し、`Clone``PartialEq` は必要な場合のみ導出する
- `// SAFETY:` コメントによる正当化がない限り `unsafe` ブロックは使用しない
### データベース
- すべてのクエリはSQLxの `query!` または `query_as!` マクロを使用 — スキーマに対してコンパイル時に検証される
- `migrations/` のマイグレーションは `sqlx migrate` を使用 — データベースを直接変更しない
- 共有状態として `sqlx::Pool<Postgres>` を使用 — リクエストごとにコネクションを作成しない
- すべてのクエリはパラメータ化プレースホルダー(`$1`, `$2`)を使用 — 文字列フォーマットは禁止
```rust
// 悪い例: 文字列補間SQLインジェクションリスク
let q = format!("SELECT * FROM users WHERE id = '{}'", id);
// 良い例: パラメータ化クエリ、コンパイル時チェック済み
let user = sqlx::query_as!(User, "SELECT * FROM users WHERE id = $1", id)
.fetch_optional(&pool)
.await?;
```
### エラーハンドリング
- `thiserror` でモジュールごとにドメインエラーenumを定義する
- `IntoResponse` でエラーをHTTPレスポンスにマップ — 内部詳細を公開しない
- 構造化ロギングには `tracing` を使用 — `println!``eprintln!` は使用しない
```rust
use thiserror::Error;
#[derive(Debug, Error)]
pub enum AppError {
#[error("Resource not found")]
NotFound,
#[error("Validation failed: {0}")]
Validation(String),
#[error("Unauthorized")]
Unauthorized,
#[error(transparent)]
Internal(#[from] anyhow::Error),
}
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, message) = match &self {
Self::NotFound => (StatusCode::NOT_FOUND, self.to_string()),
Self::Validation(msg) => (StatusCode::BAD_REQUEST, msg.clone()),
Self::Unauthorized => (StatusCode::UNAUTHORIZED, self.to_string()),
Self::Internal(err) => {
tracing::error!(?err, "internal error");
(StatusCode::INTERNAL_SERVER_ERROR, "Internal error".into())
}
};
(status, Json(json!({ "error": message }))).into_response()
}
}
```
### テスト
- 各ソースファイル内の `#[cfg(test)]` モジュールにユニットテストを記述する
- `tests/` ディレクトリに実際のPostgreSQLTestcontainersまたはDockerを使用した統合テストを記述する
- 自動マイグレーションとロールバック付きのデータベーステストには `#[sqlx::test]` を使用する
- 外部サービスのモックには `mockall` または `wiremock` を使用する
### コードスタイル
- 最大行長: 100文字rustfmtにより強制
- インポートのグループ化: `std`、外部クレート、`crate`/`super` — 空白行で区切る
- モジュール: モジュールごとに1ファイル、`mod.rs` は再エクスポートのみ
- 型: PascalCase、関数/変数: snake_case、定数: UPPER_SNAKE_CASE
## ファイル構成
```
src/
main.rs # エントリーポイント、サーバーセットアップ、グレースフルシャットダウン
lib.rs # 統合テスト用の再エクスポート
config.rs # envyまたはfigmentによる環境設定
router.rs # すべてのルートを持つAxumルーター
middleware/
auth.rs # JWT抽出とバリデーション
logging.rs # リクエスト/レスポンスのトレーシング
handlers/
mod.rs # ルートハンドラー(薄く — サービスに委任)
users.rs
orders.rs
services/
mod.rs # ビジネスロジック
users.rs
orders.rs
repositories/
mod.rs # データベースアクセスSQLxクエリ
users.rs
orders.rs
domain/
mod.rs # ドメイン型、エラーenum
user.rs
order.rs
migrations/
001_create_users.sql
002_create_orders.sql
tests/
common/mod.rs # 共有テストヘルパー、テストサーバーセットアップ
api_users.rs # ユーザーエンドポイントの統合テスト
api_orders.rs # 注文エンドポイントの統合テスト
```
## 主要なパターン
### ハンドラー(薄く)
```rust
async fn create_user(
State(ctx): State<AppState>,
Json(payload): Json<CreateUserRequest>,
) -> Result<(StatusCode, Json<UserResponse>), AppError> {
let user = ctx.user_service.create(payload).await?;
Ok((StatusCode::CREATED, Json(UserResponse::from(user))))
}
```
### サービス(ビジネスロジック)
```rust
impl UserService {
pub async fn create(&self, req: CreateUserRequest) -> Result<User, AppError> {
if self.repo.find_by_email(&req.email).await?.is_some() {
return Err(AppError::Validation("Email already registered".into()));
}
let password_hash = hash_password(&req.password)?;
let user = self.repo.insert(&req.email, &req.name, &password_hash).await?;
Ok(user)
}
}
```
### リポジトリ(データアクセス)
```rust
impl UserRepository {
pub async fn find_by_email(&self, email: &str) -> Result<Option<User>, sqlx::Error> {
sqlx::query_as!(User, "SELECT * FROM users WHERE email = $1", email)
.fetch_optional(&self.pool)
.await
}
pub async fn insert(
&self,
email: &str,
name: &str,
password_hash: &str,
) -> Result<User, sqlx::Error> {
sqlx::query_as!(
User,
r#"INSERT INTO users (email, name, password_hash)
VALUES ($1, $2, $3) RETURNING *"#,
email, name, password_hash,
)
.fetch_one(&self.pool)
.await
}
}
```
### 統合テスト
```rust
#[tokio::test]
async fn test_create_user() {
let app = spawn_test_app().await;
let response = app
.client
.post(&format!("{}/api/v1/users", app.address))
.json(&json!({
"email": "alice@example.com",
"name": "Alice",
"password": "securepassword123"
}))
.send()
.await
.expect("Failed to send request");
assert_eq!(response.status(), StatusCode::CREATED);
let body: serde_json::Value = response.json().await.unwrap();
assert_eq!(body["email"], "alice@example.com");
}
#[tokio::test]
async fn test_create_user_duplicate_email() {
let app = spawn_test_app().await;
// 最初のユーザーを作成
create_test_user(&app, "alice@example.com").await;
// 重複を試みる
let response = create_user_request(&app, "alice@example.com").await;
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
}
```
## 環境変数
```bash
# サーバー
HOST=0.0.0.0
PORT=8080
RUST_LOG=info,tower_http=debug
# データベース
DATABASE_URL=postgres://user:pass@localhost:5432/myapp
# 認証
JWT_SECRET=your-secret-key-min-32-chars
JWT_EXPIRY_HOURS=24
# 任意
CORS_ALLOWED_ORIGINS=http://localhost:3000
```
## テスト戦略
```bash
# すべてのテストを実行
cargo test
# 出力付きで実行
cargo test -- --nocapture
# 特定のテストモジュールを実行
cargo test api_users
# カバレッジチェックcargo-llvm-covが必要
cargo llvm-cov --html
open target/llvm-cov/html/index.html
# リント
cargo clippy -- -D warnings
# フォーマットチェック
cargo fmt -- --check
```
## ECCワークフロー
```bash
# 計画
/plan "Add order fulfillment with Stripe payment"
# TDDによる開発
/tdd # cargo test ベースのTDDワークフロー
# レビュー
/code-review # Rust固有のコードレビュー
/security-scan # 依存関係監査 + unsafeスキャン
# 検証
/verify # ビルド、clippy、テスト、セキュリティスキャン
```
## Git ワークフロー
- `feat:` 新機能、`fix:` バグ修正、`refactor:` コード変更
- `main` からフィーチャーブランチを切り、PRが必要
- CI: `cargo fmt --check`, `cargo clippy`, `cargo test`, `cargo audit`
- デプロイ: `scratch` または `distroless` ベースのDockerマルチステージビルド