BluePeriod Docs
開発

開発ガイドライン

プロジェクトの開発品質と一貫性を維持するための規約集

開発ガイドライン (06_development_guidelines.md)

1. 概要

このドキュメントは、本プロジェクトにおける開発の品質と一貫性を維持するためのガイドラインを定めます。コードの可読性、保守性、拡張性を高め、チームメンバー間の協業を円滑にすることを目的とします。

1.1. パッケージマネージャーについて

本プロジェクトはBunを使用しています。npmではありません。

  • インストール: bun install(リポジトリルートで実行)
  • スクリプト実行: bun run <script>
  • 依存関係追加: bun add <package>
  • 開発サーバー: bun run dev

2026年3月にnpmからBunに移行しました。詳細は 02_technology_stack.md を参照してください。

2. コーディング規約

2.1. 基本方針

  • リンター: ESLintを利用して静的解析を行います。
  • 設定: Next.jsの推奨するeslint-config-next/core-web-vitalsおよびeslint-config-next/typescriptを基本設定として採用しています。詳細はnext-app/eslint.config.mjsを参照してください。
  • 実行: 開発中はエディタのESLintプラグインでリアルタイムに問題を検出し、コミット前にはbun run lintコマンドでコード全体の検証を行ってください。

2.2. 命名規則

  • 変数・関数: camelCase (例: fetchData, userName)
  • コンポーネント: PascalCase (例: ChatView, MainPanel)
  • 型・インターフェース: PascalCase (例: ProjectRecord, ChatMessage)
  • ファイル名:
    • Reactコンポーネント: PascalCase.tsx (例: ChatView.tsx)
    • それ以外のTypeScriptファイル: kebab-case.ts (例: project-atoms.ts)
  • ストレージキー (localStorage/Atoms):
    • フォーマット: bp:<category>:<key-name>
    • 規則: すべて小文字、単語区切りはハイフン (kebab-case)、カテゴリ区切りはコロン (:)。
    • 例: bp:ui:active-project-id, bp:sync:last-synced-at
    • 詳細については /doc/log/proposals/2026/01/2026-01-12_1210_proposal_storage-key-naming-convention.md を参照。

2.3. コンポーネント設計

  • 関心事の分離: UIコンポーネントは状態管理やビジネスロジックから分離し、可能な限りPureに保ちます。ロジックはカスタムフック (/hooks) やJotaiのAtom (/stores) にカプセル化します。
  • 粒度: 巨大なコンポーネントは避け、意味のある単位で小さなコンポーネントに分割します。
  • UIライブラリ: shadcn/uiをベースとして使用します。既存のコンポーネントを積極的に再利用し、新しいコンポーネントを作成する際は既存の設計思想を踏襲してください。
  • アイコン: Lucide React を使用します。UIでアイコンを使用する際は、絵文字や画像ファイルではなく、原則としてLucide Reactのコンポーネントを利用してください。
  • ローディングUI: データ読み込みなど、非同期処理が発生する箇所では必ずローディング状態を示すUIを実装してください。
    • 優先度 高: shadcn/uiのSkeletonコンポーネントを使用し、コンテンツのレイアウトを維持したままローディング状態を示します。
    • 優先度 中: スピナーなど、他のローディング表現も適宜使用可能ですが、ユーザー体験の観点から可能な限りSkeletonの使用を検討してください。
  • 一貫したスタイリング: カラーやスペーシングは、必ず 09_design_system.md で定義されたセマンティックトークンを使用してください。ハードコードされた即値の使用や、Raw Colorの使用は禁止です。

2.4. 状態管理 (Jotai)

  • Atomの分割: Atomはドメインごと、または機能ごとにファイルを分割して管理します (/storesディレクトリ内)。
  • スコープ: Atomは可能な限り最小のスコープで定義し、グローバルな状態を不必要に増やさないように注意します。
  • 命名: Atom変数には ...Atom という接尾辞をつけます (例: projectDataAtom)。

2.5. バックエンド通信 (Supabase)

Supabaseとの通信には、Next.jsの実行コンテキストに応じて適切なクライアントを使用する必要があります。

  • クライアントコンポーネント ('use client') での使用:

    • ファイル: src/lib/supabase/client.ts
    • 概要: ブラウザ環境でのみ安全に動作するクライアントです。Reactのフック(useState, useEffectなど)を持つコンポーネント内で使用してください。
  • サーバーコンポーネント, Server Actions, Route Handlersでの使用:

    • ファイル: src/lib/supabase/server.ts
    • 概要: サーバーサイドでのみ動作するクライアントです。Cookieの読み書きを伴うため、ブラウザ環境では動作しません。非同期処理やデータフェッチを行うサーバーコンポーネント、フォーム送信を処理するServer Actions、APIエンドポイントを定義するRoute Handlers内で使用してください。

2.6. データベース型定義の生成

Supabaseのデータベーススキーマと連動したTypeScriptの型定義は、以下のコマンドで生成・更新できます。

bun run gen:types

重要:

  • データベースのテーブルやカラムに変更を加えた後は、必ずこのコマンドを実行して next-app/src/lib/types/supabase.ts を最新の状態に更新してください。
  • このコマンドは、Windows環境で発生しがちなファイルの文字化け問題を回避する設定を含んでいます。手動で bunx supabase gen types... を実行すると問題が再発する可能性があるため、必ず bun run gen:types を使用してください。

2.7. Hono API の開発

API の実装には Hono を使用し、モジュール化された構造とプラットフォーム非依存のロジックを維持してください。

  • エントリポイント: すべての API リクエストは app/api/[[...route]]/route.ts を経由します。
    • 重要: route.ts では必ず GET, POST, PUT, DELETE, PATCH すべてのメソッドを handle(app) でエクスポートしてください。エクスポート漏れがあると 405 Method Not Allowed エラーが発生します。
  • モジュール分割: 各機能(例: stripe, infra, auth, projects, library, publish)は src/server/api/ 内に個別の Hono インスタンスとして作成し、メインアプリに api.route('/path', module) でマウントします。
    • ルーティングの注意 (trailing slash): Hono のサブアプリ・マウント形式では、/api/library(末尾なし)と /api/library/(末尾あり)の挙動が異なる場合があります。
      • サブアプリ内で .get('/', ...) と定義している場合、マウントポイントの末尾スラッシュがないリクエスト(/api/library)は「空文字」として扱われ、マッチしません。
      • 対策として、共通のハンドラを定義し library.get('/', handler)library.get('', handler) (空文字) の両方を登録するか、リダイレクトを活用してください。
  • ロジックの分離 (Service Layer パターン):
    • API ハンドラ(Controller)内にはビジネスロジックを直接記述しないでください。
    • すべてのロジック(DB操作、外部通信、データ変換)は src/lib/features/<feature-name>/service.ts に抽出します。
    • API ハンドラは、リクエストの検証(Zod)、サービスの呼び出し、レスポンスの返却のみを担当します。これにより、同じロジックをデスクトップ版など他の環境でも再利用可能になります。
  • リクエストパラメータの柔軟性:
    • 実装の際は、フロントエンドが GET/DELETE でクエリパラメータを使う場合と、POST/PATCH で JSON ボディを使う場合の両方を考慮し、柔軟に取得できるようにしてください(例: c.req.query('id') || (await c.req.json()).id)。
  • 型安全性 (バリデーション):
    • リクエストの検証には @hono/zod-validator を使用してください。
    • zod のバージョンは、プロジェクト全体の型不整合を避けるため 4.1.12 に固定して使用してください。
  • ランタイム: Vercel の関数制限を回避するため、原則として Edge Runtime (export const runtime = 'edge') で動作するように実装してください。
    • Edge 環境では supabase.auth.getSession() ではなく supabase.auth.getUser() を使用して安全にユーザー認証を行ってください。
  • 型安全性 (RPC): クライアント側で型安全な通信を行うため、AppType をエクスポートし、Hono Client (hono/client) を利用可能な状態に保ってください。

2.8. 翻訳(i18n)

実装時には、必ずi18n準拠でのUI実装をおこないます。 日本語でテキストをハードコードするなどは厳禁です。 ただし、そこまで重要でないテキストの場合は、英語でとりあえずハードコードすることは許可します。

2.9. プロットデータの多言語表示 (i18n)

プロット構造(Part, Chapter, Story等)を表示する際は、単に title フィールドを表示するのではなく、plotTranslations データの有無を確認し、現在の表示言語設定に応じた翻訳タイトルを優先して表示するように実装してください。

  • 参照: TableOfContents.tsx における getTranslatedTitle の実装パターン。
  • 言語コードの扱い: en-US 等のロケールではなく、ベースとなる言語コード (en, ja) をキーとして使用してください。

2.10. 画像データの取り扱い

本プロジェクトでは、キャラクターアイコンや作品の表紙画像をブラウザの IndexedDB に Base64 形式で保存します。ストレージ容量の節約と同期パフォーマンス向上のため、以下のルールを遵守してください。

  • 自動圧縮の適用: 画像を保存する前に、必ずリサイズと圧縮を行ってください。
  • 共有ユーティリティの利用: @/lib/image-processing にある processImageAsDataUrl を使用して、一貫した圧縮処理(WebP形式、適切な解像度制限)を適用してください。
  • 推奨設定:
    • キャラクターアイコン: 最大 512px
    • 作品表紙: 最大 1024px (アスペクト比 1:1.6 推奨)
    • 品質設定: quality: 0.8 程度

2.11. AIエージェント実装時の注意点

  • コンテキストの疎結合化: ツール実行の結果や大規模な生成データを、そのまま会話履歴(Context)に埋め込まないでください。コンテキストウィンドウの鮮度を保つことが最優先です。
  • サマリーの活用: src/lib/chat/formatters.tsformatMessageWithThoughts 等のフォーマッタレベルで、長大なツール引数や出力は自動的にサマリー(文字数など)に変換されるように実装してください。
  • 外部メモリへの委譲: 大規模な成果物は Session Artifacts として外部(DB)に保存し、AIには必要な時だけ read ツールで明示的に取得させるように設計してください。
  • 表示と実態の同期: UIで「折りたたまれている」詳細は、モデルのコンテキスト内でも要約されるべきです。詳細は 12_ai_agent_architecture.md を参照してください。

3. Git運用ルール

3.1. ブランチ戦略

GitHub Flow を採用します。

  1. mainブランチ: 現在、諸事情につき、mainはつかっておりません

  2. devブランチ: 実質的にメインブランチです。常にデプロイ可能な安定した状態を保ちます。直接のコミットは基本的には禁止です。

  3. フィーチャーブランチ:

    • 新機能開発、バグ修正、リファクタリングなど、全ての作業はdevブランチから新しいブランチを作成して行います。
    • ブランチ名は、その目的が分かりやすいように命名します。
      • feat/... (新機能)
      • fix/... (バグ修正)
      • refactor/... (リファクタリング)
      • docs/... (ドキュメント)
      • 例: feat/add-chat-character-edit-function

※ここは現在のところOFFにしてありますので無視して構いません。 {/* 3. プルリクエスト (Pull Request): - 作業が完了したら、mainブランチへのマージをリクエストするプルリクエストを作成します。 - プルリクエストには、変更の概要、目的、関連するIssueなどを記述します。 - コードレビューが完了し、CI(継続的インテグレーション)のチェックが通るまでマージは行いません。 */}

3.2. コミットメッセージ規約

Conventional Commits 規約に準拠します。これにより、コミット履歴の可読性が向上し、将来的なリリースノートの自動生成も可能になります。

  • フォーマット:

    <type>(<scope>): <subject>
    
    <body>
    
    <footer>
  • typeの種類:

    • feat: 新機能の追加
    • fix: バグ修正
    • docs: ドキュメントのみの変更
    • style: コードの動作に影響しない、フォーマットなどの変更
    • refactor: バグ修正や機能追加ではないコードの変更
    • perf: パフォーマンスを向上させるコードの変更
    • test: テストの追加・修正
    • chore: ビルドプロセスや補助ツールの変更
  • scope (任意): 変更が影響する範囲 (例: chat, db, api)

  • subject (必須): 変更内容の簡潔な説明 (50文字以内)

  • 言語: コミットメッセージの本文およびタイトルは、原則として日本語で記述してください。これにより、開発チーム内での変更意図の把握を迅速化します。

  • concrete example:

    feat(chat): ストリーミングレスポンスのサポートを追加
    fix(db): chatMessagesテーブルのインデックススキーマを修正
    
    以前のスキーマでは大量のチャット履歴をクエリする際にパフォーマンスが低下していました。
    この変更により、複合インデックスを追加してパフォーマンスを向上させました。

4. AIアシスタントのための実装前チェックリスト

AIアシスタントがタスクを遂行する際、以下の項目を必ずセルフチェックしてください。

  • ガイドラインの再読: 06_development_guidelines.md を最新の状態まで読んだか?
  • 思想の再確認: すべての根幹となる 00_philosophies_of_blueperiod を読み、特に「深いエージェント」としての振る舞いを理解しているか?
  • デザインシステムの確認: UI変更を伴う場合、09_design_system.md を読んだか?
  • セマンティックトークンの使用: ハードコードされたRaw Color (bg-blue-500等) を使用せず、bg-primary等のトークンを使用しているか?
  • 命名規則の遵守: ファイル名、関数名、Atom名、ストレージキー名が規約通りか?
  • i18nの徹底: テキストをハードコードせず、ja.json / en.json に追加して t() 関数を使用しているか?
  • 影響分析: 変更が他のコンポーネントやAtomの挙動に悪影響を与えないか?
  • IndexedDBの日付ガード: データベースへの保存や同期データの復元時に、@/lib/utils/dateensureDate を使用して日付オブジェクトを保護しているか?(標準の Date 以外は索引されないため)
    • 重要: ensureDateDate 型を期待しています。テーブルのTypeScript型定義(lib/types.ts)で createdAt: Date と宣言している場合、値の生成時も必ず new Date() を使用し、Date.now()(number)を使用しないこと。型と実値のミスマッチは ensureDate のパースエラーとクラッシュなき日時すり替えを引き起こします。
    • 型定義の一貫性ルール: Dexieのテーブル定義(lib/db.ts のインライン型)と lib/types.ts の型定義は、日付フィールドの型が必ず一致していることを確認すること。どちらか一方で number、他方で Date という混在は厳禁。
  • Message Normalization: LLM API 呼び出しの直前で normalizeMessages を適用し、System Prompt の順序や重複を最適化しているか?
  • AI Temporal Context: getCurrentTimestampForAI を使用してシステムステータスに現在時刻(タイムゾーン付き)を含めているか? また、メッセージ履歴に formatTimestampForAI 等を用いて時間情報を付与しているか?

5. Hono & Edge API 開発ガイドライン

Vercel Edge Runtime 上で Hono を用いて API を開発する際は、以下の点に留意してください。

5.1. ランタイムとポータビリティ

  • Runtime 明示: ファイル先頭に export const runtime = 'edge'; を記述してください。
  • Service Layer の分離: ビジネスロジックは Hono のハンドラに直接書かず、src/lib/features/ 配下のサービス関数として抽出してください。

5.2. セキュリティと認証

  • Auth: Hono ミドルウェアで検証済みのユーザー情報を c.get('user') で取得して使用してください。
  • getUser: セッション偽装を防ぐため、常に supabase.auth.getUser() またはミドルウェアの検証結果を信頼してください。

5.3. 型定義とバリデーション

  • Zod: リクエストボディやクエリパラメータの検証には zValidator を使用し、型安全性を確保してください。
  • any の禁止: API の境界では特に厳格に型を定義し、可能な限り any を使用しないでください。

5.4. Trailing Slash

  • Hono のメインアプリケーション([[...route]]/route.ts)で { strict: false } を設定しています。これにより、/api/path/api/path/ の両方が同一エンドポイントとして処理されます。各サブモジュール側で個別にリダイレクトや重複定義を行う必要はありません。

5.5. バリデーションとエラーハンドリングの標準化

  • 共有ユーティリティ: src/server/api/common.tsvalidationHookerrorResponse を必ず使用してください。
  • バリデーション: zValidator の第3引数として validationHook を渡すことで、フロントエンドに対して「どのフィールドがどのように不正か」を詳細に含む 400 Bad Request を自動返却します。
  • 内部エラー: try-catchcatch ブロックでは return errorResponse.internalError(c, error) を使用してください。これにより、適切なログ出力と 500 レスポンスが統一された形式で行われます。
  • 認証エラー: 認証が必要なエンドポイントでは return errorResponse.unauthorized(c) を使用してください。

関連ドキュメント:

On this page