api.md 4.89 KB

REST API + 代码骨架

新增 5 个 REST 端点,全部挂在 /api/devloop/*。骨架代码合计约 700 行,分布在 3 个新文件 + 1 处修改。

端点清单

方法 路径 说明 触发的 Loop
POST /api/devloop/projects 创建项目,传入初始需求 L3 启动
POST /api/devloop/projects/:pid/requirement 追加人类反馈,触发 PRD 增量更新 L3
POST /api/devloop/projects/:pid/run 启动 / 续跑 LoopController L1 + L2
GET /api/devloop/projects/:pid/state 返回 units.json + 当前 loop 阶段 UI 轮询
GET /api/devloop/projects/:pid/stream SSE — 实时推送 Agent 输出 / 状态变更 UI 流式
POST /api/devloop/projects/:pid/sign-off 人类显式 sign-off,状态置 shipped-final L3 终止
POST /api/devloop/projects/:pid/abandon 放弃项目(保留数据,从列表移除) L3 终止

Request / Response 示例

create requirement (L3) state SSE stream

# 创建项目
# 严格按 CLAUDE.md 警告:先写 /tmp/req.json,再 -d @file
curl -X POST http://localhost:3010/api/devloop/projects \
  -H "Content-Type: application/json" \
  -d @/tmp/create.json

# /tmp/create.json — 单行紧凑
{"company_id":"c-lemonv-001","name":"Auto Auth System","requirement":"需要一个邮箱密码登录的系统"}

# 响应
{
  "project_id": "p-731042",
  "status": "prd_drafting",
  "stream_url": "/api/devloop/projects/p-731042/stream"
}
# 追加新需求
curl -X POST http://localhost:3010/api/devloop/projects/p-731042/requirement \
  -H "Content-Type: application/json" \
  -d @/tmp/feedback.json

# /tmp/feedback.json
{"text":"再加 GitHub OAuth","origin":"yibo"}

# 响应(即刻返回,PM 是异步跑)
{
  "accepted": true,
  "queued_rev": 3,
  "eta_seconds": 30
}
# 查询状态
curl http://localhost:3010/api/devloop/projects/p-731042/state

{
  "project_id": "p-731042",
  "prd_rev": "3",
  "sdd_rev": "5",
  "current_loop": "L1",
  "units": [
    { "id": "auth-be",    "status": "passed"  },
    { "id": "auth-fe",    "status": "testing" },
    { "id": "oauth-be",   "status": "pending" }
  ],
  "l2_rounds": 0,
  "l2_budget": 3,
  "agents_active": ["tester:auth-fe"]
}
# SSE 流(浏览器或 curl --no-buffer)
curl -N http://localhost:3010/api/devloop/projects/p-731042/stream

event: unit.state
data: {"unit_id":"auth-fe","from":"coding","to":"testing"}

event: agent.stream
data: {"agent":"tester","unit_id":"auth-fe","chunk":"PASS tests/login.spec.ts > valid creds\n"}

event: agent.stream
data: {"agent":"tester","unit_id":"auth-fe","chunk":"FAIL tests/login.spec.ts > invalid pwd\n"}

event: unit.state
data: {"unit_id":"auth-fe","from":"testing","to":"failed","retries":1}

event: prd.updated
data: {"rev":4,"changeSummary":"+ NFR: session timeout 1h"}

routes/devloop.js 骨架

// server/routes/devloop.js  · NEW · ~200 行
const express = require('express');
const { loopController } = require('../src/core/loop-controller');
const { docStore }       = require('../services/doc-store');
const { unitRegistry }   = require('../services/unit-registry');
const { sseBroker }      = require('../services/sse-broker');

const router = express.Router();

router.post('/projects', async (req, res) => {
  const { company_id, name, requirement } = req.body;
  const pid = await loopController.createProject({ company_id, name });
  loopController.onHumanFeedback(pid, { text: requirement, origin: req.user?.id });
  res.json({ project_id: pid, status: 'prd_drafting',
              stream_url: `/api/devloop/projects/${pid}/stream` });
});

router.post('/projects/:pid/requirement', async (req, res) => {
  loopController.onHumanFeedback(req.params.pid, req.body);
  res.json({ accepted: true });
});

router.get('/projects/:pid/state', (req, res) => {
  res.json(loopController.getState(req.params.pid));
});

router.get('/projects/:pid/stream', (req, res) => {
  sseBroker.subscribe(req.params.pid, req, res);
});

module.exports = router;

挂载到 server/index.js

仅 1 行改动:

// server/index.js 第 90 行后追加
app.use('/api/devloop', require('./routes/devloop'));

认证

沿用 routes/auth.js 的 JWT 中间件:

  • POST 类端点:必须带 Authorization: Bearer <jwt>,校验 req.user.company_id 与 path 中的 cid 匹配。
  • GET state / stream:同上。
  • Open API 调用(无人类 cookie,纯 server-to-server):使用现有的 OPEN_API_KEYS 环境变量 + X-API-Key header。

初版不做 RBAC(任何登录用户都能创建项目)。多用户隔离靠 cid。这是已知简化,P5 再加。