06 · API/REST + 骨架

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启动 / 续跑 LoopControllerL1 + L2
GET/api/devloop/projects/:pid/state返回 units.json + 当前 loop 阶段UI 轮询
GET/api/devloop/projects/:pid/streamSSE — 实时推送 Agent 输出 / 状态变更UI 流式
POST/api/devloop/projects/:pid/sign-off人类显式 sign-off,状态置 shipped-finalL3 终止
POST/api/devloop/projects/:pid/abandon放弃项目(保留数据,从列表移除)L3 终止

Request / Response 示例

# 创建项目
# 严格按 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"
}

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 再加。