アーキテクチャ概要

RoomCraft — v1.0.0 — 2026-03-19

アーキテクチャ概要

RoomCraft のシステムアーキテクチャドキュメントです。


システム構成図

graph TB
    subgraph Client["クライアント (ブラウザ)"]
        UI["Next.js App Router\n(React 19)"]
        3D["3Dレンダラー\n(Three.js / R3F)"]
        Store["状態管理\n(Zustand)"]
    end

    subgraph Server["Next.js Server (App Router)"]
        Pages["Server Components\nPage Rendering"]
        API["API Routes\n(/api/*)"]
    end

    subgraph Data["データ層"]
        Prisma["Prisma ORM"]
        PG["PostgreSQL"]
    end

    subgraph External["外部サービス"]
        Stripe["Stripe\n(決済)"]
        S3["AWS S3\n(3Dモデル・画像)"]
    end

    subgraph Infra["AWS インフラ"]
        ECR["Amazon ECR\n(コンテナレジストリ)"]
        ECS["Amazon ECS\n(コンテナ実行)"]
        CB["AWS CodeBuild\n(CI/CD)"]
        CP["AWS CodePipeline\n(パイプライン)"]
    end

    UI --> Pages
    UI --> API
    3D --> S3
    Store --> UI
    Pages --> Prisma
    API --> Prisma
    API --> Stripe
    Prisma --> PG
    CB --> ECR
    ECR --> ECS
    CP --> CB
    CP --> ECS

技術選定理由

Next.js 15 (App Router)

  • Server Components によるSSR/SSGで初期表示を高速化
  • API Routes でバックエンドAPIをモノリポで管理。デプロイ構成をシンプルに保てる
  • next/image による画像最適化、next/font によるフォント最適化が標準提供

Three.js / @react-three/fiber

  • 3Dインテリアシミュレーションのコア機能を実現するために採用
  • @react-three/drei が提供するヘルパー(OrbitControls, Environment, useGLTF等)でThree.jsの複雑なボイラープレートを削減
  • React のコンポーネントモデルで3Dシーンを宣言的に記述できる

Zustand

  • 3Dシミュレーター上での家具配置状態(位置・回転・選択中家具など)を複数コンポーネント間で共有するために採用
  • Redux に比べてボイラープレートが少なく、TypeScript との親和性が高い

Prisma + PostgreSQL

  • 型安全なデータベースアクセスを実現(生成された型がTypeScriptと完全に連携)
  • JSONカラム(floorPlan, furniture, wallSettings 等)でルームの自由形式データを格納
  • @prisma/adapter-pg でEdge Runtime対応も可能

Stripe

  • 家具EC購入の決済処理に採用
  • Webhook による注文状態の非同期更新に対応

データフロー

消費者フロー(3Dシミュレーション → 購入)

sequenceDiagram
    actor Consumer as 消費者
    participant Catalog as カタログページ
    participant Simulator as 3Dシミュレーター
    participant Cart as カート
    participant Order as 注文API
    participant DB as PostgreSQL

    Consumer->>Catalog: 商品を検索・閲覧
    Catalog->>DB: GET /api/products
    Consumer->>Simulator: ルームを作成 / 既存ルームを開く
    Simulator->>DB: GET /api/rooms/:id

    loop 家具を試し置き
        Consumer->>Simulator: 商品をドラッグ配置
        Simulator->>Simulator: Three.jsシーン更新 (Zustand)
        Consumer->>Simulator: 保存
        Simulator->>DB: PATCH /api/rooms/:id (furniture JSON更新)
    end

    Consumer->>Cart: 気に入った商品をカートに追加
    Cart->>DB: POST /api/cart

    Consumer->>Order: 注文確定
    Order->>DB: POST /api/orders (OrderItem作成)
    Order-->>Consumer: 注文完了

AIコーディネートフロー

sequenceDiagram
    actor Consumer as 消費者
    participant AI as AIコーディネートAPI
    participant DB as PostgreSQL

    Consumer->>AI: POST /api/ai-coordinate\n(budget, style, roomWidth, roomDepth)
    AI->>DB: 予算内・スタイル条件で商品を検索
    DB-->>AI: 最大100件の商品リスト
    AI->>AI: 3パターンのコーディネートを生成\n(予算の85%/90%/95%で組み合わせ)
    AI-->>Consumer: 3パターンのコーディネート提案
    Consumer->>Consumer: 提案をルームに反映 / カートに追加

メーカー管理フロー

sequenceDiagram
    actor Maker as メーカー担当者
    participant Dashboard as メーカーダッシュボード
    participant ProductAPI as 商品API
    participant OrderAPI as 注文API
    participant Analytics as 分析API
    participant DB as PostgreSQL

    Maker->>Dashboard: ログイン
    Maker->>ProductAPI: 商品を登録\n(POST /api/maker/products)
    ProductAPI->>DB: Product + Variant + ThreeDModel 作成

    Note over Maker,DB: 消費者が商品を購入

    Maker->>OrderAPI: 注文を確認\n(GET /api/maker/orders)
    OrderAPI->>DB: makerId で絞り込んだ注文一覧
    Maker->>Analytics: 売上分析を確認\n(GET /api/maker/analytics?period=month)
    Analytics->>DB: 期間内の配達済み注文から売上集計
    Analytics-->>Maker: 商品別売上・総売上・コンバージョン率

データモデル

erDiagram
    User {
        string id PK
        string email
        string name
        UserRole role
    }
    Maker {
        string id PK
        string name
        string slug
        MakerPlan plan
        MakerStatus status
        decimal commissionRate
    }
    Product {
        string id PK
        string makerId FK
        string categoryId FK
        string name
        decimal price
        ProductStatus status
        int stockCount
    }
    ProductVariant {
        string id PK
        string productId FK
        VariantType type
        string name
        string value
        decimal priceOverride
    }
    ThreeDModel {
        string id PK
        string productId FK
        string fileUrl
        string format
        ModelStatus status
    }
    Category {
        string id PK
        string name
        string slug
        string parentId FK
    }
    Room {
        string id PK
        string userId FK
        string name
        json floorPlan
        json furniture
        json wallSettings
        json floorSettings
        json lightSettings
    }
    CartItem {
        string id PK
        string userId FK
        string productId FK
        string variantId FK
        int quantity
    }
    Order {
        string id PK
        string userId FK
        string makerId FK
        OrderStatus status
        decimal totalAmount
        json shippingAddress
    }
    OrderItem {
        string id PK
        string orderId FK
        string productId FK
        string variantId FK
        int quantity
        decimal price
    }
    CommunityPost {
        string id PK
        string userId FK
        string roomId FK
        string title
        int likes
        PostStatus status
    }
    Favorite {
        string id PK
        string userId FK
        string productId FK
    }
    MakerStaff {
        string id PK
        string makerId FK
        string userId FK
        StaffRole role
    }

    User ||--o{ Room : "作成"
    User ||--o{ CartItem : "持つ"
    User ||--o{ Order : "発注"
    User ||--o{ CommunityPost : "投稿"
    User ||--o{ Favorite : "お気に入り"
    User ||--o{ MakerStaff : "スタッフ"
    Maker ||--o{ Product : "出品"
    Maker ||--o{ Order : "受注"
    Maker ||--o{ MakerStaff : "所属"
    Product ||--o{ ProductVariant : "バリアント"
    Product ||--o{ ThreeDModel : "3Dモデル"
    Product ||--o{ CartItem : "カート"
    Product ||--o{ OrderItem : "注文明細"
    Product ||--o{ Favorite : "お気に入り"
    Category ||--o{ Product : "分類"
    Category ||--o{ Category : "階層"
    Room ||--o{ CommunityPost : "紐付き投稿"
    Order ||--o{ OrderItem : "明細"

レイヤー構成

src/ ├── app/ # プレゼンテーション層 (Next.js Pages + API Routes) │ ├── (auth)/ # 認証ページ │ ├── api/ # API エンドポイント │ └── [各ページ]/ # UI ページ ├── components/ # 再利用可能UIコンポーネント │ ├── three/ # 3D専用コンポーネント │ └── ui/ # 汎用UIコンポーネント ├── lib/ # ユーティリティ・クライアント初期化 │ └── prisma.ts # Prisma シングルトンクライアント ├── stores/ # クライアント状態管理 (Zustand) └── types/ # 共有TypeScript型定義

API Routes の責務

route.ts は以下のみを担当します:

  1. リクエストパラメータのバリデーション
  2. Prisma を通じたデータベースアクセス
  3. JSONレスポンスの返却とエラーハンドリング

ビジネスロジックが複雑になる場合は src/lib/ 以下にサービス関数として切り出します。


インフラ構成(AWS)

GitHub ↓ push AWS CodePipeline ↓ ソース取得 AWS CodeBuild (buildspec.yml) ↓ Dockerイメージビルド・ECRプッシュ Amazon ECR ↓ イメージデプロイ Amazon ECS (Fargate) ↓ コンテナ起動 Application Load Balancer ↓ トラフィック エンドユーザー

Dockerマルチステージビルド

Dockerfile は3ステージ構成でイメージサイズを最小化します:

ステージ目的
depsnode_modules のインストールのみ
builderprisma generate + next build
runner.next/standalone のみを含む軽量本番イメージ

Next.js の output: 'standalone' モードにより、node_modules 全体をコピーせずに実行可能なサーバーを生成します。