Board Planner について
Board Plannerは、カンバンボード、スプリント、プロジェクト管理にREST APIとMCPサーバーを組み合わせた、小規模チームとコーディングエージェント向けのツールです。ボード、API、MCPで権限とタスク履歴を共有し、承認済みタスクは設定した手順とゲートに沿ってワーカーが実行できます。
主な機能
- 01カンバンボード、スプリント、依存関係、サブタスク
- 02REST APIと46個のMCPツール
- 03プロジェクト単位のAPIトークン権限
- 04エージェントの手順と実行ゲートの設定
- 05タスク履歴、監査ログ、6種類のダッシュボードチャート
活用シーン
- 01チームのタスクとスプリントの調整
- 02コーディングエージェントによる対象プロジェクトのタスク参照と更新
- 03承認済みタスクをワーカーに渡し、設定したチェックを実行
- 04プロジェクトの進捗とタスク履歴の確認
MCP 対応
アプリには `POST /api/mcp` で利用できるHTTP MCPサーバーが組み込まれており、46個のツールを提供します。クライアントは範囲を限定したAPIトークンで接続し、MCP操作にはREST APIやボードと同じ権限が適用されます。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://{organisation}.board-planner.com/api/mcpclaude mcp add --transport http rafalpodles-board-planner https://{organisation}.board-planner.com/api/mcp{"mcpServers":{"rafalpodles-board-planner":{"type":"http","url":"https://{organisation}.board-planner.com/api/mcp"}}}Cursor で開く{"servers":{"rafalpodles-board-planner":{"type":"http","url":"https://{organisation}.board-planner.com/api/mcp"}}}VS Code で開く{"mcpServers":{"rafalpodles-board-planner":{"type":"http","url":"https://{organisation}.board-planner.com/api/mcp"}}}{"mcpServers":{"rafalpodles-board-planner":{"serverUrl":"https://{organisation}.board-planner.com/api/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
詳細
Board Planner
ボードはひとつ。チームもエージェントも、そこで作業します。
小規模チームが実際に運用できるカンバンボード、スプリント、ダッシュボードに、MCP サーバーと REST API を組み合わせました。コーディングエージェントも、ほかのメンバーと同じルールのもとで同じタスクに取り組めます。
多くのトラッカーは、自動化を後付けします。ボットがコメントを投稿し、スクリプトがカードを移動させ、実際の作業状況はボードから見えない場所に残ります。Board Planner は逆の発想から始まります。ボード、REST API、MCP サーバーは、ひとつのモデルにアクセスするための 3 つの入口であり、どの入口でも同じ権限チェックが行われます。エージェントがタスクを レビュー中 に移動する際は、担当者がカードをドラッグするときと同じステータスルールが適用され、同じ履歴に同じ記録が残ります。
クラウドまたはセルフホスト
クラウド版では、登録すると、board-planner.com のサブドメインに新しい組織が作成されます。カード登録不要の Pro トライアルが 30 日間利用でき、その後は Free に移行します。Free では、メンバー 10 人まで、プロジェクトとタスクは無制限、REST API、MCP サーバー、1 台のマシンでのワーカーとエージェントが利用できます。または、メンバー数の上限が増え、マシンを何台でも使え、当社のキーによる毎月の AI 利用枠と Coda 同期が追加される Pro を選択できます。エージェント、ワーカー、API トークンはメンバー数に含まれません。
自分のサーバーでは、docker compose up を実行すると、自分専用の組織が 1 つ作成されます。Community エディションは AGPL-3.0 で、メンバー数やマシン数に制限はなく、AI 機能は自分のキーで実行します。Pro のセルフホスト版では、Coda 同期とメールサポートが追加されます。
自分のキーを使った AI は、すべてのプランで無料です。また、Free で提供される機能が Pro に移行することはありません。料金と詳細な比較は、board-planner.com/pricing をご覧ください。
作業をマシンに引き継ぐ
マシンにコードを書かせるツールは、今や数多くあります。Board Planner が扱うのは、その周辺にあるすべてのことです。誰が作業を提案したのか、誰が承認したのか、マシンに何を変更する権限があったのか、完了前に何を通過する必要があったのか、そしてどこで作業を止めて引き継ぐのか。
その一連の流れの両端を担うのが、2 種類のエージェントです。提案して内容を書き残す PM エージェントと、承認済みのタスクを引き受けて実行する 実行ワーカーです。どちらも、許可されていない判断を勝手に行うことはありません。
PM エージェントは、プロジェクト内に常駐するプロジェクトマネージャーです。ボードを読み、行き詰まっているタスク、重複しているタスク、足りないタスクに気づき、誰も頼んでいないチケットを大量に登録するのではなく、判断材料を提示します。誰もやりたがらない作業、たとえば受け入れ条件を設定せずに作成されたタスクに条件を書き加えたり、重複を見つけたり、スプリントの実際の進捗を伝えたりするのが得意です。
このスクリーンショットでは、返信の下にあるバッジがアクションを示しています。メッセージと書き込みは 1 つの記録なので、単に言及しただけでなく、返信と同時に ORB-9 も変更されたことがわかります。また、指示に従ってタスクは元の場所に残しています。ボードのレビューでは change_status と create_task が無効になるため、自律実行でも、ボードをひそかに一晩で再編成することなく、問題を知らせることができます。
プロジェクトごとにデフォルトでは無効になっており、無条件に信頼するのではなく、使用量が計測されます。自律ターンもユーザーのターンも含め、すべての呼び出しが組織ごとのトークン数としてカウントされ、インスタンスで設定できる利用上限に対して計上されます。また、インスタンス管理者は、プロジェクト設定で上書きできない形で、プロジェクト単位でこの機能をロックして無効にできます。OPENROUTER_API_KEY がない場合、ページにその旨が表示され、機能は動作しません。AI Assist も同じキーを使用します。
📖 PM エージェント · 自律的なボードレビュー
人に任せるときと同じように、エージェントに引き継ぎます
タスクを割り当て、エージェントを指定し、承認する列にドラッグします。この 2 つが引き継ぎの条件です。エージェントが指定されていないタスクでは何も実行されず、プロジェクトのデフォルト設定にフォールバックすることもありません。ほかの人があなたに割り当てたタスクは提案であり、あなたのマシンで実行待ちになっている仕事ではありません。
エージェントはステップとゲートのリストです
エージェントは順序付けられたブロックのリストで、種類は次の 2 つだけです。
| 何かを変更できますか? | 実行を停止できますか? | |
|---|---|---|
| ステップ — Implement、Push、Pull request、Merge | はい | いいえ |
| ゲート — Size、Protected files、Test written、Builds、Tests pass、Reviewed | いいえ | はい |
ステップは拒否できず、ゲートは書き込みができません。そのため、実行を停止できるブロックはすべてゲートであり、そのすべてをひと目で確認できます。
各ステップはそれぞれ独立したモデルセッションです。1 つのエージェント内にある 2 つのステップが共有するのはタスクとワークツリーだけです。そのため、分析してから実装するのと、1 つのモデルに両方を依頼するのとでは結果が異なります。2 番目のステップが読み取るのは、最初のステップが書いた内容であり、考えていた内容ではありません。
マージは切り替え設定ではなく、ステップです。「自動マージ」のチェックボックスはなく、レビュー設定に連動するルールもありません。エージェントは、シーケンスの最後に Merge ブロックがある場合にマージします。ブロックを省略すると、実行はプルリクエストの段階で停止します。
3 つのエージェントが付属しています。Default、With security review、Merges its own work です。エディターを一度も開かないプロジェクトでは、Default が実行されます。
この設計では、マシンは信頼されていません
ここを正しく仕上げるのに最も時間がかかりました。実際のリポジトリで安全に引き継ぎを使えるのは、このためです。
| 保証 | その理由 |
|---|---|
| サーバーがパスを送ることはありません | 割り当てで指定するのはタスクと Git リモートです。ワーカーは自分のマシン上にあるファイルを使って独自にチェックアウトを解決するため、データの保存場所はローカルで決められます。 |
| 読み取り専用のステップを書き込み可能にすることはできません | Read only は、ワーカーが独自に作成するツールリストになります。ボード側から指定できるものではないため、タスクにどのようなプロンプトを入力しても、書き込みアクセスは許可されません。 |
| マシンが実装していないチェックがあると実行は停止します | 不明な種類を指定するゲートはスキップせずに拒否します。チェックがない状態を、チェックに合格した状態と見なしてはいけません。 |
| レビューされていないリポジトリ独自のスクリプトは実行されません | Protected files による事前確認が済んでいない変更に対して、Builds または Tests-pass のゲートを設定すると、エディターはこれを拒否します。これにより、エージェントが書いたスクリプトは、書き込みが許可されていたかどうかの確認が済むまで実行されません。 |
| ワーカーが保持する認証情報は1つだけで、データベースの認証情報は保持しません | 発行済みの cpw_ 認証情報を使い、REST 経由でアプリと通信します。エージェントが書いたコードを実行するマシンに、データベースの認証情報を持たせるべきではありません。 |
| 指定したアカウントとしてプッシュします | gh auth switch は開発者のマシン上のグローバルな状態です。そのため、最後に誰かが切り替えたアカウントを使うのではなく、ワーカーごとにアカウントを固定します。 |
| 実行中のタスクは移動できません | 実行がタスクを保持している間、列から移動させるステータス変更は、ボード、編集フォーム、MCP、PM エージェントを含むすべての更新経路で 409 を返して拒否されます。これを強制的に回避できるのは人間だけです。マシン認証情報による操作は拒否されます。 |
| 失敗は人間が確認できる状態になります | 使用量の上限に達した場合は、試行回数を払い戻してタスクを戻します。クラッシュした場合は、試行回数を1回消費します。失敗が繰り返されると、再試行回数を使い切った時点で停止し、いつまでも繰り返すことはありません。 |
実行中の情報は、その都度すべてタスクに記録されるため、タスクのコメントが実行ログになります。ブランチ、編集内容、どのゲートが拒否したか、モデルの残り使用量を確認できます。別の通信経路も、CI のタブも必要ありません。
📖 詳細はこちら:エージェント ·
実行ワーカー ·
worker/README.md
ボードのその他の機能
まずはボードとして
列の名前も順序も自由に設定できます。各列には自動化が理解できる役割(backlog、approved、active、review、blocked、done)を割り当てるため、Up next を Ready に変更しても何も壊れません。review の役割を持つ列は、自動化を停止する目印となり、作業は人間による確認を待ちます。ドラッグ&ドロップ対応のボード、リスト表示、スプリント、依存関係とサブタスク、繰り返しタスクに加え、アプリのどこからでもすべてのタスクを検索できる ⌘K 検索を備えています。
システムのテーマに従い、アプリ全体が次の両方に対応しています。
作業に必要なものをすべてタスクにまとめられます
1つずつチェックできる受け入れ条件、依存関係、タスクを完了させるプルリクエスト、プロジェクトごとに定義できるカスタムフィールド、作成後のすべてのコメントと変更を記録できます。ブランチ名を bp-8/dark-mode にすると、プルリクエストが自動でタスクを見つけます。
エージェントも同じボードで作業します
HTTP 経由で使える46個の MCP ツールにより、ターミナルからボードを操作できます。Claude Code はバックログを読み取り、タスクを引き受けて移動できます。操作にはチームメイトと同じ権限が適用されます。API トークンは特定のプロジェクトに限定でき、その範囲は一元的に適用されるため、REST と MCP のどちらでも有効です。
月曜日の質問に答えるのに十分な情報
作業の進み具合、積み上がっているもの、着手したのと同じ速さで完了できているかを確認できます。 スプレッドシートなしで、6つのグラフを表示します。
その他
アプリ内、メール、Slack、Discordで通知を受け取れます。ユーザー、プロジェクト、イベントごとに設定できます。プロジェクトの監査証跡。署名付きWebhook。GitHubとGitLabのPR連携。スマートフォンでも使えます。
クイックスタート
Docker Compose 2.24以降が必要です。それより古いComposeでは、.envがなくてもenv_fileの記述が原因でファイルを読み込めません。それ以外は何も必要ありません。NodeもMongoDBも、リポジトリのクローンも不要です。
curl -fsSLO https://raw.githubusercontent.com/rafalpodles/board-planner/main/docker-compose.yml
docker compose up -d
このコマンドは公開イメージghcr.io/rafalpodles/board-plannerを実行します。このイメージは1.1.0以降の各リリースでlinux/amd64およびlinux/arm64向けにビルドされています。1.0.xはこれより前のバージョンで、イメージはありません。:latestは最新リリースを指します。バージョンを固定するには、Composeファイルと同じ場所にある.envにBOARD_PLANNER_VERSION=1.2.3を設定してください。アップグレードするには、docker compose pull && docker compose up -dを実行します。
mainブランチのComposeファイルには、1.1.2以降のイメージが必要です。COOKIE_ALLOW_INSECURE=autoを渡しますが、1.1.1ではこの設定を認識しないため、localhost以外で平文HTTP経由で提供される1.1.1のイメージにはサインインできません。1.1.1で実行する場合は、.envにCOOKIE_ALLOW_INSECURE=1を設定してください。
クローンから実行する場合は、docker compose up -d --buildを実行してください。 docker compose up -dだけでは、チェックアウトしたコードではなく、直近のリリースを取得して実行します。--buildを付けると、チェックアウトしたコードをビルドして実行します。
http://localhost:3000を開きます。サインインページで最初に作成されたアカウントがインスタンス管理者になります。それ以降のアカウントは、Settings → Usersから作成します。
最初のアカウントを作成するにはセットアップコードが必要なので、初期状態のインスタンスにあなたより先にアクセスした人がアカウントを取得することはできません。BOOTSTRAP_TOKENを設定しない場合、アカウントがない状態でアプリを起動すると、アプリがコードを生成してサーバーログに出力します。docker compose logs app | grep "setup code"で確認できます。コードはメモリに保持されるため、再起動すると新しいコードが出力されます。また、複数のレプリカがある場合は、それぞれが独自のコードを出力します。その場合は、代わりにBOOTSTRAP_TOKENを設定してください。
停止するにはdocker compose downを実行します。データベースはmongo-dataボリュームに保存され、停止後も保持されます。docker compose down -vを実行すると削除されます。
公開イメージより前のビルドからアップグレードする場合
.envのNEXT_PUBLIC_APP_URLをPUBLIC_ORIGINに変更してください。アプリは古い名前をまったく読み込みません。PUBLIC_ORIGINが設定されていない場合、docker-compose.ymlはNEXT_PUBLIC_APP_URLの値をPUBLIC_ORIGINとして渡すため、.envを変更しなくてもリンクは維持されます。ただし、このフォールバックがあるのはComposeファイルを使う場合のみです。イメージを別の方法で実行する場合は、PUBLIC_ORIGIN自体を設定する必要があります。
Dockerを使わない場合
自分で用意したNode 26とMongoDB 4.4以降が必要です。
npm install
MONGODB_URI=mongodb://localhost:27017/boardplanner npm run build
MONGODB_URI=mongodb://localhost:27017/boardplanner npm start
開発サーバーを起動するにはnpm run devを実行します。以下の変数を保存する場所として、.env.exampleを.env.localにコピーしてください。npm startはPORTで待ち受けます。PORTは、まず環境変数から、次にNext.jsが読み込む順序に従って.env.production.local、.env.local、.env.production、.envから取得されます。いずれにも指定がない場合は3000を使います。
エージェントを接続する
MCP サーバーはアプリに組み込まれており、POST /api/mcp で利用できます。クローンもビルドも不要です。設定 → API トークンでトークンを作成し、エージェントが操作するプロジェクトにスコープを設定して、クライアントを 1 つの URL に接続します。
{
"mcpServers": {
"boardplanner": {
"type": "http",
"url": "https://your-instance.example.com/api/mcp",
"headers": { "Authorization": "Bearer cp_..." }
}
}
}
エージェントが作業するグループに分けられた 46 個のツールを利用できます。全ツールの一覧と各ツールが返す内容については、MCP ページをご覧ください。
- プロジェクトとタスク:
list_projects、get_project、list_tasks、get_task、create_task、update_task、change_task_status、reorder_tasks、search_tasks、my_tasks、archive_task、unarchive_task、delete_task(ボードのオーナーのみ) - 一括操作:
create_tasks、update_tasks、link_task_pairs(1 回の呼び出しで最大 30 件または 60 件を処理し、項目ごとに結果を返します) - リンクとチェックリスト:
link_tasks、unlink_tasks、add_checklist_item、set_checklist_item、remove_checklist_item - スプリント:
list_sprints、get_sprint、create_sprint、update_sprint、delete_sprint - コメントと履歴:
add_comment、list_comments、edit_comment、delete_comment、get_task_activity、watch_task、unwatch_task - メンバーとエージェント:
list_members、whoami、list_agents - レポート:
get_project_stats、list_runs、list_notifications、mark_notifications_read - ボードの設定(追加のみ):
add_custom_field、add_field_option、add_category(アプリと同様、すべてのメンバーが操作できます)、add_column、rename_column(プロジェクトのオーナーのみ)。その他の項目の削除や名前の変更は、引き続きアプリで行います。 - リポジトリ:
sync_repositoryは、同期ボタンと同様に、ボードのプルリクエストまたはマージリクエストと CI バッジを更新します。
トークンを貼り付ける代わりにコネクターを利用するクライアント向けに、同じ URL で OAuth 2.1 with PKCE と動的クライアント登録を完全にサポートしています。クライアントシークレットは不要です。
サーバーは接続時に、すべてのクライアントにボードの操作方法を伝えます。選択、担当、報告、エスカレーション、完了までのワークフロー全体を利用するには、Claude Code にエージェントスキルをインストールしてください。
/plugin install board-planner --marketplace rafalpodles/board-planner
エージェントスキルをご覧ください。
設定
データベース以外はすべて省略できます。docker-compose.yml と同じディレクトリに .env ファイルを置いて設定を上書きしてください。compose ファイルは、NODE_ENV、PORT、HOSTNAME をそれぞれ production、3000、0.0.0.0 に固定し、それ以外のファイル内のすべての変数をアプリに渡します。
| 変数 | デフォルト | 説明 |
|---|---|---|
MONGODB_URI | mongodb://mongo:27017/boardplanner | 同梱の MongoDB の代わりに、独自の MongoDB をアプリに指定します |
APP_PORT | 3000 | アプリが公開されるホストポート |
APP_ORIGIN | http://localhost:${APP_PORT} | アプリの配信元となるオリジンをカンマ区切りで指定します。PUBLIC_ORIGIN とともに、ブラウザーから Sec-Fetch-Site が送信されない場合に、書き込みリクエストの Origin を照合する対象となります |
PUBLIC_ORIGIN | NEXT_PUBLIC_APP_URL。それ以外は http://localhost:${APP_PORT}(compose)。それ以外の場合、オリジンがちょうど 1 つのときは APP_ORIGIN | このインスタンス自身のアドレスとして使用され、送信するすべてのリンクのベースとなります。MCP、PM OAuth、ワーカーの登録に必要です |
BOARD_PLANNER_VERSION | latest | compose で実行する公開済みイメージ |
BOOTSTRAP_TOKEN | 生成され、ログに出力されます | 最初のアカウントを作成するためのセットアップコードです。16 文字以上にしてください。ログを確認できない場合は設定してください |
COOKIE_ALLOW_INSECURE | auto(compose)。それ以外はオフ | 1 を指定すると、プレーン HTTP で配信されるインスタンス向けに、Secure 属性および __Host- プレフィックスなしでセッション Cookie を発行します。auto の場合は、PUBLIC_ORIGIN とすべての APP_ORIGIN が http:// で、サインインが https:// 経由でない場合に限りそうします。0、空、または未設定の場合はセキュア Cookie になります |
TRUSTED_PROXY_HOPS | 0 | このアプリの前段にあるプロキシが X-Forwarded-For に追加するホップ数 |
ENCRYPTION_KEY | — | 保存された連携トークンとチャット Webhook URL を保存時に暗号化するための 32 バイトのキー。16 進数または標準 Base64(Base64url ではありません)で指定します |
ENCRYPTION_KEYS_OLD | — | ローテーション後も旧キーで暗号化されたデータを読み取れるようにする、カンマ区切りの使用済みキー |
WEBHOOK_SIGNING_SECRET | — | 送信する Webhook 配信に署名します |
AI_MONTHLY_TOKENS、AI_MEMBER_TOKENS、AI_TRIAL_TOKENS、AI_DAILY_PERCENT | — | 組織がインスタンスの AI キーで使用できるトークン数を、すべての呼び出しで計算します。UTC の月単位(10 人を超えるアクティブメンバー 1 人ごとに AI_MEMBER_TOKENS を加算)、トライアル単位、および 1 日あたり最大 AI_DAILY_PERCENT までです。上限に達すると、AI は使用済み数と更新日を含む 429 を返します。設定しない場合は無効で、0 も無効です。組織独自のキーは使用量を計算しますが、制限されません。各ユーザーは 15 分ごとに AI Assist の生成を最大 20 回まで開始でき、同時に実行できるのは 1 回です |
OPENROUTER_API_KEY、PM_MAX_TOKENS、PM_SCHEDULER_TICK_MS | — | PM エージェントと AI Assist(タスクの下書き)は、どちらも OPENROUTER_API_KEY と、Settings → AI key で設定する単一のモデルを使用します。OPENAI_API_KEY と PM_MODEL は読み込まれなくなりました |
OPENROUTER_BASE_URL | https://openrouter.ai/api/v1 | PM エージェントと AI Assist の呼び出し先です。プロキシ、または別の OpenAI 互換エンドポイントを指定できます |
SMTP_HOST、SMTP_PORT、SMTP_USER、SMTP_PASS、SMTP_FROM | — | メール通知 |
DIGEST_HOUR、DIGEST_TIMEZONE、DIGEST_TICK_MS | 7、Europe/Warsaw、300000 | オプトイン方式の日次ダイジェストの送信時刻 |
GITHUB_SYNC_TICK_MS | 300000 | GitHub トークンを持つプロジェクトの再同期間隔です。0 にするとバックグラウンド同期がオフになります。複数のリポジトリを登録したプロジェクトでは、リポジトリごとに一連のリクエストが発生します |
GITHUB_API_BASE_URL | https://api.github.com | GitHub Enterprise Server 用の GitHub API の場所 |
COOKIE_ALLOW_INSECURE と APP_ORIGIN — TLS の背後にある場合は、PUBLIC_ORIGIN に https アドレスを設定します
どちらも**ランタイム**値であり、リクエストごとに読み込まれます。compose ファイルは、`.env` に別の値が指定されていない限り、`COOKIE_ALLOW_INSECURE=auto` を渡します。空の値は未設定として扱われます。`auto` は、`PUBLIC_ORIGIN` と `APP_ORIGIN` のすべてのエントリが `http://`(compose のデフォルト値である `http://localhost`)の場合に限り、プレーンな Cookie を発行します。これは、ブラウザーが localhost 以外ではプレーンな HTTP 経由の `Secure` Cookie を黙って破棄し、その後のログイン済みリクエストがすべて 401 で失敗するためです。**インスタンスを TLS の背後に置いたら、`PUBLIC_ORIGIN`(および `APP_ORIGIN`)をその `https://` アドレスに設定してください。**ほかに変更を加えなくても、Cookie は `Secure` になり、`__Host-` が付きます。設定するまでは、`Origin` が `https://` のサインインには `auto` が引き続きセキュア Cookie を発行するため、オリジンをデフォルトのままにして TLS 経由でアクセスしても、インスタンスのセキュリティが低下することはありません。`COOKIE_ALLOW_INSECURE=0` はオリジンの設定に関係なくセキュア Cookie を強制し、`1` はプレーンな Cookie を強制します。compose 以外では、アプリ自体のデフォルトはセキュア Cookie であり、`1` または `auto` の場合にのみ無効になります。
COOKIE_ALLOW_INSECURE=1 の場合、APP_ORIGIN は必須です。設定されていないとアプリは起動を拒否します。また、1 と https:// の APP_ORIGIN または PUBLIC_ORIGIN を組み合わせた場合も同様です。ブラウザーがリクエストの送信元がアプリ自身のオリジンであることを証明しない限り、書き込みは拒否されます。localhost 以外でプレーンな HTTP を使うと、ブラウザーは Sec-Fetch-Site ヘッダーを送信しないため、残る証明方法は Origin がこのリストまたは PUBLIC_ORIGIN と一致することだけです。ユーザーが実際に開く URL(https://board.example.com、または LAN でセルフホストする場合は http://192.168.1.10:3000)を、末尾にパスを付けずに設定してください。
同じフォールバックは、プロキシまたは CDN が Sec-Fetch-* ヘッダーを削除する場合にも適用されます。その場合、書き込み、サインイン、OAuth の認可手順は、Origin が APP_ORIGIN または PUBLIC_ORIGIN のいずれかと一致する場合にのみ許可されます。アプリは、Origin はあるものの Sec-Fetch-Site がないリクエストを初めて検出したときに、警告を 1 回ログに記録します。
TRUSTED_PROXY_HOPS — 少なすぎる設定のほうが深刻です
この設定によって、ここで X-Forwarded-For を信頼するかどうかが決まります。ログイン失敗のスロットリングが基準にできるのはこの値だけです。このヘッダーは通常のヘッダーです。アプリの前段に何もない場合、呼び出し元が値を変えるたびに新しいカウンターが割り当てられ、スロットリングは機能しません。そのため、デフォルトは 0 です。ヘッダーは一切読み込まれず、匿名の呼び出し元は引き上げられたしきい値の共有バケットを使います。
リバースプロキシの背後にある場合は、そのヘッダーに値を追加するプロキシの数を設定してください。推測ではなく、実際に計測してください。下記を参照してください。前段に nginx または Caddy が 1 台だけあり、ほかに何もない場合は 1 です。
値を間違えると、どちらの方向にも影響が出ます。大きく設定しすぎると、ヘッダーは指定内容と一致しないものとして拒否されます。その場合、サインインは 1 つのバケットを共有します。上限はありますが共有されます。一方、リンクがランダムなルート(パスワードリセット、メール確認)、クライアント登録、マシン登録では誰もカウントされず、アプリは 10 分ごとにその旨をログに記録します。小さく設定しすぎると、カウントされるアドレスはクライアントのものではなく、プロキシチェーンが書き込んだものになります。そのため、あらゆるリクエストが同じバケットに入る可能性があります。また、そのバケットはアプリから見ると実際のアドレスのように見えるため、引き上げられた匿名用の上限ではなく、厳しいアドレスごとの上限が適用されます。
推測せずに計測してください。 0 の状態で、アドレス別にスロットリングするルート(サインイン、パスワードリセット、OAuth エンドポイント、マシン登録、アカウント変更)に X-Forwarded-For を含むリクエストを送ると、ヘッダーに含まれていたエントリ数を示す警告がアプリのログに記録されます。
A request arrived with X-Forwarded-For carrying 2 entries while TRUSTED_PROXY_HOPS=0, so the
header is ignored and the login throttle has no per-address key. …
CDN の前に、それ自体がプロキシとして動作するホスティングプラットフォームがある場合は、各プロキシが値を追加するため、複数のエントリーが記録されると予想してください。件数はログで確認できます。料金を支払っているボックスの数を数えても、ホップ数は分かりません。だからこそ、測定が必要なのです。
この件数が正しいのは、すべてのプロキシが値を追加する場合だけです。 ヘッダーを置き換えるプロキシは、それより前の情報をすべて隠します。Caddy は、前段のプロキシを
trusted_proxies
に指定しない限り、まさにそのように動作します。CDN の背後にそのようなプロキシがあると、ログには 1 と記録されます。その場合に 1 を設定すると、スロットリングの基準が訪問者ではなく CDN のエッジアドレスになり、上記の「少なすぎる」場合の問題が起こります。各プロキシが値を追加するようにしてから、測定してください。
チェーン全体を経由して、ご自身が送信したリクエストの件数を確認してください。呼び出し元もヘッダーを送信でき、アプリに通常より短い経路で到達するヘルスチェックや稼働監視プローブには、ブラウザーより少ないエントリーしか含まれません。そのため、アプリは最初の件数だけでなく、新しい件数ごとに報告します。最初の4種類の異なる件数はすぐに記録され、それ以降の新しい件数は、10分間の待機を経てから記録されます。この上限は、悪意のある呼び出し元に占有される可能性があります。 アプリは、正規のサインインと偽造ヘッダーを区別できません。そのため、呼び出し元が数分おきに新しいヘッダーの長さを送信すると、枠が占有され続け、ご自身の行が一度も表示されない場合があります。再起動すると最初の4枠が空くので、再起動した直後にサインインを試みてください。これは低速な偽造トラフィックには有効ですが、呼び出し元が毎秒数件のリクエストを送ると、すぐに枠が再び占有されます。その場合、確実な対処方法は、公開状態を止めることです。送信元をブロックするか、同じチェーンの背後にあるステージング環境またはローカル実行環境で件数を確認してください。アドレスをまったく含まないヘッダーは報告されず、4枠のいずれも消費しません。
IPv6 の呼び出し元は /64 単位で数えられます。 /64 に属する1台のホストは 2^64 個のアドレスを持つため、アドレス単位で数えると、リクエストごとに新しいバケットが割り当てられてしまいます。スロットリングでは、IPv6 クライアントを先頭の64ビットで識別します。IPv4 は変更されません。また、IPv4 マップアドレス、または既知の NAT64 プレフィックス(64:ff9b::/96)で表された IPv4 クライアントは、その IPv4 ホストとして数えられます。先頭の64ビットがすべてゼロのアドレス(ループバック、未指定アドレス、旧形式の IPv4 互換アドレス)は、その範囲が誰のサブネットでもないため、アドレス全体で数えられます。独自のプレフィックスを持つ NAT64 は、他の IPv6 ネットワークと区別できないため、同じく先頭の64ビットで数えられます。/64 または /96 のプレフィックスの背後では全員が同じバケットを共有しますが、より短いプレフィックス(/32 から /56)では、各 IPv4 アドレスの一部がこの64ビット内に入るため、クライアントは複数のバケットに分散します。セッションに保存され、監査ログに記録されるアドレスは、引き続き完全なアドレスです。/56 または /48 を割り当てられたホストでは、バケットがそれぞれ256個または65,536個に分散します。
ENCRYPTION_KEY — 生成方法とローテーション方法
アプリが保存する GitHub、GitLab、Coda、MCP の認証情報と、プロジェクトのチームチャンネルおよび各自の通知に使う Slack/Discord のウェブフック URL を暗号化します。受信ウェブフック URL はベアラー認証情報であり、これを持つ人は誰でもインテグレーションとしてそのチャンネルに投稿できます。`openssl rand -hex 32` で生成してください。これが設定されていないと、これらのフィールドは保存できません。アプリはシークレットを平文で書き込む代わりに、保存時にエラーを返し、起動時にもその旨を通知します。**このインスタンスにキーが設定される前からチームチャンネルを使っていたボードでは、URLが平文のまま保存されています。これらは読み込まれなくなったため、`npx tsx scripts/migrate-channel-webhooks.ts` で書き換えるまで、そのチャンネルには何も配信されません。いずれにしても、Slack または Discord で URL をローテーションすることをお勧めします。** キーが設定されているものの、32 バイトの16進数または標準 Base64 ではない場合、**アプリの起動は停止します**。誤った値が設定された変数は、未設定の場合と同じではなく、未設定として扱ってはいけません。これには、Base64URL や、たまたま32バイトにデコードされるパスフレーズも含まれます。このような値ですでにシークレットを保存している場合は、新しいキーを生成しないでください。代わりに、同じバイト列を次のコマンドで16進数に変換して設定してください。
`node -e 'console.log(Buffer.from(process.env.ENCRYPTION_KEY.trim(), "base64").toString("hex"))'`
ローテーションするには、新しいキーを ENCRYPTION_KEY に設定し、古いキーを ENCRYPTION_KEYS_OLD に移します(カンマ区切りで、複数世代のキーを共存させられます)。保存された各値には、それを書き込んだキーが記録されるため、新旧のシークレットを並行して読み込めます。再保存された値は新しいキーで書き込まれます。廃止したキーをリストから削除するのは、それを参照する値がなくなってからにしてください。読み込めないキーに遭遇すると、アプリは不足しているキー ID を示します。
PUBLIC_ORIGIN — 利用者が使うアドレスを設定します
アプリが自身へのリンクを作成するとき、メール、Slack または Discord のメッセージ、Coda の行、承認のためにワーカーのマシンで開くページなど、すべてのリンクの先頭には PUBLIC_ORIGIN が使われます。これはアプリの実行時に読み込まれるため、公開済みのイメージをすべてのインスタンスで使用できます。ビルド時にアドレスが埋め込まれることはありません。
PUBLIC_ORIGIN が存在するのは、APP_ORIGIN では「このインスタンス自身のアドレスはどれか」という問いに答えられないためです。APP_ORIGIN はリストであり、どの項目が公開アドレスなのかを示すものはありません。オリジンが1つだけ指定されている場合はそれが使われます。それ以外の場合、推測は行われません。
そのため、compose のデフォルト以外のアドレスからアクセスできるインスタンスでは、PUBLIC_ORIGIN を設定する必要があります。 これが解決できない場合:
- MCP エンドポイント、2つの
/.well-knownドキュメント、PM エージェントの OAuthredirect_uri、ワーカーの登録、メールによるパスワードリセットは 500 を返します。 - メールアドレスの変更は、確認リンクを作成できないため 503 を返します。
- 通知メール、Slack、Discord のメッセージはリンクなしで送信され、Coda の行には空の Link が設定されます。
意図的な動作です。以前これらの値の代わりに使われていたのは、リクエストヘッダーまたはビルドマシンのアドレスでした。PUBLIC_ORIGIN を設定せずに APP_ORIGIN に2つ目のオリジンを追加した場合も同じ状態になります。リストでは、どの項目がインスタンス自身のアドレスなのかを示せないためです。値は http/https の URL でなければなりません。board.example.com:8443 は、どれほど URL らしく見えても該当しません。
重要
MongoDB は 4.4 に固定されており、ホストポートには公開されていません。アクセスできるのはアプリコンテナだけです。集約処理では、5.0 以降でのみ使える演算子を意図的に避けています。このバージョン固定により、それが維持されます。
構成
Next.js 16(App Router)と TypeScript、Tailwind CSS 4、MongoDB と Mongoose を使用しています。認証には、ブラウザーではセッション Cookie、API クライアントと OAuth では Bearer トークンを使います。ブラウザーにパスワードが保持されることはありません。
src/
app/api/ REST API — ~150 routes, plus the MCP endpoint at /api/mcp
app/ board, task detail, sprints, dashboard, search, settings
components/ kanban/, tasks/, search/, shell/, pm/, settings/, ui/
lib/ auth, notifications, webhooks, custom fields, PM agent, force guard
models/ Mongoose schemas
worker/ execution worker — claims tasks, runs an agent, enforces gates
menubar/ macOS menu bar app
e2e/ Playwright specs
開発
npm test # unit tests (vitest)
npm run test:e2e # end-to-end tests (playwright)
npx tsc --noEmit # types
フィクスチャはデフォルトでは分離されていないため、e2e の実行には専用のポートとデータベースを割り当ててください。
E2E_PORT=3200 PM_STUB_PORT=3201 E2E_MONGODB_URI=mongodb://localhost:27017/local_e2e npx playwright test
Web サイトとドキュメント
board-planner.com は製品の概要を体験できるページです。カードを実際にドラッグできるボード、実行中のワーカーを途中で停止してみる体験、そして拒否するゲートがあります。
board-planner.com/docs は全 33 ページのマニュアルであり、唯一の信頼できる情報源です。board-planner-site リポジトリで管理され、マージ時に公開されるため、掲載ページが製品より遅れることはありません。
| ページ | 内容 |
|---|---|
| Board Planner とは | アイデア、対象ユーザー、対象外となるもの |
| クイックスタート | 最初のプロジェクト、最初のタスク、最初のエージェント |
| PM エージェント | 有効化の方法、変更可能な内容、使用する利用枠 |
| Claude Code と MCP | 46 個のツール、スコープ付きトークン、OAuth コネクター |
| エージェント | ステップ、ゲート、実行時に実際に行われること |
| 実行ワーカー | マシンの登録、ピックアップされるタスク、停止方法 |
| インストールと実行 | すべての環境変数、ビルド、デプロイ |
| REST API | エンドポイント、認証、ページネーション |
ライセンス
Board Planner は、GNU Affero General Public License v3 に基づくフリーソフトウェアです。例外は 1 つのディレクトリである src/ee/ で、商用の Enterprise Edition が含まれています。ライセンスは独自の条件に従い、Board Planner のサブスクリプションまたはライセンスキーがあれば利用できます。ここには有料コネクター(現在は Coda 同期)が含まれており、有料 AI 機能も今後ここに追加されます。それ以外への貢献は歓迎します。詳しくはCONTRIBUTING.mdをご覧ください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。