内容
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/logo-dark.svg">
<img src="docs/logo.svg" alt="aeman" width="300">
</picture>
</p>
# aeman
aeman 是一个为工程团队提供短期规划的系统,它可以帮助工程师保持专注,每天进行冲刺,并使计划外的工作可见。**GitHub Projects v2 作为存储**,因此 aeman 没有自己的数据库。整个系统打包成一个独立的 Go 二进制文件:一个嵌入式 React 单页应用(通过 `go:embed`),一个 JSON REST API,一个 WebSocket **监视** 流,用于保持每个打开的看板实时更新,以及一个用于 AI 代理的 MCP 服务器 — 所有这些都驱动同一个看板服务,以 GitHub 作为单一的事实来源。
## 概念
两种互补的视图 — 个人日看板和团队看板:
- **我** — 您的个人日看板。您在选定日期的卡片,按四个颜色区域堆叠,右侧有可编辑的笔记日志。您还可以 **以** 另一个人的身份查看,以查看(和操作)他们的看板,只需单击一下即可恢复到您自己。
- **灰色** — 常规的、计划内的工作。
- **绿色** — 在其他区域清空后才开始。
- **黄色** — 在当天弹出的计划外工作。
- **红色** — 必须在当天结束前解决。
- **团队** — 团队看板:选定日期的按人 × 区域网格,按团队过滤。列是人员(带有 GitHub 头像和姓名),行是相同的颜色区域。列可以拖动或打乱,人员即使在没有卡片的日子里也可以保留一列。
每个卡片都带有 **准备度滑块** (0-100%),一个 **阶段** (锁定/审查/重复/完成),它会重新着色条形,一个可选的 **团队** ,一个年龄计数器,以及链接回其源问题的链接。单击卡片的头像以重新分配其团队或人员,或单击日期计数器以编辑其日期。故意没有内置的时间跟踪器。
每个打开的看板都是 **实时的** :队友的编辑 — 或 AI 代理通过 MCP 的编辑 — 会在大约一秒钟内出现在每个人的屏幕上,无需重新加载。
### 冲刺
冲刺是开放式的,由人工推进: **延续** 开始团队的新冲刺,开始于今天,并将未完成的卡片向前推进(也有一个 *无团队* 组)。卡片上有两个日期 — 它所属的冲刺(**冲刺开始** )和它实际开始的日期(**开始** ,作为历史记录) — 因此团队看板会在冲刺日期、当天创建的日期以及冲刺通过的过去日期显示它。 **+1 天 / +1 周** 将卡片从今天开始延期,隐藏它直到其新日期,而不会丢失历史记录。当前冲刺按团队跟踪,因此工程师在多个团队中可以看到每个团队的当前卡片。完整的日期模型位于 [docs/dates.md](docs/dates.md)。
### 每周团队计划
在团队网格下方是一个每周计划:分配给团队的业务任务,分为两组(按星期三/星期五)。团队负责人将计划卡拖到团队成员上以将其投入工作 — 相同的卡然后在网格中显示,同时保留在计划中,用彩色左侧条标记。细的整体进度条跟踪计划的完成情况,每个周的 **延续** 将未完成的计划卡移到下一周 — 一个独立于每日冲刺的周期。
## 架构
```
┌──────────────────────────────────────────────┐ ┌──────────────────────┐
│ aeman 二进制文件(Go) │ │ GitHub Projects v2 │
│ │ │ (数据后端) │
│ 嵌入式 SPA ───► REST /api/v1 ──┐ │ │ │
│ ▲ │ 看板 │ gh │ │
│ └──── WS /api/v1/watch ◄────┤ 服务 ┼────────┼─► GraphQL API │
│ │ + 缓存 │ token │ │
│ AI 代理 ───► MCP(stdio,/mcp)─┘ │ │ │
└──────────────────────────────────────────────┘ └──────────────────────┘
```
- **Kubernetes 风格的 API 和实时同步** :卡片、冲刺、笔记和看板顺序都是资源(`{kind, metadata, spec, status}`);客户端列出它们(`GET /api/v1/cards`),然后通过 WebSocket 应用 `ADDED / MODIFIED / DELETED` 资源事件的监视流 — 可选地通过相同的选择器限定在某个视图上。每次写入 — 从 UI、REST API 或通过 MCP 的代理 — 都通过具有共享内存存储的看板服务,重新加载仅触及的卡片,并在大约一秒钟内到达每个打开的看板(客户端自己的更改不会回声到它)。
- 存储仅是缓存:GitHub 仍然是事实来源和唯一的持久性。
- 浏览器从不持有令牌:二进制文件在服务器端解析一个(本地 `gh auth token` ,或在自托管模式下按用户 OAuth 会话),用于看板服务和用于配置文件查找的 `/api/github/*` 代理。
- 前端保留一个小型提供者接口(REST 提供者是默认的;直接 GraphQL 提供者仍然作为参考),因此可以添加其他后端(GitLab,Redmine,…)。
### 字段
aeman 将其所有状态保存在 GitHub 项目字段中,**并根据需要延迟创建它们** :指向任何项目,第一个卡片或团队更改都会提供缺少的字段(区域、进度、阶段、团队、开始、冲刺开始、日期、计划、周)。无需手动设置。
## 要求
- [GitHub CLI(`gh`)](https://cli.github.com/) 已通过 `project` 和 `repo` 范围认证(`gh auth login`)。
- Go 1.26+ 和 Node.js 20+ 来从源代码构建。
## 构建和运行
```sh
make build # 构建 SPA,然后是单个二进制文件
./aeman serve # 启动服务器并打开 UI
```
在开发过程中:
```sh
make frontend # 将 SPA 构建到 web/dist
make run # go run ./cmd/aeman serve
```
`aeman serve` 标志:`--addr` (监听地址),`--owner` (默认组织/用户),`--project` (默认项目编号),`--lock-board` (固定看板并忽略客户端提供的属主/项目),`--open` (打开浏览器),`--verbose` 。属主/项目/锁定看板的默认值也可以通过 `AEMAN_OWNER` , `AEMAN_PROJECT` 和 `AEMAN_LOCK_BOARD` 设置。
## API 和 MCP 服务器
同一个二进制文件通过三种方式驱动看板:嵌入式 UI, `/api/v1` 下的 JSON HTTP API,以及用于 AI 代理的 MCP 服务器(`aeman mcp` 在 stdio 上,或在自托管 OAuth 模式下安装在 `/mcp` )。所有这些都调用同一个看板服务,因此代理所做的更改会实时显示在每个打开的看板上。 `GET /api/v1` 返回每个端点的机器可读目录;有关端点、卡片模型、监视协议、MCP 工具集和客户端配置,请参见 [docs/api.md](docs/api.md) 。看板逻辑本身是可导入的: `pkg/` 下的包(域规则、看板服务、GitHub 后端、MCP 工具集)允许外部工具 — 例如本地的、保护隐私的 MCP 服务器,直接与 GitHub 通信 — 运行完全相同的看板合约;请参见 [docs/embedding.md](docs/embedding.md) 。
```sh
aeman mcp --owner acme --project 7 # 在 stdio 上启动 MCP 服务器
```
## 自托管部署(多用户)
对于一个共享实例,每个访问者都使用 GitHub 登录并使用自己的令牌,设置 OAuth 环境变量和二进制开关,从本地 `gh` 模式切换到 GitHub OAuth 网页流和按用户会话:
- `AEMAN_GITHUB_CLIENT_ID` / `AEMAN_GITHUB_CLIENT_SECRET` — 来自 GitHub OAuth 应用。
- `AEMAN_BASE_URL` — 公共源;回调是 `<AEMAN_BASE_URL>/auth/callback` 。
- `AEMAN_SCOPES` — OAuth 范围(默认 `repo project` )。
`docker-compose.yml` (aeman + Caddy 带有自动 HTTPS)和分步指南位于 [docs/deploy.md](docs/deploy.md) 中:
```sh
cp .env.example .env # 填写 OAuth + 隧道值
docker compose up -d --build
```
## 许可证
[Apache License 2.0](LICENSE)。