关于 Board Planner
Board Planner 将看板、冲刺和项目跟踪与 REST API、MCP 服务结合,面向小型团队和编码 Agent。看板、API 与 MCP 共用权限和任务历史;可选 Worker 按设定步骤与关卡执行已批准的任务。
主要功能
- 01看板、冲刺、依赖项和子任务
- 02REST API 与 46 个 MCP 工具
- 03按项目限定的 API 令牌权限
- 04可配置的 Agent 步骤和执行关卡
- 05任务历史、审计记录和六种仪表盘图表
适用场景
- 01协调团队任务和冲刺工作
- 02让编码 Agent 读取并更新指定项目的任务
- 03将已批准任务交给 Worker 并执行设定检查
- 04查看项目进度和任务历史
MCP 相关
应用内置 HTTP MCP 服务,地址为 `POST /api/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 则从另一个方向出发。看板、REST API 和 MCP 服务是进入同一模型的三扇门,背后执行相同的权限检查。Agent 将任务移至 In Review 时,遵循的状态规则与手动拖动卡片的人相同,也会在同一历史记录中留下相同的轨迹。
云端或自托管
使用云端服务时,注册会在 board-planner.com 的专属子域名下创建一个新组织。新组织会获得 30 天 Pro 试用期,无需绑定银行卡;试用结束后转为 Free 方案——最多 10 名成员、无限项目和任务、REST API、MCP 服务,以及可在一台机器上运行的工作进程和 Agent;也可选择 Pro 方案,享有更多成员、不限机器数量、使用我们密钥的每月 AI 额度和 Coda 同步。Agent、工作进程和 API 令牌都不计为成员。
在自己的服务器上,运行 docker compose up 即可创建一个属于自己的组织。Community 版本采用 AGPL-3.0,没有成员或机器数量限制,AI 功能使用你自己的密钥;可自托管的 Pro 版本则增加了 Coda 同步和电子邮件支持。
所有方案均可免费使用自己的密钥运行 AI,且 Free 方案中提供的功能不会转为 Pro。价格和完整对比请见 board-planner.com/pricing。
将工作交给机器
如今有很多工具可以让机器编写代码。Board Planner 关注的是与之相关的一切:谁提出了工作、谁批准了工作、机器获准修改哪些内容、任何改动合入前必须通过哪些检查,以及机器何时停下并将工作交还给你。
这条流程的两端各有一个 Agent:负责提出建议并记录事项的 PM Agent,以及接手已批准任务并执行的工作进程。它们都不会擅自做出你未授权的决定。
PM Agent 是驻留在项目中的项目经理。它会查看看板,发现卡住、重复或缺失的内容,并直接给你带来决策,而不是创建一堆没人要求的工单。它擅长处理那些没人喜欢做的工作:为创建时缺少验收标准的任务编写标准、找出重复项,并说明冲刺的实际进展。
在该截图中,回复下方的徽标就是操作记录——消息和写入操作属于同一条记录,因此你可以看到回复同时修改了 ORB-9,而不只是谈论它。并且,它让任务留在原处,因为这是收到的指示。看板审查会禁用 change_status 和 create_task,因此自动执行流程可以告诉你哪里出了问题,而不会在一夜之间悄悄重新整理你的看板。
它默认关闭,且按项目设置;用量会计量,而不是盲目信任:每次调用都会按组织统计 Token 用量,包括自主执行轮次和你的调用,并计入实例可设定的额度;实例管理员还可以为某个项目锁定关闭此功能,且项目设置无法覆盖该限制。没有 OPENROUTER_API_KEY 时,页面会说明这一点,功能也会保持未启用;AI Assist 使用同一个密钥。
像交接给真人一样把任务交给它
分配任务、指定 Agent,再将任务拖到你认可的列中。这两项合在一起就是交接——未指定 Agent 的任务不会执行,也不会退回到项目默认设置。别人分配给你的任务只是一个提议,并不是已排队等待在你的机器上执行的工作。
Agent 由步骤和关卡组成
Agent 是一个有序的区块列表,且恰好只有两种类型:
| 能否更改内容? | 能否停止运行? | |
|---|---|---|
| 步骤 — 实现、推送、拉取请求、合并 | 是 | 否 |
| 关卡 — 规模、受保护文件、已编写测试、构建、测试通过、已审查 | 否 | 是 |
步骤无法拒绝执行,关卡无法写入,因此所有可能停止运行的区块都是关卡,你可以一目了然地查看它们。
每个步骤都是独立的模型会话。同一 Agent 中的两个步骤共享任务和工作树,除此之外互不共享,这就是为什么先分析,再实现不同于让一个模型同时完成两件事:第二个步骤读取第一个步骤写下的内容,而不是它当时的思考过程。
合并是一个步骤,而不是一个开关。 没有“自动合并”复选框,也没有将合并与审查设置绑定的规则。Agent 会合并,是因为它的执行顺序以 Merge 区块结束;不添加该区块,运行就会在拉取请求处停止。
它附带三个 Agent:默认、带安全审查和合并自己的工作。从未打开编辑器的项目会运行默认 Agent。
机器默认不可信
这是我们花最长时间才做对的部分,也是交接机制能够安全用于真实代码仓库的原因:
| 保证 | 原因 |
|---|---|
| 服务端从不发送路径 | 任务分配只指定任务和 git 远程仓库。工作者会根据自己机器上的文件解析自己的检出目录,因此所有内容的位置都由本地决定。 |
| 只读步骤无法被诱导写入 | Read only 会变成由工作者自行构建的工具列表。看板无法表达这一设置,因此任务中输入的任何提示词都无法授予写入权限。 |
| 机器不支持的检查会中止运行 | 如果关卡指定了未知类型,就会拒绝而非跳过——缺失的检查绝不能被误认为已通过的检查。 |
| 仓库自己的脚本不会未经审核就执行 | 如果某项更改尚未通过 Protected files 读取,编辑器就会拒绝对其执行 Builds 或 Tests-pass 关卡。因此,Agent 刚写好的脚本不会在有人检查它是否获准写入之前运行。 |
| 工作者只持有一个凭证,绝不持有数据库凭证 | 它使用铸造的 cpw_ 凭证注册,通过 REST 与应用通信。执行 Agent 编写代码的机器不该持有数据库凭证。 |
| 它会以你指定的账户推送 | gh auth switch 是开发者机器上的全局状态,因此身份会按工作者固定,而不会留给上次有人切换到的账户。 |
| 被暂挂的任务无法移动 | 运行暂时占用任务期间,任何会让任务离开当前栏目的状态更改都会被拒绝,所有写入途径——看板、编辑表单、MCP、PM Agent——都会返回 409。强行越过限制必须由人操作:任何机器凭证都会被拒绝。 |
| 失败会交由人工处理 | 达到使用限额时,任务会退回且返还本次尝试次数;崩溃则会消耗一次尝试。重复失败最终会耗尽重试次数并停止,而不是无限循环。 |
整个运行过程会实时记录到任务中,因此任务评论就是运行日志——分支、编辑内容、哪个关卡拒绝了操作、剩余的大模型配额。没有旁路,也不必切换到 CI 标签页。
📖 完整说明:Agents ·
Execution workers ·
worker/README.md
看板的其他功能
看板为先
列名由你指定,顺序由你选择。每列都会映射到自动化能够理解的角色
(backlog、approved、active、review、blocked、done),所以将 Up next 重命名为 Ready
不会影响任何功能。任何角色为 review 的列都是自动化的停止标志,工作会在这里等待人工处理。看板支持拖放、列表视图、冲刺、依赖项和子任务、循环任务,还能在应用的任何位置通过 ⌘K 搜索所有任务。
应用会遵循你的系统主题,并且整体采用以下两种模式设计:
一个任务包含工作所需的一切
可逐项勾选完成的验收标准、依赖项、关闭该任务的拉取请求、由你为每个项目定义的自定义字段,以及自任务创建以来的所有评论和更改。将分支命名为 bp-8/dark-mode,拉取请求就会自动找到对应任务。
你的 Agent 使用同一个看板
通过 HTTP 提供的 46 个 MCP 工具可将看板带到你的终端中,让 Claude Code 读取待办事项、认领任务并推进任务——使用的权限与团队成员相同。API 令牌可限定到特定项目,且访问范围由中央统一强制执行,因此 REST 和 MCP 都同样适用。
足以回答周一的问题
你的进展如何、积压了多少事情,以及完成任务的速度是否跟得上启动任务的速度。 六张图表,无需电子表格。
其他功能
可在应用内、通过电子邮件或发送到 Slack 和 Discord 的通知——按用户、项目和事件分别设置。项目 审计跟踪。已签名的 Webhook。关联 GitHub 和 GitLab PR。可在手机上使用。
快速开始
你需要 Docker 和 Compose 2.24 或更新版本——较旧的 Compose 会拒绝文件中的 env_file 条目,即使没有 .env 文件也一样。除此之外不需要任何东西:无需 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 不识别此设置,因此使用 1.1.1 镜像时,除 localhost 以外的任何位置通过普通 HTTP 提供服务都会导致无法登录。若要搭配该文件运行 1.1.1,请在 .env 中设置 COOKIE_ALLOW_INSECURE=1。
从克隆的代码库运行 docker compose up -d --build。 单独运行 docker compose up -d 会拉取并运行最新的已发布版本,而不是你检出的代码;--build 会构建检出的代码并运行它。
打开 http://localhost:3000。在登录页面创建的第一个账户会成为此实例的管理员;此后的所有账户都通过设置 → 用户创建。
创建第一个账户时需要输入设置代码,以防其他人在你之前访问全新的实例并抢先注册。除非你设置了 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 仍会将旧变量作为 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——先从环境变量读取,再依次从 .env.production.local、.env.local、.env.production 和 .env 读取,顺序与 Next 读取这些文件的顺序一致;如果这些位置都没有指定端口,则监听 3000。
连接 Agent
MCP 服务已内置于应用的 POST /api/mcp 端点中——无需克隆,也无需构建。在 设置 → API 令牌 下创建一个令牌,将其范围限定为 Agent 应操作的项目,然后让客户端连接到一个 URL:
{
"mcpServers": {
"boardplanner": {
"type": "http",
"url": "https://your-instance.example.com/api/mcp",
"headers": { "Authorization": "Bearer cp_..." }
}
}
}
共有 46 个工具,按 Agent 常用的操作分组——完整列表以及每个工具的用途,请参阅 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(每次调用最多处理 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 - 人员和 Agent:
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 中安装 Agent 技能:
/plugin install board-planner --marketplace rafalpodles/board-planner
请参阅 Agent 技能。
配置
除数据库外,所有配置均为可选项。将覆盖项放入与 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} | 提供应用服务的来源,以逗号分隔。浏览器未发送 Sec-Fetch-Site 时,系统会结合 PUBLIC_ORIGIN,检查写入请求的 Origin 是否在其中 |
PUBLIC_ORIGIN | NEXT_PUBLIC_APP_URL;否则为 http://localhost:${APP_PORT}(compose);其他情况下,如果 APP_ORIGIN 仅指定一个来源,则使用该来源 | 此实例将其自身视为的唯一地址,也是它发送的所有链接的基址。MCP、PM OAuth 和注册工作器均需要此项 |
BOARD_PLANNER_VERSION | latest | compose 运行的已发布镜像版本 |
BOOTSTRAP_TOKEN | 自动生成并打印到日志 | 创建首个账户时使用的设置码,长度至少为 16 个字符。如果无法读取日志,请自行设置 |
COOKIE_ALLOW_INSECURE | auto(compose);其他情况为关闭 | 1 会签发不带 Secure 属性和 __Host- 前缀的会话 Cookie,供通过普通 HTTP 提供服务的实例使用。auto 仅在 PUBLIC_ORIGIN 和每个 APP_ORIGIN 均为 http://,且登录请求不是通过 https:// 发出时才会这样设置。0、空值或未设置:使用安全 Cookie |
TRUSTED_PROXY_HOPS | 0 | 此应用前方有多少个代理会向 X-Forwarded-For 追加地址 |
ENCRYPTION_KEY | — | 32 字节,使用十六进制或标准 base64 编码(非 base64url),用于加密静态存储的集成令牌和聊天 Webhook URL |
ENCRYPTION_KEYS_OLD | — | 以逗号分隔的已停用密钥,以便轮换密钥后仍可读取旧密钥加密的数据 |
WEBHOOK_SIGNING_SECRET | — | 对发出的 Webhook 投递进行签名 |
AI_MONTHLY_TOKENS、AI_MEMBER_TOKENS、AI_TRIAL_TOKENS、AI_DAILY_PERCENT | — | 组织可使用此实例 AI 密钥的额度,按每次调用消耗的令牌数计算:每个 UTC 月(超过 10 名活跃成员后,每增加一名成员还会增加 AI_MEMBER_TOKENS 额度)、每次试用,以及每天最多可用月额度的 AI_DAILY_PERCENT。超出后,AI 会返回 429,并附上已使用的令牌数及额度续期日期。默认关闭,设置后启用;设为 0 即关闭。组织自己的密钥会计入用量,但不受限制。每个人每 15 分钟还可启动 20 次 AI Assist 生成,每次只能启动一个 |
OPENROUTER_API_KEY、PM_MAX_TOKENS、PM_SCHEDULER_TICK_MS | — | PM Agent 和 AI Assist(任务起草)都使用 OPENROUTER_API_KEY,并共用一个在“设置” → “AI 密钥”中设置的模型。不再读取 OPENAI_API_KEY 和 PM_MODEL |
OPENROUTER_BASE_URL | https://openrouter.ai/api/v1 | PM Agent 和 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 API 的地址,适用于 GitHub Enterprise Server |
COOKIE_ALLOW_INSECURE 和 APP_ORIGIN — 在 TLS 后方运行时,将 PUBLIC_ORIGIN 设为 https 地址
这两个值都是**运行时**值,每次请求都会读取。compose 文件会传入 `COOKIE_ALLOW_INSECURE=auto`,除非 `.env` 中另有设置;空值视为未设置。只有当 `PUBLIC_ORIGIN` 和 `APP_ORIGIN` 中的每一项都是 `http://` 时,`auto` 才会签发非安全 Cookie——也就是 compose 的默认值 `http://localhost`。这是因为浏览器会静默丢弃通过普通 HTTP 传输、且目标不是 localhost 的 `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 匹配。请将其设为用户实际打开的网址,例如 https://board.example.com,或用于局域网自托管的 http://192.168.1.10:3000,且不要带尾部路径。
同样的回退机制也适用于代理或 CDN 剥离 Sec-Fetch-* 标头的情况:只有当 Origin 属于 APP_ORIGIN 或 PUBLIC_ORIGIN 时,写入操作、登录和 OAuth 授权步骤才会通过。应用首次看到带有 Origin 但没有 Sec-Fetch-Site 的请求时,会记录一条警告。
TRUSTED_PROXY_HOPS — 设得过小更糟
此项决定应用是否信任 X-Forwarded-For。失败登录限流只能依据此标头进行;它毕竟只是一个标头:如果应用前面没有代理,调用方每次请求只需更改标头,就能获得新的计数器,限流便形同虚设。因此默认值为 0——完全不读取该标头,匿名调用方共用一个阈值较高的计数桶。
位于反向代理之后时,将其设为会向该标头追加内容的代理数量——请实际测量,不要猜;见下文。前面只有一台 nginx 或 Caddy 时,设为 1。
数量设错会带来两方面的后果。设得过高时,标头会因与配置不符而被拒绝——登录请求随后共用一个计数桶,虽有上限,但会被共同使用;而链接为随机值的路由(密码重置、电子邮件确认)、客户端注册和机器注册都不会计数,应用每十分钟会在日志中提示一次。设得过低时,计数的地址会是代理链写入的地址,而非客户端地址,因此全世界的请求都可能落入同一个计数桶——且应用会将该计数桶视为真实地址,按严格的单地址上限计量,而不是较宽松的匿名上限。
请实际测量,不要猜。 当值为 0 时,向按地址限流的路由发送带有 X-Forwarded-For 的请求——例如登录、密码重置、OAuth 端点、机器注册和账户变更——应用会记录一条警告,说明该标头包含多少项:
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. …
要生成该行日志,请保持变量未设置,并在用户使用的地址处**尝试登录**。密码错误也可以。*加载*页面不会记录任何内容:只有按地址限流时才会读取此标头;在登录路由中,这发生在系统确认用户名和密码均已填写之后。然后从日志中读取计数,将 `TRUSTED_PROXY_HOPS` 设为该值并重启——警告就会消失。
如果 CDN 前面还有一个会做代理的托管平台,日志中可能会有多条记录,因为每一层都会追加一个条目。日志会告诉你具体有多少层;数你付费使用的服务并不能得出跳数,这正是需要实际测量的原因。
只有每个代理都会追加时,计数才是正确的值。 有些代理会替换标头,从而隐藏之前的所有内容——除非在 Caddy 的
trusted_proxies
中指定其前面的代理,否则 Caddy 就会这样做。在 CDN 后面使用这样的代理,日志会显示 1;此时将其设为 1,限流就会依据 CDN 的边缘地址,而不是访客地址——这就是上文提到的“值过低”问题。请先让每个代理都追加,再进行测量。
请从你自己通过完整代理链发出的请求中读取计数。调用方也可以发送该标头,而且通过较短路径访问应用的健康检查或运行时间探测所携带的条目数会少于浏览器请求。因此,应用会报告每个新计数,而不只报告第一个:前四个不同计数会立即记录,之后出现的新计数则要等十分钟才会记录。这个上限可能会被人恶意占满。 应用无法分辨你的登录请求和伪造标头的请求,因此调用方每隔几分钟发送一个新的标头长度,就能持续占用名额,让你的日志行始终无法出现。重启会释放前四个名额,因此可以重启后立即尝试登录——这足以应对缓慢的伪造流量,但如果调用方每秒发送几次请求,就会立刻重新占满名额。此时可靠的做法是消除暴露风险:屏蔽该来源,或从使用相同代理链的预发布部署或本地运行中读取计数。完全不携带地址的标头永远不会被记录,也不会占用四个名额中的任何一个。
IPv6 调用方按其 /64 计数。 /64 子网上的一台主机拥有 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 webhook URL——传入 webhook URL 是一种持有者凭据,任何持有它的人都能以该集成的身份向对应频道发送消息。使用 `openssl rand -hex 32` 生成密钥。没有密钥就无法保存这些字段——应用会在保存时返回错误,而不是以明文写入密钥,并会在启动时说明这一点。**如果某个看板在此实例设置密钥之前就使用了团队频道,这些 URL 仍以明文存储,但现在已不会读取,因此该频道不会发送任何内容,直到运行 `npx tsx scripts/migrate-channel-webhooks.ts` 将它们重写;无论如何,都值得在 Slack 或 Discord 中轮换这些 URL。** 如果已设置密钥,但它不是 32 字节的十六进制或标准 base64,**应用将无法启动**:输错的变量不等于变量缺失,不能当作缺失处理。这也包括 base64url,以及碰巧能解码为 32 字节的口令。如果已使用这样的值保存了密钥,不要生成新密钥——请用以下命令将相同字节转换为十六进制:
`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 无法回答“此实例自己的地址是什么”:它是一个列表,也没有任何信息指出哪个条目是公开地址。只有当它恰好指定一个来源时,才会使用该值;否则不会进行任何猜测。
因此,只要实例可通过 compose 默认地址以外的地址访问,就必须设置 PUBLIC_ORIGIN。 当它解析为空时:
- MCP 端点、两个
/.well-known文档、PM Agent 的 OAuthredirect_uri、工作器注册以及通过邮件进行的密码重置都会返回 500; - 更改电子邮件地址会返回 503,因为无法生成确认链接;
- 通知邮件、Slack 和 Discord 消息仍会发送,但不包含链接;Coda 行中的 Link 则为空。
这是有意为之:这些内容过去回退使用的值来自请求标头或构建机器上的地址。如果只在 APP_ORIGIN 中添加第二个来源,却不设置 PUBLIC_ORIGIN,也会出现这种情况,因为列表无法指出哪个条目是实例自己的地址。它必须是一个 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 运行分配专属端口和数据库,因为 fixture 默认并非隔离:
E2E_PORT=3200 PM_STUB_PORT=3201 E2E_MONGODB_URI=mongodb://localhost:27017/local_e2e npx playwright test
网站和文档
board-planner.com 是产品导览:你可以实际拖动卡片的看板、可以尝试中断正在运行的工作进程,以及会拒绝请求的关卡。
board-planner.com/docs 是使用手册,共三十三页,也是唯一可信来源:文档位于 board-planner-site 仓库中,合并后即会发布,因此文档页面始终与产品同步。
| 页面 | 内容 |
|---|---|
| 什么是 Board Planner | 核心理念、适用人群,以及它不是什么 |
| 快速入门 | 第一个项目、第一个任务、第一个 Agent |
| PM Agent | 如何启用、它可以更改什么,以及它使用的额度 |
| Claude Code 和 MCP | 四十六种工具、作用域令牌、OAuth 连接器 |
| Agents | 步骤、关卡,以及一次运行实际会做什么 |
| 执行工作进程 | 注册机器、哪些任务会被选取,以及如何停止工作进程 |
| 安装和运行 | 所有环境变量、构建和部署 |
| REST API | 端点、身份验证、分页 |
许可证
Board Planner 是基于 GNU Affero General Public License v3 发布的自由软件。有一个目录例外:src/ee/ 是商业版 Enterprise Edition,依据其自身条款授权,可通过 Board Planner 订阅或许可证密钥使用。它包含付费连接器,目前有 Coda 同步功能;付费 AI 功能也将放在这里。欢迎为其他所有内容贡献代码,详见 CONTRIBUTING.md。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。