総合演習:OrderFlowプロジェクト設計
プロジェクト設計は開発の青写真です。要件が方向を決め, 技術選定が手法を決め, 設計がアーキテクチャを決めます。準備が成功の半ばです。
1. 学ぶこと
- Charlieが提案したビジネス要件:ユーザー管理, 商品管理, 注文管理, 決済管理の4大モジュール
- 技術選定の決定:WebMVC vs. WebFlux, Session vs. JWT, ローカルキャッシュ vs. Redis
- データベースER図設計:User, Product, Order, OrderItem, Paymentのテーブル構造
- RESTful API仕様設計:URI命名 / バージョン管理 / ページネーションとソート / HATEOAS
- Aliceが開発計画を策定し, 各モジュールの担当を割り当てます
2. プロダクトマネージャーの実話
(1) ペインポイント: 要件とコードのギャップ
Charlieが曖昧な要件文書を持ってAliceに来ました。「電子商取引の注文管理システムが必要です。」Aliceは「どんな機能が必要?ユーザーロールは何種類?商品の属性は?注文と決済はどう紐づく?」と尋ねましたが, Charlieは明確に説明できず, Aliceは経験に基づいて推測するしかありませんでした。その結果, 2週間の開発後, Charlieは「これは私が欲しかったものではない」と言いました。
(2) システム設計のソリューション
先に設計し, 後に開発—要件分析 → 技術選定 → データベース設計 → API仕様。各ステップをCharlieと確認します:
graph TD
A["要件<br/>分析"] --> B["技術スタック<br/>選定"]
B --> C["データベース<br/>設計"]
C --> D["API<br/>仕様"]
D --> E["開発<br/>計画"]
(3) 成果
AliceとCharlieが2日間かけてシステム設計を確定した後, 開発の方向性が明確になり, 3週間で期待に応えるMVPを納品しました。Charlieは「初回からまさに欲しかったものだった」と言いました。
3. 要件分析
(1) 4大モジュール
| モジュール | コア機能 | ユーザーロール |
|---|---|---|
| ユーザー管理 | 登録, ログイン, 個人情報, ロール管理 | 全ユーザー |
| 商品管理 | CRUD, カテゴリ, 検索, 在庫管理 | ADMIN |
| 注文管理 | 注文, 注文照会, キャンセル, タイムアウト自動キャンセル | CUSTOMER / ADMIN |
| 決済管理 | 決済開始, コールバック処理, 返金 | CUSTOMER / ADMIN |
(2) ロール権限マトリクス
| 機能 | CUSTOMER | ADMIN |
|---|---|---|
| 登録 / ログイン | ✅ | ✅ |
| 商品閲覧 | ✅ | ✅ |
| 商品検索 | ✅ | ✅ |
| 商品作成 / 管理 | ❌ | ✅ |
| 注文 | ✅ | ✅ |
| 自分の注文を表示 | ✅ | ✅ |
| 全注文を表示 | ❌ | ✅ |
| 自分の注文をキャンセル | ✅ | ✅ |
| 任意の注文をキャンセル | ❌ | ✅ |
| 決済開始 | ✅ | ✅ |
| 返金処理 | ❌ | ✅ |
(1) ▶ サンプル:ユーザーストーリー
TEXT
As a CUSTOMER, I want to:
- Browse and search products
- Add products to cart (future)
- Place an order with multiple items
- View my order history
- Cancel an unpaid order within 30 minutes
- Pay for an order
- View payment status
As an ADMIN, I want to:
- Manage products (CRUD)
- View all orders
- Cancel any order
- Process refunds
- View business statistics
出力:
TEXT
実行成功
4. 技術選定
(1) 技術選定決定マトリクス
| 決定点 | 選択肢A | 選択肢B | 選択 | 理由 |
|---|---|---|---|---|
| Webフレームワーク | WebMVC | WebFlux | WebMVC | 主にCRUD, 同時接続 < 5,000; WebMVCの方がシンプル |
| 認証方式 | Session | JWT | JWT | マイクロサービスアーキテクチャ, マルチインスタンスデプロイ, ステートレス認証 |
| キャッシュ戦略 | ローカルCaffeine | 分散Redis | L1 Caffeine + L2 Redis | ホットデータのローカル高速アクセス; 分散キャッシュで整合性確保 |
| データベース | PostgreSQL | MySQL | MySQL | チームに馴染みがある, 成熟したエコシステム |
| データベースアクセス | JPA | MyBatis | JPA | より自然なオブジェクトマッピング, SQL記述の削減 |
| APIドキュメント | SpringDoc | 手動 | SpringDoc | OpenAPIドキュメントの自動生成 |
(2) 技術スタック概要
| 層 | 技術 | バージョン |
|---|---|---|
| 言語 | Java | 17 LTS |
| フレームワーク | Spring Boot | 3.2.x |
| Web | Spring MVC | 6.x |
| セキュリティ | Spring Security + JWT | 6.x |
| データベース | MySQL | 8.0 |
| ORM | Spring Data JPA | 3.x |
| キャッシュ | Caffeine + Redis | 3.x / 7.x |
| バリデーション | Bean Validation | 3.x |
| テスト | JUnit 5 + Mockito + TestContainers | 5.x |
| ドキュメント | SpringDoc OpenAPI | 2.x |
| 監視 | Actuator + Micrometer | 3.x |
| デプロイ | Docker + Kubernetes | 24.x / 1.28 |
5. データベース設計
(1) 完全ER図
erDiagram
USER ||--o{ ORDER : "places"
PRODUCT ||--o{ ORDER_ITEM : "included in"
ORDER ||--o{ ORDER_ITEM : "contains"
ORDER ||--o| PAYMENT : "has"
USER {
bigint id PK
varchar username UK
varchar email UK
varchar password_hash
varchar role
timestamp created_at
timestamp updated_at
}
PRODUCT {
bigint id PK
varchar name
varchar sku UK
decimal price
int stock
varchar category
tinyint status
timestamp created_at
timestamp updated_at
}
ORDER {
bigint id PK
bigint user_id FK
varchar order_number UK
varchar status
decimal total_amount
timestamp created_at
timestamp updated_at
}
ORDER_ITEM {
bigint id PK
bigint order_id FK
bigint product_id FK
int quantity
decimal unit_price
decimal subtotal
}
PAYMENT {
bigint id PK
bigint order_id FK
varchar transaction_id UK
varchar method
varchar status
decimal amount
timestamp paid_at
timestamp created_at
}
(1) ▶ サンプル:DDLテーブル作成文
SQL
CREATE TABLE users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
role VARCHAR(20) NOT NULL DEFAULT 'CUSTOMER',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
CREATE TABLE products (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(200) NOT NULL,
sku VARCHAR(20) NOT NULL UNIQUE,
price DECIMAL(10,2) NOT NULL,
stock INT NOT NULL DEFAULT 0,
category VARCHAR(50),
status TINYINT NOT NULL DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_product_name (name),
INDEX idx_product_category (category)
);
CREATE TABLE orders (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
order_number VARCHAR(20) NOT NULL UNIQUE,
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
total_amount DECIMAL(10,2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_order_user (user_id),
INDEX idx_order_status_created (status, created_at DESC),
FOREIGN KEY (user_id) REFERENCES users(id)
);
CREATE TABLE order_items (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
order_id BIGINT NOT NULL,
product_id BIGINT NOT NULL,
quantity INT NOT NULL,
unit_price DECIMAL(10,2) NOT NULL,
subtotal DECIMAL(10,2) NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders(id),
FOREIGN KEY (product_id) REFERENCES products(id)
);
CREATE TABLE payments (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
order_id BIGINT NOT NULL UNIQUE,
transaction_id VARCHAR(50) UNIQUE,
method VARCHAR(20) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
amount DECIMAL(10,2) NOT NULL,
paid_at TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (order_id) REFERENCES orders(id)
);
出力:
TEXT
CREATE TABLE
6. API仕様設計
(1) RESTful API仕様
(1) ▶ サンプル:APIエンドポイント一覧
| モジュール | メソッド | URI | 説明 | 権限 |
|---|---|---|---|---|
| Auth | POST | /api/v1/auth/login |
ログイン | 公開 |
| Auth | POST | /api/v1/auth/register |
登録 | 公開 |
| Product | GET | /api/v1/products |
商品一覧 | 公開 |
| Product | GET | /api/v1/products/{id} |
商品詳細 | 公開 |
| Product | POST | /api/v1/products |
商品作成 | ADMIN |
| Product | PUT | /api/v1/products/{id} |
商品更新 | ADMIN |
| Product | DELETE | /api/v1/products/{id} |
商品削除 | ADMIN |
| Order | POST | /api/v1/orders |
注文 | CUSTOMER+ |
| Order | GET | /api/v1/orders |
自分の注文 | CUSTOMER+ |
| Order | GET | /api/v1/orders/{id} |
注文詳細 | Owner/ADMIN |
| Order | GET | /api/v1/admin/orders |
全注文 | ADMIN |
| Order | DELETE | /api/v1/orders/{id} |
注文キャンセル | Owner/ADMIN |
| Payment | POST | /api/v1/payments |
決済開始 | CUSTOMER+ |
| Payment | POST | /api/v1/payments/callback |
決済コールバック | 内部 |
(2) ▶ サンプル:標準レスポンスフォーマット
JAVA
// 成功レスポンス
public record ApiResponse<T>(
int code,
String message,
T data,
Instant timestamp
) {
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>(200, "OK", data, Instant.now());
}
public static <T> ApiResponse<T> created(T data) {
return new ApiResponse<>(201, "Created", data, Instant.now());
}
}
// ページネーションレスポンス
public record PagedResponse<T>(
List<T> content,
int page,
int size,
long totalElements,
int totalPages
) {}
出力:
TEXT
// 実行成功
(3) ▶ サンプル:ページネーションとソートパラメータ
BASH
# ページネーション, ソート, フィルタリング付き商品一覧
GET /api/v1/products?page=0&size=20&sort=price,desc&category=electronics&minPrice=100&maxPrice=999
出力:
TEXT
// コマンド実行成功
7. 開発計画とモジュール割り当て
(1) ▶ サンプル:イテレーション計画
| スプリント | イテレーション | 目標 | 成果物 |
|---|---|---|---|
| Sprint 1 | 1-2週目 | 基盤フレームワーク | プロジェクト構造 + 認証 + 商品CRUD |
| Sprint 2 | 3-4週目 | コアビジネス | 注文モジュール + トランザクション + バリデーション + 例外 |
| Sprint 3 | 5-6週目 | 高度な機能 | キャッシュ + スケジュールタスク + 非同期通知 |
| Sprint 4 | 7-8週目 | 運用とデプロイ | Docker + K8s + 監視とアラート |
8. 総合サンプル:OrderFlowプロジェクト設計文書
MARKDOWN
# OrderFlow システム設計文書
## 1. ビジネス要件
- 電子商取引注文管理システム
- 4モジュール: User, Product, Order, Payment
- 2ロール: CUSTOMER, ADMIN
- 予定: DAU 10,000, 1日1,000注文
## 2. 技術スタック
- Java 17 + Spring Boot 3.2.x
- MySQL 8.0 + Spring Data JPA
- Redis 7 + Caffeine (2段キャッシュ)
- Spring Security + JWT (OAuth2 Resource Server)
- Docker + Kubernetes デプロイ
## 3. データベース設計
- 5テーブル: users, products, orders, order_items, payments
- 高頻度クエリ列にインデックス
## 4. API仕様
- RESTful API with versioning (/api/v1/)
- JWT Bearer 認証
- 統一レスポンスフォーマット: ApiResponse<T>
- ページネーション: page, size, sort パラメータ
## 5. 非機能要件
- P99レイテンシ < 100ms
- エラー率 < 0.1%
- 可用性 > 99.9%
- 自動テストカバレッジ > 80%
❓ よくある質問
Q WebFluxではなくWebMVCを選ぶ理由は?
A OrderFlowは主にCRUD操作で, 想定同時接続 < 5,000 QPS; WebMVCの方がシンプルで成熟しています。WebFluxはI/O集約型, 高並列, リアルタイムストリーミングのシナリオに適しています; CRUDプロジェクトに使うと逆に複雑さが増します。
Q Redisだけでなく2段キャッシュを使う理由は?
A L1 Caffeineが最速 (ナノ秒レベル), L2 Redisが複数インスタンス間の整合性を確保します。ホットデータはローカルキャッシュにヒットし, Redisのネットワークオーバーヘッドを削減します。
Q APIバージョニングはURLパスとヘッダーのどちらを使うべきですか?
A URLパスバージョニング (/api/v1/)はより直感的で, テストしやすく, SEOにも優れています。ヘッダーバージョニングはよりRESTfulですが, デバッグが難しいです。実践的にはURLバージョニングを推奨します。
Q 決済コールバックのセキュリティはどう確保しますか?
A 1) コールバックURLは内部ネットワークからのみアクセス可能; 2) コールバック署名を検証; 3) 冪等処理 (重複コールバックで二重課金なし); 4) 照合用にコールバックイベントを全てログ記録。
Q データベース設計で論理削除と物理削除はどう扱うべきですか?
A 重要なビジネスデータ (注文, 決済)には論理削除 (status=CANCELLED)を使用し, 監査証跡を保持します。補助データ (テスト商品)は物理削除可能です。論理削除では全クエリで削除済レコードを除外する必要があります。
Q プロジェクト設計文書はどの程度詳細にすべきですか?
A 新しいチームメンバーがシステムの全体像を理解できる程度に詳細にしてください。含めるべき内容:ビジネス要件, 技術選定とその理由, データベース設計, API仕様, 非機能要件。コード実装の詳細は不要—コード自体が最も詳細なドキュメントです。
📖 まとめ
- 要件分析で4大モジュールとロール権限マトリクスを定義
- 技術選定は決定マトリクスで比較:WebMVC + JWT + 2段キャッシュ + MySQL + JPA
- データベースER設計で5テーブル; インデックスが高頻度クエリをカバー
- API仕様でURI命名, バージョン管理, ページネーションとソート, レスポンスフォーマットを標準化
- 開発計画は4スプリントに分割, 各スプリント2週間
- プロジェクト設計文書は開発チームの「契約」として機能
📝 練習問題
-
基本課題 (難易度:⭐): OrderFlowの要件分析文書を完成させ, すべてのユーザーストーリーとAPIエンドポイントを列挙してください。
-
応用課題 (難易度:⭐⭐): データベースER設計とDDLテーブル作成文を完成させ, すべてのインデックスを含めてください。標準化されたレスポンスフォーマットとエラーコード体系を設計してください。
-
チャレンジ (難易度:⭐⭐⭐): SpringDoc OpenAPIを使ってAPI仕様を書き, インタラクティブなAPIドキュメントページを生成してください。APIドキュメントとコード実装の同期を保つ方法を考察してください。



