Skip to content

サーバー構成 (アーキテクチャ)

LiGA リニューアルで採用するシステム構成の設計。

✅ 決定事項

採用構成

  • モノレポ (pnpm workspaces + Turborepo) で apps/webapps/api を同一リポジトリ管理
  • apps/web = Next.js 15 (CMS なし)
    • 参加者UI / 運営UI (大会作成画面) / スタッフUI / master 系 admin UI を全部 Next.js が担う
    • Master / Template / Media は /manage/masters/* に自作 admin UI を置く (Payload のような汎用 CMS は導入しない)
  • apps/api = Hono + zod
    • Tournament / Registration / Payment / Notification など業務トランザクション全般 (hot path)
    • DB スキーマは packages/db に集約、master は ID + Publish-time Snapshot で参照
  • packages/db = Drizzle スキーマ + クライアント
    • 全テーブル (auth / master / business) を 1 schema に集約
    • dev は PGlite、本番は Cloud SQL (PostgreSQL)
  • packages/shared に型 / zod スキーマを集約し、web と api で共有
  • DB: PostgreSQL 1個・同一スキーマ。テーブル prefix なし (Better Auth の規定テーブル + 自前 master / business が同居)

Hono を採用した理由 (NestJS 不採用)

LiGA 規模 (バックエンド 1〜3人 / 想定エンドポイント 〜80) では NestJS の DI / Module / Decorator の規約は過剰。Hono に zod + drizzle + フォルダ規約を足せば Nest と同等の構造を作れて、フレームワーク税が日々のスピードを削る要因にならない。Nest が必要になる閾値は (a) 開発者 5人以上、(b) エンドポイント 100超、(c) イベント駆動 / マイクロサービス化、(d) OpenAPI を契約として配布、のいずれかが必要になった時点。

役割分担

レイヤ技術役割
UI 層Next.js 15 (App Router / RSC + Server Actions)参加者UI / 運営UI / スタッフUI
Master 管理 UINext.js (/manage/masters/*)Levels / Sports / Venues / Prizes / Organizers / Campaigns / Templates の CRUD
業務ロジック APIHono (Node ランタイム)Tournament / Registration / 決済 / スコア / 通知 (hot path)
DB スキーマ + クライアントDrizzle (packages/db)全テーブル定義 / マイグレーション / ORM クライアント
DBPostgreSQL (本番: Cloud SQL) / PGlite (dev)1 DB / 1 スキーマ / prefix なし
メディア自前アップロード + Cloudflare R2 (本番) / 公開ディレクトリ (dev)画像アップロード・サムネイル生成 (sharp) は自前実装
認証Better Auth + Drizzle adapter詳細は 認証 / 認可 参照
キャッシュ / QueueRedisジョブキュー / pub-sub (Phase 2 以降)

デプロイ構成

┌──────────────────────────── Browser ─────────────────────────────┐
└────────────┬─────────────────────────────────┬───────────────────┘
             │                                 │
       https request                     https request
             ▼                                 ▼
┌─── App #1: Next.js (Vercel) ────────┐  ┌─── App #2: Hono (Cloud Run) ─┐
│                                       │  │                                │
│  /                  参加者UI          │  │  /healthz                      │
│  /tournaments       大会一覧/詳細     │  │  /availability                 │
│  /tournaments/new   運営UI (作成)     │  │  /registrations                │
│  /mypage            参加者マイページ  │  │  /payments/webhook             │
│  /manage            運営ダッシュボード│  │  /scores                       │
│  /manage/masters/*  master 管理UI     │  │  ...                           │
│  /api/auth/*        Better Auth       │  │                                │
│                                       │  │                                │
└──────────┬────────────────────────────┘  └────────────┬───────────────────┘
           │                                            │
           │       packages/db (Drizzle)                │
           └────────────┬───────────────────────────────┘

              ┌──────────────────────┐
              │    PostgreSQL        │
              │  (Cloud SQL / 1 DB)  │
              │  ─────────────────   │
              │  user, session, ...  │  (Better Auth)
              │  levels, sports, ... │  (master)
              │  media               │  (自前)
              │  tournaments,        │  (business)
              │  tournament_plans,   │
              │  registrations, ...  │
              └──────────────────────┘

ホスティング想定

  • 本番:
    • フロント: Vercel (Next.js)
    • バックエンド: Cloud Run (Hono / Node)
    • DB: Cloud SQL (PostgreSQL)
    • メディア: Cloudflare R2 (S3 互換)
  • dev: PGlite (file-based) で本番互換 (pgTable スキーマそのまま流用)
  • Hono は Edge / Node どちらも可。MVP は Cloud Run で揃える

次のアクション

  1. packages/db 立ち上げ (Drizzle + PGlite + Cloud SQL アダプタ準備)
  2. Better Auth 統合 (詳細は 認証設計 参照)
  3. /manage/masters/* 自作 admin UI
  4. 業務ロジックの順次 Hono 実装 (申込 / 決済 / スコア)
  5. ホスティング決定 (Vercel + Cloud Run + Cloud SQL でほぼ確)
  6. CI/CD (PR ごとプレビュー環境)

補足

📂 候補4案の比較 (採用は C + Hono 派生)

検討時に並べた4案。最終的には C (Next + 自作 API、CMS なし) をベースに、業務ロジック分離のため API レイヤを Hono で立てた構成 (C+Hono) を採用。Payload 同居案 (B) は一度仮採用したが、/admin UI が /manage のブランドと噛み合わない / Custom Auth Strategy の常時メンテ負担 / マスタは数十行レベルで CMS の旨味が薄い、を理由に再評価で離脱。

A. Next + Payload + NestJS (3層)

  • Pros: 関心分離が明確 / 業務ロジックの型安全 / 各層独立スケール / 公開 API 出しやすい
  • Cons: デプロイ 2ヶ所 / 認証同期の設計必要 / Nest の boilerplate 税
  • 想定工数: 5〜7ヶ月
  • 不採用理由: LiGA 規模では Nest が過剰

B. Next + Payload (2層)

  • Pros: 1リポ・1デプロイ / getPayload() で BFF 不要 / admin auto-generate / 立ち上げ最速
  • Cons: /admin のブランドが /manage と分離 / 業務ロジックが Payload hooks に集中すると複雑化 / Better Auth との Custom Strategy が常時メンテ対象
  • 想定工数: 3〜5ヶ月
  • 不採用理由: master が数十行レベルなので CMS の auto-admin の旨味が薄く、Custom Strategy のコストが上回る

C. Next + 自作 API (CMS なし) ← 採用ベース

  • Pros: 完全コントロール / Payload の breaking change に依存しない / /manage のブランドで master 管理 UI まで統一 / Better Auth セッションを Cookie 1本で完結
  • Cons: master 管理 UI を自作 (5〜6 画面、各 1〜2h で済む規模) / メディアアップロードを自前実装
  • 採用後の工夫: 申込・決済系を Hono に切り出して C' (Next + Hono) としている

D. Next + Supabase (BaaS)

  • Pros: Auth / DB / Storage / Realtime 即時 / 無料枠
  • Cons: ベンダーロックイン / 業務ロジックは Edge Functions の制約
  • 不採用理由: 長期コストとロックインリスク
📂 評価軸マトリクス (4案)
評価軸A · 3層B · Payload同居C+Hono · 採用D · BaaS
初期コスト
admin UI 自動化△ (自作)
ブランド統一××
認証の単純さ△ (Custom Strategy)◎ (Cookie 1本)
ロックイン
学習コスト
📂 NestJS vs Hono の閾値判断メモ

Hono → NestJS への切替を検討する目安:

指標閾値補足
バックエンド開発者数5人以上規約による物理的なコード分割が効いてくる
エンドポイント数80〜100 超横断関心事が増えて Decorator + Interceptor が活きる
パターンCQRS / Saga / Outbox / gRPC 等が必要Nest にビルトインの利点
OpenAPI自動生成を「契約」として使うNest の Swagger 統合が成熟
ジョブBullMQ + Schedule の構造化@nestjs/bull @nestjs/schedule が便利

LiGA Ver1〜Ver2 想定ではどれも当てはまらないため、Hono を継続採用。

📂 Payload を採用しなかった経緯 (B 案 → C 案)

設計初期は B 案 (Next + Payload 同居) を仮採用していた (app/(payload)/admin で 1リポ・1デプロイ完結、master の auto-admin が魅力)。再評価で C 案へ振り直した理由:

  1. /admin のデザインが /manage のブランドと噛み合わない: /manage 側は bg-stone-50 / カスタム typography で統一、/admin は Payload 標準 UI のままなので運営の体感が分断される
  2. master が小さい: Levels 5件 / Sports 5件 / Venues 23件 など、各テーブル数十行。auto-admin の節約効果が、自作 admin UI 1〜2h × 5〜6 画面の労力を下回らない
  3. Custom Auth Strategy の継続コスト: Better Auth と Payload を橋渡しする Custom Strategy がバージョンアップで微妙に壊れる場所になる
  4. スキーマ二重管理: Payload push: true と Drizzle マイグレーションが共存すると、誰がどのテーブルを所有しているか追いにくい
  5. 段階的脱却の負債: 残しておくと「Phase 2 で消す」が永遠に来ない。最初から無いほうが綺麗

C 案では Master / Template / Media を /manage/masters/* の自作 UI で扱い、Better Auth のセッションを Cookie 1本で完結させる。失うのは Payload の auto-admin と Lexical エディタくらいで、TipTap や plain text に降格すれば実用には問題ない。