Version 1.0.0 | CRM(広告代理店向け)
※ この図はシステム構成図です。詳細は別途ご説明いたします。
アーキテクチャ選定: モジュラーモノリス
広告代理店CRMの規模・チーム体制を考慮し、マイクロサービスではなくモジュラーモノリスを採用する。各ドメインモジュールは明確な境界を持ち、将来的にマイクロサービスへ分離可能な設計とする。
選定理由:
apps/web/
├── app/ # Next.js App Router
│ ├── (auth)/ # 認証グループ
│ │ ├── login/page.tsx
│ │ ├── forgot-password/page.tsx
│ │ └── layout.tsx
│ │
│ ├── (dashboard)/ # 認証済みグループ
│ │ ├── layout.tsx # サイドバー + ヘッダー共通レイアウト
│ │ ├── page.tsx # ダッシュボード
│ │ ├── clients/
│ │ │ ├── page.tsx
│ │ │ ├── new/page.tsx
│ │ │ └── [clientId]/
│ │ │ ├── page.tsx
│ │ │ ├── edit/page.tsx
│ │ │ ├── campaigns/page.tsx
│ │ │ └── contacts/page.tsx
│ │ ├── campaigns/
│ │ │ ├── page.tsx
│ │ │ ├── new/page.tsx
│ │ │ └── [campaignId]/
│ │ │ ├── page.tsx
│ │ │ ├── edit/page.tsx
│ │ │ ├── media-plans/page.tsx
│ │ │ └── reports/page.tsx
│ │ ├── contacts/
│ │ ├── media/
│ │ ├── reports/
│ │ │ ├── page.tsx
│ │ │ ├── sales/page.tsx
│ │ │ └── performance/page.tsx
│ │ ├── billing/
│ │ ├── tasks/
│ │ └── settings/
│ │ ├── page.tsx
│ │ ├── organization/page.tsx
│ │ ├── members/page.tsx
│ │ └── profile/page.tsx
│ │
│ ├── api/auth/[...nextauth]/route.ts
│ ├── layout.tsx
│ ├── not-found.tsx
│ └── error.tsx
│
├── components/
│ ├── ui/ # shadcn/ui ベース
│ ├── features/ # 機能別コンポーネント
│ │ ├── clients/
│ │ ├── campaigns/
│ │ ├── contacts/
│ │ ├── media/
│ │ ├── reports/
│ │ ├── billing/
│ │ └── tasks/
│ └── layouts/
│ ├── sidebar.tsx
│ ├── header.tsx
│ └── breadcrumb.tsx
│
├── hooks/
├── stores/ # Zustand
│ ├── ui-store.ts
│ ├── filter-store.ts
│ └── notification-store.ts
├── lib/
│ ├── api-client.ts
│ ├── auth.ts
│ ├── query-keys.ts
│ └── utils.ts
├── types/
└── constants/
| 状態の種類 | 管理手法 | 例 |
|---|---|---|
| サーバー状態 | TanStack Query | クライアント一覧、案件詳細、レポートデータ |
| UIグローバル状態 | Zustand | サイドバー開閉、テーマ、通知トースト |
| フォーム状態 | React Hook Form | 各種入力フォーム |
| URL状態 | Next.js searchParams | フィルタ、ソート、ページネーション |
※ この図はシステム構成図です。詳細は別途ご説明いたします。
apps/api/src/modules/campaigns/
├── campaign.module.ts
├── controllers/
│ └── campaign.controller.ts # HTTPリクエスト受付、バリデーション
├── services/
│ └── campaign.service.ts # ビジネスロジック
├── repositories/
│ └── campaign.repository.ts # データアクセス(Prisma経由)
├── dto/
│ ├── create-campaign.dto.ts
│ └── update-campaign.dto.ts
├── entities/
│ └── campaign.entity.ts
├── guards/
│ └── campaign-access.guard.ts
├── events/
│ ├── campaign-created.event.ts
│ └── campaign-status-changed.event.ts
├── listeners/
│ └── campaign-event.listener.ts
└── __tests__/
├── campaign.controller.spec.ts
└── campaign.service.spec.ts
レイヤー間の依存方向:
Controller → Service → Repository → Prisma Client
↓
EventEmitter → Listener → 他モジュールService
apps/api/src/core/
├── decorators/
│ ├── current-user.decorator.ts
│ └── tenant-id.decorator.ts
├── filters/
│ └── global-exception.filter.ts
├── guards/
│ ├── jwt-auth.guard.ts
│ └── roles.guard.ts
├── interceptors/
│ ├── tenant.interceptor.ts
│ ├── logging.interceptor.ts
│ └── transform.interceptor.ts
├── middleware/
│ └── tenant-context.middleware.ts
├── pipes/
│ └── validation.pipe.ts
└── prisma/
├── prisma.module.ts
└── prisma.service.ts
方式: 共有DB + テナントID列 (Row-Level Isolation)
※ この図はシステム構成図です。詳細は別途ご説明いたします。
※ この図はシステム構成図です。詳細は別途ご説明いたします。
httpOnly, Secure, SameSite=Strict| ロール | 説明 |
|---|---|
OWNER | テナントオーナー - 全操作 + テナント設定 |
ADMIN | 管理者 - 全データ閲覧・編集 + メンバー管理 |
MANAGER | マネージャー - 担当チームの全データ |
MEMBER | 一般メンバー - 担当クライアント・案件 |
VIEWER | 閲覧者 - 閲覧のみ |
3段階のガード:
JwtAuthGuard → JWT有効性 + テナントID抽出RolesGuard → ロールベースの機能アクセス制御ResourceOwnerGuard → リソース単位のアクセス制御※ この図はシステム構成図です。詳細は別途ご説明いたします。
| 環境 | 用途 | 構成 |
|---|---|---|
| production | 本番 | ECS auto-scaling, RDS Multi-AZ, Redis Cluster |
| staging | 受入テスト | ECS最小構成, RDS Single-AZ |
| development | 開発 | ECS最小構成, RDS Single-AZ |
| コンポーネント | トリガー |
|---|---|
| Frontend/API ECS | CPU 70% / メモリ 80% |
| Worker ECS | SQSキュー深度 |
| RDS | Read Replica追加 |
※ この図はシステム構成図です。詳細は別途ご説明いたします。
| ステップ | ツール | 所要時間 |
|---|---|---|
| Lint | ESLint + Prettier | ~30秒 |
| 型チェック | TypeScript | ~1分 |
| ユニットテスト | Vitest | ~2分 |
| ビルド | Docker multi-stage | ~3分 |
| E2Eテスト | Playwright | ~5分 |
DBマイグレーション: prisma migrate deploy をデプロイ前にECS Run Taskで実行
パッケージマネージャ: pnpm workspaces + Turborepo
crm/
├── .github/workflows/
│ ├── ci.yml
│ ├── deploy-staging.yml
│ └── deploy-production.yml
│
├── apps/
│ ├── web/ # Next.js フロントエンド
│ │ ├── app/
│ │ ├── components/
│ │ ├── hooks/
│ │ ├── stores/
│ │ ├── lib/
│ │ ├── types/
│ │ ├── public/
│ │ ├── next.config.ts
│ │ ├── tailwind.config.ts
│ │ ├── Dockerfile
│ │ └── package.json
│ │
│ └── api/ # NestJS バックエンド
│ ├── src/
│ │ ├── main.ts
│ │ ├── app.module.ts
│ │ ├── core/
│ │ └── modules/
│ │ ├── auth/
│ │ ├── tenant/
│ │ ├── client/
│ │ ├── campaign/
│ │ ├── contact/
│ │ ├── media/
│ │ ├── report/
│ │ ├── billing/
│ │ ├── task/
│ │ ├── notification/
│ │ └── file/
│ ├── prisma/
│ │ ├── schema.prisma
│ │ ├── migrations/
│ │ └── seed.ts
│ ├── test/
│ ├── Dockerfile
│ └── package.json
│
├── packages/
│ ├── shared-types/ # 共有型定義
│ ├── shared-utils/ # 共有ユーティリティ
│ ├── ui/ # 共有UIコンポーネント
│ └── eslint-config/ # ESLint共有設定
│
├── infra/
│ ├── cdk/ # AWS CDK (IaC)
│ └── docker/
│ └── docker-compose.yml # ローカル開発用
│
├── e2e/ # Playwright E2Eテスト
│
├── turbo.json
├── pnpm-workspace.yaml
├── package.json
├── tsconfig.base.json
└── .env.example
apps/web → packages/shared-types, packages/shared-utils, packages/eslint-config
apps/api → packages/shared-types, packages/shared-utils, packages/eslint-config
e2e → packages/shared-types
| 判断項目 | 選択 | 根拠 |
|---|---|---|
| アーキテクチャ | モジュラーモノリス | チーム規模に対して最適、将来分離可能 |
| マルチテナント | 共有DB + RLS | コスト効率優先 |
| 認証 | NextAuth.js + JWT | Next.jsとの統合が最も自然 |
| 認可 | RBAC | 代理店の組織構造に合致 |
| キャッシュ | Redis (Read-Through) | 一覧系APIの負荷軽減 |
| 非同期処理 | SQS + Worker | レポート生成等の重い処理を分離 |
| モノレポ | pnpm + Turborepo | 型共有の即時反映、ビルドキャッシュ |
| IaC | AWS CDK | TypeScriptで統一 |